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 "static_text.h"
40 #include "lib/config.h"
41 #include "lib/ratio.h"
42 #include "lib/filter.h"
43 #include "lib/dcp_content_type.h"
46 #include "lib/cross.h"
47 #include "lib/exceptions.h"
48 #include <dcp/locale_convert.h>
49 #include <dcp/exceptions.h>
50 #include <dcp/certificate_chain.h>
51 #include <wx/stdpaths.h>
52 #include <wx/preferences.h>
53 #include <wx/spinctrl.h>
54 #include <wx/filepicker.h>
56 #include <boost/filesystem.hpp>
57 #include <boost/foreach.hpp>
68 using boost::shared_ptr;
69 using boost::function;
70 using boost::optional;
71 using dcp::locale_convert;
73 class PlayerGeneralPage : public GeneralPage
76 PlayerGeneralPage (wxSize panel_size, int border)
77 : GeneralPage (panel_size, border)
83 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
84 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
87 add_language_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;
270 /** @class PlayerAdvancedPage
271 * @brief Advanced page of the preferences dialog for the player.
273 class PlayerAdvancedPage : public StockPage
276 PlayerAdvancedPage (wxSize panel_size, int border)
277 : StockPage (Kind_Advanced, panel_size, border)
282 , _log_debug_decode (0)
286 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
288 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
290 flags |= wxALIGN_RIGHT;
293 wxStaticText* m = new StaticText (parent, text);
294 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
299 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
300 table->AddGrowableCol (1, 1);
301 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
304 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
305 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
306 _log_general = new CheckBox (_panel, _("General"));
307 t->Add (_log_general, 1, wxEXPAND | wxALL);
308 _log_warning = new CheckBox (_panel, _("Warnings"));
309 t->Add (_log_warning, 1, wxEXPAND | wxALL);
310 _log_error = new CheckBox (_panel, _("Errors"));
311 t->Add (_log_error, 1, wxEXPAND | wxALL);
312 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
313 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
314 t->Add (_log_timing, 1, wxEXPAND | wxALL);
315 _log_debug_decode = new CheckBox (_panel, _("Debug"));
316 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
317 table->Add (t, 0, wxALL, 6);
320 #ifdef DCPOMATIC_WINDOWS
321 _win32_console = new CheckBox (_panel, _("Open console window"));
322 table->Add (_win32_console, 1, wxEXPAND | wxALL);
323 table->AddSpacer (0);
326 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
327 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
328 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
329 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
330 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
331 #ifdef DCPOMATIC_WINDOWS
332 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::win32_console_changed, this));
336 void config_changed ()
338 Config* config = Config::instance ();
340 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
341 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
342 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
343 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
344 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
345 #ifdef DCPOMATIC_WINDOWS
346 checked_set (_win32_console, config->win32_console());
353 if (_log_general->GetValue ()) {
354 types |= LogEntry::TYPE_GENERAL;
356 if (_log_warning->GetValue ()) {
357 types |= LogEntry::TYPE_WARNING;
359 if (_log_error->GetValue ()) {
360 types |= LogEntry::TYPE_ERROR;
362 if (_log_timing->GetValue ()) {
363 types |= LogEntry::TYPE_TIMING;
365 if (_log_debug_decode->GetValue ()) {
366 types |= LogEntry::TYPE_DEBUG_DECODE;
368 Config::instance()->set_log_types (types);
371 #ifdef DCPOMATIC_WINDOWS
372 void win32_console_changed ()
374 Config::instance()->set_win32_console (_win32_console->GetValue ());
378 wxCheckBox* _log_general;
379 wxCheckBox* _log_warning;
380 wxCheckBox* _log_error;
381 wxCheckBox* _log_timing;
382 wxCheckBox* _log_debug_decode;
383 #ifdef DCPOMATIC_WINDOWS
384 wxCheckBox* _win32_console;
389 #ifdef DCPOMATIC_VARIANT_SWAROOP
390 class WatermarkPage : public StandardPage
393 WatermarkPage (wxSize panel_size, int border)
394 : StandardPage (panel_size, border)
397 wxString GetName () const
399 return _("Watermark");
403 wxBitmap GetLargeIcon () const
405 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
406 return wxBitmap ("watermark", wxBITMAP_TYPE_PNG_RESOURCE);
413 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
414 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
418 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
419 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
420 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
423 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
424 _period = new wxSpinCtrl (_panel, wxID_ANY);
425 _period->SetRange (1, 60);
426 table->Add (_period, wxGBPosition(r, 1));
427 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
430 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
431 _duration = new wxSpinCtrl (_panel, wxID_ANY);
432 _duration->SetRange (100, 5000);
433 table->Add (_duration, wxGBPosition(r, 1));
434 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
437 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
438 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
439 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
442 void config_changed ()
444 Config* config = Config::instance ();
445 checked_set (_theatre, config->player_watermark_theatre());
446 checked_set (_duration, config->player_watermark_duration());
447 checked_set (_period, config->player_watermark_period());
450 void theatre_changed ()
452 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
455 void period_changed ()
457 Config::instance()->set_player_watermark_period(_period->GetValue());
460 void duration_changed ()
462 Config::instance()->set_player_watermark_duration(_duration->GetValue());
465 wxTextCtrl* _theatre;
467 wxSpinCtrl* _duration;
470 class DevicesPage : public StandardPage
473 DevicesPage (wxSize panel_size, int border)
474 : StandardPage (panel_size, border)
477 wxString GetName () const
483 wxBitmap GetLargeIcon () const
485 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
486 return wxBitmap ("devices", wxBITMAP_TYPE_PNG_RESOURCE);
493 vector<EditableListColumn> columns;
494 columns.push_back(EditableListColumn(wx_to_std(_("Manufacturer ID"))));
495 columns.push_back(EditableListColumn(wx_to_std(_("Product code"))));
496 columns.push_back(EditableListColumn(wx_to_std(_("Serial"))));
497 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture week"))));
498 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture year"))));
499 _monitor_list = new EditableList<Monitor, MonitorDialog> (
502 boost::bind (&Config::required_monitors, Config::instance()),
503 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
504 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
508 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
510 wxButton* get = new Button(_panel, _("Read current devices"));
511 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
512 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
517 Config::instance()->set_required_monitors(get_monitors());
518 _monitor_list->refresh ();
521 string monitor_column (Monitor m, int c)
525 return m.manufacturer_id;
527 return locale_convert<string>(m.manufacturer_product_code);
529 return locale_convert<string>(m.serial_number);
531 return locale_convert<string>(m.week_of_manufacture);
533 return locale_convert<string>(m.year_of_manufacture);
535 DCPOMATIC_ASSERT(false);
541 void config_changed ()
543 _monitor_list->refresh ();
547 EditableList<Monitor, MonitorDialog>* _monitor_list;
553 create_player_config_dialog ()
555 wxPreferencesEditor* e = new wxPreferencesEditor (_("DCP-o-matic Player Preferences"));
558 /* Width that we force some of the config panels to be on OSX so that
559 the containing window doesn't shrink too much when we select those panels.
560 This is obviously an unpleasant hack.
562 wxSize ps = wxSize (520, -1);
563 int const border = 16;
565 wxSize ps = wxSize (-1, -1);
566 int const border = 8;
569 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
570 e->AddPage (new SoundPage(ps, border));
571 e->AddPage (new LocationsPage(ps, border));
572 e->AddPage (new KeysPage(ps, border));
573 #ifdef DCPOMATIC_VARIANT_SWAROOP
574 e->AddPage (new WatermarkPage(ps, border));
575 e->AddPage (new DevicesPage(ps, border));
577 e->AddPage (new PlayerAdvancedPage(ps, border));