Merge.
[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 container"), true);
271                 _container = new wxChoice (panel, wxID_ANY);
272                 table->Add (_container);
273                 
274                 add_label_to_sizer (table, panel, _("Default content type"), true);
275                 _dcp_content_type = new wxChoice (panel, wxID_ANY);
276                 table->Add (_dcp_content_type);
277                 
278                 {
279                         add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
280                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
281                         _j2k_bandwidth = new wxSpinCtrl (panel);
282                         s->Add (_j2k_bandwidth);
283                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
284                         table->Add (s, 1);
285                 }
286                 
287                 {
288                         add_label_to_sizer (table, panel, _("Default audio delay"), true);
289                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
290                         _audio_delay = new wxSpinCtrl (panel);
291                         s->Add (_audio_delay);
292                         add_label_to_sizer (s, panel, _("ms"), false);
293                         table->Add (s, 1);
294                 }
295
296                 add_label_to_sizer (table, panel, _("Default issuer"), true);
297                 _issuer = new wxTextCtrl (panel, wxID_ANY);
298                 table->Add (_issuer, 1, wxEXPAND);
299
300                 add_label_to_sizer (table, panel, _("Default creator"), true);
301                 _creator = new wxTextCtrl (panel, wxID_ANY);
302                 table->Add (_creator, 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<Ratio const *> ratio = Ratio::all ();
316                 int n = 0;
317                 for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) {
318                         _container->Append (std_to_wx ((*i)->nickname ()));
319                         if (*i == config->default_container ()) {
320                                 _container->SetSelection (n);
321                         }
322                         ++n;
323                 }
324                 
325                 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
326                 
327                 vector<DCPContentType const *> const ct = DCPContentType::all ();
328                 n = 0;
329                 for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
330                         _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
331                         if (*i == config->default_dcp_content_type ()) {
332                                 _dcp_content_type->SetSelection (n);
333                         }
334                         ++n;
335                 }
336                 
337                 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
338                 
339                 _j2k_bandwidth->SetRange (50, 250);
340                 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
341                 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
342                 
343                 _audio_delay->SetRange (-1000, 1000);
344                 _audio_delay->SetValue (config->default_audio_delay ());
345                 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
346
347                 _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer));
348                 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
349                 _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
350                 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::creator_changed, this));
351
352                 return panel;
353         }
354
355 private:
356         void j2k_bandwidth_changed ()
357         {
358                 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
359         }
360         
361         void audio_delay_changed ()
362         {
363                 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
364         }
365
366         void directory_changed ()
367         {
368                 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
369         }
370
371         void edit_isdcf_metadata_clicked (wxWindow* parent)
372         {
373                 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
374                 d->ShowModal ();
375                 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
376                 d->Destroy ();
377         }
378
379         void still_length_changed ()
380         {
381                 Config::instance()->set_default_still_length (_still_length->GetValue ());
382         }
383         
384         void container_changed ()
385         {
386                 vector<Ratio const *> ratio = Ratio::all ();
387                 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
388         }
389         
390         void dcp_content_type_changed ()
391         {
392                 vector<DCPContentType const *> ct = DCPContentType::all ();
393                 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
394         }
395
396         void issuer_changed ()
397         {
398                 libdcp::XMLMetadata m = Config::instance()->dcp_metadata ();
399                 m.issuer = wx_to_std (_issuer->GetValue ());
400                 Config::instance()->set_dcp_metadata (m);
401         }
402         
403         void creator_changed ()
404         {
405                 libdcp::XMLMetadata m = Config::instance()->dcp_metadata ();
406                 m.creator = wx_to_std (_creator->GetValue ());
407                 Config::instance()->set_dcp_metadata (m);
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* _container;
420         wxChoice* _dcp_content_type;
421         wxTextCtrl* _issuer;
422         wxTextCtrl* _creator;
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, _("From address"), true);
674                 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
675                 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
676
677                 add_label_to_sizer (table, panel, _("CC address"), true);
678                 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
679                 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
680                 
681                 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
682                 s->Add (_kdm_email, 1.5, wxEXPAND | wxALL, _border);
683
684                 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
685                 s->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
686
687                 Config* config = Config::instance ();
688                 _mail_server->SetValue (std_to_wx (config->mail_server ()));
689                 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
690                 _mail_user->SetValue (std_to_wx (config->mail_user ()));
691                 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
692                 _mail_password->SetValue (std_to_wx (config->mail_password ()));
693                 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
694                 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
695                 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
696                 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
697                 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
698                 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
699                 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
700                 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
701
702                 return panel;
703         }
704
705 private:
706         void mail_server_changed ()
707         {
708                 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
709         }
710         
711         void mail_user_changed ()
712         {
713                 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
714         }
715         
716         void mail_password_changed ()
717         {
718                 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
719         }
720         
721         void kdm_from_changed ()
722         {
723                 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
724         }
725
726         void kdm_cc_changed ()
727         {
728                 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
729         }
730         
731         void kdm_email_changed ()
732         {
733                 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
734         }
735
736         void reset_kdm_email ()
737         {
738                 Config::instance()->reset_kdm_email ();
739                 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
740         }
741
742         wxTextCtrl* _mail_server;
743         wxTextCtrl* _mail_user;
744         wxTextCtrl* _mail_password;
745         wxTextCtrl* _kdm_from;
746         wxTextCtrl* _kdm_cc;
747         wxTextCtrl* _kdm_email;
748         wxButton* _reset_kdm_email;
749 };
750
751 class AdvancedPage : public wxStockPreferencesPage, public Page
752 {
753 public:
754
755         AdvancedPage (wxSize panel_size, int border)
756                 : wxStockPreferencesPage (Kind_Advanced)
757                 , Page (panel_size, border)
758         {}
759         
760         wxWindow* CreateWindow (wxWindow* parent)
761         {
762                 wxPanel* panel = new wxPanel (parent);
763
764                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
765                 panel->SetSizer (s);
766
767                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
768                 table->AddGrowableCol (1, 1);
769                 s->Add (table, 1, wxALL | wxEXPAND, _border);
770
771                 {
772                         add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
773                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
774                         _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
775                         s->Add (_maximum_j2k_bandwidth, 1);
776                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
777                         table->Add (s, 1);
778                 }
779
780                 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
781                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
782                 table->AddSpacer (0);
783
784                 add_label_to_sizer (table, panel, _("Log"), true);
785                 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
786                 table->Add (_log_general, 1, wxEXPAND | wxALL);
787                 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
788                 table->AddSpacer (0);
789                 table->Add (_log_warning, 1, wxEXPAND | wxALL);
790                 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
791                 table->AddSpacer (0);
792                 table->Add (_log_error, 1, wxEXPAND | wxALL);
793                 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
794                 table->AddSpacer (0);
795                 table->Add (_log_timing, 1, wxEXPAND | wxALL);
796
797                 Config* config = Config::instance ();
798                 
799                 _maximum_j2k_bandwidth->SetRange (1, 500);
800                 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
801                 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
802                 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
803                 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
804                 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
805                 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
806                 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
807                 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
808                 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
809                 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
810                 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
811                 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
812                 
813                 return panel;
814         }
815
816 private:
817
818         void maximum_j2k_bandwidth_changed ()
819         {
820                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
821         }
822
823         void allow_any_dcp_frame_rate_changed ()
824         {
825                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
826         }
827
828         void log_changed ()
829         {
830                 int types = 0;
831                 if (_log_general->GetValue ()) {
832                         types |= Log::TYPE_GENERAL;
833                 }
834                 if (_log_warning->GetValue ()) {
835                         types |= Log::TYPE_WARNING;
836                 }
837                 if (_log_error->GetValue ())  {
838                         types |= Log::TYPE_ERROR;
839                 }
840                 if (_log_timing->GetValue ()) {
841                         types |= Log::TYPE_TIMING;
842                 }
843                 Config::instance()->set_log_types (types);
844         }
845         
846         wxSpinCtrl* _maximum_j2k_bandwidth;
847         wxCheckBox* _allow_any_dcp_frame_rate;
848         wxCheckBox* _log_general;
849         wxCheckBox* _log_warning;
850         wxCheckBox* _log_error;
851         wxCheckBox* _log_timing;
852 };
853         
854 wxPreferencesEditor*
855 create_config_dialog ()
856 {
857         wxPreferencesEditor* e = new wxPreferencesEditor ();
858
859 #ifdef DCPOMATIC_OSX
860         /* Width that we force some of the config panels to be on OSX so that
861            the containing window doesn't shrink too much when we select those panels.
862            This is obviously an unpleasant hack.
863         */
864         wxSize ps = wxSize (480, -1);
865         int const border = 16;
866 #else
867         wxSize ps = wxSize (-1, -1);
868         int const border = 8;
869 #endif
870         
871         e->AddPage (new GeneralPage (ps, border));
872         e->AddPage (new DefaultsPage (ps, border));
873         e->AddPage (new EncodingServersPage (ps, border));
874         e->AddPage (new ColourConversionsPage (ps, border));
875         e->AddPage (new TMSPage (ps, border));
876         e->AddPage (new KDMEmailPage (ps, border));
877         e->AddPage (new AdvancedPage (ps, border));
878         return e;
879 }