2 Copyright (C) 2012-2019 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 add_label_to_sizer (table, _panel, _("Video display mode"), true, wxGBPosition(r, 0));
106 _video_display_mode = new wxChoice (_panel, wxID_ANY);
107 _video_display_mode->Append (_("Simple (safer)"));
108 _video_display_mode->Append (_("OpenGL (faster)"));
109 table->Add (_video_display_mode, wxGBPosition(r, 1));
112 wxStaticText* restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false, wxGBPosition(r, 0));
113 wxFont font = restart->GetFont();
114 font.SetStyle (wxFONTSTYLE_ITALIC);
115 font.SetPointSize (font.GetPointSize() - 1);
116 restart->SetFont (font);
119 _respect_kdm = new CheckBox (_panel, _("Respect KDM validity periods"));
120 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
123 add_label_to_sizer (table, _panel, _("Activity log file"), true, wxGBPosition (r, 0));
124 _activity_log_file = new FilePickerCtrl (_panel, _("Select activity log file"), "*", true, true);
125 table->Add (_activity_log_file, wxGBPosition(r, 1));
128 add_label_to_sizer (table, _panel, _("Debug log file"), true, wxGBPosition (r, 0));
129 _debug_log_file = new FilePickerCtrl (_panel, _("Select debug log file"), "*", true, true);
130 table->Add (_debug_log_file, wxGBPosition(r, 1));
133 #ifdef DCPOMATIC_VARIANT_SWAROOP
134 add_label_to_sizer (table, _panel, _("KDM server URL"), true, wxGBPosition(r, 0));
135 _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
136 table->Add (_kdm_server_url, wxGBPosition (r, 1));
139 add_label_to_sizer (table, _panel, _("Lock file"), true, wxGBPosition(r, 0));
140 _lock_file = new FilePickerCtrl (_panel, _("Select lock file"), "*", true, true);
141 table->Add (_lock_file, wxGBPosition (r, 1));
145 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
146 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
147 _video_display_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::video_display_mode_changed, this));
148 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
149 _activity_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::activity_log_file_changed, this));
150 _debug_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::debug_log_file_changed, this));
151 #ifdef DCPOMATIC_VARIANT_SWAROOP
152 _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
153 _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this));
157 void config_changed ()
159 GeneralPage::config_changed ();
161 Config* config = Config::instance ();
163 switch (config->player_mode()) {
164 case Config::PLAYER_MODE_WINDOW:
165 checked_set (_player_mode, 0);
167 case Config::PLAYER_MODE_FULL:
168 checked_set (_player_mode, 1);
170 case Config::PLAYER_MODE_DUAL:
171 checked_set (_player_mode, 2);
175 switch (config->video_view_type()) {
176 case Config::VIDEO_VIEW_SIMPLE:
177 checked_set (_video_display_mode, 0);
179 case Config::VIDEO_VIEW_OPENGL:
180 checked_set (_video_display_mode, 1);
184 checked_set (_image_display, config->image_display());
185 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
186 if (config->player_activity_log_file()) {
187 checked_set (_activity_log_file, *config->player_activity_log_file());
189 if (config->player_debug_log_file()) {
190 checked_set (_debug_log_file, *config->player_debug_log_file());
192 #ifdef DCPOMATIC_VARIANT_SWAROOP
193 checked_set (_kdm_server_url, config->kdm_server_url());
194 if (config->player_lock_file()) {
195 checked_set (_lock_file, config->player_lock_file().get());
201 void player_mode_changed ()
203 switch (_player_mode->GetSelection()) {
205 Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
208 Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
211 Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
216 void image_display_changed ()
218 Config::instance()->set_image_display(_image_display->GetSelection());
221 void video_display_mode_changed ()
223 if (_video_display_mode->GetSelection() == 0) {
224 Config::instance()->set_video_view_type (Config::VIDEO_VIEW_SIMPLE);
226 Config::instance()->set_video_view_type (Config::VIDEO_VIEW_OPENGL);
230 void respect_kdm_changed ()
232 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
235 void activity_log_file_changed ()
237 Config::instance()->set_player_activity_log_file(wx_to_std(_activity_log_file->GetPath()));
240 void debug_log_file_changed ()
242 Config::instance()->set_player_debug_log_file(wx_to_std(_debug_log_file->GetPath()));
245 #ifdef DCPOMATIC_VARIANT_SWAROOP
246 void kdm_server_url_changed ()
248 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
251 void lock_file_changed ()
253 Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
257 wxChoice* _player_mode;
258 wxChoice* _image_display;
259 wxChoice* _video_display_mode;
260 wxCheckBox* _respect_kdm;
261 FilePickerCtrl* _activity_log_file;
262 FilePickerCtrl* _debug_log_file;
263 #ifdef DCPOMATIC_VARIANT_SWAROOP
264 wxTextCtrl* _kdm_server_url;
265 FilePickerCtrl* _lock_file;
269 class LocationsPage : public StandardPage
272 LocationsPage (wxSize panel_size, int border)
273 : StandardPage (panel_size, border)
276 wxString GetName () const
278 return _("Locations");
282 wxBitmap GetLargeIcon () const
284 return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
294 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
295 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
297 add_label_to_sizer (table, _panel, _("Content directory"), true, wxGBPosition (r, 0));
298 _content_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
299 table->Add (_content_directory, wxGBPosition (r, 1));
302 add_label_to_sizer (table, _panel, _("Playlist directory"), true, wxGBPosition (r, 0));
303 _playlist_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
304 table->Add (_playlist_directory, wxGBPosition (r, 1));
307 add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0));
308 _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
309 table->Add (_kdm_directory, wxGBPosition (r, 1));
312 #ifdef DCPOMATIC_VARIANT_SWAROOP
313 add_label_to_sizer (table, _panel, _("Background image"), true, wxGBPosition (r, 0));
314 _background_image = new FilePickerCtrl (_panel, _("Select image file"), "*.png;*.jpg;*.jpeg;*.tif;*.tiff", true);
315 table->Add (_background_image, wxGBPosition (r, 1));
319 _content_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::content_directory_changed, this));
320 _playlist_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::playlist_directory_changed, this));
321 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this));
322 #ifdef DCPOMATIC_VARIANT_SWAROOP
323 _background_image->Bind (wxEVT_FILEPICKER_CHANGED, bind(&LocationsPage::background_image_changed, this));
327 void config_changed ()
329 Config* config = Config::instance ();
331 if (config->player_content_directory()) {
332 checked_set (_content_directory, *config->player_content_directory());
334 if (config->player_playlist_directory()) {
335 checked_set (_playlist_directory, *config->player_playlist_directory());
337 if (config->player_kdm_directory()) {
338 checked_set (_kdm_directory, *config->player_kdm_directory());
340 #ifdef DCPOMATIC_VARIANT_SWAROOP
341 if (config->player_background_image()) {
342 checked_set (_background_image, *config->player_background_image());
347 void content_directory_changed ()
349 Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath()));
352 void playlist_directory_changed ()
354 Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath()));
357 void kdm_directory_changed ()
359 Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
362 #ifdef DCPOMATIC_VARIANT_SWAROOP
363 void background_image_changed ()
365 boost::filesystem::path const f = wx_to_std(_background_image->GetPath());
366 if (!boost::filesystem::is_regular_file(f) || !wxImage::CanRead(std_to_wx(f.string()))) {
367 error_dialog (0, _("Could not load image file."));
368 if (Config::instance()->player_background_image()) {
369 checked_set (_background_image, *Config::instance()->player_background_image());
374 Config::instance()->set_player_background_image(f);
378 wxDirPickerCtrl* _content_directory;
379 wxDirPickerCtrl* _playlist_directory;
380 wxDirPickerCtrl* _kdm_directory;
381 #ifdef DCPOMATIC_VARIANT_SWAROOP
382 FilePickerCtrl* _background_image;
386 #ifdef DCPOMATIC_VARIANT_SWAROOP
387 class WatermarkPage : public StandardPage
390 WatermarkPage (wxSize panel_size, int border)
391 : StandardPage (panel_size, border)
394 wxString GetName () const
396 return _("Watermark");
400 wxBitmap GetLargeIcon () const
402 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
403 return wxBitmap ("watermark", wxBITMAP_TYPE_PNG_RESOURCE);
410 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
411 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
415 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
416 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
417 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
420 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
421 _period = new wxSpinCtrl (_panel, wxID_ANY);
422 _period->SetRange (1, 60);
423 table->Add (_period, wxGBPosition(r, 1));
424 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
427 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
428 _duration = new wxSpinCtrl (_panel, wxID_ANY);
429 _duration->SetRange (100, 5000);
430 table->Add (_duration, wxGBPosition(r, 1));
431 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
434 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
435 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
436 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
439 void config_changed ()
441 Config* config = Config::instance ();
442 checked_set (_theatre, config->player_watermark_theatre());
443 checked_set (_duration, config->player_watermark_duration());
444 checked_set (_period, config->player_watermark_period());
447 void theatre_changed ()
449 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
452 void period_changed ()
454 Config::instance()->set_player_watermark_period(_period->GetValue());
457 void duration_changed ()
459 Config::instance()->set_player_watermark_duration(_duration->GetValue());
462 wxTextCtrl* _theatre;
464 wxSpinCtrl* _duration;
467 class DevicesPage : public StandardPage
470 DevicesPage (wxSize panel_size, int border)
471 : StandardPage (panel_size, border)
474 wxString GetName () const
480 wxBitmap GetLargeIcon () const
482 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
483 return wxBitmap ("devices", wxBITMAP_TYPE_PNG_RESOURCE);
490 vector<EditableListColumn> columns;
491 columns.push_back(EditableListColumn(wx_to_std(_("Manufacturer ID"))));
492 columns.push_back(EditableListColumn(wx_to_std(_("Product code"))));
493 columns.push_back(EditableListColumn(wx_to_std(_("Serial"))));
494 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture week"))));
495 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture year"))));
496 _monitor_list = new EditableList<Monitor, MonitorDialog> (
499 boost::bind (&Config::required_monitors, Config::instance()),
500 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
501 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
505 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
507 wxButton* get = new Button(_panel, _("Read current devices"));
508 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
509 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
514 Config::instance()->set_required_monitors(get_monitors());
515 _monitor_list->refresh ();
518 string monitor_column (Monitor m, int c)
522 return m.manufacturer_id;
524 return locale_convert<string>(m.manufacturer_product_code);
526 return locale_convert<string>(m.serial_number);
528 return locale_convert<string>(m.week_of_manufacture);
530 return locale_convert<string>(m.year_of_manufacture);
532 DCPOMATIC_ASSERT(false);
538 void config_changed ()
540 _monitor_list->refresh ();
544 EditableList<Monitor, MonitorDialog>* _monitor_list;
550 create_player_config_dialog ()
552 wxPreferencesEditor* e = new wxPreferencesEditor ();
555 /* Width that we force some of the config panels to be on OSX so that
556 the containing window doesn't shrink too much when we select those panels.
557 This is obviously an unpleasant hack.
559 wxSize ps = wxSize (520, -1);
560 int const border = 16;
562 wxSize ps = wxSize (-1, -1);
563 int const border = 8;
566 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
567 e->AddPage (new LocationsPage(ps, border));
568 e->AddPage (new KeysPage(ps, border));
569 #ifdef DCPOMATIC_VARIANT_SWAROOP
570 e->AddPage (new WatermarkPage(ps, border));
571 e->AddPage (new DevicesPage(ps, border));