2d4ac3fdf9f98c233772be37f20ebbf73e45015e
[dcpomatic.git] / src / wx / full_config_dialog.cc
1 /*
2     Copyright (C) 2012-2019 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 "static_text.h"
40 #include "check_box.h"
41 #include "dcpomatic_button.h"
42 #include "password_entry.h"
43 #include "lib/config.h"
44 #include "lib/ratio.h"
45 #include "lib/filter.h"
46 #include "lib/dcp_content_type.h"
47 #include "lib/log.h"
48 #include "lib/util.h"
49 #include "lib/cross.h"
50 #include "lib/exceptions.h"
51 #include <dcp/locale_convert.h>
52 #include <dcp/exceptions.h>
53 #include <dcp/certificate_chain.h>
54 #include <wx/stdpaths.h>
55 #include <wx/preferences.h>
56 #include <wx/spinctrl.h>
57 #include <wx/filepicker.h>
58 #include <RtAudio.h>
59 #include <boost/filesystem.hpp>
60 #include <boost/foreach.hpp>
61 #include <iostream>
62
63 using std::vector;
64 using std::string;
65 using std::list;
66 using std::cout;
67 using std::pair;
68 using std::make_pair;
69 using std::map;
70 using boost::bind;
71 using boost::shared_ptr;
72 using boost::function;
73 using boost::optional;
74 #if BOOST_VERSION >= 106100
75 using namespace boost::placeholders;
76 #endif
77 using dcp::locale_convert;
78
79 class FullGeneralPage : public GeneralPage
80 {
81 public:
82         FullGeneralPage (wxSize panel_size, int border)
83                 : GeneralPage (panel_size, border)
84         {}
85
86 private:
87         void setup ()
88         {
89                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
90                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
91
92                 int r = 0;
93                 add_language_controls (table, r);
94
95                 add_label_to_sizer (table, _panel, _("Interface complexity"), true, wxGBPosition(r, 0));
96                 _interface_complexity = new wxChoice (_panel, wxID_ANY);
97                 table->Add (_interface_complexity, wxGBPosition (r, 1));
98                 ++r;
99
100                 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
101                 _master_encoding_threads = new wxSpinCtrl (_panel);
102                 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
103                 ++r;
104
105                 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
106                 _server_encoding_threads = new wxSpinCtrl (_panel);
107                 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
108                 ++r;
109
110                 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
111                 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, true);
112                 table->Add (_config_file, wxGBPosition (r, 1));
113                 ++r;
114
115                 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
116                 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, true);
117                 table->Add (_cinemas_file, wxGBPosition (r, 1));
118                 Button* export_cinemas = new Button (_panel, _("Export..."));
119                 table->Add (export_cinemas, wxGBPosition (r, 2));
120                 ++r;
121
122 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
123                 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
124                 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
125                 ++r;
126 #endif
127
128                 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
129                 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
130                 ++r;
131
132                 add_update_controls (table, r);
133
134                 _config_file->Bind  (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::config_file_changed,   this));
135                 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::cinemas_file_changed,  this));
136
137                 _interface_complexity->Append (_("Simple"));
138                 _interface_complexity->Append (_("Full"));
139                 _interface_complexity->Bind (wxEVT_CHOICE, boost::bind(&FullGeneralPage::interface_complexity_changed, this));
140
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));
146
147 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
148                 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
149 #endif
150                 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
151         }
152
153         void config_changed ()
154         {
155                 Config* config = Config::instance ();
156
157                 switch (config->interface_complexity()) {
158                 case Config::INTERFACE_SIMPLE:
159                         checked_set (_interface_complexity, 0);
160                         break;
161                 case Config::INTERFACE_FULL:
162                         checked_set (_interface_complexity, 1);
163                         break;
164                 }
165                 checked_set (_master_encoding_threads, config->master_encoding_threads ());
166                 checked_set (_server_encoding_threads, config->server_encoding_threads ());
167 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
168                 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
169 #endif
170                 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
171                 checked_set (_config_file, config->config_file());
172                 checked_set (_cinemas_file, config->cinemas_file());
173
174                 GeneralPage::config_changed ();
175         }
176
177         void export_cinemas_file ()
178         {
179                 wxFileDialog* d = new wxFileDialog (
180                         _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT ("XML files (*.xml)|*.xml"),
181                         wxFD_SAVE | wxFD_OVERWRITE_PROMPT
182                 );
183
184                 if (d->ShowModal () == wxID_OK) {
185                         boost::filesystem::copy_file (Config::instance()->cinemas_file(), wx_to_std(d->GetPath()));
186                 }
187                 d->Destroy ();
188         }
189
190         void interface_complexity_changed ()
191         {
192                 if (_interface_complexity->GetSelection() == 0) {
193                         Config::instance()->set_interface_complexity (Config::INTERFACE_SIMPLE);
194                 } else {
195                         Config::instance()->set_interface_complexity (Config::INTERFACE_FULL);
196                 }
197         }
198
199
200 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
201         void analyse_ebur128_changed ()
202         {
203                 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
204         }
205 #endif
206
207         void automatic_audio_analysis_changed ()
208         {
209                 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
210         }
211
212         void master_encoding_threads_changed ()
213         {
214                 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue ());
215         }
216
217         void server_encoding_threads_changed ()
218         {
219                 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue ());
220         }
221
222         void config_file_changed ()
223         {
224                 Config* config = Config::instance();
225                 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
226                 if (new_file == config->config_file()) {
227                         return;
228                 }
229                 bool copy_and_link = true;
230                 if (boost::filesystem::exists(new_file)) {
231                         ConfigMoveDialog* d = new ConfigMoveDialog (_panel, new_file);
232                         if (d->ShowModal() == wxID_OK) {
233                                 copy_and_link = false;
234                         }
235                         d->Destroy ();
236                 }
237
238                 if (copy_and_link) {
239                         config->write ();
240                         if (new_file != config->config_file()) {
241                                 config->copy_and_link (new_file);
242                         }
243                 } else {
244                         config->link (new_file);
245                 }
246         }
247
248         void cinemas_file_changed ()
249         {
250                 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
251         }
252
253         wxChoice* _interface_complexity;
254         wxSpinCtrl* _master_encoding_threads;
255         wxSpinCtrl* _server_encoding_threads;
256         FilePickerCtrl* _config_file;
257         FilePickerCtrl* _cinemas_file;
258 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
259         wxCheckBox* _analyse_ebur128;
260 #endif
261         wxCheckBox* _automatic_audio_analysis;
262 };
263
264 class DefaultsPage : public Page
265 {
266 public:
267         DefaultsPage (wxSize panel_size, int border)
268                 : Page (panel_size, border)
269         {}
270
271         wxString GetName () const
272         {
273                 return _("Defaults");
274         }
275
276 #ifdef DCPOMATIC_OSX
277         wxBitmap GetLargeIcon () const
278         {
279                 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
280         }
281 #endif
282
283 private:
284         void setup ()
285         {
286                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
287                 table->AddGrowableCol (1, 1);
288                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
289
290                 {
291                         add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
292                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
293                         _still_length = new wxSpinCtrl (_panel);
294                         s->Add (_still_length);
295                         add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
296                         table->Add (s, 1);
297                 }
298
299                 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
300 #ifdef DCPOMATIC_USE_OWN_PICKER
301                 _directory = new DirPickerCtrl (_panel);
302 #else
303                 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
304 #endif
305                 table->Add (_directory, 1, wxEXPAND);
306
307                 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
308                 _isdcf_metadata_button = new Button (_panel, _("Edit..."));
309                 table->Add (_isdcf_metadata_button);
310
311                 add_label_to_sizer (table, _panel, _("Default container"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
312                 _container = new wxChoice (_panel, wxID_ANY);
313                 table->Add (_container);
314
315                 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
316                 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
317                 table->Add (_dcp_content_type);
318
319                 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
320                 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
321                 table->Add (_dcp_audio_channels);
322
323                 {
324                         add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
325                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
326                         _j2k_bandwidth = new wxSpinCtrl (_panel);
327                         s->Add (_j2k_bandwidth);
328                         add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
329                         table->Add (s, 1);
330                 }
331
332                 {
333                         add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
334                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
335                         _audio_delay = new wxSpinCtrl (_panel);
336                         s->Add (_audio_delay);
337                         add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
338                         table->Add (s, 1);
339                 }
340
341                 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
342                 _standard = new wxChoice (_panel, wxID_ANY);
343                 table->Add (_standard);
344
345                 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
346 #ifdef DCPOMATIC_USE_OWN_PICKER
347                 _kdm_directory = new DirPickerCtrl (_panel);
348 #else
349                 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
350 #endif
351
352                 table->Add (_kdm_directory, 1, wxEXPAND);
353
354                 _still_length->SetRange (1, 3600);
355                 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
356
357                 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
358                 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
359
360                 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
361
362                 BOOST_FOREACH (Ratio const * i, Ratio::containers()) {
363                         _container->Append (std_to_wx(i->container_nickname()));
364                 }
365
366                 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
367
368                 BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) {
369                         _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
370                 }
371
372                 setup_audio_channels_choice (_dcp_audio_channels, 2);
373
374                 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
375                 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
376
377                 _j2k_bandwidth->SetRange (50, 250);
378                 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
379
380                 _audio_delay->SetRange (-1000, 1000);
381                 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
382
383                 _standard->Append (_("SMPTE"));
384                 _standard->Append (_("Interop"));
385                 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_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<DCPContentType const *> const ct = DCPContentType::all ();
400                 for (size_t i = 0; i < ct.size(); ++i) {
401                         if (ct[i] == config->default_dcp_content_type ()) {
402                                 _dcp_content_type->SetSelection (i);
403                         }
404                 }
405
406                 checked_set (_still_length, config->default_still_length ());
407                 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
408                 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
409                 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
410                 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
411                 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
412                 checked_set (_audio_delay, config->default_audio_delay ());
413                 checked_set (_standard, config->default_interop() ? 1 : 0);
414         }
415
416         void j2k_bandwidth_changed ()
417         {
418                 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
419         }
420
421         void audio_delay_changed ()
422         {
423                 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
424         }
425
426         void dcp_audio_channels_changed ()
427         {
428                 int const s = _dcp_audio_channels->GetSelection ();
429                 if (s != wxNOT_FOUND) {
430                         Config::instance()->set_default_dcp_audio_channels (
431                                 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
432                                 );
433                 }
434         }
435
436         void directory_changed ()
437         {
438                 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
439         }
440
441         void kdm_directory_changed ()
442         {
443                 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
444         }
445
446         void edit_isdcf_metadata_clicked ()
447         {
448                 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
449                 d->ShowModal ();
450                 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
451                 d->Destroy ();
452         }
453
454         void still_length_changed ()
455         {
456                 Config::instance()->set_default_still_length (_still_length->GetValue ());
457         }
458
459         void container_changed ()
460         {
461                 vector<Ratio const *> ratio = Ratio::containers ();
462                 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
463         }
464
465         void dcp_content_type_changed ()
466         {
467                 vector<DCPContentType const *> ct = DCPContentType::all ();
468                 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
469         }
470
471         void standard_changed ()
472         {
473                 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
474         }
475
476         wxSpinCtrl* _j2k_bandwidth;
477         wxSpinCtrl* _audio_delay;
478         wxButton* _isdcf_metadata_button;
479         wxSpinCtrl* _still_length;
480 #ifdef DCPOMATIC_USE_OWN_PICKER
481         DirPickerCtrl* _directory;
482         DirPickerCtrl* _kdm_directory;
483 #else
484         wxDirPickerCtrl* _directory;
485         wxDirPickerCtrl* _kdm_directory;
486 #endif
487         wxChoice* _container;
488         wxChoice* _dcp_content_type;
489         wxChoice* _dcp_audio_channels;
490         wxChoice* _standard;
491 };
492
493 class EncodingServersPage : public Page
494 {
495 public:
496         EncodingServersPage (wxSize panel_size, int border)
497                 : Page (panel_size, border)
498         {}
499
500         wxString GetName () const
501         {
502                 return _("Servers");
503         }
504
505 #ifdef DCPOMATIC_OSX
506         wxBitmap GetLargeIcon () const
507         {
508                 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
509         }
510 #endif
511
512 private:
513         void setup ()
514         {
515                 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
516                 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
517
518                 vector<EditableListColumn> columns;
519                 columns.push_back (EditableListColumn(_("IP address / host name")));
520                 _servers_list = new EditableList<string, ServerDialog> (
521                         _panel,
522                         columns,
523                         boost::bind (&Config::servers, Config::instance()),
524                         boost::bind (&Config::set_servers, Config::instance(), _1),
525                         boost::bind (&EncodingServersPage::server_column, this, _1)
526                         );
527
528                 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
529
530                 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
531         }
532
533         void config_changed ()
534         {
535                 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
536                 _servers_list->refresh ();
537         }
538
539         void use_any_servers_changed ()
540         {
541                 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
542         }
543
544         string server_column (string s)
545         {
546                 return s;
547         }
548
549         wxCheckBox* _use_any_servers;
550         EditableList<string, ServerDialog>* _servers_list;
551 };
552
553 class TMSPage : public Page
554 {
555 public:
556         TMSPage (wxSize panel_size, int border)
557                 : Page (panel_size, border)
558         {}
559
560         wxString GetName () const
561         {
562                 return _("TMS");
563         }
564
565 #ifdef DCPOMATIC_OSX
566         wxBitmap GetLargeIcon () const
567         {
568                 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
569         }
570 #endif
571
572 private:
573         void setup ()
574         {
575                 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
576                 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
577
578                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
579                 table->AddGrowableCol (1, 1);
580                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
581
582                 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
583                 _tms_protocol = new wxChoice (_panel, wxID_ANY);
584                 table->Add (_tms_protocol, 1, wxEXPAND);
585
586                 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
587                 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
588                 table->Add (_tms_ip, 1, wxEXPAND);
589
590                 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
591                 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
592                 table->Add (_tms_path, 1, wxEXPAND);
593
594                 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
595                 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
596                 table->Add (_tms_user, 1, wxEXPAND);
597
598                 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
599                 _tms_password = new PasswordEntry (_panel);
600                 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
601
602                 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
603                 _tms_protocol->Append (_("FTP (for Dolby)"));
604
605                 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
606                 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
607                 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
608                 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
609                 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
610                 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
611         }
612
613         void config_changed ()
614         {
615                 Config* config = Config::instance ();
616
617                 checked_set (_upload, config->upload_after_make_dcp());
618                 checked_set (_tms_protocol, config->tms_protocol ());
619                 checked_set (_tms_ip, config->tms_ip ());
620                 checked_set (_tms_path, config->tms_path ());
621                 checked_set (_tms_user, config->tms_user ());
622                 checked_set (_tms_password, config->tms_password ());
623         }
624
625         void upload_changed ()
626         {
627                 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
628         }
629
630         void tms_protocol_changed ()
631         {
632                 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
633         }
634
635         void tms_ip_changed ()
636         {
637                 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
638         }
639
640         void tms_path_changed ()
641         {
642                 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
643         }
644
645         void tms_user_changed ()
646         {
647                 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
648         }
649
650         void tms_password_changed ()
651         {
652                 Config::instance()->set_tms_password (_tms_password->get());
653         }
654
655         CheckBox* _upload;
656         wxChoice* _tms_protocol;
657         wxTextCtrl* _tms_ip;
658         wxTextCtrl* _tms_path;
659         wxTextCtrl* _tms_user;
660         PasswordEntry* _tms_password;
661 };
662
663 static string
664 column (string s)
665 {
666         return s;
667 }
668
669 class EmailPage : public Page
670 {
671 public:
672         EmailPage (wxSize panel_size, int border)
673                 : Page (panel_size, border)
674         {}
675
676         wxString GetName () const
677         {
678                 return _("Email");
679         }
680
681 #ifdef DCPOMATIC_OSX
682         wxBitmap GetLargeIcon () const
683         {
684                 return wxBitmap ("email", wxBITMAP_TYPE_PNG_RESOURCE);
685         }
686 #endif
687
688 private:
689         void setup ()
690         {
691                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
692                 table->AddGrowableCol (1, 1);
693                 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
694
695                 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
696                 {
697                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
698                         _server = new wxTextCtrl (_panel, wxID_ANY);
699                         s->Add (_server, 1, wxEXPAND | wxALL);
700                         add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
701                         _port = new wxSpinCtrl (_panel, wxID_ANY);
702                         _port->SetRange (0, 65535);
703                         s->Add (_port);
704                         add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
705                         _protocol = new wxChoice (_panel, wxID_ANY);
706                         /* Make sure this matches the switches in config_changed and port_changed below */
707                         _protocol->Append (_("Auto"));
708                         _protocol->Append (_("Plain"));
709                         _protocol->Append (_("STARTTLS"));
710                         _protocol->Append (_("SSL"));
711                         s->Add (_protocol);
712                         table->Add (s, 1, wxEXPAND | wxALL);
713                 }
714
715                 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
716                 _user = new wxTextCtrl (_panel, wxID_ANY);
717                 table->Add (_user, 1, wxEXPAND | wxALL);
718
719                 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
720                 _password = new PasswordEntry (_panel);
721                 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
722
723                 _server->Bind (wxEVT_TEXT, boost::bind (&EmailPage::server_changed, this));
724                 _port->Bind (wxEVT_SPINCTRL, boost::bind (&EmailPage::port_changed, this));
725                 _protocol->Bind (wxEVT_CHOICE, boost::bind (&EmailPage::protocol_changed, this));
726                 _user->Bind (wxEVT_TEXT, boost::bind (&EmailPage::user_changed, this));
727                 _password->Changed.connect (boost::bind (&EmailPage::password_changed, this));
728         }
729
730         void config_changed ()
731         {
732                 Config* config = Config::instance ();
733
734                 checked_set (_server, config->mail_server ());
735                 checked_set (_port, config->mail_port ());
736                 switch (config->mail_protocol()) {
737                 case EMAIL_PROTOCOL_AUTO:
738                         checked_set (_protocol, 0);
739                         break;
740                 case EMAIL_PROTOCOL_PLAIN:
741                         checked_set (_protocol, 1);
742                         break;
743                 case EMAIL_PROTOCOL_STARTTLS:
744                         checked_set (_protocol, 2);
745                         break;
746                 case EMAIL_PROTOCOL_SSL:
747                         checked_set (_protocol, 3);
748                         break;
749                 }
750                 checked_set (_user, config->mail_user ());
751                 checked_set (_password, config->mail_password());
752         }
753
754         void server_changed ()
755         {
756                 Config::instance()->set_mail_server (wx_to_std (_server->GetValue ()));
757         }
758
759         void port_changed ()
760         {
761                 Config::instance()->set_mail_port (_port->GetValue ());
762         }
763
764         void protocol_changed ()
765         {
766                 switch (_protocol->GetSelection()) {
767                 case 0:
768                         Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_AUTO);
769                         break;
770                 case 1:
771                         Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_PLAIN);
772                         break;
773                 case 2:
774                         Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_STARTTLS);
775                         break;
776                 case 3:
777                         Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_SSL);
778                         break;
779                 }
780         }
781
782         void user_changed ()
783         {
784                 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
785         }
786
787         void password_changed ()
788         {
789                 Config::instance()->set_mail_password(_password->get());
790         }
791
792         wxTextCtrl* _server;
793         wxSpinCtrl* _port;
794         wxChoice* _protocol;
795         wxTextCtrl* _user;
796         PasswordEntry* _password;
797 };
798
799 class KDMEmailPage : public Page
800 {
801 public:
802
803         KDMEmailPage (wxSize panel_size, int border)
804 #ifdef DCPOMATIC_OSX
805                 /* We have to force both width and height of this one */
806                 : Page (wxSize (panel_size.GetWidth(), 128), border)
807 #else
808                 : Page (panel_size, border)
809 #endif
810         {}
811
812         wxString GetName () const
813         {
814                 return _("KDM Email");
815         }
816
817 #ifdef DCPOMATIC_OSX
818         wxBitmap GetLargeIcon () const
819         {
820                 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
821         }
822 #endif
823
824 private:
825         void setup ()
826         {
827                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
828                 table->AddGrowableCol (1, 1);
829                 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
830
831                 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
832                 _subject = new wxTextCtrl (_panel, wxID_ANY);
833                 table->Add (_subject, 1, wxEXPAND | wxALL);
834
835                 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
836                 _from = new wxTextCtrl (_panel, wxID_ANY);
837                 table->Add (_from, 1, wxEXPAND | wxALL);
838
839                 vector<EditableListColumn> columns;
840                 columns.push_back (EditableListColumn(_("Address")));
841                 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
842                 _cc = new EditableList<string, EmailDialog> (
843                         _panel,
844                         columns,
845                         bind (&Config::kdm_cc, Config::instance()),
846                         bind (&Config::set_kdm_cc, Config::instance(), _1),
847                         bind (&column, _1)
848                         );
849                 table->Add (_cc, 1, wxEXPAND | wxALL);
850
851                 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
852                 _bcc = new wxTextCtrl (_panel, wxID_ANY);
853                 table->Add (_bcc, 1, wxEXPAND | wxALL);
854
855                 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
856                 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
857
858                 _reset_email = new Button (_panel, _("Reset to default subject and text"));
859                 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
860
861                 _cc->layout ();
862
863                 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
864                 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
865                 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
866                 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
867                 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
868         }
869
870         void config_changed ()
871         {
872                 Config* config = Config::instance ();
873
874                 checked_set (_subject, config->kdm_subject ());
875                 checked_set (_from, config->kdm_from ());
876                 checked_set (_bcc, config->kdm_bcc ());
877                 checked_set (_email, Config::instance()->kdm_email ());
878         }
879
880         void kdm_subject_changed ()
881         {
882                 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
883         }
884
885         void kdm_from_changed ()
886         {
887                 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
888         }
889
890         void kdm_bcc_changed ()
891         {
892                 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
893         }
894
895         void kdm_email_changed ()
896         {
897                 if (_email->GetValue().IsEmpty ()) {
898                         /* Sometimes we get sent an erroneous notification that the email
899                            is empty; I don't know why.
900                         */
901                         return;
902                 }
903                 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
904         }
905
906         void reset_email ()
907         {
908                 Config::instance()->reset_kdm_email ();
909                 checked_set (_email, Config::instance()->kdm_email ());
910         }
911
912         wxTextCtrl* _subject;
913         wxTextCtrl* _from;
914         EditableList<string, EmailDialog>* _cc;
915         wxTextCtrl* _bcc;
916         wxTextCtrl* _email;
917         wxButton* _reset_email;
918 };
919
920 class NotificationsPage : public Page
921 {
922 public:
923         NotificationsPage (wxSize panel_size, int border)
924 #ifdef DCPOMATIC_OSX
925                 /* We have to force both width and height of this one */
926                 : Page (wxSize (panel_size.GetWidth(), 128), border)
927 #else
928                 : Page (panel_size, border)
929 #endif
930         {}
931
932         wxString GetName () const
933         {
934                 return _("Notifications");
935         }
936
937 #ifdef DCPOMATIC_OSX
938         wxBitmap GetLargeIcon () const
939         {
940                 return wxBitmap ("notifications", wxBITMAP_TYPE_PNG_RESOURCE);
941         }
942 #endif
943
944 private:
945         void setup ()
946         {
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, wxEXPAND | wxALL, _border);
950
951                 _enable_message_box = new CheckBox (_panel, _("Message box"));
952                 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
953                 table->AddSpacer (0);
954
955                 _enable_email = new CheckBox (_panel, _("Email"));
956                 table->Add (_enable_email, 1, wxEXPAND | wxALL);
957                 table->AddSpacer (0);
958
959                 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
960                 _subject = new wxTextCtrl (_panel, wxID_ANY);
961                 table->Add (_subject, 1, wxEXPAND | wxALL);
962
963                 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
964                 _from = new wxTextCtrl (_panel, wxID_ANY);
965                 table->Add (_from, 1, wxEXPAND | wxALL);
966
967                 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
968                 _to = new wxTextCtrl (_panel, wxID_ANY);
969                 table->Add (_to, 1, wxEXPAND | wxALL);
970
971                 vector<EditableListColumn> columns;
972                 columns.push_back (EditableListColumn(_("Address")));
973                 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
974                 _cc = new EditableList<string, EmailDialog> (
975                         _panel,
976                         columns,
977                         bind (&Config::notification_cc, Config::instance()),
978                         bind (&Config::set_notification_cc, Config::instance(), _1),
979                         bind (&column, _1)
980                         );
981                 table->Add (_cc, 1, wxEXPAND | wxALL);
982
983                 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
984                 _bcc = new wxTextCtrl (_panel, wxID_ANY);
985                 table->Add (_bcc, 1, wxEXPAND | wxALL);
986
987                 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
988                 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
989
990                 _reset_email = new Button (_panel, _("Reset to default subject and text"));
991                 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
992
993                 _cc->layout ();
994
995                 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
996                 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
997
998                 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
999                 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1000                 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1001                 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1002                 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1003                 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1004
1005                 update_sensitivity ();
1006         }
1007
1008         void update_sensitivity ()
1009         {
1010                 bool const s = _enable_email->GetValue();
1011                 _subject->Enable(s);
1012                 _from->Enable(s);
1013                 _to->Enable(s);
1014                 _cc->Enable(s);
1015                 _bcc->Enable(s);
1016                 _email->Enable(s);
1017                 _reset_email->Enable(s);
1018         }
1019
1020         void config_changed ()
1021         {
1022                 Config* config = Config::instance ();
1023
1024                 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1025                 checked_set (_enable_email, config->notification(Config::EMAIL));
1026                 checked_set (_subject, config->notification_subject ());
1027                 checked_set (_from, config->notification_from ());
1028                 checked_set (_to, config->notification_to ());
1029                 checked_set (_bcc, config->notification_bcc ());
1030                 checked_set (_email, Config::instance()->notification_email ());
1031
1032                 update_sensitivity ();
1033         }
1034
1035         void notification_subject_changed ()
1036         {
1037                 Config::instance()->set_notification_subject (wx_to_std (_subject->GetValue ()));
1038         }
1039
1040         void notification_from_changed ()
1041         {
1042                 Config::instance()->set_notification_from (wx_to_std (_from->GetValue ()));
1043         }
1044
1045         void notification_to_changed ()
1046         {
1047                 Config::instance()->set_notification_to (wx_to_std (_to->GetValue ()));
1048         }
1049
1050         void notification_bcc_changed ()
1051         {
1052                 Config::instance()->set_notification_bcc (wx_to_std (_bcc->GetValue ()));
1053         }
1054
1055         void notification_email_changed ()
1056         {
1057                 if (_email->GetValue().IsEmpty ()) {
1058                         /* Sometimes we get sent an erroneous notification that the email
1059                            is empty; I don't know why.
1060                         */
1061                         return;
1062                 }
1063                 Config::instance()->set_notification_email (wx_to_std (_email->GetValue ()));
1064         }
1065
1066         void reset_email ()
1067         {
1068                 Config::instance()->reset_notification_email ();
1069                 checked_set (_email, Config::instance()->notification_email ());
1070         }
1071
1072         void type_changed (wxCheckBox* b, Config::Notification n)
1073         {
1074                 Config::instance()->set_notification(n, b->GetValue());
1075                 update_sensitivity ();
1076         }
1077
1078         wxCheckBox* _enable_message_box;
1079         wxCheckBox* _enable_email;
1080
1081         wxTextCtrl* _subject;
1082         wxTextCtrl* _from;
1083         wxTextCtrl* _to;
1084         EditableList<string, EmailDialog>* _cc;
1085         wxTextCtrl* _bcc;
1086         wxTextCtrl* _email;
1087         wxButton* _reset_email;
1088 };
1089
1090 class CoverSheetPage : public Page
1091 {
1092 public:
1093
1094         CoverSheetPage (wxSize panel_size, int border)
1095 #ifdef DCPOMATIC_OSX
1096                 /* We have to force both width and height of this one */
1097                 : Page (wxSize (panel_size.GetWidth(), 128), border)
1098 #else
1099                 : Page (panel_size, border)
1100 #endif
1101         {}
1102
1103         wxString GetName () const
1104         {
1105                 return _("Cover Sheet");
1106         }
1107
1108 #ifdef DCPOMATIC_OSX
1109         wxBitmap GetLargeIcon () const
1110         {
1111                 return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE);
1112         }
1113 #endif
1114
1115 private:
1116         void setup ()
1117         {
1118                 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1119                 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1120
1121                 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1122                 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1123
1124                 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1125                 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1126         }
1127
1128         void config_changed ()
1129         {
1130                 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
1131         }
1132
1133         void cover_sheet_changed ()
1134         {
1135                 if (_cover_sheet->GetValue().IsEmpty ()) {
1136                         /* Sometimes we get sent an erroneous notification that the cover sheet
1137                            is empty; I don't know why.
1138                         */
1139                         return;
1140                 }
1141                 Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ()));
1142         }
1143
1144         void reset_cover_sheet ()
1145         {
1146                 Config::instance()->reset_cover_sheet ();
1147                 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
1148         }
1149
1150         wxTextCtrl* _cover_sheet;
1151         wxButton* _reset_cover_sheet;
1152 };
1153
1154
1155 class IdentifiersPage : public Page
1156 {
1157 public:
1158         IdentifiersPage (wxSize panel_size, int border)
1159                 : Page (panel_size, border)
1160         {}
1161
1162         wxString GetName () const
1163         {
1164                 return _("Identifiers");
1165         }
1166
1167 #ifdef DCPOMATIC_OSX
1168         wxBitmap GetLargeIcon () const
1169         {
1170                 return wxBitmap ("identifiers", wxBITMAP_TYPE_PNG_RESOURCE);
1171         }
1172 #endif
1173
1174 private:
1175         void setup ()
1176         {
1177                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1178                 table->AddGrowableCol (1, 1);
1179
1180                 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1181                 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1182                 _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."));
1183                 table->Add (_issuer, 1, wxALL | wxEXPAND);
1184
1185                 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1186                 _creator = new wxTextCtrl (_panel, wxID_ANY);
1187                 _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."));
1188                 table->Add (_creator, 1, wxALL | wxEXPAND);
1189
1190                 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1191                 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1192                 _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."));
1193                 table->Add (_company_name, 1, wxALL | wxEXPAND);
1194
1195                 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1196                 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1197                 _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."));
1198                 table->Add (_product_name, 1, wxALL | wxEXPAND);
1199
1200                 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1201                 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1202                 _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."));
1203                 table->Add (_product_version, 1, wxALL | wxEXPAND);
1204
1205                 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1206                 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1207                 _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."));
1208                 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1209
1210                 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1211
1212                 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1213                 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1214                 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1215                 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1216                 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1217                 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1218         }
1219
1220         void config_changed ()
1221         {
1222                 Config* config = Config::instance ();
1223                 checked_set (_issuer, config->dcp_issuer ());
1224                 checked_set (_creator, config->dcp_creator ());
1225                 checked_set (_company_name, config->dcp_company_name ());
1226                 checked_set (_product_name, config->dcp_product_name ());
1227                 checked_set (_product_version, config->dcp_product_version ());
1228                 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1229         }
1230
1231         void issuer_changed ()
1232         {
1233                 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
1234         }
1235
1236         void creator_changed ()
1237         {
1238                 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
1239         }
1240
1241         void company_name_changed ()
1242         {
1243                 Config::instance()->set_dcp_company_name (wx_to_std(_company_name->GetValue()));
1244         }
1245
1246         void product_name_changed ()
1247         {
1248                 Config::instance()->set_dcp_product_name (wx_to_std(_product_name->GetValue()));
1249         }
1250
1251         void product_version_changed ()
1252         {
1253                 Config::instance()->set_dcp_product_version (wx_to_std(_product_version->GetValue()));
1254         }
1255
1256         void j2k_comment_changed ()
1257         {
1258                 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1259         }
1260
1261         wxTextCtrl* _issuer;
1262         wxTextCtrl* _creator;
1263         wxTextCtrl* _company_name;
1264         wxTextCtrl* _product_name;
1265         wxTextCtrl* _product_version;
1266         wxTextCtrl* _j2k_comment;
1267 };
1268
1269
1270 /** @class AdvancedPage
1271  *  @brief Advanced page of the preferences dialog.
1272  */
1273 class AdvancedPage : public Page
1274 {
1275 public:
1276         AdvancedPage (wxSize panel_size, int border)
1277                 : Page (panel_size, border)
1278                 , _maximum_j2k_bandwidth (0)
1279                 , _allow_any_dcp_frame_rate (0)
1280                 , _allow_any_container (0)
1281                 , _show_experimental_audio_processors (0)
1282                 , _only_servers_encode (0)
1283                 , _log_general (0)
1284                 , _log_warning (0)
1285                 , _log_error (0)
1286                 , _log_timing (0)
1287                 , _log_debug_threed (0)
1288                 , _log_debug_encode (0)
1289                 , _log_debug_email (0)
1290                 , _log_debug_video_view (0)
1291                 , _log_debug_player (0)
1292                 , _log_debug_audio_analysis (0)
1293         {}
1294
1295         wxString GetName () const
1296         {
1297                 return _("Advanced");
1298         }
1299
1300 #ifdef DCPOMATIC_OSX
1301         wxBitmap GetLargeIcon () const
1302         {
1303                 return wxBitmap ("advanced", wxBITMAP_TYPE_PNG_RESOURCE);
1304         }
1305 #endif
1306
1307 private:
1308         void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1309         {
1310                 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1311 #ifdef __WXOSX__
1312                 flags |= wxALIGN_RIGHT;
1313                 text += wxT (":");
1314 #endif
1315                 wxStaticText* m = new StaticText (parent, text);
1316                 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1317         }
1318
1319         void setup ()
1320         {
1321                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1322                 table->AddGrowableCol (1, 1);
1323                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1324
1325                 {
1326                         add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1327                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1328                         _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1329                         s->Add (_maximum_j2k_bandwidth, 1);
1330                         add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1331                         table->Add (s, 1);
1332                 }
1333
1334                 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1335                 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1336                 table->Add (_video_display_mode);
1337
1338                 wxStaticText* restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1339                 wxFont font = restart->GetFont();
1340                 font.SetStyle (wxFONTSTYLE_ITALIC);
1341                 font.SetPointSize (font.GetPointSize() - 1);
1342                 restart->SetFont (font);
1343                 table->AddSpacer (0);
1344
1345                 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1346                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1347                 table->AddSpacer (0);
1348
1349                 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1350                 table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
1351                 table->AddSpacer (0);
1352
1353                 restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
1354                 restart->SetFont (font);
1355                 table->AddSpacer (0);
1356
1357                 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1358                 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL);
1359                 table->AddSpacer (0);
1360
1361                 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1362                 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1363                 table->AddSpacer (0);
1364
1365                 {
1366                         add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1367                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1368                         _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1369                         s->Add (_frames_in_memory_multiplier, 1);
1370                         table->Add (s, 1);
1371                 }
1372
1373                 {
1374                         add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1375                         dcp::NameFormat::Map titles;
1376                         titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1377                         dcp::NameFormat::Map examples;
1378                         examples['t'] = "cpl";
1379                         _dcp_metadata_filename_format = new NameFormatEditor (
1380                                 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1381                                 );
1382                         table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1383                 }
1384
1385                 {
1386                         add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1387                         dcp::NameFormat::Map titles;
1388                         titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1389                         titles['r'] = wx_to_std (_("reel number"));
1390                         titles['n'] = wx_to_std (_("number of reels"));
1391                         titles['c'] = wx_to_std (_("content filename"));
1392                         dcp::NameFormat::Map examples;
1393                         examples['t'] = "j2c";
1394                         examples['r'] = "1";
1395                         examples['n'] = "4";
1396                         examples['c'] = "myfile.mp4";
1397                         _dcp_asset_filename_format = new NameFormatEditor (
1398                                 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1399                                 );
1400                         table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1401                 }
1402
1403                 {
1404                         add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1405                         wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1406                         _log_general = new CheckBox (_panel, _("General"));
1407                         t->Add (_log_general, 1, wxEXPAND | wxALL);
1408                         _log_warning = new CheckBox (_panel, _("Warnings"));
1409                         t->Add (_log_warning, 1, wxEXPAND | wxALL);
1410                         _log_error = new CheckBox (_panel, _("Errors"));
1411                         t->Add (_log_error, 1, wxEXPAND | wxALL);
1412                         /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1413                         _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1414                         t->Add (_log_timing, 1, wxEXPAND | wxALL);
1415                         _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1416                         t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1417                         _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1418                         t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1419                         _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1420                         t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1421                         _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1422                         t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1423                         _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1424                         t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1425                         _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1426                         t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1427                         table->Add (t, 0, wxALL, 6);
1428                 }
1429
1430 #ifdef DCPOMATIC_WINDOWS
1431                 _win32_console = new CheckBox (_panel, _("Open console window"));
1432                 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1433                 table->AddSpacer (0);
1434 #endif
1435
1436                 _maximum_j2k_bandwidth->SetRange (1, 1000);
1437                 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1438                 _video_display_mode->Append (_("Simple (safer)"));
1439                 _video_display_mode->Append (_("OpenGL (faster)"));
1440                 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1441                 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1442                 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1443                 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1444                 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1445                 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1446                 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1447                 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1448                 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1449                 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1450                 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1451                 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1452                 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1453                 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1454                 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1455                 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1456                 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1457                 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1458 #ifdef DCPOMATIC_WINDOWS
1459                 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1460 #endif
1461         }
1462
1463         void config_changed ()
1464         {
1465                 Config* config = Config::instance ();
1466
1467                 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1468                 switch (config->video_view_type()) {
1469                 case Config::VIDEO_VIEW_SIMPLE:
1470                         checked_set (_video_display_mode, 0);
1471                         break;
1472                 case Config::VIDEO_VIEW_OPENGL:
1473                         checked_set (_video_display_mode, 1);
1474                         break;
1475                 }
1476                 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1477                 checked_set (_allow_any_container, config->allow_any_container ());
1478                 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1479                 checked_set (_only_servers_encode, config->only_servers_encode ());
1480                 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1481                 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1482                 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1483                 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1484                 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREED);
1485                 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1486                 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1487                 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1488                 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1489                 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1490                 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1491 #ifdef DCPOMATIC_WINDOWS
1492                 checked_set (_win32_console, config->win32_console());
1493 #endif
1494         }
1495
1496         void maximum_j2k_bandwidth_changed ()
1497         {
1498                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1499         }
1500
1501         void video_display_mode_changed ()
1502         {
1503                 if (_video_display_mode->GetSelection() == 0) {
1504                         Config::instance()->set_video_view_type (Config::VIDEO_VIEW_SIMPLE);
1505                 } else {
1506                         Config::instance()->set_video_view_type (Config::VIDEO_VIEW_OPENGL);
1507                 }
1508         }
1509
1510         void frames_in_memory_multiplier_changed ()
1511         {
1512                 Config::instance()->set_frames_in_memory_multiplier (_frames_in_memory_multiplier->GetValue());
1513         }
1514
1515         void allow_any_dcp_frame_rate_changed ()
1516         {
1517                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1518         }
1519
1520         void allow_any_container_changed ()
1521         {
1522                 Config::instance()->set_allow_any_container (_allow_any_container->GetValue ());
1523         }
1524
1525         void show_experimental_audio_processors_changed ()
1526         {
1527                 Config::instance()->set_show_experimental_audio_processors (_show_experimental_audio_processors->GetValue ());
1528         }
1529
1530         void only_servers_encode_changed ()
1531         {
1532                 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1533         }
1534
1535         void dcp_metadata_filename_format_changed ()
1536         {
1537                 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1538         }
1539
1540         void dcp_asset_filename_format_changed ()
1541         {
1542                 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1543         }
1544
1545         void log_changed ()
1546         {
1547                 int types = 0;
1548                 if (_log_general->GetValue ()) {
1549                         types |= LogEntry::TYPE_GENERAL;
1550                 }
1551                 if (_log_warning->GetValue ()) {
1552                         types |= LogEntry::TYPE_WARNING;
1553                 }
1554                 if (_log_error->GetValue ())  {
1555                         types |= LogEntry::TYPE_ERROR;
1556                 }
1557                 if (_log_timing->GetValue ()) {
1558                         types |= LogEntry::TYPE_TIMING;
1559                 }
1560                 if (_log_debug_threed->GetValue ()) {
1561                         types |= LogEntry::TYPE_DEBUG_THREED;
1562                 }
1563                 if (_log_debug_encode->GetValue ()) {
1564                         types |= LogEntry::TYPE_DEBUG_ENCODE;
1565                 }
1566                 if (_log_debug_email->GetValue ()) {
1567                         types |= LogEntry::TYPE_DEBUG_EMAIL;
1568                 }
1569                 if (_log_debug_video_view->GetValue()) {
1570                         types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1571                 }
1572                 if (_log_debug_player->GetValue()) {
1573                         types |= LogEntry::TYPE_DEBUG_PLAYER;
1574                 }
1575                 if (_log_debug_audio_analysis->GetValue()) {
1576                         types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1577                 }
1578                 Config::instance()->set_log_types (types);
1579         }
1580
1581 #ifdef DCPOMATIC_WINDOWS
1582         void win32_console_changed ()
1583         {
1584                 Config::instance()->set_win32_console (_win32_console->GetValue ());
1585         }
1586 #endif
1587
1588         wxSpinCtrl* _maximum_j2k_bandwidth;
1589         wxChoice* _video_display_mode;
1590         wxSpinCtrl* _frames_in_memory_multiplier;
1591         wxCheckBox* _allow_any_dcp_frame_rate;
1592         wxCheckBox* _allow_any_container;
1593         wxCheckBox* _show_experimental_audio_processors;
1594         wxCheckBox* _only_servers_encode;
1595         NameFormatEditor* _dcp_metadata_filename_format;
1596         NameFormatEditor* _dcp_asset_filename_format;
1597         wxCheckBox* _log_general;
1598         wxCheckBox* _log_warning;
1599         wxCheckBox* _log_error;
1600         wxCheckBox* _log_timing;
1601         wxCheckBox* _log_debug_threed;
1602         wxCheckBox* _log_debug_encode;
1603         wxCheckBox* _log_debug_email;
1604         wxCheckBox* _log_debug_video_view;
1605         wxCheckBox* _log_debug_player;
1606         wxCheckBox* _log_debug_audio_analysis;
1607 #ifdef DCPOMATIC_WINDOWS
1608         wxCheckBox* _win32_console;
1609 #endif
1610 };
1611
1612 wxPreferencesEditor*
1613 create_full_config_dialog ()
1614 {
1615         wxPreferencesEditor* e = new wxPreferencesEditor ();
1616
1617 #ifdef DCPOMATIC_OSX
1618         /* Width that we force some of the config panels to be on OSX so that
1619            the containing window doesn't shrink too much when we select those panels.
1620            This is obviously an unpleasant hack.
1621         */
1622         wxSize ps = wxSize (700, -1);
1623         int const border = 16;
1624 #else
1625         wxSize ps = wxSize (-1, -1);
1626         int const border = 8;
1627 #endif
1628
1629         e->AddPage (new FullGeneralPage (ps, border));
1630         e->AddPage (new SoundPage (ps, border));
1631         e->AddPage (new DefaultsPage (ps, border));
1632         e->AddPage (new EncodingServersPage (ps, border));
1633         e->AddPage (new KeysPage (ps, border));
1634         e->AddPage (new TMSPage (ps, border));
1635         e->AddPage (new EmailPage (ps, border));
1636         e->AddPage (new KDMEmailPage (ps, border));
1637         e->AddPage (new NotificationsPage (ps, border));
1638         e->AddPage (new CoverSheetPage (ps, border));
1639         e->AddPage (new IdentifiersPage (ps, border));
1640         e->AddPage (new AdvancedPage (ps, border));
1641         return e;
1642 }