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 "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"
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>
55 #include <boost/filesystem.hpp>
56 #include <boost/foreach.hpp>
67 using boost::shared_ptr;
68 using boost::function;
69 using boost::optional;
70 using dcp::locale_convert;
72 class PlayerGeneralPage : public GeneralPage
75 PlayerGeneralPage (wxSize panel_size, int border)
76 : GeneralPage (panel_size, border)
82 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
83 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
86 add_language_controls (table, r);
87 add_play_sound_controls (table, r);
88 add_update_controls (table, r);
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));
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));
105 _respect_kdm = new CheckBox (_panel, _("Respect KDM validity periods"));
106 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
109 add_label_to_sizer (table, _panel, _("Activity log file"), true, wxGBPosition (r, 0));
110 _activity_log_file = new FilePickerCtrl (_panel, _("Select activity log file"), "*", true);
111 table->Add (_activity_log_file, wxGBPosition(r, 1));
114 add_label_to_sizer (table, _panel, _("Debug log file"), true, wxGBPosition (r, 0));
115 _debug_log_file = new FilePickerCtrl (_panel, _("Select debug log file"), "*", true);
116 table->Add (_debug_log_file, wxGBPosition(r, 1));
119 #ifdef DCPOMATIC_VARIANT_SWAROOP
120 add_label_to_sizer (table, _panel, _("KDM server URL"), true, wxGBPosition(r, 0));
121 _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
122 table->Add (_kdm_server_url, wxGBPosition (r, 1));
125 add_label_to_sizer (table, _panel, _("Lock file"), true, wxGBPosition(r, 0));
126 _lock_file = new FilePickerCtrl (_panel, _("Select lock file"), "*", true);
127 table->Add (_lock_file, wxGBPosition (r, 1));
131 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
132 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
133 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
134 _activity_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::activity_log_file_changed, this));
135 _debug_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::debug_log_file_changed, this));
136 #ifdef DCPOMATIC_VARIANT_SWAROOP
137 _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
138 _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this));
142 void config_changed ()
144 GeneralPage::config_changed ();
146 Config* config = Config::instance ();
148 switch (config->player_mode()) {
149 case Config::PLAYER_MODE_WINDOW:
150 checked_set (_player_mode, 0);
152 case Config::PLAYER_MODE_FULL:
153 checked_set (_player_mode, 1);
155 case Config::PLAYER_MODE_DUAL:
156 checked_set (_player_mode, 2);
160 checked_set (_image_display, config->image_display());
161 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
162 if (config->player_activity_log_file()) {
163 checked_set (_activity_log_file, *config->player_activity_log_file());
165 if (config->player_debug_log_file()) {
166 checked_set (_debug_log_file, *config->player_debug_log_file());
168 #ifdef DCPOMATIC_VARIANT_SWAROOP
169 checked_set (_kdm_server_url, config->kdm_server_url());
170 if (config->player_lock_file()) {
171 checked_set (_lock_file, config->player_lock_file().get());
177 void player_mode_changed ()
179 switch (_player_mode->GetSelection()) {
181 Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
184 Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
187 Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
192 void image_display_changed ()
194 Config::instance()->set_image_display(_image_display->GetSelection());
197 void respect_kdm_changed ()
199 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
202 void activity_log_file_changed ()
204 Config::instance()->set_player_activity_log_file(wx_to_std(_activity_log_file->GetPath()));
207 void debug_log_file_changed ()
209 Config::instance()->set_player_debug_log_file(wx_to_std(_debug_log_file->GetPath()));
212 #ifdef DCPOMATIC_VARIANT_SWAROOP
213 void kdm_server_url_changed ()
215 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
218 void lock_file_changed ()
220 Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
224 wxChoice* _player_mode;
225 wxChoice* _image_display;
226 wxCheckBox* _respect_kdm;
227 FilePickerCtrl* _activity_log_file;
228 FilePickerCtrl* _debug_log_file;
229 #ifdef DCPOMATIC_VARIANT_SWAROOP
230 wxTextCtrl* _kdm_server_url;
231 FilePickerCtrl* _lock_file;
235 class LocationsPage : public StandardPage
238 LocationsPage (wxSize panel_size, int border)
239 : StandardPage (panel_size, border)
242 wxString GetName () const
244 return _("Locations");
248 wxBitmap GetLargeIcon () const
250 return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
260 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
261 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
263 add_label_to_sizer (table, _panel, _("Content directory"), true, wxGBPosition (r, 0));
264 _content_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
265 table->Add (_content_directory, wxGBPosition (r, 1));
268 add_label_to_sizer (table, _panel, _("Playlist directory"), true, wxGBPosition (r, 0));
269 _playlist_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
270 table->Add (_playlist_directory, wxGBPosition (r, 1));
273 add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0));
274 _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
275 table->Add (_kdm_directory, wxGBPosition (r, 1));
278 #ifdef DCPOMATIC_VARIANT_SWAROOP
279 add_label_to_sizer (table, _panel, _("Background image"), true, wxGBPosition (r, 0));
280 _background_image = new FilePickerCtrl (_panel, _("Select image file"), "*.png;*.jpg;*.jpeg;*.tif;*.tiff", true);
281 table->Add (_background_image, wxGBPosition (r, 1));
285 _content_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::content_directory_changed, this));
286 _playlist_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::playlist_directory_changed, this));
287 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this));
288 #ifdef DCPOMATIC_VARIANT_SWAROOP
289 _background_image->Bind (wxEVT_FILEPICKER_CHANGED, bind(&LocationsPage::background_image_changed, this));
293 void config_changed ()
295 Config* config = Config::instance ();
297 if (config->player_content_directory()) {
298 checked_set (_content_directory, *config->player_content_directory());
300 if (config->player_playlist_directory()) {
301 checked_set (_playlist_directory, *config->player_playlist_directory());
303 if (config->player_kdm_directory()) {
304 checked_set (_kdm_directory, *config->player_kdm_directory());
306 #ifdef DCPOMATIC_VARIANT_SWAROOP
307 if (config->player_background_image()) {
308 checked_set (_background_image, *config->player_background_image());
313 void content_directory_changed ()
315 Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath()));
318 void playlist_directory_changed ()
320 Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath()));
323 void kdm_directory_changed ()
325 Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
328 #ifdef DCPOMATIC_VARIANT_SWAROOP
329 void background_image_changed ()
331 boost::filesystem::path const f = wx_to_std(_background_image->GetPath());
332 if (!boost::filesystem::is_regular_file(f) || !wxImage::CanRead(std_to_wx(f.string()))) {
333 error_dialog (0, _("Could not load image file."));
334 if (Config::instance()->player_background_image()) {
335 checked_set (_background_image, *Config::instance()->player_background_image());
340 Config::instance()->set_player_background_image(f);
344 wxDirPickerCtrl* _content_directory;
345 wxDirPickerCtrl* _playlist_directory;
346 wxDirPickerCtrl* _kdm_directory;
347 #ifdef DCPOMATIC_VARIANT_SWAROOP
348 FilePickerCtrl* _background_image;
352 #ifdef DCPOMATIC_VARIANT_SWAROOP
353 class WatermarkPage : public StandardPage
356 WatermarkPage (wxSize panel_size, int border)
357 : StandardPage (panel_size, border)
360 wxString GetName () const
362 return _("Watermark");
368 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
369 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
373 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
374 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
375 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
378 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
379 _period = new wxSpinCtrl (_panel, wxID_ANY);
380 _period->SetRange (1, 60);
381 table->Add (_period, wxGBPosition(r, 1));
382 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
385 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
386 _duration = new wxSpinCtrl (_panel, wxID_ANY);
387 _duration->SetRange (100, 5000);
388 table->Add (_duration, wxGBPosition(r, 1));
389 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
392 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
393 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
394 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
397 void config_changed ()
399 Config* config = Config::instance ();
400 checked_set (_theatre, config->player_watermark_theatre());
401 checked_set (_duration, config->player_watermark_duration());
402 checked_set (_period, config->player_watermark_period());
405 void theatre_changed ()
407 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
410 void period_changed ()
412 Config::instance()->set_player_watermark_period(_period->GetValue());
415 void duration_changed ()
417 Config::instance()->set_player_watermark_duration(_duration->GetValue());
420 wxTextCtrl* _theatre;
422 wxSpinCtrl* _duration;
425 class DevicesPage : public StandardPage
428 DevicesPage (wxSize panel_size, int border)
429 : StandardPage (panel_size, border)
432 wxString GetName () const
440 vector<string> columns;
441 columns.push_back(wx_to_std(_("Manufacturer ID")));
442 columns.push_back(wx_to_std(_("Product code")));
443 columns.push_back(wx_to_std(_("Serial")));
444 columns.push_back(wx_to_std(_("Manufacture week")));
445 columns.push_back(wx_to_std(_("Manufacture year")));
446 _monitor_list = new EditableList<Monitor, MonitorDialog> (
449 boost::bind (&Config::required_monitors, Config::instance()),
450 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
451 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
456 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
458 wxButton* get = new Button(_panel, _("Read current devices"));
459 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
460 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
465 Config::instance()->set_required_monitors(get_monitors());
466 _monitor_list->refresh ();
469 string monitor_column (Monitor m, int c)
473 return m.manufacturer_id;
475 return locale_convert<string>(m.manufacturer_product_code);
477 return locale_convert<string>(m.serial_number);
479 return locale_convert<string>(m.week_of_manufacture);
481 return locale_convert<string>(m.year_of_manufacture);
483 DCPOMATIC_ASSERT(false);
489 void config_changed ()
491 _monitor_list->refresh ();
495 EditableList<Monitor, MonitorDialog>* _monitor_list;
501 create_player_config_dialog ()
503 wxPreferencesEditor* e = new wxPreferencesEditor ();
506 /* Width that we force some of the config panels to be on OSX so that
507 the containing window doesn't shrink too much when we select those panels.
508 This is obviously an unpleasant hack.
510 wxSize ps = wxSize (520, -1);
511 int const border = 16;
513 wxSize ps = wxSize (-1, -1);
514 int const border = 8;
517 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
518 e->AddPage (new LocationsPage(ps, border));
519 e->AddPage (new KeysPage(ps, border));
520 #ifdef DCPOMATIC_VARIANT_SWAROOP
521 e->AddPage (new WatermarkPage(ps, border));
522 e->AddPage (new DevicesPage(ps, border));