Add locations page for some player preferences.
[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 #endif
119
120                 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
121                 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
122                 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
123                 _log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::log_file_changed, this));
124 #ifdef DCPOMATIC_VARIANT_SWAROOP
125                 _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
126 #endif
127         }
128
129         void config_changed ()
130         {
131                 GeneralPage::config_changed ();
132
133                 Config* config = Config::instance ();
134
135                 switch (config->player_mode()) {
136                 case Config::PLAYER_MODE_WINDOW:
137                         checked_set (_player_mode, 0);
138                         break;
139                 case Config::PLAYER_MODE_FULL:
140                         checked_set (_player_mode, 1);
141                         break;
142                 case Config::PLAYER_MODE_DUAL:
143                         checked_set (_player_mode, 2);
144                         break;
145                 }
146
147                 checked_set (_image_display, config->image_display());
148                 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
149                 if (config->player_log_file()) {
150                         checked_set (_log_file, *config->player_log_file());
151                 }
152 #ifdef DCPOMATIC_VARIANT_SWAROOP
153                 checked_set (_kdm_server_url, config->kdm_server_url());
154 #endif
155         }
156
157 private:
158         void player_mode_changed ()
159         {
160                 switch (_player_mode->GetSelection()) {
161                 case 0:
162                         Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
163                         break;
164                 case 1:
165                         Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
166                         break;
167                 case 2:
168                         Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
169                         break;
170                 }
171         }
172
173         void image_display_changed ()
174         {
175                 Config::instance()->set_image_display(_image_display->GetSelection());
176         }
177
178         void respect_kdm_changed ()
179         {
180                 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
181         }
182
183         void log_file_changed ()
184         {
185                 Config::instance()->set_player_log_file(wx_to_std(_log_file->GetPath()));
186         }
187
188 #ifdef DCPOMATIC_VARIANT_SWAROOP
189         void kdm_server_url_changed ()
190         {
191                 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
192         }
193 #endif
194
195         wxChoice* _player_mode;
196         wxChoice* _image_display;
197         wxCheckBox* _respect_kdm;
198         FilePickerCtrl* _log_file;
199 #ifdef DCPOMATIC_VARIANT_SWAROOP
200         wxTextCtrl* _kdm_server_url;
201 #endif
202 };
203
204 class LocationsPage : public StandardPage
205 {
206 public:
207         LocationsPage (wxSize panel_size, int border)
208                 : StandardPage (panel_size, border)
209         {}
210
211         wxString GetName () const
212         {
213                 return _("Locations");
214         }
215
216 #ifdef DCPOMATIC_OSX
217         wxBitmap GetLargeIcon () const
218         {
219                 return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
220         }
221 #endif
222
223 private:
224         void setup ()
225         {
226
227                 int r = 0;
228
229                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
230                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
231
232                 add_label_to_sizer (table, _panel, _("DCP directory"), true, wxGBPosition (r, 0));
233                 _dcp_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
234                 table->Add (_dcp_directory, wxGBPosition (r, 1));
235                 ++r;
236
237                 add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0));
238                 _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
239                 table->Add (_kdm_directory, wxGBPosition (r, 1));
240                 ++r;
241
242 #ifdef DCPOMATIC_VARIANT_SWAROOP
243                 add_label_to_sizer (table, _panel, _("Background image"), true, wxGBPosition (r, 0));
244                 _background_image = new FilePickerCtrl (_panel, _("Select image file"), "*.png;*.jpg;*.jpeg;*.tif;*.tiff", true);
245                 table->Add (_background_image, wxGBPosition (r, 1));
246                 ++r;
247 #endif
248
249                 _dcp_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::dcp_directory_changed, this));
250                 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this));
251 #ifdef DCPOMATIC_VARIANT_SWAROOP
252                 _background_image->Bind (wxEVT_FILEPICKER_CHANGED, bind(&LocationsPage::background_image_changed, this));
253 #endif
254         }
255
256         void config_changed ()
257         {
258                 Config* config = Config::instance ();
259
260                 if (config->player_dcp_directory()) {
261                         checked_set (_dcp_directory, *config->player_dcp_directory());
262                 }
263                 if (config->player_kdm_directory()) {
264                         checked_set (_kdm_directory, *config->player_kdm_directory());
265                 }
266 #ifdef DCPOMATIC_VARIANT_SWAROOP
267                 if (config->player_background_image()) {
268                         checked_set (_background_image, *config->player_background_image());
269                 }
270 #endif
271         }
272
273         void dcp_directory_changed ()
274         {
275                 Config::instance()->set_player_dcp_directory(wx_to_std(_dcp_directory->GetPath()));
276         }
277
278         void kdm_directory_changed ()
279         {
280                 Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
281         }
282
283 #ifdef DCPOMATIC_VARIANT_SWAROOP
284         void background_image_changed ()
285         {
286                 Config::instance()->set_player_background_image(wx_to_std(_background_image->GetPath()));
287         }
288 #endif
289
290         wxDirPickerCtrl* _dcp_directory;
291         wxDirPickerCtrl* _kdm_directory;
292 #ifdef DCPOMATIC_VARIANT_SWAROOP
293         FilePickerCtrl* _background_image;
294 #endif
295 };
296
297 #ifdef DCPOMATIC_VARIANT_SWAROOP
298 class WatermarkPage : public StandardPage
299 {
300 public:
301         WatermarkPage (wxSize panel_size, int border)
302                 : StandardPage (panel_size, border)
303         {}
304
305         wxString GetName () const
306         {
307                 return _("Watermark");
308         }
309
310 private:
311         void setup ()
312         {
313                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
314                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
315
316                 int r = 0;
317
318                 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
319                 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
320                 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
321                 ++r;
322
323                 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
324                 _period = new wxSpinCtrl (_panel, wxID_ANY);
325                 _period->SetRange (1, 60);
326                 table->Add (_period, wxGBPosition(r, 1));
327                 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
328                 ++r;
329
330                 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
331                 _duration = new wxSpinCtrl (_panel, wxID_ANY);
332                 _duration->SetRange (100, 5000);
333                 table->Add (_duration, wxGBPosition(r, 1));
334                 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
335                 ++r;
336
337                 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
338                 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
339                 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
340         }
341
342         void config_changed ()
343         {
344                 Config* config = Config::instance ();
345                 checked_set (_theatre, config->player_watermark_theatre());
346                 checked_set (_duration, config->player_watermark_duration());
347                 checked_set (_period, config->player_watermark_period());
348         }
349
350         void theatre_changed ()
351         {
352                 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
353         }
354
355         void period_changed ()
356         {
357                 Config::instance()->set_player_watermark_period(_period->GetValue());
358         }
359
360         void duration_changed ()
361         {
362                 Config::instance()->set_player_watermark_duration(_duration->GetValue());
363         }
364
365         wxTextCtrl* _theatre;
366         wxSpinCtrl* _period;
367         wxSpinCtrl* _duration;
368 };
369
370 class DevicesPage : public StandardPage
371 {
372 public:
373         DevicesPage (wxSize panel_size, int border)
374                 : StandardPage (panel_size, border)
375         {}
376
377         wxString GetName () const
378         {
379                 return _("Devices");
380         }
381
382 private:
383         void setup ()
384         {
385                 vector<string> columns;
386                 columns.push_back(wx_to_std(_("Manufacturer ID")));
387                 columns.push_back(wx_to_std(_("Product code")));
388                 columns.push_back(wx_to_std(_("Serial")));
389                 columns.push_back(wx_to_std(_("Manufacture week")));
390                 columns.push_back(wx_to_std(_("Manufacture year")));
391                 _monitor_list = new EditableList<Monitor, MonitorDialog> (
392                         _panel,
393                         columns,
394                         boost::bind (&Config::required_monitors, Config::instance()),
395                         boost::bind (&Config::set_required_monitors, Config::instance(), _1),
396                         boost::bind (&DevicesPage::monitor_column, this, _1, _2),
397                         true,
398                         true,
399                         100
400                         );
401                 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
402
403                 wxButton* get = new wxButton(_panel, wxID_ANY, _("Read current devices"));
404                 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
405                 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
406         }
407
408         void get_clicked ()
409         {
410                 Config::instance()->set_required_monitors(get_monitors());
411                 _monitor_list->refresh ();
412         }
413
414         string monitor_column (Monitor m, int c)
415         {
416                 switch (c) {
417                 case 0:
418                         return m.manufacturer_id;
419                 case 1:
420                         return locale_convert<string>(m.manufacturer_product_code);
421                 case 2:
422                         return locale_convert<string>(m.serial_number);
423                 case 3:
424                         return locale_convert<string>(m.week_of_manufacture);
425                 case 4:
426                         return locale_convert<string>(m.year_of_manufacture);
427                 default:
428                         DCPOMATIC_ASSERT(false);
429                 }
430
431                 return "";
432         }
433
434         void config_changed ()
435         {
436                 _monitor_list->refresh ();
437         }
438
439 private:
440         EditableList<Monitor, MonitorDialog>* _monitor_list;
441 };
442
443 #endif
444
445 wxPreferencesEditor*
446 create_player_config_dialog ()
447 {
448         wxPreferencesEditor* e = new wxPreferencesEditor ();
449
450 #ifdef DCPOMATIC_OSX
451         /* Width that we force some of the config panels to be on OSX so that
452            the containing window doesn't shrink too much when we select those panels.
453            This is obviously an unpleasant hack.
454         */
455         wxSize ps = wxSize (520, -1);
456         int const border = 16;
457 #else
458         wxSize ps = wxSize (-1, -1);
459         int const border = 8;
460 #endif
461
462         e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
463         e->AddPage (new LocationsPage(ps, border));
464         e->AddPage (new KeysPage(ps, border));
465 #ifdef DCPOMATIC_VARIANT_SWAROOP
466         e->AddPage (new WatermarkPage(ps, border));
467         e->AddPage (new DevicesPage(ps, border));
468 #endif
469         return e;
470 }