2 Copyright (C) 2012-2017 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/>.
21 /** @file src/full_config_dialog.cc
22 * @brief A dialogue to edit all DCP-o-matic configuration.
25 #include "full_config_dialog.h"
27 #include "editable_list.h"
28 #include "filter_dialog.h"
29 #include "dir_picker_ctrl.h"
30 #include "file_picker_ctrl.h"
31 #include "isdcf_metadata_dialog.h"
32 #include "server_dialog.h"
33 #include "make_chain_dialog.h"
34 #include "email_dialog.h"
35 #include "name_format_editor.h"
36 #include "nag_dialog.h"
37 #include "config_move_dialog.h"
38 #include "config_dialog.h"
39 #include "lib/config.h"
40 #include "lib/ratio.h"
41 #include "lib/filter.h"
42 #include "lib/dcp_content_type.h"
45 #include "lib/cross.h"
46 #include "lib/exceptions.h"
47 #include <dcp/locale_convert.h>
48 #include <dcp/exceptions.h>
49 #include <dcp/certificate_chain.h>
50 #include <wx/stdpaths.h>
51 #include <wx/preferences.h>
52 #include <wx/spinctrl.h>
53 #include <wx/filepicker.h>
55 #include <boost/filesystem.hpp>
56 #include <boost/foreach.hpp>
67 using boost::shared_ptr;
68 using boost::function;
69 using boost::optional;
70 using dcp::locale_convert;
72 class FullGeneralPage : public GeneralPage
75 FullGeneralPage (wxSize panel_size, int border)
76 : GeneralPage (panel_size, border)
82 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
83 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
86 add_language_controls (table, r);
88 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
89 _master_encoding_threads = new wxSpinCtrl (_panel);
90 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
93 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
94 _server_encoding_threads = new wxSpinCtrl (_panel);
95 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
98 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
99 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true);
100 table->Add (_config_file, wxGBPosition (r, 1));
103 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
104 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true);
105 table->Add (_cinemas_file, wxGBPosition (r, 1));
108 add_play_sound_controls (table, r);
110 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
111 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
112 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
116 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
117 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
120 add_update_controls (table, r);
122 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
123 bottom_table->AddGrowableCol (1, 1);
125 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
126 _issuer = new wxTextCtrl (_panel, wxID_ANY);
127 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
129 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
130 _creator = new wxTextCtrl (_panel, wxID_ANY);
131 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
133 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
136 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::config_file_changed, this));
137 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::cinemas_file_changed, this));
139 _master_encoding_threads->SetRange (1, 128);
140 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
141 _server_encoding_threads->SetRange (1, 128);
142 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
144 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
145 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
147 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
149 _issuer->Bind (wxEVT_TEXT, boost::bind (&FullGeneralPage::issuer_changed, this));
150 _creator->Bind (wxEVT_TEXT, boost::bind (&FullGeneralPage::creator_changed, this));
153 void config_changed ()
155 Config* 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 (_issuer, config->dcp_issuer ());
164 checked_set (_creator, config->dcp_creator ());
165 checked_set (_config_file, config->config_file());
166 checked_set (_cinemas_file, config->cinemas_file());
168 GeneralPage::config_changed ();
172 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
173 void analyse_ebur128_changed ()
175 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
179 void automatic_audio_analysis_changed ()
181 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
184 void master_encoding_threads_changed ()
186 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue ());
189 void server_encoding_threads_changed ()
191 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue ());
194 void issuer_changed ()
196 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
199 void creator_changed ()
201 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
204 void config_file_changed ()
206 Config* config = Config::instance();
207 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
208 if (new_file == config->config_file()) {
211 bool copy_and_link = true;
212 if (boost::filesystem::exists(new_file)) {
213 ConfigMoveDialog* d = new ConfigMoveDialog (_panel, new_file);
214 if (d->ShowModal() == wxID_OK) {
215 copy_and_link = false;
222 if (new_file != config->config_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 wxCheckBox* _analyse_ebur128;
242 wxCheckBox* _automatic_audio_analysis;
244 wxTextCtrl* _creator;
247 class DefaultsPage : public StandardPage
250 DefaultsPage (wxSize panel_size, int border)
251 : StandardPage (panel_size, border)
254 wxString GetName () const
256 return _("Defaults");
260 wxBitmap GetLargeIcon () const
262 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
269 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
270 table->AddGrowableCol (1, 1);
271 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
274 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
275 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
276 _still_length = new wxSpinCtrl (_panel);
277 s->Add (_still_length);
278 add_label_to_sizer (s, _panel, _("s"), false);
282 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
283 #ifdef DCPOMATIC_USE_OWN_PICKER
284 _directory = new DirPickerCtrl (_panel);
286 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
288 table->Add (_directory, 1, wxEXPAND);
290 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
291 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
292 table->Add (_isdcf_metadata_button);
294 add_label_to_sizer (table, _panel, _("Default container"), true);
295 _container = new wxChoice (_panel, wxID_ANY);
296 table->Add (_container);
298 add_label_to_sizer (table, _panel, _("Default scale-to"), true);
299 _scale_to = new wxChoice (_panel, wxID_ANY);
300 table->Add (_scale_to);
302 add_label_to_sizer (table, _panel, _("Default content type"), true);
303 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
304 table->Add (_dcp_content_type);
306 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
307 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
308 table->Add (_dcp_audio_channels);
311 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
312 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
313 _j2k_bandwidth = new wxSpinCtrl (_panel);
314 s->Add (_j2k_bandwidth);
315 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
320 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
321 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
322 _audio_delay = new wxSpinCtrl (_panel);
323 s->Add (_audio_delay);
324 add_label_to_sizer (s, _panel, _("ms"), false);
328 add_label_to_sizer (table, _panel, _("Default standard"), true);
329 _standard = new wxChoice (_panel, wxID_ANY);
330 table->Add (_standard);
332 add_label_to_sizer (table, _panel, _("Default KDM directory"), true);
333 #ifdef DCPOMATIC_USE_OWN_PICKER
334 _kdm_directory = new DirPickerCtrl (_panel);
336 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
338 table->Add (_kdm_directory, 1, wxEXPAND);
340 _still_length->SetRange (1, 3600);
341 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
343 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
344 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
346 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
348 BOOST_FOREACH (Ratio const * i, Ratio::containers()) {
349 _container->Append (std_to_wx(i->container_nickname()));
352 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
354 _scale_to->Append (_("Guess from content"));
356 BOOST_FOREACH (Ratio const * i, Ratio::all()) {
357 _scale_to->Append (std_to_wx(i->image_nickname()));
360 _scale_to->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::scale_to_changed, this));
362 BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) {
363 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
366 setup_audio_channels_choice (_dcp_audio_channels, 2);
368 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
369 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
371 _j2k_bandwidth->SetRange (50, 250);
372 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
374 _audio_delay->SetRange (-1000, 1000);
375 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
377 _standard->Append (_("SMPTE"));
378 _standard->Append (_("Interop"));
379 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
382 void config_changed ()
384 Config* config = Config::instance ();
386 vector<Ratio const *> containers = Ratio::containers ();
387 for (size_t i = 0; i < containers.size(); ++i) {
388 if (containers[i] == config->default_container ()) {
389 _container->SetSelection (i);
393 vector<Ratio const *> ratios = Ratio::all ();
394 for (size_t i = 0; i < ratios.size(); ++i) {
395 if (ratios[i] == config->default_scale_to ()) {
396 _scale_to->SetSelection (i + 1);
400 if (!config->default_scale_to()) {
401 _scale_to->SetSelection (0);
404 vector<DCPContentType const *> const ct = DCPContentType::all ();
405 for (size_t i = 0; i < ct.size(); ++i) {
406 if (ct[i] == config->default_dcp_content_type ()) {
407 _dcp_content_type->SetSelection (i);
411 checked_set (_still_length, config->default_still_length ());
412 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
413 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
414 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
415 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
416 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
417 checked_set (_audio_delay, config->default_audio_delay ());
418 checked_set (_standard, config->default_interop() ? 1 : 0);
421 void j2k_bandwidth_changed ()
423 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
426 void audio_delay_changed ()
428 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
431 void dcp_audio_channels_changed ()
433 int const s = _dcp_audio_channels->GetSelection ();
434 if (s != wxNOT_FOUND) {
435 Config::instance()->set_default_dcp_audio_channels (
436 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
441 void directory_changed ()
443 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
446 void kdm_directory_changed ()
448 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
451 void edit_isdcf_metadata_clicked ()
453 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
455 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
459 void still_length_changed ()
461 Config::instance()->set_default_still_length (_still_length->GetValue ());
464 void container_changed ()
466 vector<Ratio const *> ratio = Ratio::containers ();
467 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
470 void scale_to_changed ()
472 int const s = _scale_to->GetSelection ();
474 Config::instance()->set_default_scale_to (0);
476 vector<Ratio const *> ratio = Ratio::all ();
477 Config::instance()->set_default_scale_to (ratio[s - 1]);
481 void dcp_content_type_changed ()
483 vector<DCPContentType const *> ct = DCPContentType::all ();
484 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
487 void standard_changed ()
489 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
492 wxSpinCtrl* _j2k_bandwidth;
493 wxSpinCtrl* _audio_delay;
494 wxButton* _isdcf_metadata_button;
495 wxSpinCtrl* _still_length;
496 #ifdef DCPOMATIC_USE_OWN_PICKER
497 DirPickerCtrl* _directory;
498 DirPickerCtrl* _kdm_directory;
500 wxDirPickerCtrl* _directory;
501 wxDirPickerCtrl* _kdm_directory;
503 wxChoice* _container;
505 wxChoice* _dcp_content_type;
506 wxChoice* _dcp_audio_channels;
510 class EncodingServersPage : public StandardPage
513 EncodingServersPage (wxSize panel_size, int border)
514 : StandardPage (panel_size, border)
517 wxString GetName () const
523 wxBitmap GetLargeIcon () const
525 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
532 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
533 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
535 vector<string> columns;
536 columns.push_back (wx_to_std (_("IP address / host name")));
537 _servers_list = new EditableList<string, ServerDialog> (
540 boost::bind (&Config::servers, Config::instance()),
541 boost::bind (&Config::set_servers, Config::instance(), _1),
542 boost::bind (&EncodingServersPage::server_column, this, _1)
545 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
547 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
550 void config_changed ()
552 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
553 _servers_list->refresh ();
556 void use_any_servers_changed ()
558 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
561 string server_column (string s)
566 wxCheckBox* _use_any_servers;
567 EditableList<string, ServerDialog>* _servers_list;
570 class TMSPage : public StandardPage
573 TMSPage (wxSize panel_size, int border)
574 : StandardPage (panel_size, border)
577 wxString GetName () const
583 wxBitmap GetLargeIcon () const
585 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
592 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
593 table->AddGrowableCol (1, 1);
594 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
596 add_label_to_sizer (table, _panel, _("Protocol"), true);
597 _tms_protocol = new wxChoice (_panel, wxID_ANY);
598 table->Add (_tms_protocol, 1, wxEXPAND);
600 add_label_to_sizer (table, _panel, _("IP address"), true);
601 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
602 table->Add (_tms_ip, 1, wxEXPAND);
604 add_label_to_sizer (table, _panel, _("Target path"), true);
605 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
606 table->Add (_tms_path, 1, wxEXPAND);
608 add_label_to_sizer (table, _panel, _("User name"), true);
609 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
610 table->Add (_tms_user, 1, wxEXPAND);
612 add_label_to_sizer (table, _panel, _("Password"), true);
613 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
614 table->Add (_tms_password, 1, wxEXPAND);
616 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
617 _tms_protocol->Append (_("FTP (for Dolby)"));
619 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
620 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
621 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
622 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
623 _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
626 void config_changed ()
628 Config* config = Config::instance ();
630 checked_set (_tms_protocol, config->tms_protocol ());
631 checked_set (_tms_ip, config->tms_ip ());
632 checked_set (_tms_path, config->tms_path ());
633 checked_set (_tms_user, config->tms_user ());
634 checked_set (_tms_password, config->tms_password ());
637 void tms_protocol_changed ()
639 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
642 void tms_ip_changed ()
644 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
647 void tms_path_changed ()
649 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
652 void tms_user_changed ()
654 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
657 void tms_password_changed ()
659 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
662 wxChoice* _tms_protocol;
664 wxTextCtrl* _tms_path;
665 wxTextCtrl* _tms_user;
666 wxTextCtrl* _tms_password;
675 class KDMEmailPage : public StandardPage
679 KDMEmailPage (wxSize panel_size, int border)
681 /* We have to force both width and height of this one */
682 : StandardPage (wxSize (480, 128), border)
684 : StandardPage (panel_size, border)
688 wxString GetName () const
690 return _("KDM Email");
694 wxBitmap GetLargeIcon () const
696 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
703 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
704 table->AddGrowableCol (1, 1);
705 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
707 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
709 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
710 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
711 s->Add (_mail_server, 1, wxEXPAND | wxALL);
712 add_label_to_sizer (s, _panel, _("port"), false);
713 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
714 _mail_port->SetRange (0, 65535);
716 table->Add (s, 1, wxEXPAND | wxALL);
719 add_label_to_sizer (table, _panel, _("Mail user name"), true);
720 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
721 table->Add (_mail_user, 1, wxEXPAND | wxALL);
723 add_label_to_sizer (table, _panel, _("Mail password"), true);
724 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
725 table->Add (_mail_password, 1, wxEXPAND | wxALL);
727 add_label_to_sizer (table, _panel, _("Subject"), true);
728 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
729 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
731 add_label_to_sizer (table, _panel, _("From address"), true);
732 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
733 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
735 vector<string> columns;
736 columns.push_back (wx_to_std (_("Address")));
737 add_label_to_sizer (table, _panel, _("CC addresses"), true);
738 _kdm_cc = new EditableList<string, EmailDialog> (
741 bind (&Config::kdm_cc, Config::instance()),
742 bind (&Config::set_kdm_cc, Config::instance(), _1),
745 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
747 add_label_to_sizer (table, _panel, _("BCC address"), true);
748 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
749 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
751 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
752 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
754 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
755 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
759 _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
760 _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
761 _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
762 _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
763 _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
764 _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
765 _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
766 _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
767 _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
770 void config_changed ()
772 Config* config = Config::instance ();
774 checked_set (_mail_server, config->mail_server ());
775 checked_set (_mail_port, config->mail_port ());
776 checked_set (_mail_user, config->mail_user ());
777 checked_set (_mail_password, config->mail_password ());
778 checked_set (_kdm_subject, config->kdm_subject ());
779 checked_set (_kdm_from, config->kdm_from ());
780 checked_set (_kdm_bcc, config->kdm_bcc ());
781 checked_set (_kdm_email, Config::instance()->kdm_email ());
784 void mail_server_changed ()
786 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
789 void mail_port_changed ()
791 Config::instance()->set_mail_port (_mail_port->GetValue ());
794 void mail_user_changed ()
796 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
799 void mail_password_changed ()
801 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
804 void kdm_subject_changed ()
806 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
809 void kdm_from_changed ()
811 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
814 void kdm_bcc_changed ()
816 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
819 void kdm_email_changed ()
821 if (_kdm_email->GetValue().IsEmpty ()) {
822 /* Sometimes we get sent an erroneous notification that the email
823 is empty; I don't know why.
827 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
830 void reset_kdm_email ()
832 Config::instance()->reset_kdm_email ();
833 checked_set (_kdm_email, Config::instance()->kdm_email ());
836 wxTextCtrl* _mail_server;
837 wxSpinCtrl* _mail_port;
838 wxTextCtrl* _mail_user;
839 wxTextCtrl* _mail_password;
840 wxTextCtrl* _kdm_subject;
841 wxTextCtrl* _kdm_from;
842 EditableList<string, EmailDialog>* _kdm_cc;
843 wxTextCtrl* _kdm_bcc;
844 wxTextCtrl* _kdm_email;
845 wxButton* _reset_kdm_email;
848 class CoverSheetPage : public StandardPage
852 CoverSheetPage (wxSize panel_size, int border)
854 /* We have to force both width and height of this one */
855 : StandardPage (wxSize (480, 128), border)
857 : StandardPage (panel_size, border)
861 wxString GetName () const
863 return _("Cover Sheet");
867 wxBitmap GetLargeIcon () const
869 return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE);
876 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
877 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
879 _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
880 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
882 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
883 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
886 void config_changed ()
888 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
891 void cover_sheet_changed ()
893 if (_cover_sheet->GetValue().IsEmpty ()) {
894 /* Sometimes we get sent an erroneous notification that the cover sheet
895 is empty; I don't know why.
899 Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ()));
902 void reset_cover_sheet ()
904 Config::instance()->reset_cover_sheet ();
905 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
908 wxTextCtrl* _cover_sheet;
909 wxButton* _reset_cover_sheet;
913 /** @class AdvancedPage
914 * @brief Advanced page of the preferences dialog.
916 class AdvancedPage : public StockPage
919 AdvancedPage (wxSize panel_size, int border)
920 : StockPage (Kind_Advanced, panel_size, border)
921 , _maximum_j2k_bandwidth (0)
922 , _allow_any_dcp_frame_rate (0)
923 , _only_servers_encode (0)
928 , _log_debug_decode (0)
929 , _log_debug_encode (0)
930 , _log_debug_email (0)
934 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
936 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
938 flags |= wxALIGN_RIGHT;
941 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
942 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
947 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
948 table->AddGrowableCol (1, 1);
949 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
952 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
953 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
954 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
955 s->Add (_maximum_j2k_bandwidth, 1);
956 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
960 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
961 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
962 table->AddSpacer (0);
964 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
965 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
966 table->AddSpacer (0);
969 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true);
970 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
971 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
972 s->Add (_frames_in_memory_multiplier, 1);
977 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
978 dcp::NameFormat::Map titles;
979 titles['t'] = "type (cpl/pkl)";
980 dcp::NameFormat::Map examples;
981 examples['t'] = "cpl";
982 _dcp_metadata_filename_format = new NameFormatEditor (
983 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
985 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
989 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
990 dcp::NameFormat::Map titles;
991 titles['t'] = "type (j2c/pcm/sub)";
992 titles['r'] = "reel number";
993 titles['n'] = "number of reels";
994 titles['c'] = "content filename";
995 dcp::NameFormat::Map examples;
996 examples['t'] = "j2c";
999 examples['c'] = "myfile.mp4";
1000 _dcp_asset_filename_format = new NameFormatEditor (
1001 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1003 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1007 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1008 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1009 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1010 t->Add (_log_general, 1, wxEXPAND | wxALL);
1011 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1012 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1013 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1014 t->Add (_log_error, 1, wxEXPAND | wxALL);
1015 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1016 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1017 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1018 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1019 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1020 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1021 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1022 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1023 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1024 table->Add (t, 0, wxALL, 6);
1027 #ifdef DCPOMATIC_WINDOWS
1028 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1029 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1030 table->AddSpacer (0);
1033 _maximum_j2k_bandwidth->SetRange (1, 1000);
1034 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1035 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1036 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1037 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1038 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1039 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1040 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1041 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1042 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1043 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1044 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1045 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1046 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1047 #ifdef DCPOMATIC_WINDOWS
1048 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1052 void config_changed ()
1054 Config* config = Config::instance ();
1056 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1057 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1058 checked_set (_only_servers_encode, config->only_servers_encode ());
1059 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1060 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1061 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1062 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1063 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1064 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1065 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1066 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1067 #ifdef DCPOMATIC_WINDOWS
1068 checked_set (_win32_console, config->win32_console());
1072 void maximum_j2k_bandwidth_changed ()
1074 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1077 void frames_in_memory_multiplier_changed ()
1079 Config::instance()->set_frames_in_memory_multiplier (_frames_in_memory_multiplier->GetValue());
1082 void allow_any_dcp_frame_rate_changed ()
1084 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1087 void only_servers_encode_changed ()
1089 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1092 void dcp_metadata_filename_format_changed ()
1094 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1097 void dcp_asset_filename_format_changed ()
1099 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1105 if (_log_general->GetValue ()) {
1106 types |= LogEntry::TYPE_GENERAL;
1108 if (_log_warning->GetValue ()) {
1109 types |= LogEntry::TYPE_WARNING;
1111 if (_log_error->GetValue ()) {
1112 types |= LogEntry::TYPE_ERROR;
1114 if (_log_timing->GetValue ()) {
1115 types |= LogEntry::TYPE_TIMING;
1117 if (_log_debug_decode->GetValue ()) {
1118 types |= LogEntry::TYPE_DEBUG_DECODE;
1120 if (_log_debug_encode->GetValue ()) {
1121 types |= LogEntry::TYPE_DEBUG_ENCODE;
1123 if (_log_debug_email->GetValue ()) {
1124 types |= LogEntry::TYPE_DEBUG_EMAIL;
1126 Config::instance()->set_log_types (types);
1129 #ifdef DCPOMATIC_WINDOWS
1130 void win32_console_changed ()
1132 Config::instance()->set_win32_console (_win32_console->GetValue ());
1136 wxSpinCtrl* _maximum_j2k_bandwidth;
1137 wxSpinCtrl* _frames_in_memory_multiplier;
1138 wxCheckBox* _allow_any_dcp_frame_rate;
1139 wxCheckBox* _only_servers_encode;
1140 NameFormatEditor* _dcp_metadata_filename_format;
1141 NameFormatEditor* _dcp_asset_filename_format;
1142 wxCheckBox* _log_general;
1143 wxCheckBox* _log_warning;
1144 wxCheckBox* _log_error;
1145 wxCheckBox* _log_timing;
1146 wxCheckBox* _log_debug_decode;
1147 wxCheckBox* _log_debug_encode;
1148 wxCheckBox* _log_debug_email;
1149 #ifdef DCPOMATIC_WINDOWS
1150 wxCheckBox* _win32_console;
1154 wxPreferencesEditor*
1155 create_full_config_dialog ()
1157 wxPreferencesEditor* e = new wxPreferencesEditor ();
1159 #ifdef DCPOMATIC_OSX
1160 /* Width that we force some of the config panels to be on OSX so that
1161 the containing window doesn't shrink too much when we select those panels.
1162 This is obviously an unpleasant hack.
1164 wxSize ps = wxSize (520, -1);
1165 int const border = 16;
1167 wxSize ps = wxSize (-1, -1);
1168 int const border = 8;
1171 e->AddPage (new FullGeneralPage (ps, border));
1172 e->AddPage (new DefaultsPage (ps, border));
1173 e->AddPage (new EncodingServersPage (ps, border));
1174 e->AddPage (new KeysPage (ps, border, true));
1175 e->AddPage (new TMSPage (ps, border));
1176 e->AddPage (new KDMEmailPage (ps, border));
1177 e->AddPage (new CoverSheetPage (ps, border));
1178 e->AddPage (new AdvancedPage (ps, border));