Merge master.
[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 container"), true);
272                 _container = new wxChoice (panel, wxID_ANY);
273                 table->Add (_container);
274                 
275                 add_label_to_sizer (table, panel, _("Default content type"), true);
276                 _dcp_content_type = new wxChoice (panel, wxID_ANY);
277                 table->Add (_dcp_content_type);
278                 
279                 {
280                         add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
281                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
282                         _j2k_bandwidth = new wxSpinCtrl (panel);
283                         s->Add (_j2k_bandwidth);
284                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
285                         table->Add (s, 1);
286                 }
287                 
288                 {
289                         add_label_to_sizer (table, panel, _("Default audio delay"), true);
290                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
291                         _audio_delay = new wxSpinCtrl (panel);
292                         s->Add (_audio_delay);
293                         add_label_to_sizer (s, panel, _("ms"), false);
294                         table->Add (s, 1);
295                 }
296
297                 add_label_to_sizer (table, panel, _("Default issuer"), true);
298                 _issuer = new wxTextCtrl (panel, wxID_ANY);
299                 table->Add (_issuer, 1, wxEXPAND);
300
301                 add_label_to_sizer (table, panel, _("Default creator"), true);
302                 _creator = new wxTextCtrl (panel, wxID_ANY);
303                 table->Add (_creator, 1, wxEXPAND);
304                 
305                 Config* config = Config::instance ();
306                 
307                 _still_length->SetRange (1, 3600);
308                 _still_length->SetValue (config->default_still_length ());
309                 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
310                 
311                 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
312                 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
313                 
314                 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
315                 
316                 vector<Ratio const *> ratio = Ratio::all ();
317                 int n = 0;
318                 for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) {
319                         _container->Append (std_to_wx ((*i)->nickname ()));
320                         if (*i == config->default_container ()) {
321                                 _container->SetSelection (n);
322                         }
323                         ++n;
324                 }
325                 
326                 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
327                 
328                 vector<DCPContentType const *> const ct = DCPContentType::all ();
329                 n = 0;
330                 for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
331                         _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
332                         if (*i == config->default_dcp_content_type ()) {
333                                 _dcp_content_type->SetSelection (n);
334                         }
335                         ++n;
336                 }
337                 
338                 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
339                 
340                 _j2k_bandwidth->SetRange (50, 250);
341                 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
342                 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
343                 
344                 _audio_delay->SetRange (-1000, 1000);
345                 _audio_delay->SetValue (config->default_audio_delay ());
346                 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
347
348                 _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer));
349                 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
350                 _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
351                 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::creator_changed, this));
352
353                 return panel;
354         }
355
356 private:
357         void j2k_bandwidth_changed ()
358         {
359                 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
360         }
361         
362         void audio_delay_changed ()
363         {
364                 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
365         }
366
367         void directory_changed ()
368         {
369                 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
370         }
371
372         void edit_isdcf_metadata_clicked (wxWindow* parent)
373         {
374                 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
375                 d->ShowModal ();
376                 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
377                 d->Destroy ();
378         }
379
380         void still_length_changed ()
381         {
382                 Config::instance()->set_default_still_length (_still_length->GetValue ());
383         }
384         
385         void container_changed ()
386         {
387                 vector<Ratio const *> ratio = Ratio::all ();
388                 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
389         }
390         
391         void dcp_content_type_changed ()
392         {
393                 vector<DCPContentType const *> ct = DCPContentType::all ();
394                 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
395         }
396
397         void issuer_changed ()
398         {
399                 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
400                 m.issuer = wx_to_std (_issuer->GetValue ());
401                 Config::instance()->set_dcp_metadata (m);
402         }
403         
404         void creator_changed ()
405         {
406                 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
407                 m.creator = wx_to_std (_creator->GetValue ());
408                 Config::instance()->set_dcp_metadata (m);
409         }
410         
411         wxSpinCtrl* _j2k_bandwidth;
412         wxSpinCtrl* _audio_delay;
413         wxButton* _isdcf_metadata_button;
414         wxSpinCtrl* _still_length;
415 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
416         DirPickerCtrl* _directory;
417 #else
418         wxDirPickerCtrl* _directory;
419 #endif
420         wxChoice* _container;
421         wxChoice* _dcp_content_type;
422         wxTextCtrl* _issuer;
423         wxTextCtrl* _creator;
424 };
425
426 class EncodingServersPage : public wxPreferencesPage, public Page
427 {
428 public:
429         EncodingServersPage (wxSize panel_size, int border)
430                 : Page (panel_size, border)
431         {}
432         
433         wxString GetName () const
434         {
435                 return _("Servers");
436         }
437
438 #ifdef DCPOMATIC_OSX    
439         wxBitmap GetLargeIcon () const
440         {
441                 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
442         }
443 #endif  
444
445         wxWindow* CreateWindow (wxWindow* parent)
446         {
447                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
448                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
449                 panel->SetSizer (s);
450                 
451                 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
452                 s->Add (_use_any_servers, 0, wxALL, _border);
453                 
454                 vector<string> columns;
455                 columns.push_back (wx_to_std (_("IP address / host name")));
456                 _servers_list = new EditableList<string, ServerDialog> (
457                         panel,
458                         columns,
459                         boost::bind (&Config::servers, Config::instance()),
460                         boost::bind (&Config::set_servers, Config::instance(), _1),
461                         boost::bind (&EncodingServersPage::server_column, this, _1)
462                         );
463                 
464                 s->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
465                 
466                 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
467                 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
468
469                 return panel;
470         }
471
472 private:        
473
474         void use_any_servers_changed ()
475         {
476                 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
477         }
478
479         string server_column (string s)
480         {
481                 return s;
482         }
483
484         wxCheckBox* _use_any_servers;
485         EditableList<string, ServerDialog>* _servers_list;
486 };
487
488 class ColourConversionsPage : public wxPreferencesPage, public Page
489 {
490 public:
491         ColourConversionsPage (wxSize panel_size, int border)
492                 : Page (panel_size, border)
493         {}
494         
495         wxString GetName () const
496         {
497                 return _("Colour Conversions");
498         }
499
500 #ifdef DCPOMATIC_OSX    
501         wxBitmap GetLargeIcon () const
502         {
503                 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
504         }
505 #endif  
506         wxWindow* CreateWindow (wxWindow* parent)
507         {
508                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
509                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
510                 panel->SetSizer (s);
511
512                 vector<string> columns;
513                 columns.push_back (wx_to_std (_("Name")));
514                 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
515                         panel,
516                         columns,
517                         boost::bind (&Config::colour_conversions, Config::instance()),
518                         boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
519                         boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
520                         300
521                         );
522
523                 s->Add (list, 1, wxEXPAND | wxALL, _border);
524                 return panel;
525         }
526
527 private:
528         string colour_conversion_column (PresetColourConversion c)
529         {
530                 return c.name;
531         }
532 };
533
534 class TMSPage : public wxPreferencesPage, public Page
535 {
536 public:
537         TMSPage (wxSize panel_size, int border)
538                 : Page (panel_size, border)
539         {}
540
541         wxString GetName () const
542         {
543                 return _("TMS");
544         }
545
546 #ifdef DCPOMATIC_OSX    
547         wxBitmap GetLargeIcon () const
548         {
549                 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
550         }
551 #endif  
552
553         wxWindow* CreateWindow (wxWindow* parent)
554         {
555                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
556                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
557                 panel->SetSizer (s);
558
559                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
560                 table->AddGrowableCol (1, 1);
561                 s->Add (table, 1, wxALL | wxEXPAND, _border);
562                 
563                 add_label_to_sizer (table, panel, _("IP address"), true);
564                 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
565                 table->Add (_tms_ip, 1, wxEXPAND);
566                 
567                 add_label_to_sizer (table, panel, _("Target path"), true);
568                 _tms_path = new wxTextCtrl (panel, wxID_ANY);
569                 table->Add (_tms_path, 1, wxEXPAND);
570                 
571                 add_label_to_sizer (table, panel, _("User name"), true);
572                 _tms_user = new wxTextCtrl (panel, wxID_ANY);
573                 table->Add (_tms_user, 1, wxEXPAND);
574                 
575                 add_label_to_sizer (table, panel, _("Password"), true);
576                 _tms_password = new wxTextCtrl (panel, wxID_ANY);
577                 table->Add (_tms_password, 1, wxEXPAND);
578                 
579                 Config* config = Config::instance ();
580                 
581                 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
582                 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
583                 _tms_path->SetValue (std_to_wx (config->tms_path ()));
584                 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
585                 _tms_user->SetValue (std_to_wx (config->tms_user ()));
586                 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
587                 _tms_password->SetValue (std_to_wx (config->tms_password ()));
588                 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
589
590                 return panel;
591         }
592
593 private:
594         void tms_ip_changed ()
595         {
596                 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
597         }
598         
599         void tms_path_changed ()
600         {
601                 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
602         }
603         
604         void tms_user_changed ()
605         {
606                 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
607         }
608         
609         void tms_password_changed ()
610         {
611                 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
612         }
613
614         wxTextCtrl* _tms_ip;
615         wxTextCtrl* _tms_path;
616         wxTextCtrl* _tms_user;
617         wxTextCtrl* _tms_password;
618 };
619
620 class KDMEmailPage : public wxPreferencesPage, public Page
621 {
622 public:
623
624         KDMEmailPage (wxSize panel_size, int border)
625                 : Page (panel_size, border)
626         {}
627         
628         wxString GetName () const
629         {
630                 return _("KDM Email");
631         }
632
633 #ifdef DCPOMATIC_OSX    
634         wxBitmap GetLargeIcon () const
635         {
636                 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
637         }
638 #endif  
639
640         wxWindow* CreateWindow (wxWindow* parent)
641         {
642                 /* We have to force both width and height of this one */
643 #ifdef DCPOMATIC_OSX
644                 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
645 #else           
646                 wxPanel* panel = new wxPanel (parent);
647 #endif          
648                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
649                 panel->SetSizer (s);
650
651                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
652                 table->AddGrowableCol (1, 1);
653                 s->Add (table, 1, wxEXPAND | wxALL, _border);
654
655                 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
656                 _mail_server = new wxTextCtrl (panel, wxID_ANY);
657                 table->Add (_mail_server, 1, wxEXPAND | wxALL);
658                 
659                 add_label_to_sizer (table, panel, _("Mail user name"), true);
660                 _mail_user = new wxTextCtrl (panel, wxID_ANY);
661                 table->Add (_mail_user, 1, wxEXPAND | wxALL);
662                 
663                 add_label_to_sizer (table, panel, _("Mail password"), true);
664                 _mail_password = new wxTextCtrl (panel, wxID_ANY);
665                 table->Add (_mail_password, 1, wxEXPAND | wxALL);
666                 
667                 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
668                 wxFont font = plain->GetFont();
669                 font.SetStyle (wxFONTSTYLE_ITALIC);
670                 font.SetPointSize (font.GetPointSize() - 1);
671                 plain->SetFont (font);
672                 table->AddSpacer (0);
673                 
674                 add_label_to_sizer (table, panel, _("From address"), true);
675                 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
676                 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
677
678                 add_label_to_sizer (table, panel, _("CC address"), true);
679                 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
680                 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
681                 
682                 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
683                 s->Add (_kdm_email, 1.5, wxEXPAND | wxALL, _border);
684
685                 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
686                 s->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
687
688                 Config* config = Config::instance ();
689                 _mail_server->SetValue (std_to_wx (config->mail_server ()));
690                 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
691                 _mail_user->SetValue (std_to_wx (config->mail_user ()));
692                 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
693                 _mail_password->SetValue (std_to_wx (config->mail_password ()));
694                 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
695                 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
696                 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
697                 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
698                 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
699                 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
700                 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
701                 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
702
703                 return panel;
704         }
705
706 private:
707         void mail_server_changed ()
708         {
709                 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
710         }
711         
712         void mail_user_changed ()
713         {
714                 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
715         }
716         
717         void mail_password_changed ()
718         {
719                 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
720         }
721         
722         void kdm_from_changed ()
723         {
724                 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
725         }
726
727         void kdm_cc_changed ()
728         {
729                 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
730         }
731         
732         void kdm_email_changed ()
733         {
734                 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
735         }
736
737         void reset_kdm_email ()
738         {
739                 Config::instance()->reset_kdm_email ();
740                 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
741         }
742
743         wxTextCtrl* _mail_server;
744         wxTextCtrl* _mail_user;
745         wxTextCtrl* _mail_password;
746         wxTextCtrl* _kdm_from;
747         wxTextCtrl* _kdm_cc;
748         wxTextCtrl* _kdm_email;
749         wxButton* _reset_kdm_email;
750 };
751
752 class AdvancedPage : public wxStockPreferencesPage, public Page
753 {
754 public:
755
756         AdvancedPage (wxSize panel_size, int border)
757                 : wxStockPreferencesPage (Kind_Advanced)
758                 , Page (panel_size, border)
759         {}
760         
761         wxWindow* CreateWindow (wxWindow* parent)
762         {
763                 wxPanel* panel = new wxPanel (parent);
764
765                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
766                 panel->SetSizer (s);
767
768                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
769                 table->AddGrowableCol (1, 1);
770                 s->Add (table, 1, wxALL | wxEXPAND, _border);
771
772                 {
773                         add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
774                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
775                         _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
776                         s->Add (_maximum_j2k_bandwidth, 1);
777                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
778                         table->Add (s, 1);
779                 }
780
781                 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
782                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
783                 table->AddSpacer (0);
784
785                 add_label_to_sizer (table, panel, _("Log"), true);
786                 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
787                 table->Add (_log_general, 1, wxEXPAND | wxALL);
788                 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
789                 table->AddSpacer (0);
790                 table->Add (_log_warning, 1, wxEXPAND | wxALL);
791                 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
792                 table->AddSpacer (0);
793                 table->Add (_log_error, 1, wxEXPAND | wxALL);
794                 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
795                 table->AddSpacer (0);
796                 table->Add (_log_timing, 1, wxEXPAND | wxALL);
797
798                 Config* config = Config::instance ();
799                 
800                 _maximum_j2k_bandwidth->SetRange (1, 500);
801                 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
802                 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
803                 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
804                 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
805                 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
806                 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
807                 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
808                 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
809                 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
810                 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
811                 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
812                 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
813                 
814                 return panel;
815         }
816
817 private:
818
819         void maximum_j2k_bandwidth_changed ()
820         {
821                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
822         }
823
824         void allow_any_dcp_frame_rate_changed ()
825         {
826                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
827         }
828
829         void log_changed ()
830         {
831                 int types = 0;
832                 if (_log_general->GetValue ()) {
833                         types |= Log::TYPE_GENERAL;
834                 }
835                 if (_log_warning->GetValue ()) {
836                         types |= Log::TYPE_WARNING;
837                 }
838                 if (_log_error->GetValue ())  {
839                         types |= Log::TYPE_ERROR;
840                 }
841                 if (_log_timing->GetValue ()) {
842                         types |= Log::TYPE_TIMING;
843                 }
844                 Config::instance()->set_log_types (types);
845         }
846         
847         wxSpinCtrl* _maximum_j2k_bandwidth;
848         wxCheckBox* _allow_any_dcp_frame_rate;
849         wxCheckBox* _log_general;
850         wxCheckBox* _log_warning;
851         wxCheckBox* _log_error;
852         wxCheckBox* _log_timing;
853 };
854         
855 wxPreferencesEditor*
856 create_config_dialog ()
857 {
858         wxPreferencesEditor* e = new wxPreferencesEditor ();
859
860 #ifdef DCPOMATIC_OSX
861         /* Width that we force some of the config panels to be on OSX so that
862            the containing window doesn't shrink too much when we select those panels.
863            This is obviously an unpleasant hack.
864         */
865         wxSize ps = wxSize (480, -1);
866         int const border = 16;
867 #else
868         wxSize ps = wxSize (-1, -1);
869         int const border = 8;
870 #endif
871         
872         e->AddPage (new GeneralPage (ps, border));
873         e->AddPage (new DefaultsPage (ps, border));
874         e->AddPage (new EncodingServersPage (ps, border));
875         e->AddPage (new ColourConversionsPage (ps, border));
876         e->AddPage (new TMSPage (ps, border));
877         e->AddPage (new KDMEmailPage (ps, border));
878         e->AddPage (new AdvancedPage (ps, border));
879         return e;
880 }