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 #if BOOST_VERSION >= 106100
72 using namespace boost::placeholders;
74 using dcp::locale_convert;
76 class PlayerGeneralPage : public GeneralPage
79 PlayerGeneralPage (wxSize panel_size, int border)
80 : GeneralPage (panel_size, border)
86 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
87 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
90 add_language_controls (table, r);
91 add_update_controls (table, r);
93 add_label_to_sizer (table, _panel, _("Start player as"), true, wxGBPosition(r, 0));
94 _player_mode = new wxChoice (_panel, wxID_ANY);
95 _player_mode->Append (_("window"));
96 _player_mode->Append (_("full screen"));
97 _player_mode->Append (_("full screen with controls on other monitor"));
98 table->Add (_player_mode, wxGBPosition(r, 1));
101 add_label_to_sizer (table, _panel, _("Dual-screen displays"), true, wxGBPosition(r, 0));
102 _image_display = new wxChoice (_panel, wxID_ANY);
103 _image_display->Append (_("Image on primary, controls on secondary"));
104 _image_display->Append (_("Image on secondary, controls on primary"));
105 table->Add (_image_display, wxGBPosition(r, 1));
108 add_label_to_sizer (table, _panel, _("Video display mode"), true, wxGBPosition(r, 0));
109 _video_display_mode = new wxChoice (_panel, wxID_ANY);
110 _video_display_mode->Append (_("Simple (safer)"));
111 _video_display_mode->Append (_("OpenGL (faster)"));
112 table->Add (_video_display_mode, wxGBPosition(r, 1));
115 wxStaticText* restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false, wxGBPosition(r, 0));
116 wxFont font = restart->GetFont();
117 font.SetStyle (wxFONTSTYLE_ITALIC);
118 font.SetPointSize (font.GetPointSize() - 1);
119 restart->SetFont (font);
122 _respect_kdm = new CheckBox (_panel, _("Respect KDM validity periods"));
123 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
126 add_label_to_sizer (table, _panel, _("Activity log file"), true, wxGBPosition (r, 0));
127 _activity_log_file = new FilePickerCtrl (_panel, _("Select activity log file"), "*", true, true);
128 table->Add (_activity_log_file, wxGBPosition(r, 1));
131 add_label_to_sizer (table, _panel, _("Debug log file"), true, wxGBPosition (r, 0));
132 _debug_log_file = new FilePickerCtrl (_panel, _("Select debug log file"), "*", true, true);
133 table->Add (_debug_log_file, wxGBPosition(r, 1));
136 #ifdef DCPOMATIC_VARIANT_SWAROOP
137 add_label_to_sizer (table, _panel, _("KDM server URL"), true, wxGBPosition(r, 0));
138 _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
139 table->Add (_kdm_server_url, wxGBPosition (r, 1));
142 add_label_to_sizer (table, _panel, _("Lock file"), true, wxGBPosition(r, 0));
143 _lock_file = new FilePickerCtrl (_panel, _("Select lock file"), "*", true, true);
144 table->Add (_lock_file, wxGBPosition (r, 1));
148 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
149 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
150 _video_display_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::video_display_mode_changed, this));
151 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
152 _activity_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::activity_log_file_changed, this));
153 _debug_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::debug_log_file_changed, this));
154 #ifdef DCPOMATIC_VARIANT_SWAROOP
155 _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
156 _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this));
160 void config_changed ()
162 GeneralPage::config_changed ();
164 Config* config = Config::instance ();
166 switch (config->player_mode()) {
167 case Config::PLAYER_MODE_WINDOW:
168 checked_set (_player_mode, 0);
170 case Config::PLAYER_MODE_FULL:
171 checked_set (_player_mode, 1);
173 case Config::PLAYER_MODE_DUAL:
174 checked_set (_player_mode, 2);
178 switch (config->video_view_type()) {
179 case Config::VIDEO_VIEW_SIMPLE:
180 checked_set (_video_display_mode, 0);
182 case Config::VIDEO_VIEW_OPENGL:
183 checked_set (_video_display_mode, 1);
187 checked_set (_image_display, config->image_display());
188 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
189 if (config->player_activity_log_file()) {
190 checked_set (_activity_log_file, *config->player_activity_log_file());
192 if (config->player_debug_log_file()) {
193 checked_set (_debug_log_file, *config->player_debug_log_file());
195 #ifdef DCPOMATIC_VARIANT_SWAROOP
196 checked_set (_kdm_server_url, config->kdm_server_url());
197 if (config->player_lock_file()) {
198 checked_set (_lock_file, config->player_lock_file().get());
204 void player_mode_changed ()
206 switch (_player_mode->GetSelection()) {
208 Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
211 Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
214 Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
219 void image_display_changed ()
221 Config::instance()->set_image_display(_image_display->GetSelection());
224 void video_display_mode_changed ()
226 if (_video_display_mode->GetSelection() == 0) {
227 Config::instance()->set_video_view_type (Config::VIDEO_VIEW_SIMPLE);
229 Config::instance()->set_video_view_type (Config::VIDEO_VIEW_OPENGL);
233 void respect_kdm_changed ()
235 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
238 void activity_log_file_changed ()
240 Config::instance()->set_player_activity_log_file(wx_to_std(_activity_log_file->GetPath()));
243 void debug_log_file_changed ()
245 Config::instance()->set_player_debug_log_file(wx_to_std(_debug_log_file->GetPath()));
248 #ifdef DCPOMATIC_VARIANT_SWAROOP
249 void kdm_server_url_changed ()
251 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
254 void lock_file_changed ()
256 Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
260 wxChoice* _player_mode;
261 wxChoice* _image_display;
262 wxChoice* _video_display_mode;
263 wxCheckBox* _respect_kdm;
264 FilePickerCtrl* _activity_log_file;
265 FilePickerCtrl* _debug_log_file;
266 #ifdef DCPOMATIC_VARIANT_SWAROOP
267 wxTextCtrl* _kdm_server_url;
268 FilePickerCtrl* _lock_file;
273 /** @class PlayerAdvancedPage
274 * @brief Advanced page of the preferences dialog for the player.
276 class PlayerAdvancedPage : public Page
279 PlayerAdvancedPage (wxSize panel_size, int border)
280 : Page (panel_size, border)
287 wxString GetName () const
289 return _("Advanced");
293 wxBitmap GetLargeIcon () const
295 return wxBitmap ("advanced", wxBITMAP_TYPE_PNG_RESOURCE);
300 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
302 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
304 flags |= wxALIGN_RIGHT;
307 wxStaticText* m = new StaticText (parent, text);
308 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
313 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
314 table->AddGrowableCol (1, 1);
315 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
318 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
319 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
320 _log_general = new CheckBox (_panel, _("General"));
321 t->Add (_log_general, 1, wxEXPAND | wxALL);
322 _log_warning = new CheckBox (_panel, _("Warnings"));
323 t->Add (_log_warning, 1, wxEXPAND | wxALL);
324 _log_error = new CheckBox (_panel, _("Errors"));
325 t->Add (_log_error, 1, wxEXPAND | wxALL);
326 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
327 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
328 t->Add (_log_timing, 1, wxEXPAND | wxALL);
329 table->Add (t, 0, wxALL, 6);
332 #ifdef DCPOMATIC_WINDOWS
333 _win32_console = new CheckBox (_panel, _("Open console window"));
334 table->Add (_win32_console, 1, wxEXPAND | wxALL);
335 table->AddSpacer (0);
338 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
339 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
340 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
341 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
342 #ifdef DCPOMATIC_WINDOWS
343 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::win32_console_changed, this));
347 void config_changed ()
349 Config* config = Config::instance ();
351 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
352 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
353 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
354 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
355 #ifdef DCPOMATIC_WINDOWS
356 checked_set (_win32_console, config->win32_console());
363 if (_log_general->GetValue ()) {
364 types |= LogEntry::TYPE_GENERAL;
366 if (_log_warning->GetValue ()) {
367 types |= LogEntry::TYPE_WARNING;
369 if (_log_error->GetValue ()) {
370 types |= LogEntry::TYPE_ERROR;
372 if (_log_timing->GetValue ()) {
373 types |= LogEntry::TYPE_TIMING;
375 Config::instance()->set_log_types (types);
378 #ifdef DCPOMATIC_WINDOWS
379 void win32_console_changed ()
381 Config::instance()->set_win32_console (_win32_console->GetValue ());
385 wxCheckBox* _log_general;
386 wxCheckBox* _log_warning;
387 wxCheckBox* _log_error;
388 wxCheckBox* _log_timing;
389 #ifdef DCPOMATIC_WINDOWS
390 wxCheckBox* _win32_console;
395 #ifdef DCPOMATIC_VARIANT_SWAROOP
396 class WatermarkPage : public StandardPage
399 WatermarkPage (wxSize panel_size, int border)
400 : StandardPage (panel_size, border)
403 wxString GetName () const
405 return _("Watermark");
409 wxBitmap GetLargeIcon () const
411 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
412 return wxBitmap ("watermark", wxBITMAP_TYPE_PNG_RESOURCE);
419 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
420 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
424 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
425 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
426 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
429 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
430 _period = new wxSpinCtrl (_panel, wxID_ANY);
431 _period->SetRange (1, 60);
432 table->Add (_period, wxGBPosition(r, 1));
433 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
436 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
437 _duration = new wxSpinCtrl (_panel, wxID_ANY);
438 _duration->SetRange (100, 5000);
439 table->Add (_duration, wxGBPosition(r, 1));
440 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
443 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
444 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
445 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
448 void config_changed ()
450 Config* config = Config::instance ();
451 checked_set (_theatre, config->player_watermark_theatre());
452 checked_set (_duration, config->player_watermark_duration());
453 checked_set (_period, config->player_watermark_period());
456 void theatre_changed ()
458 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
461 void period_changed ()
463 Config::instance()->set_player_watermark_period(_period->GetValue());
466 void duration_changed ()
468 Config::instance()->set_player_watermark_duration(_duration->GetValue());
471 wxTextCtrl* _theatre;
473 wxSpinCtrl* _duration;
476 class DevicesPage : public StandardPage
479 DevicesPage (wxSize panel_size, int border)
480 : StandardPage (panel_size, border)
483 wxString GetName () const
489 wxBitmap GetLargeIcon () const
491 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
492 return wxBitmap ("devices", wxBITMAP_TYPE_PNG_RESOURCE);
499 vector<EditableListColumn> columns;
500 columns.push_back(EditableListColumn(_("Manufacturer ID")));
501 columns.push_back(EditableListColumn(_("Product code")));
502 columns.push_back(EditableListColumn(_("Serial")));
503 columns.push_back(EditableListColumn(_("Manufacture week")));
504 columns.push_back(EditableListColumn(_("Manufacture year")));
505 _monitor_list = new EditableList<Monitor, MonitorDialog> (
508 boost::bind (&Config::required_monitors, Config::instance()),
509 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
510 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
514 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
516 wxButton* get = new Button(_panel, _("Read current devices"));
517 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
518 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
523 Config::instance()->set_required_monitors(get_monitors());
524 _monitor_list->refresh ();
527 string monitor_column (Monitor m, int c)
531 return m.manufacturer_id;
533 return locale_convert<string>(m.manufacturer_product_code);
535 return locale_convert<string>(m.serial_number);
537 return locale_convert<string>(m.week_of_manufacture);
539 return locale_convert<string>(m.year_of_manufacture);
541 DCPOMATIC_ASSERT(false);
547 void config_changed ()
549 _monitor_list->refresh ();
553 EditableList<Monitor, MonitorDialog>* _monitor_list;
559 create_player_config_dialog ()
561 wxPreferencesEditor* e = new wxPreferencesEditor (_("DCP-o-matic Player Preferences"));
564 /* Width that we force some of the config panels to be on OSX so that
565 the containing window doesn't shrink too much when we select those panels.
566 This is obviously an unpleasant hack.
568 wxSize ps = wxSize (520, -1);
569 int const border = 16;
571 wxSize ps = wxSize (-1, -1);
572 int const border = 8;
575 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
576 e->AddPage (new SoundPage(ps, border));
577 e->AddPage (new LocationsPage(ps, border));
578 e->AddPage (new KeysPage(ps, border));
579 #ifdef DCPOMATIC_VARIANT_SWAROOP
580 e->AddPage (new WatermarkPage(ps, border));
581 e->AddPage (new DevicesPage(ps, border));
583 e->AddPage (new PlayerAdvancedPage(ps, border));