Move email server preferences into a separate tab.
[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 EmailPage : public StandardPage
689 {
690 public:
691         EmailPage (wxSize panel_size, int border)
692 #ifdef DCPOMATIC_OSX
693                 /* We have to force both width and height of this one */
694                 : StandardPage (wxSize (480, 128), border)
695 #else
696                 : StandardPage (panel_size, border)
697 #endif
698         {}
699
700         wxString GetName () const
701         {
702                 return _("Email");
703         }
704
705 #ifdef DCPOMATIC_OSX
706         wxBitmap GetLargeIcon () const
707         {
708                 return wxBitmap ("email", wxBITMAP_TYPE_PNG_RESOURCE);
709         }
710 #endif
711
712 private:
713         void setup ()
714         {
715                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
716                 table->AddGrowableCol (1, 1);
717                 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
718
719                 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
720                 {
721                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
722                         _server = new wxTextCtrl (_panel, wxID_ANY);
723                         s->Add (_server, 1, wxEXPAND | wxALL);
724                         add_label_to_sizer (s, _panel, _("port"), false);
725                         _port = new wxSpinCtrl (_panel, wxID_ANY);
726                         _port->SetRange (0, 65535);
727                         s->Add (_port);
728                         table->Add (s, 1, wxEXPAND | wxALL);
729                 }
730
731                 add_label_to_sizer (table, _panel, _("Mail user name"), true);
732                 _user = new wxTextCtrl (_panel, wxID_ANY);
733                 table->Add (_user, 1, wxEXPAND | wxALL);
734
735                 add_label_to_sizer (table, _panel, _("Mail password"), true);
736                 _password = new wxTextCtrl (_panel, wxID_ANY);
737                 table->Add (_password, 1, wxEXPAND | wxALL);
738
739                 _server->Bind (wxEVT_TEXT, boost::bind (&EmailPage::server_changed, this));
740                 _port->Bind (wxEVT_SPINCTRL, boost::bind (&EmailPage::port_changed, this));
741                 _user->Bind (wxEVT_TEXT, boost::bind (&EmailPage::user_changed, this));
742                 _password->Bind (wxEVT_TEXT, boost::bind (&EmailPage::password_changed, this));
743         }
744
745         void config_changed ()
746         {
747                 Config* config = Config::instance ();
748
749                 checked_set (_server, config->mail_server ());
750                 checked_set (_port, config->mail_port ());
751                 checked_set (_user, config->mail_user ());
752                 checked_set (_password, config->mail_password ());
753         }
754
755         void server_changed ()
756         {
757                 Config::instance()->set_mail_server (wx_to_std (_server->GetValue ()));
758         }
759
760         void port_changed ()
761         {
762                 Config::instance()->set_mail_port (_port->GetValue ());
763         }
764
765         void user_changed ()
766         {
767                 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
768         }
769
770         void password_changed ()
771         {
772                 Config::instance()->set_mail_password (wx_to_std (_password->GetValue ()));
773         }
774
775         wxTextCtrl* _server;
776         wxSpinCtrl* _port;
777         wxTextCtrl* _user;
778         wxTextCtrl* _password;
779 };
780
781 class KDMEmailPage : public StandardPage
782 {
783 public:
784
785         KDMEmailPage (wxSize panel_size, int border)
786 #ifdef DCPOMATIC_OSX
787                 /* We have to force both width and height of this one */
788                 : StandardPage (wxSize (480, 128), border)
789 #else
790                 : StandardPage (panel_size, border)
791 #endif
792         {}
793
794         wxString GetName () const
795         {
796                 return _("KDM Email");
797         }
798
799 #ifdef DCPOMATIC_OSX
800         wxBitmap GetLargeIcon () const
801         {
802                 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
803         }
804 #endif
805
806 private:
807         void setup ()
808         {
809                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
810                 table->AddGrowableCol (1, 1);
811                 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
812
813                 add_label_to_sizer (table, _panel, _("Subject"), true);
814                 _subject = new wxTextCtrl (_panel, wxID_ANY);
815                 table->Add (_subject, 1, wxEXPAND | wxALL);
816
817                 add_label_to_sizer (table, _panel, _("From address"), true);
818                 _from = new wxTextCtrl (_panel, wxID_ANY);
819                 table->Add (_from, 1, wxEXPAND | wxALL);
820
821                 vector<string> columns;
822                 columns.push_back (wx_to_std (_("Address")));
823                 add_label_to_sizer (table, _panel, _("CC addresses"), true);
824                 _cc = new EditableList<string, EmailDialog> (
825                         _panel,
826                         columns,
827                         bind (&Config::kdm_cc, Config::instance()),
828                         bind (&Config::set_kdm_cc, Config::instance(), _1),
829                         bind (&column, _1)
830                         );
831                 table->Add (_cc, 1, wxEXPAND | wxALL);
832
833                 add_label_to_sizer (table, _panel, _("BCC address"), true);
834                 _bcc = new wxTextCtrl (_panel, wxID_ANY);
835                 table->Add (_bcc, 1, wxEXPAND | wxALL);
836
837                 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
838                 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
839
840                 _reset_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
841                 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
842
843                 _cc->layout ();
844
845                 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
846                 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
847                 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
848                 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
849                 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
850         }
851
852         void config_changed ()
853         {
854                 Config* config = Config::instance ();
855
856                 checked_set (_subject, config->kdm_subject ());
857                 checked_set (_from, config->kdm_from ());
858                 checked_set (_bcc, config->kdm_bcc ());
859                 checked_set (_email, Config::instance()->kdm_email ());
860         }
861
862         void kdm_subject_changed ()
863         {
864                 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
865         }
866
867         void kdm_from_changed ()
868         {
869                 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
870         }
871
872         void kdm_bcc_changed ()
873         {
874                 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
875         }
876
877         void kdm_email_changed ()
878         {
879                 if (_email->GetValue().IsEmpty ()) {
880                         /* Sometimes we get sent an erroneous notification that the email
881                            is empty; I don't know why.
882                         */
883                         return;
884                 }
885                 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
886         }
887
888         void reset_email ()
889         {
890                 Config::instance()->reset_kdm_email ();
891                 checked_set (_email, Config::instance()->kdm_email ());
892         }
893
894         wxTextCtrl* _subject;
895         wxTextCtrl* _from;
896         EditableList<string, EmailDialog>* _cc;
897         wxTextCtrl* _bcc;
898         wxTextCtrl* _email;
899         wxButton* _reset_email;
900 };
901
902 class CoverSheetPage : public StandardPage
903 {
904 public:
905
906         CoverSheetPage (wxSize panel_size, int border)
907 #ifdef DCPOMATIC_OSX
908                 /* We have to force both width and height of this one */
909                 : StandardPage (wxSize (480, 128), border)
910 #else
911                 : StandardPage (panel_size, border)
912 #endif
913         {}
914
915         wxString GetName () const
916         {
917                 return _("Cover Sheet");
918         }
919
920 #ifdef DCPOMATIC_OSX
921         wxBitmap GetLargeIcon () const
922         {
923                 return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE);
924         }
925 #endif
926
927 private:
928         void setup ()
929         {
930                 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
931                 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
932
933                 _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
934                 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
935
936                 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
937                 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
938         }
939
940         void config_changed ()
941         {
942                 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
943         }
944
945         void cover_sheet_changed ()
946         {
947                 if (_cover_sheet->GetValue().IsEmpty ()) {
948                         /* Sometimes we get sent an erroneous notification that the cover sheet
949                            is empty; I don't know why.
950                         */
951                         return;
952                 }
953                 Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ()));
954         }
955
956         void reset_cover_sheet ()
957         {
958                 Config::instance()->reset_cover_sheet ();
959                 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
960         }
961
962         wxTextCtrl* _cover_sheet;
963         wxButton* _reset_cover_sheet;
964 };
965
966
967 /** @class AdvancedPage
968  *  @brief Advanced page of the preferences dialog.
969  */
970 class AdvancedPage : public StockPage
971 {
972 public:
973         AdvancedPage (wxSize panel_size, int border)
974                 : StockPage (Kind_Advanced, panel_size, border)
975                 , _maximum_j2k_bandwidth (0)
976                 , _allow_any_dcp_frame_rate (0)
977                 , _only_servers_encode (0)
978                 , _log_general (0)
979                 , _log_warning (0)
980                 , _log_error (0)
981                 , _log_timing (0)
982                 , _log_debug_decode (0)
983                 , _log_debug_encode (0)
984                 , _log_debug_email (0)
985         {}
986
987 private:
988         void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
989         {
990                 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
991 #ifdef __WXOSX__
992                 flags |= wxALIGN_RIGHT;
993                 text += wxT (":");
994 #endif
995                 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
996                 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
997         }
998
999         void setup ()
1000         {
1001                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1002                 table->AddGrowableCol (1, 1);
1003                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1004
1005                 {
1006                         add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1007                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1008                         _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1009                         s->Add (_maximum_j2k_bandwidth, 1);
1010                         add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1011                         table->Add (s, 1);
1012                 }
1013
1014                 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1015                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1016                 table->AddSpacer (0);
1017
1018                 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1019                 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1020                 table->AddSpacer (0);
1021
1022                 {
1023                         add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true);
1024                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1025                         _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1026                         s->Add (_frames_in_memory_multiplier, 1);
1027                         table->Add (s, 1);
1028                 }
1029
1030                 {
1031                         add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1032                         dcp::NameFormat::Map titles;
1033                         titles['t'] = "type (cpl/pkl)";
1034                         dcp::NameFormat::Map examples;
1035                         examples['t'] = "cpl";
1036                         _dcp_metadata_filename_format = new NameFormatEditor (
1037                                 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1038                                 );
1039                         table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1040                 }
1041
1042                 {
1043                         add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1044                         dcp::NameFormat::Map titles;
1045                         titles['t'] = "type (j2c/pcm/sub)";
1046                         titles['r'] = "reel number";
1047                         titles['n'] = "number of reels";
1048                         titles['c'] = "content filename";
1049                         dcp::NameFormat::Map examples;
1050                         examples['t'] = "j2c";
1051                         examples['r'] = "1";
1052                         examples['n'] = "4";
1053                         examples['c'] = "myfile.mp4";
1054                         _dcp_asset_filename_format = new NameFormatEditor (
1055                                 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1056                                 );
1057                         table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1058                 }
1059
1060                 {
1061                         add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1062                         wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1063                         _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1064                         t->Add (_log_general, 1, wxEXPAND | wxALL);
1065                         _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1066                         t->Add (_log_warning, 1, wxEXPAND | wxALL);
1067                         _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1068                         t->Add (_log_error, 1, wxEXPAND | wxALL);
1069                         /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1070                         _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1071                         t->Add (_log_timing, 1, wxEXPAND | wxALL);
1072                         _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1073                         t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1074                         _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1075                         t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1076                         _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1077                         t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1078                         table->Add (t, 0, wxALL, 6);
1079                 }
1080
1081 #ifdef DCPOMATIC_WINDOWS
1082                 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1083                 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1084                 table->AddSpacer (0);
1085 #endif
1086
1087                 _maximum_j2k_bandwidth->SetRange (1, 1000);
1088                 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1089                 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1090                 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1091                 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1092                 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1093                 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1094                 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1095                 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1096                 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1097                 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1098                 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1099                 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1100                 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1101 #ifdef DCPOMATIC_WINDOWS
1102                 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1103 #endif
1104         }
1105
1106         void config_changed ()
1107         {
1108                 Config* config = Config::instance ();
1109
1110                 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1111                 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1112                 checked_set (_only_servers_encode, config->only_servers_encode ());
1113                 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1114                 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1115                 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1116                 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1117                 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1118                 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1119                 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1120                 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1121 #ifdef DCPOMATIC_WINDOWS
1122                 checked_set (_win32_console, config->win32_console());
1123 #endif
1124         }
1125
1126         void maximum_j2k_bandwidth_changed ()
1127         {
1128                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1129         }
1130
1131         void frames_in_memory_multiplier_changed ()
1132         {
1133                 Config::instance()->set_frames_in_memory_multiplier (_frames_in_memory_multiplier->GetValue());
1134         }
1135
1136         void allow_any_dcp_frame_rate_changed ()
1137         {
1138                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1139         }
1140
1141         void only_servers_encode_changed ()
1142         {
1143                 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1144         }
1145
1146         void dcp_metadata_filename_format_changed ()
1147         {
1148                 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1149         }
1150
1151         void dcp_asset_filename_format_changed ()
1152         {
1153                 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1154         }
1155
1156         void log_changed ()
1157         {
1158                 int types = 0;
1159                 if (_log_general->GetValue ()) {
1160                         types |= LogEntry::TYPE_GENERAL;
1161                 }
1162                 if (_log_warning->GetValue ()) {
1163                         types |= LogEntry::TYPE_WARNING;
1164                 }
1165                 if (_log_error->GetValue ())  {
1166                         types |= LogEntry::TYPE_ERROR;
1167                 }
1168                 if (_log_timing->GetValue ()) {
1169                         types |= LogEntry::TYPE_TIMING;
1170                 }
1171                 if (_log_debug_decode->GetValue ()) {
1172                         types |= LogEntry::TYPE_DEBUG_DECODE;
1173                 }
1174                 if (_log_debug_encode->GetValue ()) {
1175                         types |= LogEntry::TYPE_DEBUG_ENCODE;
1176                 }
1177                 if (_log_debug_email->GetValue ()) {
1178                         types |= LogEntry::TYPE_DEBUG_EMAIL;
1179                 }
1180                 Config::instance()->set_log_types (types);
1181         }
1182
1183 #ifdef DCPOMATIC_WINDOWS
1184         void win32_console_changed ()
1185         {
1186                 Config::instance()->set_win32_console (_win32_console->GetValue ());
1187         }
1188 #endif
1189
1190         wxSpinCtrl* _maximum_j2k_bandwidth;
1191         wxSpinCtrl* _frames_in_memory_multiplier;
1192         wxCheckBox* _allow_any_dcp_frame_rate;
1193         wxCheckBox* _only_servers_encode;
1194         NameFormatEditor* _dcp_metadata_filename_format;
1195         NameFormatEditor* _dcp_asset_filename_format;
1196         wxCheckBox* _log_general;
1197         wxCheckBox* _log_warning;
1198         wxCheckBox* _log_error;
1199         wxCheckBox* _log_timing;
1200         wxCheckBox* _log_debug_decode;
1201         wxCheckBox* _log_debug_encode;
1202         wxCheckBox* _log_debug_email;
1203 #ifdef DCPOMATIC_WINDOWS
1204         wxCheckBox* _win32_console;
1205 #endif
1206 };
1207
1208 wxPreferencesEditor*
1209 create_full_config_dialog ()
1210 {
1211         wxPreferencesEditor* e = new wxPreferencesEditor ();
1212
1213 #ifdef DCPOMATIC_OSX
1214         /* Width that we force some of the config panels to be on OSX so that
1215            the containing window doesn't shrink too much when we select those panels.
1216            This is obviously an unpleasant hack.
1217         */
1218         wxSize ps = wxSize (520, -1);
1219         int const border = 16;
1220 #else
1221         wxSize ps = wxSize (-1, -1);
1222         int const border = 8;
1223 #endif
1224
1225         e->AddPage (new FullGeneralPage (ps, border));
1226         e->AddPage (new DefaultsPage (ps, border));
1227         e->AddPage (new EncodingServersPage (ps, border));
1228         e->AddPage (new KeysPage (ps, border));
1229         e->AddPage (new TMSPage (ps, border));
1230         e->AddPage (new EmailPage (ps, border));
1231         e->AddPage (new KDMEmailPage (ps, border));
1232         e->AddPage (new CoverSheetPage (ps, border));
1233         e->AddPage (new AdvancedPage (ps, border));
1234         return e;
1235 }