Merge branch 'master' of ssh://git.carlh.net/home/carl/git/dcpomatic
[dcpomatic.git] / src / wx / full_config_dialog.cc
1 /*
2     Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21 /** @file src/full_config_dialog.cc
22  *  @brief A dialogue to edit all DCP-o-matic configuration.
23  */
24
25 #include "full_config_dialog.h"
26 #include "wx_util.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"
43 #include "lib/log.h"
44 #include "lib/util.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>
54 #include <RtAudio.h>
55 #include <boost/filesystem.hpp>
56 #include <boost/foreach.hpp>
57 #include <iostream>
58
59 using std::vector;
60 using std::string;
61 using std::list;
62 using std::cout;
63 using std::pair;
64 using std::make_pair;
65 using std::map;
66 using boost::bind;
67 using boost::shared_ptr;
68 using boost::function;
69 using boost::optional;
70 using dcp::locale_convert;
71
72 class FullGeneralPage : public GeneralPage
73 {
74 public:
75         FullGeneralPage (wxSize panel_size, int border)
76                 : GeneralPage (panel_size, border)
77         {}
78
79 private:
80         void setup ()
81         {
82                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
83                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
84
85                 int r = 0;
86                 add_language_controls (table, r);
87
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));
91                 ++r;
92
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));
96                 ++r;
97
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));
101                 ++r;
102
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));
106                 ++r;
107
108                 add_play_sound_controls (table, r);
109
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));
113                 ++r;
114 #endif
115
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));
118                 ++r;
119
120                 add_update_controls (table, r);
121
122                 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
123                 bottom_table->AddGrowableCol (1, 1);
124
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);
128
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);
132
133                 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
134                 ++r;
135
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));
138
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));
143
144 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
145                 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
146 #endif
147                 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
148
149                 _issuer->Bind (wxEVT_TEXT, boost::bind (&FullGeneralPage::issuer_changed, this));
150                 _creator->Bind (wxEVT_TEXT, boost::bind (&FullGeneralPage::creator_changed, this));
151         }
152
153         void config_changed ()
154         {
155                 Config* config = Config::instance ();
156
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 ());
161 #endif
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());
167
168                 GeneralPage::config_changed ();
169         }
170
171
172 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
173         void analyse_ebur128_changed ()
174         {
175                 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
176         }
177 #endif
178
179         void automatic_audio_analysis_changed ()
180         {
181                 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
182         }
183
184         void master_encoding_threads_changed ()
185         {
186                 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue ());
187         }
188
189         void server_encoding_threads_changed ()
190         {
191                 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue ());
192         }
193
194         void issuer_changed ()
195         {
196                 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
197         }
198
199         void creator_changed ()
200         {
201                 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
202         }
203
204         void config_file_changed ()
205         {
206                 Config* config = Config::instance();
207                 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
208                 if (new_file == config->config_file()) {
209                         return;
210                 }
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;
216                         }
217                         d->Destroy ();
218                 }
219
220                 if (copy_and_link) {
221                         config->write ();
222                         if (new_file != config->config_file()) {
223                                 config->copy_and_link (new_file);
224                         }
225                 } else {
226                         config->link (new_file);
227                 }
228         }
229
230         void cinemas_file_changed ()
231         {
232                 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
233         }
234
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;
241 #endif
242         wxCheckBox* _automatic_audio_analysis;
243         wxTextCtrl* _issuer;
244         wxTextCtrl* _creator;
245 };
246
247 class DefaultsPage : public StandardPage
248 {
249 public:
250         DefaultsPage (wxSize panel_size, int border)
251                 : StandardPage (panel_size, border)
252         {}
253
254         wxString GetName () const
255         {
256                 return _("Defaults");
257         }
258
259 #ifdef DCPOMATIC_OSX
260         wxBitmap GetLargeIcon () const
261         {
262                 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
263         }
264 #endif
265
266 private:
267         void setup ()
268         {
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);
272
273                 {
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);
279                         table->Add (s, 1);
280                 }
281
282                 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
283 #ifdef DCPOMATIC_USE_OWN_PICKER
284                 _directory = new DirPickerCtrl (_panel);
285 #else
286                 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
287 #endif
288                 table->Add (_directory, 1, wxEXPAND);
289
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);
293
294                 add_label_to_sizer (table, _panel, _("Default container"), true);
295                 _container = new wxChoice (_panel, wxID_ANY);
296                 table->Add (_container);
297
298                 add_label_to_sizer (table, _panel, _("Default scale-to"), true);
299                 _scale_to = new wxChoice (_panel, wxID_ANY);
300                 table->Add (_scale_to);
301
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);
305
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);
309
310                 {
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);
316                         table->Add (s, 1);
317                 }
318
319                 {
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);
325                         table->Add (s, 1);
326                 }
327
328                 add_label_to_sizer (table, _panel, _("Default standard"), true);
329                 _standard = new wxChoice (_panel, wxID_ANY);
330                 table->Add (_standard);
331
332                 add_label_to_sizer (table, _panel, _("Default KDM directory"), true);
333 #ifdef DCPOMATIC_USE_OWN_PICKER
334                 _kdm_directory = new DirPickerCtrl (_panel);
335 #else
336                 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
337 #endif
338
339                 table->Add (_kdm_directory, 1, wxEXPAND);
340
341                 _upload_after_make_dcp = new wxCheckBox (_panel, wxID_ANY, _("Default to enabling upload of DCP to TMS"));
342                 table->Add (_upload_after_make_dcp, 1, wxEXPAND);
343
344                 _still_length->SetRange (1, 3600);
345                 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
346
347                 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
348                 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
349
350                 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
351
352                 BOOST_FOREACH (Ratio const * i, Ratio::containers()) {
353                         _container->Append (std_to_wx(i->container_nickname()));
354                 }
355
356                 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
357
358                 _scale_to->Append (_("Guess from content"));
359
360                 BOOST_FOREACH (Ratio const * i, Ratio::all()) {
361                         _scale_to->Append (std_to_wx(i->image_nickname()));
362                 }
363
364                 _scale_to->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::scale_to_changed, this));
365
366                 BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) {
367                         _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
368                 }
369
370                 setup_audio_channels_choice (_dcp_audio_channels, 2);
371
372                 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
373                 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
374
375                 _j2k_bandwidth->SetRange (50, 250);
376                 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
377
378                 _audio_delay->SetRange (-1000, 1000);
379                 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
380
381                 _standard->Append (_("SMPTE"));
382                 _standard->Append (_("Interop"));
383                 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
384
385                 _upload_after_make_dcp->Bind (wxEVT_CHECKBOX, boost::bind (&DefaultsPage::upload_after_make_dcp_changed, this));
386         }
387
388         void config_changed ()
389         {
390                 Config* config = Config::instance ();
391
392                 vector<Ratio const *> containers = Ratio::containers ();
393                 for (size_t i = 0; i < containers.size(); ++i) {
394                         if (containers[i] == config->default_container ()) {
395                                 _container->SetSelection (i);
396                         }
397                 }
398
399                 vector<Ratio const *> ratios = Ratio::all ();
400                 for (size_t i = 0; i < ratios.size(); ++i) {
401                         if (ratios[i] == config->default_scale_to ()) {
402                                 _scale_to->SetSelection (i + 1);
403                         }
404                 }
405
406                 if (!config->default_scale_to()) {
407                         _scale_to->SetSelection (0);
408                 }
409
410                 vector<DCPContentType const *> const ct = DCPContentType::all ();
411                 for (size_t i = 0; i < ct.size(); ++i) {
412                         if (ct[i] == config->default_dcp_content_type ()) {
413                                 _dcp_content_type->SetSelection (i);
414                         }
415                 }
416
417                 checked_set (_still_length, config->default_still_length ());
418                 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
419                 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
420                 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
421                 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
422                 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
423                 checked_set (_audio_delay, config->default_audio_delay ());
424                 checked_set (_standard, config->default_interop() ? 1 : 0);
425                 checked_set (_upload_after_make_dcp, config->default_upload_after_make_dcp());
426         }
427
428         void j2k_bandwidth_changed ()
429         {
430                 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
431         }
432
433         void audio_delay_changed ()
434         {
435                 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
436         }
437
438         void dcp_audio_channels_changed ()
439         {
440                 int const s = _dcp_audio_channels->GetSelection ();
441                 if (s != wxNOT_FOUND) {
442                         Config::instance()->set_default_dcp_audio_channels (
443                                 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
444                                 );
445                 }
446         }
447
448         void directory_changed ()
449         {
450                 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
451         }
452
453         void kdm_directory_changed ()
454         {
455                 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
456         }
457
458         void edit_isdcf_metadata_clicked ()
459         {
460                 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
461                 d->ShowModal ();
462                 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
463                 d->Destroy ();
464         }
465
466         void still_length_changed ()
467         {
468                 Config::instance()->set_default_still_length (_still_length->GetValue ());
469         }
470
471         void container_changed ()
472         {
473                 vector<Ratio const *> ratio = Ratio::containers ();
474                 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
475         }
476
477         void scale_to_changed ()
478         {
479                 int const s = _scale_to->GetSelection ();
480                 if (s == 0) {
481                         Config::instance()->set_default_scale_to (0);
482                 } else {
483                         vector<Ratio const *> ratio = Ratio::all ();
484                         Config::instance()->set_default_scale_to (ratio[s - 1]);
485                 }
486         }
487
488         void dcp_content_type_changed ()
489         {
490                 vector<DCPContentType const *> ct = DCPContentType::all ();
491                 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
492         }
493
494         void standard_changed ()
495         {
496                 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
497         }
498
499         void upload_after_make_dcp_changed ()
500         {
501                 Config::instance()->set_default_upload_after_make_dcp (_upload_after_make_dcp->GetValue ());
502         }
503
504         wxSpinCtrl* _j2k_bandwidth;
505         wxSpinCtrl* _audio_delay;
506         wxButton* _isdcf_metadata_button;
507         wxSpinCtrl* _still_length;
508 #ifdef DCPOMATIC_USE_OWN_PICKER
509         DirPickerCtrl* _directory;
510         DirPickerCtrl* _kdm_directory;
511 #else
512         wxDirPickerCtrl* _directory;
513         wxDirPickerCtrl* _kdm_directory;
514 #endif
515         wxChoice* _container;
516         wxChoice* _scale_to;
517         wxChoice* _dcp_content_type;
518         wxChoice* _dcp_audio_channels;
519         wxChoice* _standard;
520         wxCheckBox* _upload_after_make_dcp;
521 };
522
523 class EncodingServersPage : public StandardPage
524 {
525 public:
526         EncodingServersPage (wxSize panel_size, int border)
527                 : StandardPage (panel_size, border)
528         {}
529
530         wxString GetName () const
531         {
532                 return _("Servers");
533         }
534
535 #ifdef DCPOMATIC_OSX
536         wxBitmap GetLargeIcon () const
537         {
538                 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
539         }
540 #endif
541
542 private:
543         void setup ()
544         {
545                 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
546                 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
547
548                 vector<string> columns;
549                 columns.push_back (wx_to_std (_("IP address / host name")));
550                 _servers_list = new EditableList<string, ServerDialog> (
551                         _panel,
552                         columns,
553                         boost::bind (&Config::servers, Config::instance()),
554                         boost::bind (&Config::set_servers, Config::instance(), _1),
555                         boost::bind (&EncodingServersPage::server_column, this, _1)
556                         );
557
558                 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
559
560                 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
561         }
562
563         void config_changed ()
564         {
565                 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
566                 _servers_list->refresh ();
567         }
568
569         void use_any_servers_changed ()
570         {
571                 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
572         }
573
574         string server_column (string s)
575         {
576                 return s;
577         }
578
579         wxCheckBox* _use_any_servers;
580         EditableList<string, ServerDialog>* _servers_list;
581 };
582
583 class TMSPage : public StandardPage
584 {
585 public:
586         TMSPage (wxSize panel_size, int border)
587                 : StandardPage (panel_size, border)
588         {}
589
590         wxString GetName () const
591         {
592                 return _("TMS");
593         }
594
595 #ifdef DCPOMATIC_OSX
596         wxBitmap GetLargeIcon () const
597         {
598                 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
599         }
600 #endif
601
602 private:
603         void setup ()
604         {
605                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
606                 table->AddGrowableCol (1, 1);
607                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
608
609                 add_label_to_sizer (table, _panel, _("Protocol"), true);
610                 _tms_protocol = new wxChoice (_panel, wxID_ANY);
611                 table->Add (_tms_protocol, 1, wxEXPAND);
612
613                 add_label_to_sizer (table, _panel, _("IP address"), true);
614                 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
615                 table->Add (_tms_ip, 1, wxEXPAND);
616
617                 add_label_to_sizer (table, _panel, _("Target path"), true);
618                 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
619                 table->Add (_tms_path, 1, wxEXPAND);
620
621                 add_label_to_sizer (table, _panel, _("User name"), true);
622                 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
623                 table->Add (_tms_user, 1, wxEXPAND);
624
625                 add_label_to_sizer (table, _panel, _("Password"), true);
626                 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
627                 table->Add (_tms_password, 1, wxEXPAND);
628
629                 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
630                 _tms_protocol->Append (_("FTP (for Dolby)"));
631
632                 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
633                 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
634                 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
635                 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
636                 _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
637         }
638
639         void config_changed ()
640         {
641                 Config* config = Config::instance ();
642
643                 checked_set (_tms_protocol, config->tms_protocol ());
644                 checked_set (_tms_ip, config->tms_ip ());
645                 checked_set (_tms_path, config->tms_path ());
646                 checked_set (_tms_user, config->tms_user ());
647                 checked_set (_tms_password, config->tms_password ());
648         }
649
650         void tms_protocol_changed ()
651         {
652                 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
653         }
654
655         void tms_ip_changed ()
656         {
657                 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
658         }
659
660         void tms_path_changed ()
661         {
662                 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
663         }
664
665         void tms_user_changed ()
666         {
667                 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
668         }
669
670         void tms_password_changed ()
671         {
672                 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
673         }
674
675         wxChoice* _tms_protocol;
676         wxTextCtrl* _tms_ip;
677         wxTextCtrl* _tms_path;
678         wxTextCtrl* _tms_user;
679         wxTextCtrl* _tms_password;
680 };
681
682 static string
683 column (string s)
684 {
685         return s;
686 }
687
688 class KDMEmailPage : public StandardPage
689 {
690 public:
691
692         KDMEmailPage (wxSize panel_size, int border)
693 #ifdef DCPOMATIC_OSX
694                 /* We have to force both width and height of this one */
695                 : StandardPage (wxSize (480, 128), border)
696 #else
697                 : StandardPage (panel_size, border)
698 #endif
699         {}
700
701         wxString GetName () const
702         {
703                 return _("KDM Email");
704         }
705
706 #ifdef DCPOMATIC_OSX
707         wxBitmap GetLargeIcon () const
708         {
709                 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
710         }
711 #endif
712
713 private:
714         void setup ()
715         {
716                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
717                 table->AddGrowableCol (1, 1);
718                 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
719
720                 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
721                 {
722                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
723                         _mail_server = new wxTextCtrl (_panel, wxID_ANY);
724                         s->Add (_mail_server, 1, wxEXPAND | wxALL);
725                         add_label_to_sizer (s, _panel, _("port"), false);
726                         _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
727                         _mail_port->SetRange (0, 65535);
728                         s->Add (_mail_port);
729                         table->Add (s, 1, wxEXPAND | wxALL);
730                 }
731
732                 add_label_to_sizer (table, _panel, _("Mail user name"), true);
733                 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
734                 table->Add (_mail_user, 1, wxEXPAND | wxALL);
735
736                 add_label_to_sizer (table, _panel, _("Mail password"), true);
737                 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
738                 table->Add (_mail_password, 1, wxEXPAND | wxALL);
739
740                 add_label_to_sizer (table, _panel, _("Subject"), true);
741                 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
742                 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
743
744                 add_label_to_sizer (table, _panel, _("From address"), true);
745                 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
746                 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
747
748                 vector<string> columns;
749                 columns.push_back (wx_to_std (_("Address")));
750                 add_label_to_sizer (table, _panel, _("CC addresses"), true);
751                 _kdm_cc = new EditableList<string, EmailDialog> (
752                         _panel,
753                         columns,
754                         bind (&Config::kdm_cc, Config::instance()),
755                         bind (&Config::set_kdm_cc, Config::instance(), _1),
756                         bind (&column, _1)
757                         );
758                 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
759
760                 add_label_to_sizer (table, _panel, _("BCC address"), true);
761                 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
762                 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
763
764                 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
765                 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
766
767                 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
768                 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
769
770                 _kdm_cc->layout ();
771
772                 _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
773                 _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
774                 _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
775                 _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
776                 _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
777                 _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
778                 _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
779                 _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
780                 _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
781         }
782
783         void config_changed ()
784         {
785                 Config* config = Config::instance ();
786
787                 checked_set (_mail_server, config->mail_server ());
788                 checked_set (_mail_port, config->mail_port ());
789                 checked_set (_mail_user, config->mail_user ());
790                 checked_set (_mail_password, config->mail_password ());
791                 checked_set (_kdm_subject, config->kdm_subject ());
792                 checked_set (_kdm_from, config->kdm_from ());
793                 checked_set (_kdm_bcc, config->kdm_bcc ());
794                 checked_set (_kdm_email, Config::instance()->kdm_email ());
795         }
796
797         void mail_server_changed ()
798         {
799                 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
800         }
801
802         void mail_port_changed ()
803         {
804                 Config::instance()->set_mail_port (_mail_port->GetValue ());
805         }
806
807         void mail_user_changed ()
808         {
809                 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
810         }
811
812         void mail_password_changed ()
813         {
814                 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
815         }
816
817         void kdm_subject_changed ()
818         {
819                 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
820         }
821
822         void kdm_from_changed ()
823         {
824                 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
825         }
826
827         void kdm_bcc_changed ()
828         {
829                 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
830         }
831
832         void kdm_email_changed ()
833         {
834                 if (_kdm_email->GetValue().IsEmpty ()) {
835                         /* Sometimes we get sent an erroneous notification that the email
836                            is empty; I don't know why.
837                         */
838                         return;
839                 }
840                 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
841         }
842
843         void reset_kdm_email ()
844         {
845                 Config::instance()->reset_kdm_email ();
846                 checked_set (_kdm_email, Config::instance()->kdm_email ());
847         }
848
849         wxTextCtrl* _mail_server;
850         wxSpinCtrl* _mail_port;
851         wxTextCtrl* _mail_user;
852         wxTextCtrl* _mail_password;
853         wxTextCtrl* _kdm_subject;
854         wxTextCtrl* _kdm_from;
855         EditableList<string, EmailDialog>* _kdm_cc;
856         wxTextCtrl* _kdm_bcc;
857         wxTextCtrl* _kdm_email;
858         wxButton* _reset_kdm_email;
859 };
860
861 class CoverSheetPage : public StandardPage
862 {
863 public:
864
865         CoverSheetPage (wxSize panel_size, int border)
866 #ifdef DCPOMATIC_OSX
867                 /* We have to force both width and height of this one */
868                 : StandardPage (wxSize (480, 128), border)
869 #else
870                 : StandardPage (panel_size, border)
871 #endif
872         {}
873
874         wxString GetName () const
875         {
876                 return _("Cover Sheet");
877         }
878
879 #ifdef DCPOMATIC_OSX
880         wxBitmap GetLargeIcon () const
881         {
882                 return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE);
883         }
884 #endif
885
886 private:
887         void setup ()
888         {
889                 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
890                 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
891
892                 _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
893                 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
894
895                 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
896                 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
897         }
898
899         void config_changed ()
900         {
901                 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
902         }
903
904         void cover_sheet_changed ()
905         {
906                 if (_cover_sheet->GetValue().IsEmpty ()) {
907                         /* Sometimes we get sent an erroneous notification that the cover sheet
908                            is empty; I don't know why.
909                         */
910                         return;
911                 }
912                 Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ()));
913         }
914
915         void reset_cover_sheet ()
916         {
917                 Config::instance()->reset_cover_sheet ();
918                 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
919         }
920
921         wxTextCtrl* _cover_sheet;
922         wxButton* _reset_cover_sheet;
923 };
924
925
926 /** @class AdvancedPage
927  *  @brief Advanced page of the preferences dialog.
928  */
929 class AdvancedPage : public StockPage
930 {
931 public:
932         AdvancedPage (wxSize panel_size, int border)
933                 : StockPage (Kind_Advanced, panel_size, border)
934                 , _maximum_j2k_bandwidth (0)
935                 , _allow_any_dcp_frame_rate (0)
936                 , _only_servers_encode (0)
937                 , _log_general (0)
938                 , _log_warning (0)
939                 , _log_error (0)
940                 , _log_timing (0)
941                 , _log_debug_decode (0)
942                 , _log_debug_encode (0)
943                 , _log_debug_email (0)
944         {}
945
946 private:
947         void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
948         {
949                 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
950 #ifdef __WXOSX__
951                 flags |= wxALIGN_RIGHT;
952                 text += wxT (":");
953 #endif
954                 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
955                 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
956         }
957
958         void setup ()
959         {
960                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
961                 table->AddGrowableCol (1, 1);
962                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
963
964                 {
965                         add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
966                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
967                         _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
968                         s->Add (_maximum_j2k_bandwidth, 1);
969                         add_label_to_sizer (s, _panel, _("Mbit/s"), false);
970                         table->Add (s, 1);
971                 }
972
973                 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
974                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
975                 table->AddSpacer (0);
976
977                 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
978                 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
979                 table->AddSpacer (0);
980
981                 {
982                         add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true);
983                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
984                         _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
985                         s->Add (_frames_in_memory_multiplier, 1);
986                         table->Add (s, 1);
987                 }
988
989                 {
990                         add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
991                         dcp::NameFormat::Map titles;
992                         titles['t'] = "type (cpl/pkl)";
993                         dcp::NameFormat::Map examples;
994                         examples['t'] = "cpl";
995                         _dcp_metadata_filename_format = new NameFormatEditor (
996                                 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
997                                 );
998                         table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
999                 }
1000
1001                 {
1002                         add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1003                         dcp::NameFormat::Map titles;
1004                         titles['t'] = "type (j2c/pcm/sub)";
1005                         titles['r'] = "reel number";
1006                         titles['n'] = "number of reels";
1007                         titles['c'] = "content filename";
1008                         dcp::NameFormat::Map examples;
1009                         examples['t'] = "j2c";
1010                         examples['r'] = "1";
1011                         examples['n'] = "4";
1012                         examples['c'] = "myfile.mp4";
1013                         _dcp_asset_filename_format = new NameFormatEditor (
1014                                 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1015                                 );
1016                         table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1017                 }
1018
1019                 {
1020                         add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1021                         wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1022                         _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1023                         t->Add (_log_general, 1, wxEXPAND | wxALL);
1024                         _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1025                         t->Add (_log_warning, 1, wxEXPAND | wxALL);
1026                         _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1027                         t->Add (_log_error, 1, wxEXPAND | wxALL);
1028                         /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1029                         _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1030                         t->Add (_log_timing, 1, wxEXPAND | wxALL);
1031                         _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1032                         t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1033                         _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1034                         t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1035                         _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1036                         t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1037                         table->Add (t, 0, wxALL, 6);
1038                 }
1039
1040 #ifdef DCPOMATIC_WINDOWS
1041                 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1042                 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1043                 table->AddSpacer (0);
1044 #endif
1045
1046                 _maximum_j2k_bandwidth->SetRange (1, 1000);
1047                 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1048                 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1049                 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1050                 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1051                 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1052                 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1053                 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1054                 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1055                 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1056                 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1057                 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1058                 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1059                 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1060 #ifdef DCPOMATIC_WINDOWS
1061                 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1062 #endif
1063         }
1064
1065         void config_changed ()
1066         {
1067                 Config* config = Config::instance ();
1068
1069                 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1070                 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1071                 checked_set (_only_servers_encode, config->only_servers_encode ());
1072                 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1073                 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1074                 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1075                 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1076                 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1077                 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1078                 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1079                 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1080 #ifdef DCPOMATIC_WINDOWS
1081                 checked_set (_win32_console, config->win32_console());
1082 #endif
1083         }
1084
1085         void maximum_j2k_bandwidth_changed ()
1086         {
1087                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1088         }
1089
1090         void frames_in_memory_multiplier_changed ()
1091         {
1092                 Config::instance()->set_frames_in_memory_multiplier (_frames_in_memory_multiplier->GetValue());
1093         }
1094
1095         void allow_any_dcp_frame_rate_changed ()
1096         {
1097                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1098         }
1099
1100         void only_servers_encode_changed ()
1101         {
1102                 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1103         }
1104
1105         void dcp_metadata_filename_format_changed ()
1106         {
1107                 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1108         }
1109
1110         void dcp_asset_filename_format_changed ()
1111         {
1112                 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1113         }
1114
1115         void log_changed ()
1116         {
1117                 int types = 0;
1118                 if (_log_general->GetValue ()) {
1119                         types |= LogEntry::TYPE_GENERAL;
1120                 }
1121                 if (_log_warning->GetValue ()) {
1122                         types |= LogEntry::TYPE_WARNING;
1123                 }
1124                 if (_log_error->GetValue ())  {
1125                         types |= LogEntry::TYPE_ERROR;
1126                 }
1127                 if (_log_timing->GetValue ()) {
1128                         types |= LogEntry::TYPE_TIMING;
1129                 }
1130                 if (_log_debug_decode->GetValue ()) {
1131                         types |= LogEntry::TYPE_DEBUG_DECODE;
1132                 }
1133                 if (_log_debug_encode->GetValue ()) {
1134                         types |= LogEntry::TYPE_DEBUG_ENCODE;
1135                 }
1136                 if (_log_debug_email->GetValue ()) {
1137                         types |= LogEntry::TYPE_DEBUG_EMAIL;
1138                 }
1139                 Config::instance()->set_log_types (types);
1140         }
1141
1142 #ifdef DCPOMATIC_WINDOWS
1143         void win32_console_changed ()
1144         {
1145                 Config::instance()->set_win32_console (_win32_console->GetValue ());
1146         }
1147 #endif
1148
1149         wxSpinCtrl* _maximum_j2k_bandwidth;
1150         wxSpinCtrl* _frames_in_memory_multiplier;
1151         wxCheckBox* _allow_any_dcp_frame_rate;
1152         wxCheckBox* _only_servers_encode;
1153         NameFormatEditor* _dcp_metadata_filename_format;
1154         NameFormatEditor* _dcp_asset_filename_format;
1155         wxCheckBox* _log_general;
1156         wxCheckBox* _log_warning;
1157         wxCheckBox* _log_error;
1158         wxCheckBox* _log_timing;
1159         wxCheckBox* _log_debug_decode;
1160         wxCheckBox* _log_debug_encode;
1161         wxCheckBox* _log_debug_email;
1162 #ifdef DCPOMATIC_WINDOWS
1163         wxCheckBox* _win32_console;
1164 #endif
1165 };
1166
1167 wxPreferencesEditor*
1168 create_full_config_dialog ()
1169 {
1170         wxPreferencesEditor* e = new wxPreferencesEditor ();
1171
1172 #ifdef DCPOMATIC_OSX
1173         /* Width that we force some of the config panels to be on OSX so that
1174            the containing window doesn't shrink too much when we select those panels.
1175            This is obviously an unpleasant hack.
1176         */
1177         wxSize ps = wxSize (520, -1);
1178         int const border = 16;
1179 #else
1180         wxSize ps = wxSize (-1, -1);
1181         int const border = 8;
1182 #endif
1183
1184         e->AddPage (new FullGeneralPage (ps, border));
1185         e->AddPage (new DefaultsPage (ps, border));
1186         e->AddPage (new EncodingServersPage (ps, border));
1187         e->AddPage (new KeysPage (ps, border));
1188         e->AddPage (new TMSPage (ps, border));
1189         e->AddPage (new KDMEmailPage (ps, border));
1190         e->AddPage (new CoverSheetPage (ps, border));
1191         e->AddPage (new AdvancedPage (ps, border));
1192         return e;
1193 }