Basics of in-place i18n with support for wxStaticText and wxCheckBox.
[dcpomatic.git] / src / wx / player_config_dialog.cc
1 /*
2     Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 /** @file src/player_config_dialog.cc
22  *  @brief A dialogue to edit DCP-o-matic Player configuration.
23  */
24
25 #include "config_dialog.h"
26 #include "wx_util.h"
27 #include "editable_list.h"
28 #include "filter_dialog.h"
29 #include "file_picker_ctrl.h"
30 #include "dir_picker_ctrl.h"
31 #include "isdcf_metadata_dialog.h"
32 #include "server_dialog.h"
33 #include "make_chain_dialog.h"
34 #include "email_dialog.h"
35 #include "name_format_editor.h"
36 #include "nag_dialog.h"
37 #include "monitor_dialog.h"
38 #include "check_box.h"
39 #include "lib/config.h"
40 #include "lib/ratio.h"
41 #include "lib/filter.h"
42 #include "lib/dcp_content_type.h"
43 #include "lib/log.h"
44 #include "lib/util.h"
45 #include "lib/cross.h"
46 #include "lib/exceptions.h"
47 #include <dcp/locale_convert.h>
48 #include <dcp/exceptions.h>
49 #include <dcp/certificate_chain.h>
50 #include <wx/stdpaths.h>
51 #include <wx/preferences.h>
52 #include <wx/spinctrl.h>
53 #include <wx/filepicker.h>
54 #include <RtAudio.h>
55 #include <boost/filesystem.hpp>
56 #include <boost/foreach.hpp>
57 #include <iostream>
58
59 using std::vector;
60 using std::string;
61 using std::list;
62 using std::cout;
63 using std::pair;
64 using std::make_pair;
65 using std::map;
66 using boost::bind;
67 using boost::shared_ptr;
68 using boost::function;
69 using boost::optional;
70 using dcp::locale_convert;
71
72 class PlayerGeneralPage : public GeneralPage
73 {
74 public:
75         PlayerGeneralPage (wxSize panel_size, int border)
76                 : GeneralPage (panel_size, border)
77         {}
78
79 private:
80         void setup ()
81         {
82                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
83                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
84
85                 int r = 0;
86                 add_language_controls (table, r);
87                 add_play_sound_controls (table, r);
88                 add_update_controls (table, r);
89
90                 add_label_to_sizer (table, _panel, _("Start player as"), true, wxGBPosition(r, 0));
91                 _player_mode = new wxChoice (_panel, wxID_ANY);
92                 _player_mode->Append (_("window"));
93                 _player_mode->Append (_("full screen"));
94                 _player_mode->Append (_("full screen with controls on other monitor"));
95                 table->Add (_player_mode, wxGBPosition(r, 1));
96                 ++r;
97
98                 add_label_to_sizer (table, _panel, _("Dual-screen displays"), true, wxGBPosition(r, 0));
99                 _image_display = new wxChoice (_panel, wxID_ANY);
100                 _image_display->Append (_("Image on primary, controls on secondary"));
101                 _image_display->Append (_("Image on secondary, controls on primary"));
102                 table->Add (_image_display, wxGBPosition(r, 1));
103                 ++r;
104
105                 _respect_kdm = new CheckBox (_panel, _("Respect KDM validity periods"));
106                 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
107                 ++r;
108
109                 add_label_to_sizer (table, _panel, _("Log file"), true, wxGBPosition (r, 0));
110                 _log_file = new FilePickerCtrl (_panel, _("Select log file"), "*", true);
111                 table->Add (_log_file, wxGBPosition (r, 1));
112                 ++r;
113
114 #ifdef DCPOMATIC_VARIANT_SWAROOP
115                 add_label_to_sizer (table, _panel, _("KDM server URL"), true, wxGBPosition(r, 0));
116                 _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
117                 table->Add (_kdm_server_url, wxGBPosition (r, 1));
118                 ++r;
119
120                 add_label_to_sizer (table, _panel, _("Lock file"), true, wxGBPosition(r, 0));
121                 _lock_file = new FilePickerCtrl (_panel, _("Select lock file"), "*", true);
122                 table->Add (_lock_file, wxGBPosition (r, 1));
123                 ++r;
124 #endif
125
126                 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
127                 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
128                 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
129                 _log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::log_file_changed, this));
130 #ifdef DCPOMATIC_VARIANT_SWAROOP
131                 _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
132                 _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this));
133 #endif
134         }
135
136         void config_changed ()
137         {
138                 GeneralPage::config_changed ();
139
140                 Config* config = Config::instance ();
141
142                 switch (config->player_mode()) {
143                 case Config::PLAYER_MODE_WINDOW:
144                         checked_set (_player_mode, 0);
145                         break;
146                 case Config::PLAYER_MODE_FULL:
147                         checked_set (_player_mode, 1);
148                         break;
149                 case Config::PLAYER_MODE_DUAL:
150                         checked_set (_player_mode, 2);
151                         break;
152                 }
153
154                 checked_set (_image_display, config->image_display());
155                 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
156                 if (config->player_log_file()) {
157                         checked_set (_log_file, *config->player_log_file());
158                 }
159 #ifdef DCPOMATIC_VARIANT_SWAROOP
160                 checked_set (_kdm_server_url, config->kdm_server_url());
161                 if (config->player_lock_file()) {
162                         checked_set (_lock_file, config->player_lock_file().get());
163                 }
164 #endif
165         }
166
167 private:
168         void player_mode_changed ()
169         {
170                 switch (_player_mode->GetSelection()) {
171                 case 0:
172                         Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
173                         break;
174                 case 1:
175                         Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
176                         break;
177                 case 2:
178                         Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
179                         break;
180                 }
181         }
182
183         void image_display_changed ()
184         {
185                 Config::instance()->set_image_display(_image_display->GetSelection());
186         }
187
188         void respect_kdm_changed ()
189         {
190                 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
191         }
192
193         void log_file_changed ()
194         {
195                 Config::instance()->set_player_log_file(wx_to_std(_log_file->GetPath()));
196         }
197
198 #ifdef DCPOMATIC_VARIANT_SWAROOP
199         void kdm_server_url_changed ()
200         {
201                 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
202         }
203
204         void lock_file_changed ()
205         {
206                 Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
207         }
208 #endif
209
210         wxChoice* _player_mode;
211         wxChoice* _image_display;
212         wxCheckBox* _respect_kdm;
213         FilePickerCtrl* _log_file;
214 #ifdef DCPOMATIC_VARIANT_SWAROOP
215         wxTextCtrl* _kdm_server_url;
216         FilePickerCtrl* _lock_file;
217 #endif
218 };
219
220 class LocationsPage : public StandardPage
221 {
222 public:
223         LocationsPage (wxSize panel_size, int border)
224                 : StandardPage (panel_size, border)
225         {}
226
227         wxString GetName () const
228         {
229                 return _("Locations");
230         }
231
232 #ifdef DCPOMATIC_OSX
233         wxBitmap GetLargeIcon () const
234         {
235                 return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
236         }
237 #endif
238
239 private:
240         void setup ()
241         {
242
243                 int r = 0;
244
245                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
246                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
247
248                 add_label_to_sizer (table, _panel, _("Content directory"), true, wxGBPosition (r, 0));
249                 _content_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
250                 table->Add (_content_directory, wxGBPosition (r, 1));
251                 ++r;
252
253                 add_label_to_sizer (table, _panel, _("Playlist directory"), true, wxGBPosition (r, 0));
254                 _playlist_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
255                 table->Add (_playlist_directory, wxGBPosition (r, 1));
256                 ++r;
257
258                 add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0));
259                 _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
260                 table->Add (_kdm_directory, wxGBPosition (r, 1));
261                 ++r;
262
263 #ifdef DCPOMATIC_VARIANT_SWAROOP
264                 add_label_to_sizer (table, _panel, _("Background image"), true, wxGBPosition (r, 0));
265                 _background_image = new FilePickerCtrl (_panel, _("Select image file"), "*.png;*.jpg;*.jpeg;*.tif;*.tiff", true);
266                 table->Add (_background_image, wxGBPosition (r, 1));
267                 ++r;
268 #endif
269
270                 _content_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::content_directory_changed, this));
271                 _playlist_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::playlist_directory_changed, this));
272                 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this));
273 #ifdef DCPOMATIC_VARIANT_SWAROOP
274                 _background_image->Bind (wxEVT_FILEPICKER_CHANGED, bind(&LocationsPage::background_image_changed, this));
275 #endif
276         }
277
278         void config_changed ()
279         {
280                 Config* config = Config::instance ();
281
282                 if (config->player_content_directory()) {
283                         checked_set (_content_directory, *config->player_content_directory());
284                 }
285                 if (config->player_playlist_directory()) {
286                         checked_set (_playlist_directory, *config->player_playlist_directory());
287                 }
288                 if (config->player_kdm_directory()) {
289                         checked_set (_kdm_directory, *config->player_kdm_directory());
290                 }
291 #ifdef DCPOMATIC_VARIANT_SWAROOP
292                 if (config->player_background_image()) {
293                         checked_set (_background_image, *config->player_background_image());
294                 }
295 #endif
296         }
297
298         void content_directory_changed ()
299         {
300                 Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath()));
301         }
302
303         void playlist_directory_changed ()
304         {
305                 Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath()));
306         }
307
308         void kdm_directory_changed ()
309         {
310                 Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
311         }
312
313 #ifdef DCPOMATIC_VARIANT_SWAROOP
314         void background_image_changed ()
315         {
316                 Config::instance()->set_player_background_image(wx_to_std(_background_image->GetPath()));
317         }
318 #endif
319
320         wxDirPickerCtrl* _content_directory;
321         wxDirPickerCtrl* _playlist_directory;
322         wxDirPickerCtrl* _kdm_directory;
323 #ifdef DCPOMATIC_VARIANT_SWAROOP
324         FilePickerCtrl* _background_image;
325 #endif
326 };
327
328 #ifdef DCPOMATIC_VARIANT_SWAROOP
329 class WatermarkPage : public StandardPage
330 {
331 public:
332         WatermarkPage (wxSize panel_size, int border)
333                 : StandardPage (panel_size, border)
334         {}
335
336         wxString GetName () const
337         {
338                 return _("Watermark");
339         }
340
341 private:
342         void setup ()
343         {
344                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
345                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
346
347                 int r = 0;
348
349                 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
350                 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
351                 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
352                 ++r;
353
354                 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
355                 _period = new wxSpinCtrl (_panel, wxID_ANY);
356                 _period->SetRange (1, 60);
357                 table->Add (_period, wxGBPosition(r, 1));
358                 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
359                 ++r;
360
361                 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
362                 _duration = new wxSpinCtrl (_panel, wxID_ANY);
363                 _duration->SetRange (100, 5000);
364                 table->Add (_duration, wxGBPosition(r, 1));
365                 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
366                 ++r;
367
368                 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
369                 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
370                 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
371         }
372
373         void config_changed ()
374         {
375                 Config* config = Config::instance ();
376                 checked_set (_theatre, config->player_watermark_theatre());
377                 checked_set (_duration, config->player_watermark_duration());
378                 checked_set (_period, config->player_watermark_period());
379         }
380
381         void theatre_changed ()
382         {
383                 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
384         }
385
386         void period_changed ()
387         {
388                 Config::instance()->set_player_watermark_period(_period->GetValue());
389         }
390
391         void duration_changed ()
392         {
393                 Config::instance()->set_player_watermark_duration(_duration->GetValue());
394         }
395
396         wxTextCtrl* _theatre;
397         wxSpinCtrl* _period;
398         wxSpinCtrl* _duration;
399 };
400
401 class DevicesPage : public StandardPage
402 {
403 public:
404         DevicesPage (wxSize panel_size, int border)
405                 : StandardPage (panel_size, border)
406         {}
407
408         wxString GetName () const
409         {
410                 return _("Devices");
411         }
412
413 private:
414         void setup ()
415         {
416                 vector<string> columns;
417                 columns.push_back(wx_to_std(_("Manufacturer ID")));
418                 columns.push_back(wx_to_std(_("Product code")));
419                 columns.push_back(wx_to_std(_("Serial")));
420                 columns.push_back(wx_to_std(_("Manufacture week")));
421                 columns.push_back(wx_to_std(_("Manufacture year")));
422                 _monitor_list = new EditableList<Monitor, MonitorDialog> (
423                         _panel,
424                         columns,
425                         boost::bind (&Config::required_monitors, Config::instance()),
426                         boost::bind (&Config::set_required_monitors, Config::instance(), _1),
427                         boost::bind (&DevicesPage::monitor_column, this, _1, _2),
428                         true,
429                         true,
430                         100
431                         );
432                 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
433
434                 wxButton* get = new wxButton(_panel, wxID_ANY, _("Read current devices"));
435                 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
436                 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
437         }
438
439         void get_clicked ()
440         {
441                 Config::instance()->set_required_monitors(get_monitors());
442                 _monitor_list->refresh ();
443         }
444
445         string monitor_column (Monitor m, int c)
446         {
447                 switch (c) {
448                 case 0:
449                         return m.manufacturer_id;
450                 case 1:
451                         return locale_convert<string>(m.manufacturer_product_code);
452                 case 2:
453                         return locale_convert<string>(m.serial_number);
454                 case 3:
455                         return locale_convert<string>(m.week_of_manufacture);
456                 case 4:
457                         return locale_convert<string>(m.year_of_manufacture);
458                 default:
459                         DCPOMATIC_ASSERT(false);
460                 }
461
462                 return "";
463         }
464
465         void config_changed ()
466         {
467                 _monitor_list->refresh ();
468         }
469
470 private:
471         EditableList<Monitor, MonitorDialog>* _monitor_list;
472 };
473
474 #endif
475
476 wxPreferencesEditor*
477 create_player_config_dialog ()
478 {
479         wxPreferencesEditor* e = new wxPreferencesEditor ();
480
481 #ifdef DCPOMATIC_OSX
482         /* Width that we force some of the config panels to be on OSX so that
483            the containing window doesn't shrink too much when we select those panels.
484            This is obviously an unpleasant hack.
485         */
486         wxSize ps = wxSize (520, -1);
487         int const border = 16;
488 #else
489         wxSize ps = wxSize (-1, -1);
490         int const border = 8;
491 #endif
492
493         e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
494         e->AddPage (new LocationsPage(ps, border));
495         e->AddPage (new KeysPage(ps, border));
496 #ifdef DCPOMATIC_VARIANT_SWAROOP
497         e->AddPage (new WatermarkPage(ps, border));
498         e->AddPage (new DevicesPage(ps, border));
499 #endif
500         return e;
501 }