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