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