306e1f208ca7874ae883d4a24e3dce9af11548e5
[dcpomatic.git] / src / wx / config_dialog.cc
1 /*
2     Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /** @file src/config_dialog.cc
21  *  @brief A dialogue to edit DCP-o-matic configuration.
22  */
23
24 #include <iostream>
25 #include <boost/lexical_cast.hpp>
26 #include <boost/filesystem.hpp>
27 #include <wx/stdpaths.h>
28 #include <wx/preferences.h>
29 #include <wx/filepicker.h>
30 #include <wx/spinctrl.h>
31 #include <dcp/colour_matrix.h>
32 #include "lib/config.h"
33 #include "lib/ratio.h"
34 #include "lib/scaler.h"
35 #include "lib/filter.h"
36 #include "lib/dcp_content_type.h"
37 #include "lib/colour_conversion.h"
38 #include "lib/log.h"
39 #include "config_dialog.h"
40 #include "wx_util.h"
41 #include "editable_list.h"
42 #include "filter_dialog.h"
43 #include "dir_picker_ctrl.h"
44 #include "isdcf_metadata_dialog.h"
45 #include "preset_colour_conversion_dialog.h"
46 #include "server_dialog.h"
47
48 using std::vector;
49 using std::string;
50 using std::list;
51 using std::cout;
52 using boost::bind;
53 using boost::shared_ptr;
54 using boost::lexical_cast;
55
56 class Page
57 {
58 public:
59         Page (wxSize panel_size, int border)
60                 : _panel_size (panel_size)
61                 , _border (border)
62         {}
63
64 protected:
65         wxSize _panel_size;
66         int _border;
67 };
68
69 class GeneralPage : public wxStockPreferencesPage, public Page
70 {
71 public:
72         GeneralPage (wxSize panel_size, int border)
73                 : wxStockPreferencesPage (Kind_General)
74                 , Page (panel_size, border)
75         {}
76
77         wxWindow* CreateWindow (wxWindow* parent)
78         {
79                 wxPanel* panel = new wxPanel (parent);
80                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
81                 panel->SetSizer (s);
82
83                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
84                 table->AddGrowableCol (1, 1);
85                 s->Add (table, 1, wxALL | wxEXPAND, _border);
86                 
87                 _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
88                 table->Add (_set_language, 1);
89                 _language = new wxChoice (panel, wxID_ANY);
90                 _language->Append (wxT ("Deutsch"));
91                 _language->Append (wxT ("English"));
92                 _language->Append (wxT ("Español"));
93                 _language->Append (wxT ("Français"));
94                 _language->Append (wxT ("Italiano"));
95                 _language->Append (wxT ("Nederlands"));
96                 _language->Append (wxT ("Svenska"));
97                 table->Add (_language);
98                 
99                 wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
100                 wxFont font = restart->GetFont();
101                 font.SetStyle (wxFONTSTYLE_ITALIC);
102                 font.SetPointSize (font.GetPointSize() - 1);
103                 restart->SetFont (font);
104                 table->AddSpacer (0);
105                 
106                 add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
107                 _num_local_encoding_threads = new wxSpinCtrl (panel);
108                 table->Add (_num_local_encoding_threads, 1);
109
110                 
111                 _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
112                 table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
113                 table->AddSpacer (0);
114                 
115                 _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
116                 table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
117                 table->AddSpacer (0);
118                 
119                 Config* config = Config::instance ();
120                 
121                 _set_language->SetValue (config->language ());
122                 
123                 if (config->language().get_value_or ("") == "fr") {
124                         _language->SetSelection (3);
125                 } else if (config->language().get_value_or ("") == "it") {
126                         _language->SetSelection (4);
127                 } else if (config->language().get_value_or ("") == "es") {
128                         _language->SetSelection (2);
129                 } else if (config->language().get_value_or ("") == "sv") {
130                         _language->SetSelection (6);
131                 } else if (config->language().get_value_or ("") == "de") {
132                         _language->SetSelection (0);
133                 } else if (config->language().get_value_or ("") == "nl") {
134                         _language->SetSelection (5);
135                 } else {
136                         _language->SetSelection (1);
137                 }
138                 
139                 setup_language_sensitivity ();
140                 
141                 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
142                 _language->Bind     (wxEVT_COMMAND_CHOICE_SELECTED,  boost::bind (&GeneralPage::language_changed,     this));
143                 
144                 _num_local_encoding_threads->SetRange (1, 128);
145                 _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
146                 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
147
148                 _check_for_updates->SetValue (config->check_for_updates ());
149                 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
150                 _check_for_test_updates->SetValue (config->check_for_test_updates ());
151                 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
152                 
153                 return panel;
154         }
155
156 private:        
157         void setup_language_sensitivity ()
158         {
159                 _language->Enable (_set_language->GetValue ());
160         }
161
162         void set_language_changed ()
163         {
164                 setup_language_sensitivity ();
165                 if (_set_language->GetValue ()) {
166                         language_changed ();
167                 } else {
168                         Config::instance()->unset_language ();
169                 }
170         }
171
172         void language_changed ()
173         {
174                 switch (_language->GetSelection ()) {
175                 case 0:
176                         Config::instance()->set_language ("de");
177                         break;
178                 case 1:
179                         Config::instance()->set_language ("en");
180                         break;
181                 case 2:
182                         Config::instance()->set_language ("es");
183                         break;
184                 case 3:
185                         Config::instance()->set_language ("fr");
186                         break;
187                 case 4:
188                         Config::instance()->set_language ("it");
189                         break;
190                 case 5:
191                         Config::instance()->set_language ("nl");
192                         break;
193                 case 6:
194                         Config::instance()->set_language ("sv");
195                         break;
196                 }
197         }
198         
199         void check_for_updates_changed ()
200         {
201                 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
202         }
203         
204         void check_for_test_updates_changed ()
205         {
206                 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
207         }
208
209         void num_local_encoding_threads_changed ()
210         {
211                 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
212         }
213
214         wxCheckBox* _set_language;
215         wxChoice* _language;
216         wxSpinCtrl* _num_local_encoding_threads;
217         wxCheckBox* _check_for_updates;
218         wxCheckBox* _check_for_test_updates;
219 };
220
221 class DefaultsPage : public wxPreferencesPage, public Page
222 {
223 public:
224         DefaultsPage (wxSize panel_size, int border)
225                 : Page (panel_size, border)
226         {}
227         
228         wxString GetName () const
229         {
230                 return _("Defaults");
231         }
232
233 #ifdef DCPOMATIC_OSX    
234         wxBitmap GetLargeIcon () const
235         {
236                 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
237         }
238 #endif  
239
240         wxWindow* CreateWindow (wxWindow* parent)
241         {
242                 wxPanel* panel = new wxPanel (parent);
243                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
244                 panel->SetSizer (s);
245
246                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
247                 table->AddGrowableCol (1, 1);
248                 s->Add (table, 1, wxALL | wxEXPAND, _border);
249                 
250                 {
251                         add_label_to_sizer (table, panel, _("Default duration of still images"), true);
252                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
253                         _still_length = new wxSpinCtrl (panel);
254                         s->Add (_still_length);
255                         add_label_to_sizer (s, panel, _("s"), false);
256                         table->Add (s, 1);
257                 }
258                 
259                 add_label_to_sizer (table, panel, _("Default directory for new films"), true);
260 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
261                 _directory = new DirPickerCtrl (panel);
262 #else   
263                 _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
264 #endif
265                 table->Add (_directory, 1, wxEXPAND);
266                 
267                 add_label_to_sizer (table, panel, _("Default ISDCF name details"), true);
268                 _isdcf_metadata_button = new wxButton (panel, wxID_ANY, _("Edit..."));
269                 table->Add (_isdcf_metadata_button);
270
271                 add_label_to_sizer (table, panel, _("Default scale to"), true);
272                 _scale = new wxChoice (panel, wxID_ANY);
273                 table->Add (_scale);
274                 
275                 add_label_to_sizer (table, panel, _("Default container"), true);
276                 _container = new wxChoice (panel, wxID_ANY);
277                 table->Add (_container);
278                 
279                 add_label_to_sizer (table, panel, _("Default content type"), true);
280                 _dcp_content_type = new wxChoice (panel, wxID_ANY);
281                 table->Add (_dcp_content_type);
282                 
283                 {
284                         add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
285                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
286                         _j2k_bandwidth = new wxSpinCtrl (panel);
287                         s->Add (_j2k_bandwidth);
288                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
289                         table->Add (s, 1);
290                 }
291                 
292                 {
293                         add_label_to_sizer (table, panel, _("Default audio delay"), true);
294                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
295                         _audio_delay = new wxSpinCtrl (panel);
296                         s->Add (_audio_delay);
297                         add_label_to_sizer (s, panel, _("ms"), false);
298                         table->Add (s, 1);
299                 }
300
301                 add_label_to_sizer (table, panel, _("Default issuer"), true);
302                 _issuer = new wxTextCtrl (panel, wxID_ANY);
303                 table->Add (_issuer, 1, wxEXPAND);
304
305                 add_label_to_sizer (table, panel, _("Default creator"), true);
306                 _creator = new wxTextCtrl (panel, wxID_ANY);
307                 table->Add (_creator, 1, wxEXPAND);
308                 
309                 Config* config = Config::instance ();
310                 
311                 _still_length->SetRange (1, 3600);
312                 _still_length->SetValue (config->default_still_length ());
313                 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
314                 
315                 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
316                 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
317                 
318                 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
319                 
320                 vector<Ratio const *> ratio = Ratio::all ();
321                 int n = 0;
322                 for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) {
323                         _scale->Append (std_to_wx ((*i)->nickname ()));
324                         if (*i == config->default_scale ()) {
325                                 _scale->SetSelection (n);
326                         }
327                         _container->Append (std_to_wx ((*i)->nickname ()));
328                         if (*i == config->default_container ()) {
329                                 _container->SetSelection (n);
330                         }
331                         ++n;
332                 }
333                 
334                 _scale->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::scale_changed, this));
335                 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
336                 
337                 vector<DCPContentType const *> const ct = DCPContentType::all ();
338                 n = 0;
339                 for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
340                         _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
341                         if (*i == config->default_dcp_content_type ()) {
342                                 _dcp_content_type->SetSelection (n);
343                         }
344                         ++n;
345                 }
346                 
347                 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
348                 
349                 _j2k_bandwidth->SetRange (50, 250);
350                 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
351                 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
352                 
353                 _audio_delay->SetRange (-1000, 1000);
354                 _audio_delay->SetValue (config->default_audio_delay ());
355                 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
356
357                 _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer));
358                 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
359                 _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
360                 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::creator_changed, this));
361
362                 return panel;
363         }
364
365 private:
366         void j2k_bandwidth_changed ()
367         {
368                 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
369         }
370         
371         void audio_delay_changed ()
372         {
373                 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
374         }
375
376         void directory_changed ()
377         {
378                 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
379         }
380
381         void edit_isdcf_metadata_clicked (wxWindow* parent)
382         {
383                 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
384                 d->ShowModal ();
385                 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
386                 d->Destroy ();
387         }
388
389         void still_length_changed ()
390         {
391                 Config::instance()->set_default_still_length (_still_length->GetValue ());
392         }
393
394         void scale_changed ()
395         {
396                 vector<Ratio const *> ratio = Ratio::all ();
397                 Config::instance()->set_default_scale (ratio[_scale->GetSelection()]);
398         }
399         
400         void container_changed ()
401         {
402                 vector<Ratio const *> ratio = Ratio::all ();
403                 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
404         }
405         
406         void dcp_content_type_changed ()
407         {
408                 vector<DCPContentType const *> ct = DCPContentType::all ();
409                 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
410         }
411
412         void issuer_changed ()
413         {
414                 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
415                 m.issuer = wx_to_std (_issuer->GetValue ());
416                 Config::instance()->set_dcp_metadata (m);
417         }
418         
419         void creator_changed ()
420         {
421                 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
422                 m.creator = wx_to_std (_creator->GetValue ());
423                 Config::instance()->set_dcp_metadata (m);
424         }
425         
426         wxSpinCtrl* _j2k_bandwidth;
427         wxSpinCtrl* _audio_delay;
428         wxButton* _isdcf_metadata_button;
429         wxSpinCtrl* _still_length;
430 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
431         DirPickerCtrl* _directory;
432 #else
433         wxDirPickerCtrl* _directory;
434 #endif
435         wxChoice* _scale;
436         wxChoice* _container;
437         wxChoice* _dcp_content_type;
438         wxTextCtrl* _issuer;
439         wxTextCtrl* _creator;
440 };
441
442 class EncodingServersPage : public wxPreferencesPage, public Page
443 {
444 public:
445         EncodingServersPage (wxSize panel_size, int border)
446                 : Page (panel_size, border)
447         {}
448         
449         wxString GetName () const
450         {
451                 return _("Servers");
452         }
453
454 #ifdef DCPOMATIC_OSX    
455         wxBitmap GetLargeIcon () const
456         {
457                 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
458         }
459 #endif  
460
461         wxWindow* CreateWindow (wxWindow* parent)
462         {
463                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
464                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
465                 panel->SetSizer (s);
466                 
467                 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
468                 s->Add (_use_any_servers, 0, wxALL, _border);
469                 
470                 vector<string> columns;
471                 columns.push_back (wx_to_std (_("IP address / host name")));
472                 _servers_list = new EditableList<string, ServerDialog> (
473                         panel,
474                         columns,
475                         boost::bind (&Config::servers, Config::instance()),
476                         boost::bind (&Config::set_servers, Config::instance(), _1),
477                         boost::bind (&EncodingServersPage::server_column, this, _1)
478                         );
479                 
480                 s->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
481                 
482                 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
483                 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
484
485                 return panel;
486         }
487
488 private:        
489
490         void use_any_servers_changed ()
491         {
492                 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
493         }
494
495         string server_column (string s)
496         {
497                 return s;
498         }
499
500         wxCheckBox* _use_any_servers;
501         EditableList<string, ServerDialog>* _servers_list;
502 };
503
504 class ColourConversionsPage : public wxPreferencesPage, public Page
505 {
506 public:
507         ColourConversionsPage (wxSize panel_size, int border)
508                 : Page (panel_size, border)
509         {}
510         
511         wxString GetName () const
512         {
513                 return _("Colour Conversions");
514         }
515
516 #ifdef DCPOMATIC_OSX    
517         wxBitmap GetLargeIcon () const
518         {
519                 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
520         }
521 #endif  
522         wxWindow* CreateWindow (wxWindow* parent)
523         {
524                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
525                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
526                 panel->SetSizer (s);
527
528                 vector<string> columns;
529                 columns.push_back (wx_to_std (_("Name")));
530                 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
531                         panel,
532                         columns,
533                         boost::bind (&Config::colour_conversions, Config::instance()),
534                         boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
535                         boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
536                         300
537                         );
538
539                 s->Add (list, 1, wxEXPAND | wxALL, _border);
540                 return panel;
541         }
542
543 private:
544         string colour_conversion_column (PresetColourConversion c)
545         {
546                 return c.name;
547         }
548 };
549
550 class TMSPage : public wxPreferencesPage, public Page
551 {
552 public:
553         TMSPage (wxSize panel_size, int border)
554                 : Page (panel_size, border)
555         {}
556
557         wxString GetName () const
558         {
559                 return _("TMS");
560         }
561
562 #ifdef DCPOMATIC_OSX    
563         wxBitmap GetLargeIcon () const
564         {
565                 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
566         }
567 #endif  
568
569         wxWindow* CreateWindow (wxWindow* parent)
570         {
571                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
572                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
573                 panel->SetSizer (s);
574
575                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
576                 table->AddGrowableCol (1, 1);
577                 s->Add (table, 1, wxALL | wxEXPAND, _border);
578                 
579                 add_label_to_sizer (table, panel, _("IP address"), true);
580                 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
581                 table->Add (_tms_ip, 1, wxEXPAND);
582                 
583                 add_label_to_sizer (table, panel, _("Target path"), true);
584                 _tms_path = new wxTextCtrl (panel, wxID_ANY);
585                 table->Add (_tms_path, 1, wxEXPAND);
586                 
587                 add_label_to_sizer (table, panel, _("User name"), true);
588                 _tms_user = new wxTextCtrl (panel, wxID_ANY);
589                 table->Add (_tms_user, 1, wxEXPAND);
590                 
591                 add_label_to_sizer (table, panel, _("Password"), true);
592                 _tms_password = new wxTextCtrl (panel, wxID_ANY);
593                 table->Add (_tms_password, 1, wxEXPAND);
594                 
595                 Config* config = Config::instance ();
596                 
597                 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
598                 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
599                 _tms_path->SetValue (std_to_wx (config->tms_path ()));
600                 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
601                 _tms_user->SetValue (std_to_wx (config->tms_user ()));
602                 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
603                 _tms_password->SetValue (std_to_wx (config->tms_password ()));
604                 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
605
606                 return panel;
607         }
608
609 private:
610         void tms_ip_changed ()
611         {
612                 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
613         }
614         
615         void tms_path_changed ()
616         {
617                 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
618         }
619         
620         void tms_user_changed ()
621         {
622                 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
623         }
624         
625         void tms_password_changed ()
626         {
627                 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
628         }
629
630         wxTextCtrl* _tms_ip;
631         wxTextCtrl* _tms_path;
632         wxTextCtrl* _tms_user;
633         wxTextCtrl* _tms_password;
634 };
635
636 class KDMEmailPage : public wxPreferencesPage, public Page
637 {
638 public:
639
640         KDMEmailPage (wxSize panel_size, int border)
641                 : Page (panel_size, border)
642         {}
643         
644         wxString GetName () const
645         {
646                 return _("KDM Email");
647         }
648
649 #ifdef DCPOMATIC_OSX    
650         wxBitmap GetLargeIcon () const
651         {
652                 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
653         }
654 #endif  
655
656         wxWindow* CreateWindow (wxWindow* parent)
657         {
658                 /* We have to force both width and height of this one */
659 #ifdef DCPOMATIC_OSX
660                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
661 #else           
662                 wxPanel* panel = new wxPanel (parent);
663 #endif          
664                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
665                 panel->SetSizer (s);
666
667                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
668                 table->AddGrowableCol (1, 1);
669                 s->Add (table, 1, wxEXPAND | wxALL, _border);
670
671                 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
672                 _mail_server = new wxTextCtrl (panel, wxID_ANY);
673                 table->Add (_mail_server, 1, wxEXPAND | wxALL);
674                 
675                 add_label_to_sizer (table, panel, _("Mail user name"), true);
676                 _mail_user = new wxTextCtrl (panel, wxID_ANY);
677                 table->Add (_mail_user, 1, wxEXPAND | wxALL);
678                 
679                 add_label_to_sizer (table, panel, _("Mail password"), true);
680                 _mail_password = new wxTextCtrl (panel, wxID_ANY);
681                 table->Add (_mail_password, 1, wxEXPAND | wxALL);
682                 
683                 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
684                 wxFont font = plain->GetFont();
685                 font.SetStyle (wxFONTSTYLE_ITALIC);
686                 font.SetPointSize (font.GetPointSize() - 1);
687                 plain->SetFont (font);
688                 table->AddSpacer (0);
689
690                 add_label_to_sizer (table, panel, _("Subject"), true);
691                 _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
692                 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
693                 
694                 add_label_to_sizer (table, panel, _("From address"), true);
695                 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
696                 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
697
698                 add_label_to_sizer (table, panel, _("CC address"), true);
699                 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
700                 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
701                 
702                 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
703                 s->Add (_kdm_email, 1.5, wxEXPAND | wxALL, _border);
704
705                 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
706                 s->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
707
708                 Config* config = Config::instance ();
709                 _mail_server->SetValue (std_to_wx (config->mail_server ()));
710                 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
711                 _mail_user->SetValue (std_to_wx (config->mail_user ()));
712                 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
713                 _mail_password->SetValue (std_to_wx (config->mail_password ()));
714                 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
715                 _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
716                 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
717                 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
718                 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
719                 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
720                 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
721                 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
722                 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
723                 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
724
725                 return panel;
726         }
727
728 private:
729         void mail_server_changed ()
730         {
731                 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
732         }
733         
734         void mail_user_changed ()
735         {
736                 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
737         }
738         
739         void mail_password_changed ()
740         {
741                 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
742         }
743
744         void kdm_subject_changed ()
745         {
746                 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
747         }
748         
749         void kdm_from_changed ()
750         {
751                 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
752         }
753
754         void kdm_cc_changed ()
755         {
756                 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
757         }
758         
759         void kdm_email_changed ()
760         {
761                 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
762         }
763
764         void reset_kdm_email ()
765         {
766                 Config::instance()->reset_kdm_email ();
767                 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
768         }
769
770         wxTextCtrl* _mail_server;
771         wxTextCtrl* _mail_user;
772         wxTextCtrl* _mail_password;
773         wxTextCtrl* _kdm_subject;
774         wxTextCtrl* _kdm_from;
775         wxTextCtrl* _kdm_cc;
776         wxTextCtrl* _kdm_email;
777         wxButton* _reset_kdm_email;
778 };
779
780 class AdvancedPage : public wxStockPreferencesPage, public Page
781 {
782 public:
783
784         AdvancedPage (wxSize panel_size, int border)
785                 : wxStockPreferencesPage (Kind_Advanced)
786                 , Page (panel_size, border)
787         {}
788         
789         wxWindow* CreateWindow (wxWindow* parent)
790         {
791                 wxPanel* panel = new wxPanel (parent);
792
793                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
794                 panel->SetSizer (s);
795
796                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
797                 table->AddGrowableCol (1, 1);
798                 s->Add (table, 1, wxALL | wxEXPAND, _border);
799
800                 {
801                         add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
802                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
803                         _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
804                         s->Add (_maximum_j2k_bandwidth, 1);
805                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
806                         table->Add (s, 1);
807                 }
808
809                 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
810                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
811                 table->AddSpacer (0);
812
813                 add_label_to_sizer (table, panel, _("Log"), true);
814                 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
815                 table->Add (_log_general, 1, wxEXPAND | wxALL);
816                 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
817                 table->AddSpacer (0);
818                 table->Add (_log_warning, 1, wxEXPAND | wxALL);
819                 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
820                 table->AddSpacer (0);
821                 table->Add (_log_error, 1, wxEXPAND | wxALL);
822                 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
823                 table->AddSpacer (0);
824                 table->Add (_log_timing, 1, wxEXPAND | wxALL);
825
826                 Config* config = Config::instance ();
827                 
828                 _maximum_j2k_bandwidth->SetRange (1, 500);
829                 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
830                 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
831                 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
832                 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
833                 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
834                 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
835                 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
836                 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
837                 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
838                 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
839                 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
840                 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
841                 
842                 return panel;
843         }
844
845 private:
846
847         void maximum_j2k_bandwidth_changed ()
848         {
849                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
850         }
851
852         void allow_any_dcp_frame_rate_changed ()
853         {
854                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
855         }
856
857         void log_changed ()
858         {
859                 int types = 0;
860                 if (_log_general->GetValue ()) {
861                         types |= Log::TYPE_GENERAL;
862                 }
863                 if (_log_warning->GetValue ()) {
864                         types |= Log::TYPE_WARNING;
865                 }
866                 if (_log_error->GetValue ())  {
867                         types |= Log::TYPE_ERROR;
868                 }
869                 if (_log_timing->GetValue ()) {
870                         types |= Log::TYPE_TIMING;
871                 }
872                 Config::instance()->set_log_types (types);
873         }
874         
875         wxSpinCtrl* _maximum_j2k_bandwidth;
876         wxCheckBox* _allow_any_dcp_frame_rate;
877         wxCheckBox* _log_general;
878         wxCheckBox* _log_warning;
879         wxCheckBox* _log_error;
880         wxCheckBox* _log_timing;
881 };
882         
883 wxPreferencesEditor*
884 create_config_dialog ()
885 {
886         wxPreferencesEditor* e = new wxPreferencesEditor ();
887
888 #ifdef DCPOMATIC_OSX
889         /* Width that we force some of the config panels to be on OSX so that
890            the containing window doesn't shrink too much when we select those panels.
891            This is obviously an unpleasant hack.
892         */
893         wxSize ps = wxSize (480, -1);
894         int const border = 16;
895 #else
896         wxSize ps = wxSize (-1, -1);
897         int const border = 8;
898 #endif
899         
900         e->AddPage (new GeneralPage (ps, border));
901         e->AddPage (new DefaultsPage (ps, border));
902         e->AddPage (new EncodingServersPage (ps, border));
903         e->AddPage (new ColourConversionsPage (ps, border));
904         e->AddPage (new TMSPage (ps, border));
905         e->AddPage (new KDMEmailPage (ps, border));
906         e->AddPage (new AdvancedPage (ps, border));
907         return e;
908 }