Add MBit/s label to JPEG2000 bandwidth configuration.
[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, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, _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                 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
678                 s->Add (_kdm_email, 1.5, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, _border);
679
680                 Config* config = Config::instance ();
681                 _mail_server->SetValue (std_to_wx (config->mail_server ()));
682                 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
683                 _mail_user->SetValue (std_to_wx (config->mail_user ()));
684                 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
685                 _mail_password->SetValue (std_to_wx (config->mail_password ()));
686                 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
687                 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
688                 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
689                 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
690                 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
691
692                 return panel;
693         }
694
695 private:
696         void mail_server_changed ()
697         {
698                 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
699         }
700         
701         void mail_user_changed ()
702         {
703                 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
704         }
705         
706         void mail_password_changed ()
707         {
708                 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
709         }
710         
711         void kdm_from_changed ()
712         {
713                 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
714         }
715
716         void kdm_email_changed ()
717         {
718                 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
719         }
720
721         wxTextCtrl* _mail_server;
722         wxTextCtrl* _mail_user;
723         wxTextCtrl* _mail_password;
724         wxTextCtrl* _kdm_from;
725         wxTextCtrl* _kdm_email;
726 };
727
728 class AdvancedPage : public wxStockPreferencesPage, public Page
729 {
730 public:
731
732         AdvancedPage (wxSize panel_size, int border)
733                 : wxStockPreferencesPage (Kind_Advanced)
734                 , Page (panel_size, border)
735         {}
736         
737         wxWindow* CreateWindow (wxWindow* parent)
738         {
739                 wxPanel* panel = new wxPanel (parent);
740
741                 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
742                 panel->SetSizer (s);
743
744                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
745                 table->AddGrowableCol (1, 1);
746                 s->Add (table, 1, wxALL | wxEXPAND, _border);
747
748                 {
749                         add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
750                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
751                         _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
752                         s->Add (_maximum_j2k_bandwidth, 1);
753                         add_label_to_sizer (s, panel, _("Mbit/s"), false);
754                         table->Add (s, 1);
755                 }
756
757                 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
758                 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
759                 table->AddSpacer (0);
760
761                 add_label_to_sizer (table, panel, _("Log"), true);
762                 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
763                 table->Add (_log_general, 1, wxEXPAND | wxALL);
764                 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
765                 table->AddSpacer (0);
766                 table->Add (_log_warning, 1, wxEXPAND | wxALL);
767                 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
768                 table->AddSpacer (0);
769                 table->Add (_log_error, 1, wxEXPAND | wxALL);
770                 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
771                 table->AddSpacer (0);
772                 table->Add (_log_timing, 1, wxEXPAND | wxALL);
773
774                 Config* config = Config::instance ();
775                 
776                 _maximum_j2k_bandwidth->SetRange (1, 500);
777                 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
778                 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
779                 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
780                 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
781                 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
782                 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
783                 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
784                 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
785                 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
786                 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
787                 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
788                 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
789                 
790                 return panel;
791         }
792
793 private:
794
795         void maximum_j2k_bandwidth_changed ()
796         {
797                 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
798         }
799
800         void allow_any_dcp_frame_rate_changed ()
801         {
802                 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
803         }
804
805         void log_changed ()
806         {
807                 int types = 0;
808                 if (_log_general->GetValue ()) {
809                         types |= Log::TYPE_GENERAL;
810                 }
811                 if (_log_warning->GetValue ()) {
812                         types |= Log::TYPE_WARNING;
813                 }
814                 if (_log_error->GetValue ())  {
815                         types |= Log::TYPE_ERROR;
816                 }
817                 if (_log_timing->GetValue ()) {
818                         types |= Log::TYPE_TIMING;
819                 }
820                 Config::instance()->set_log_types (types);
821         }
822         
823         wxSpinCtrl* _maximum_j2k_bandwidth;
824         wxCheckBox* _allow_any_dcp_frame_rate;
825         wxCheckBox* _log_general;
826         wxCheckBox* _log_warning;
827         wxCheckBox* _log_error;
828         wxCheckBox* _log_timing;
829 };
830         
831 wxPreferencesEditor*
832 create_config_dialog ()
833 {
834         wxPreferencesEditor* e = new wxPreferencesEditor ();
835
836 #ifdef DCPOMATIC_OSX
837         /* Width that we force some of the config panels to be on OSX so that
838            the containing window doesn't shrink too much when we select those panels.
839            This is obviously an unpleasant hack.
840         */
841         wxSize ps = wxSize (480, -1);
842         int const border = 16;
843 #else
844         wxSize ps = wxSize (-1, -1);
845         int const border = 8;
846 #endif
847         
848         e->AddPage (new GeneralPage (ps, border));
849         e->AddPage (new DefaultsPage (ps, border));
850         e->AddPage (new EncodingServersPage (ps, border));
851         e->AddPage (new ColourConversionsPage (ps, border));
852         e->AddPage (new TMSPage (ps, border));
853         e->AddPage (new KDMEmailPage (ps, border));
854         e->AddPage (new AdvancedPage (ps, border));
855         return e;
856 }