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