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);
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);
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);
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");
402 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
403 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
407 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
408 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
409 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
412 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
413 _period = new wxSpinCtrl (_panel, wxID_ANY);
414 _period->SetRange (1, 60);
415 table->Add (_period, wxGBPosition(r, 1));
416 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
419 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
420 _duration = new wxSpinCtrl (_panel, wxID_ANY);
421 _duration->SetRange (100, 5000);
422 table->Add (_duration, wxGBPosition(r, 1));
423 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
426 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
427 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
428 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
431 void config_changed ()
433 Config* config = Config::instance ();
434 checked_set (_theatre, config->player_watermark_theatre());
435 checked_set (_duration, config->player_watermark_duration());
436 checked_set (_period, config->player_watermark_period());
439 void theatre_changed ()
441 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
444 void period_changed ()
446 Config::instance()->set_player_watermark_period(_period->GetValue());
449 void duration_changed ()
451 Config::instance()->set_player_watermark_duration(_duration->GetValue());
454 wxTextCtrl* _theatre;
456 wxSpinCtrl* _duration;
459 class DevicesPage : public StandardPage
462 DevicesPage (wxSize panel_size, int border)
463 : StandardPage (panel_size, border)
466 wxString GetName () const
474 vector<EditableListColumn> columns;
475 columns.push_back(EditableListColumn(wx_to_std(_("Manufacturer ID"))));
476 columns.push_back(EditableListColumn(wx_to_std(_("Product code"))));
477 columns.push_back(EditableListColumn(wx_to_std(_("Serial"))));
478 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture week"))));
479 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture year"))));
480 _monitor_list = new EditableList<Monitor, MonitorDialog> (
483 boost::bind (&Config::required_monitors, Config::instance()),
484 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
485 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
489 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
491 wxButton* get = new Button(_panel, _("Read current devices"));
492 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
493 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
498 Config::instance()->set_required_monitors(get_monitors());
499 _monitor_list->refresh ();
502 string monitor_column (Monitor m, int c)
506 return m.manufacturer_id;
508 return locale_convert<string>(m.manufacturer_product_code);
510 return locale_convert<string>(m.serial_number);
512 return locale_convert<string>(m.week_of_manufacture);
514 return locale_convert<string>(m.year_of_manufacture);
516 DCPOMATIC_ASSERT(false);
522 void config_changed ()
524 _monitor_list->refresh ();
528 EditableList<Monitor, MonitorDialog>* _monitor_list;
534 create_player_config_dialog ()
536 wxPreferencesEditor* e = new wxPreferencesEditor ();
539 /* Width that we force some of the config panels to be on OSX so that
540 the containing window doesn't shrink too much when we select those panels.
541 This is obviously an unpleasant hack.
543 wxSize ps = wxSize (520, -1);
544 int const border = 16;
546 wxSize ps = wxSize (-1, -1);
547 int const border = 8;
550 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
551 e->AddPage (new LocationsPage(ps, border));
552 e->AddPage (new KeysPage(ps, border));
553 #ifdef DCPOMATIC_VARIANT_SWAROOP
554 e->AddPage (new WatermarkPage(ps, border));
555 e->AddPage (new DevicesPage(ps, border));