2 Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
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.
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.
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/>.
21 /** @file src/player_config_dialog.cc
22 * @brief A dialogue to edit DCP-o-matic Player configuration.
25 #include "config_dialog.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"
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>
54 #include <boost/filesystem.hpp>
55 #include <boost/foreach.hpp>
66 using boost::shared_ptr;
67 using boost::function;
68 using boost::optional;
69 using dcp::locale_convert;
71 class PlayerGeneralPage : public GeneralPage
74 PlayerGeneralPage (wxSize panel_size, int border)
75 : GeneralPage (panel_size, border)
81 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
82 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
85 add_language_controls (table, r);
86 add_play_sound_controls (table, r);
87 add_update_controls (table, r);
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));
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));
104 _respect_kdm = new wxCheckBox (_panel, wxID_ANY, _("Respect KDM validity periods"));
105 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
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));
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));
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));
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));
135 void config_changed ()
137 GeneralPage::config_changed ();
139 Config* config = Config::instance ();
141 switch (config->player_mode()) {
142 case Config::PLAYER_MODE_WINDOW:
143 checked_set (_player_mode, 0);
145 case Config::PLAYER_MODE_FULL:
146 checked_set (_player_mode, 1);
148 case Config::PLAYER_MODE_DUAL:
149 checked_set (_player_mode, 2);
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());
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());
167 void player_mode_changed ()
169 switch (_player_mode->GetSelection()) {
171 Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
174 Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
177 Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
182 void image_display_changed ()
184 Config::instance()->set_image_display(_image_display->GetSelection());
187 void respect_kdm_changed ()
189 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
192 void log_file_changed ()
194 Config::instance()->set_player_log_file(wx_to_std(_log_file->GetPath()));
197 #ifdef DCPOMATIC_VARIANT_SWAROOP
198 void kdm_server_url_changed ()
200 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
203 void lock_file_changed ()
205 Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
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;
219 class LocationsPage : public StandardPage
222 LocationsPage (wxSize panel_size, int border)
223 : StandardPage (panel_size, border)
226 wxString GetName () const
228 return _("Locations");
232 wxBitmap GetLargeIcon () const
234 return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
244 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
245 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
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));
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));
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));
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));
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));
277 void config_changed ()
279 Config* config = Config::instance ();
281 if (config->player_content_directory()) {
282 checked_set (_content_directory, *config->player_content_directory());
284 if (config->player_playlist_directory()) {
285 checked_set (_playlist_directory, *config->player_playlist_directory());
287 if (config->player_kdm_directory()) {
288 checked_set (_kdm_directory, *config->player_kdm_directory());
290 #ifdef DCPOMATIC_VARIANT_SWAROOP
291 if (config->player_background_image()) {
292 checked_set (_background_image, *config->player_background_image());
297 void content_directory_changed ()
299 Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath()));
302 void playlist_directory_changed ()
304 Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath()));
307 void kdm_directory_changed ()
309 Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
312 #ifdef DCPOMATIC_VARIANT_SWAROOP
313 void background_image_changed ()
315 Config::instance()->set_player_background_image(wx_to_std(_background_image->GetPath()));
319 wxDirPickerCtrl* _content_directory;
320 wxDirPickerCtrl* _playlist_directory;
321 wxDirPickerCtrl* _kdm_directory;
322 #ifdef DCPOMATIC_VARIANT_SWAROOP
323 FilePickerCtrl* _background_image;
327 #ifdef DCPOMATIC_VARIANT_SWAROOP
328 class WatermarkPage : public StandardPage
331 WatermarkPage (wxSize panel_size, int border)
332 : StandardPage (panel_size, border)
335 wxString GetName () const
337 return _("Watermark");
343 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
344 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
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));
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));
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));
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));
372 void config_changed ()
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());
380 void theatre_changed ()
382 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
385 void period_changed ()
387 Config::instance()->set_player_watermark_period(_period->GetValue());
390 void duration_changed ()
392 Config::instance()->set_player_watermark_duration(_duration->GetValue());
395 wxTextCtrl* _theatre;
397 wxSpinCtrl* _duration;
400 class DevicesPage : public StandardPage
403 DevicesPage (wxSize panel_size, int border)
404 : StandardPage (panel_size, border)
407 wxString GetName () const
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> (
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),
431 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
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));
440 Config::instance()->set_required_monitors(get_monitors());
441 _monitor_list->refresh ();
444 string monitor_column (Monitor m, int c)
448 return m.manufacturer_id;
450 return locale_convert<string>(m.manufacturer_product_code);
452 return locale_convert<string>(m.serial_number);
454 return locale_convert<string>(m.week_of_manufacture);
456 return locale_convert<string>(m.year_of_manufacture);
458 DCPOMATIC_ASSERT(false);
464 void config_changed ()
466 _monitor_list->refresh ();
470 EditableList<Monitor, MonitorDialog>* _monitor_list;
476 create_player_config_dialog ()
478 wxPreferencesEditor* e = new wxPreferencesEditor ();
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.
485 wxSize ps = wxSize (520, -1);
486 int const border = 16;
488 wxSize ps = wxSize (-1, -1);
489 int const border = 8;
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));