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