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