5479c22cee8857955cc321208264a05ca764e194
[dcpomatic.git] / src / wx / config_dialog.cc
1 /*
2     Copyright (C) 2012 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/notebook.h>
29 #include <libdcp/colour_matrix.h>
30 #include "lib/config.h"
31 #include "lib/server.h"
32 #include "lib/ratio.h"
33 #include "lib/scaler.h"
34 #include "lib/filter.h"
35 #include "lib/dcp_content_type.h"
36 #include "lib/colour_conversion.h"
37 #include "config_dialog.h"
38 #include "wx_util.h"
39 #include "filter_dialog.h"
40 #include "server_dialog.h"
41 #include "dir_picker_ctrl.h"
42 #include "dci_metadata_dialog.h"
43 #include "preset_colour_conversion_dialog.h"
44
45 using std::vector;
46 using std::string;
47 using std::list;
48 using boost::bind;
49 using boost::shared_ptr;
50 using boost::lexical_cast;
51
52 ConfigDialog::ConfigDialog (wxWindow* parent)
53         : wxDialog (parent, wxID_ANY, _("DCP-o-matic Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
54 {
55         wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
56         _notebook = new wxNotebook (this, wxID_ANY);
57         s->Add (_notebook, 1);
58
59         make_misc_panel ();
60         _notebook->AddPage (_misc_panel, _("Miscellaneous"), true);
61         make_servers_panel ();
62         _notebook->AddPage (_servers_panel, _("Encoding servers"), false);
63         make_colour_conversions_panel ();
64         _notebook->AddPage (_colour_conversions_panel, _("Colour conversions"), false);
65         make_metadata_panel ();
66         _notebook->AddPage (_metadata_panel, _("Metadata"), false);
67         make_tms_panel ();
68         _notebook->AddPage (_tms_panel, _("TMS"), false);
69         make_kdm_email_panel ();
70         _notebook->AddPage (_kdm_email_panel, _("KDM email"), false);
71
72         wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
73         overall_sizer->Add (s, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
74
75         wxSizer* buttons = CreateSeparatedButtonSizer (wxOK);
76         if (buttons) {
77                 overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
78         }
79
80         SetSizer (overall_sizer);
81         overall_sizer->Layout ();
82         overall_sizer->SetSizeHints (this);
83 }
84
85 void
86 ConfigDialog::make_misc_panel ()
87 {
88         _misc_panel = new wxPanel (_notebook);
89         wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
90         _misc_panel->SetSizer (s);
91
92         wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
93         table->AddGrowableCol (1, 1);
94         s->Add (table, 1, wxALL | wxEXPAND, 8);
95
96         _set_language = new wxCheckBox (_misc_panel, wxID_ANY, _("Set language"));
97         table->Add (_set_language, 1);
98         _language = new wxChoice (_misc_panel, wxID_ANY);
99         _language->Append (wxT ("English"));
100         _language->Append (wxT ("Français"));
101         _language->Append (wxT ("Italiano"));
102         _language->Append (wxT ("Español"));
103         _language->Append (wxT ("Svenska"));
104         table->Add (_language);
105
106         wxStaticText* restart = add_label_to_sizer (table, _misc_panel, _("(restart DCP-o-matic to see language changes)"), false);
107         wxFont font = restart->GetFont();
108         font.SetStyle (wxFONTSTYLE_ITALIC);
109         font.SetPointSize (font.GetPointSize() - 1);
110         restart->SetFont (font);
111         table->AddSpacer (0);
112
113         add_label_to_sizer (table, _misc_panel, _("Threads to use for encoding on this host"), true);
114         _num_local_encoding_threads = new wxSpinCtrl (_misc_panel);
115         table->Add (_num_local_encoding_threads, 1);
116
117         add_label_to_sizer (table, _misc_panel, _("Outgoing mail server"), true);
118         _mail_server = new wxTextCtrl (_misc_panel, wxID_ANY);
119         table->Add (_mail_server, 1, wxEXPAND | wxALL);
120
121         add_label_to_sizer (table, _misc_panel, _("From address for KDM emails"), true);
122         _kdm_from = new wxTextCtrl (_misc_panel, wxID_ANY);
123         table->Add (_kdm_from, 1, wxEXPAND | wxALL);
124         
125         {
126                 add_label_to_sizer (table, _misc_panel, _("Default duration of still images"), true);
127                 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
128                 _default_still_length = new wxSpinCtrl (_misc_panel);
129                 s->Add (_default_still_length);
130                 add_label_to_sizer (s, _misc_panel, _("s"), false);
131                 table->Add (s, 1);
132         }
133
134         add_label_to_sizer (table, _misc_panel, _("Default directory for new films"), true);
135 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
136         _default_directory = new DirPickerCtrl (_misc_panel);
137 #else   
138         _default_directory = new wxDirPickerCtrl (_misc_panel, wxDD_DIR_MUST_EXIST);
139 #endif
140         table->Add (_default_directory, 1, wxEXPAND);
141
142         add_label_to_sizer (table, _misc_panel, _("Default DCI name details"), true);
143         _default_dci_metadata_button = new wxButton (_misc_panel, wxID_ANY, _("Edit..."));
144         table->Add (_default_dci_metadata_button);
145
146         add_label_to_sizer (table, _misc_panel, _("Default container"), true);
147         _default_container = new wxChoice (_misc_panel, wxID_ANY);
148         table->Add (_default_container);
149
150         add_label_to_sizer (table, _misc_panel, _("Default content type"), true);
151         _default_dcp_content_type = new wxChoice (_misc_panel, wxID_ANY);
152         table->Add (_default_dcp_content_type);
153
154         {
155                 add_label_to_sizer (table, _misc_panel, _("Default JPEG2000 bandwidth"), true);
156                 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
157                 _default_j2k_bandwidth = new wxSpinCtrl (_misc_panel);
158                 s->Add (_default_j2k_bandwidth);
159                 add_label_to_sizer (s, _misc_panel, _("MBps"), false);
160                 table->Add (s, 1);
161         }
162         
163         Config* config = Config::instance ();
164
165         _set_language->SetValue (config->language ());
166
167         if (config->language().get_value_or ("") == "fr") {
168                 _language->SetSelection (1);
169         } else if (config->language().get_value_or ("") == "it") {
170                 _language->SetSelection (2);
171         } else if (config->language().get_value_or ("") == "es") {
172                 _language->SetSelection (3);
173         } else if (config->language().get_value_or ("") == "sv") {
174                 _language->SetSelection (4);
175         } else {
176                 _language->SetSelection (0);
177         }
178
179         setup_language_sensitivity ();
180
181         _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ConfigDialog::set_language_changed, this));
182         _language->Bind     (wxEVT_COMMAND_CHOICE_SELECTED,  boost::bind (&ConfigDialog::language_changed,     this));
183
184         _num_local_encoding_threads->SetRange (1, 128);
185         _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
186         _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ConfigDialog::num_local_encoding_threads_changed, this));
187
188         _mail_server->SetValue (std_to_wx (config->mail_server ()));
189         _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::mail_server_changed, this));
190         _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
191         _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::kdm_from_changed, this));
192
193         _default_still_length->SetRange (1, 3600);
194         _default_still_length->SetValue (config->default_still_length ());
195         _default_still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ConfigDialog::default_still_length_changed, this));
196
197         _default_directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
198         _default_directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&ConfigDialog::default_directory_changed, this));
199
200         _default_dci_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ConfigDialog::edit_default_dci_metadata_clicked, this));
201
202         vector<Ratio const *> ratio = Ratio::all ();
203         int n = 0;
204         for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) {
205                 _default_container->Append (std_to_wx ((*i)->nickname ()));
206                 if (*i == config->default_container ()) {
207                         _default_container->SetSelection (n);
208                 }
209                 ++n;
210         }
211
212         _default_container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ConfigDialog::default_container_changed, this));
213         
214         vector<DCPContentType const *> const ct = DCPContentType::all ();
215         n = 0;
216         for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
217                 _default_dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
218                 if (*i == config->default_dcp_content_type ()) {
219                         _default_dcp_content_type->SetSelection (n);
220                 }
221                 ++n;
222         }
223
224         _default_dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ConfigDialog::default_dcp_content_type_changed, this));
225
226         _default_j2k_bandwidth->SetRange (50, 250);
227         _default_j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
228         _default_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ConfigDialog::default_j2k_bandwidth_changed, this));
229 }
230
231 void
232 ConfigDialog::make_tms_panel ()
233 {
234         _tms_panel = new wxPanel (_notebook);
235         wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
236         _tms_panel->SetSizer (s);
237
238         wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
239         table->AddGrowableCol (1, 1);
240         s->Add (table, 1, wxALL | wxEXPAND, 8);
241
242         add_label_to_sizer (table, _tms_panel, _("IP address"), true);
243         _tms_ip = new wxTextCtrl (_tms_panel, wxID_ANY);
244         table->Add (_tms_ip, 1, wxEXPAND);
245
246         add_label_to_sizer (table, _tms_panel, _("Target path"), true);
247         _tms_path = new wxTextCtrl (_tms_panel, wxID_ANY);
248         table->Add (_tms_path, 1, wxEXPAND);
249
250         add_label_to_sizer (table, _tms_panel, _("User name"), true);
251         _tms_user = new wxTextCtrl (_tms_panel, wxID_ANY);
252         table->Add (_tms_user, 1, wxEXPAND);
253
254         add_label_to_sizer (table, _tms_panel, _("Password"), true);
255         _tms_password = new wxTextCtrl (_tms_panel, wxID_ANY);
256         table->Add (_tms_password, 1, wxEXPAND);
257
258         Config* config = Config::instance ();
259         
260         _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
261         _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_ip_changed, this));
262         _tms_path->SetValue (std_to_wx (config->tms_path ()));
263         _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_path_changed, this));
264         _tms_user->SetValue (std_to_wx (config->tms_user ()));
265         _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_user_changed, this));
266         _tms_password->SetValue (std_to_wx (config->tms_password ()));
267         _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_password_changed, this));
268 }
269
270 void
271 ConfigDialog::make_metadata_panel ()
272 {
273         _metadata_panel = new wxPanel (_notebook);
274         wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
275         _metadata_panel->SetSizer (s);
276
277         wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
278         table->AddGrowableCol (1, 1);
279         s->Add (table, 1, wxALL | wxEXPAND, 8);
280
281         add_label_to_sizer (table, _metadata_panel, _("Issuer"), true);
282         _issuer = new wxTextCtrl (_metadata_panel, wxID_ANY);
283         table->Add (_issuer, 1, wxEXPAND);
284
285         add_label_to_sizer (table, _metadata_panel, _("Creator"), true);
286         _creator = new wxTextCtrl (_metadata_panel, wxID_ANY);
287         table->Add (_creator, 1, wxEXPAND);
288
289         Config* config = Config::instance ();
290
291         _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer));
292         _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::issuer_changed, this));
293         _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
294         _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::creator_changed, this));
295 }
296
297 static std::string
298 server_column (ServerDescription s, int c)
299 {
300         switch (c) {
301         case 0:
302                 return s.host_name ();
303         case 1:
304                 return lexical_cast<string> (s.threads ());
305         }
306
307         return "";
308 }
309
310 void
311 ConfigDialog::make_servers_panel ()
312 {
313         vector<string> columns;
314         columns.push_back (wx_to_std (_("IP address")));
315         columns.push_back (wx_to_std (_("Threads")));
316         _servers_panel = new EditableList<ServerDescription, ServerDialog> (
317                 _notebook,
318                 columns,
319                 boost::bind (&Config::servers, Config::instance()),
320                 boost::bind (&Config::set_servers, Config::instance(), _1),
321                 boost::bind (&server_column, _1, _2)
322                 );
323 }
324
325 void
326 ConfigDialog::language_changed ()
327 {
328         switch (_language->GetSelection ()) {
329         case 0:
330                 Config::instance()->set_language ("en");
331                 break;
332         case 1:
333                 Config::instance()->set_language ("fr");
334                 break;
335         case 2:
336                 Config::instance()->set_language ("it");
337                 break;
338         case 3:
339                 Config::instance()->set_language ("es");
340                 break;
341         case 4:
342                 Config::instance()->set_language ("sv");
343                 break;
344         }
345 }
346
347 void
348 ConfigDialog::tms_ip_changed ()
349 {
350         Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
351 }
352
353 void
354 ConfigDialog::tms_path_changed ()
355 {
356         Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
357 }
358
359 void
360 ConfigDialog::tms_user_changed ()
361 {
362         Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
363 }
364
365 void
366 ConfigDialog::tms_password_changed ()
367 {
368         Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
369 }
370
371 void
372 ConfigDialog::num_local_encoding_threads_changed ()
373 {
374         Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
375 }
376
377 void
378 ConfigDialog::default_directory_changed ()
379 {
380         Config::instance()->set_default_directory (wx_to_std (_default_directory->GetPath ()));
381 }
382
383 void
384 ConfigDialog::edit_default_dci_metadata_clicked ()
385 {
386         DCIMetadataDialog* d = new DCIMetadataDialog (this, Config::instance()->default_dci_metadata ());
387         d->ShowModal ();
388         Config::instance()->set_default_dci_metadata (d->dci_metadata ());
389         d->Destroy ();
390 }
391
392 void
393 ConfigDialog::set_language_changed ()
394 {
395         setup_language_sensitivity ();
396         if (_set_language->GetValue ()) {
397                 language_changed ();
398         } else {
399                 Config::instance()->unset_language ();
400         }
401 }
402
403 void
404 ConfigDialog::setup_language_sensitivity ()
405 {
406         _language->Enable (_set_language->GetValue ());
407 }
408
409 void
410 ConfigDialog::default_still_length_changed ()
411 {
412         Config::instance()->set_default_still_length (_default_still_length->GetValue ());
413 }
414
415 void
416 ConfigDialog::default_container_changed ()
417 {
418         vector<Ratio const *> ratio = Ratio::all ();
419         Config::instance()->set_default_container (ratio[_default_container->GetSelection()]);
420 }
421
422 void
423 ConfigDialog::default_dcp_content_type_changed ()
424 {
425         vector<DCPContentType const *> ct = DCPContentType::all ();
426         Config::instance()->set_default_dcp_content_type (ct[_default_dcp_content_type->GetSelection()]);
427 }
428
429 void
430 ConfigDialog::issuer_changed ()
431 {
432         libdcp::XMLMetadata m = Config::instance()->dcp_metadata ();
433         m.issuer = wx_to_std (_issuer->GetValue ());
434         Config::instance()->set_dcp_metadata (m);
435 }
436
437 void
438 ConfigDialog::creator_changed ()
439 {
440         libdcp::XMLMetadata m = Config::instance()->dcp_metadata ();
441         m.creator = wx_to_std (_creator->GetValue ());
442         Config::instance()->set_dcp_metadata (m);
443 }
444
445 void
446 ConfigDialog::default_j2k_bandwidth_changed ()
447 {
448         Config::instance()->set_default_j2k_bandwidth (_default_j2k_bandwidth->GetValue() * 1000000);
449 }
450
451 static std::string
452 colour_conversion_column (PresetColourConversion c)
453 {
454         return c.name;
455 }
456
457 void
458 ConfigDialog::make_colour_conversions_panel ()
459 {
460         vector<string> columns;
461         columns.push_back (wx_to_std (_("Name")));
462         _colour_conversions_panel = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
463                 _notebook,
464                 columns,
465                 boost::bind (&Config::colour_conversions, Config::instance()),
466                 boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
467                 boost::bind (&colour_conversion_column, _1)
468                 );
469 }
470
471 void
472 ConfigDialog::mail_server_changed ()
473 {
474         Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
475 }
476
477
478 void
479 ConfigDialog::kdm_from_changed ()
480 {
481         Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
482 }
483
484 void
485 ConfigDialog::make_kdm_email_panel ()
486 {
487         _kdm_email_panel = new wxPanel (_notebook);
488         wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
489         _kdm_email_panel->SetSizer (s);
490
491         _kdm_email = new wxTextCtrl (_kdm_email_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
492         s->Add (_kdm_email, 1, wxEXPAND | wxALL);
493
494         _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::kdm_email_changed, this));
495         _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
496 }
497
498 void
499 ConfigDialog::kdm_email_changed ()
500 {
501         Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
502 }