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)
285 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
287 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
289 flags |= wxALIGN_RIGHT;
292 wxStaticText* m = new StaticText (parent, text);
293 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
298 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
299 table->AddGrowableCol (1, 1);
300 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
303 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
304 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
305 _log_general = new CheckBox (_panel, _("General"));
306 t->Add (_log_general, 1, wxEXPAND | wxALL);
307 _log_warning = new CheckBox (_panel, _("Warnings"));
308 t->Add (_log_warning, 1, wxEXPAND | wxALL);
309 _log_error = new CheckBox (_panel, _("Errors"));
310 t->Add (_log_error, 1, wxEXPAND | wxALL);
311 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
312 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
313 t->Add (_log_timing, 1, wxEXPAND | wxALL);
314 table->Add (t, 0, wxALL, 6);
317 #ifdef DCPOMATIC_WINDOWS
318 _win32_console = new CheckBox (_panel, _("Open console window"));
319 table->Add (_win32_console, 1, wxEXPAND | wxALL);
320 table->AddSpacer (0);
323 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
324 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
325 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
326 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
327 #ifdef DCPOMATIC_WINDOWS
328 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::win32_console_changed, this));
332 void config_changed ()
334 Config* config = Config::instance ();
336 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
337 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
338 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
339 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
340 #ifdef DCPOMATIC_WINDOWS
341 checked_set (_win32_console, config->win32_console());
348 if (_log_general->GetValue ()) {
349 types |= LogEntry::TYPE_GENERAL;
351 if (_log_warning->GetValue ()) {
352 types |= LogEntry::TYPE_WARNING;
354 if (_log_error->GetValue ()) {
355 types |= LogEntry::TYPE_ERROR;
357 if (_log_timing->GetValue ()) {
358 types |= LogEntry::TYPE_TIMING;
360 Config::instance()->set_log_types (types);
363 #ifdef DCPOMATIC_WINDOWS
364 void win32_console_changed ()
366 Config::instance()->set_win32_console (_win32_console->GetValue ());
370 wxCheckBox* _log_general;
371 wxCheckBox* _log_warning;
372 wxCheckBox* _log_error;
373 wxCheckBox* _log_timing;
374 #ifdef DCPOMATIC_WINDOWS
375 wxCheckBox* _win32_console;
380 #ifdef DCPOMATIC_VARIANT_SWAROOP
381 class WatermarkPage : public StandardPage
384 WatermarkPage (wxSize panel_size, int border)
385 : StandardPage (panel_size, border)
388 wxString GetName () const
390 return _("Watermark");
394 wxBitmap GetLargeIcon () const
396 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
397 return wxBitmap ("watermark", wxBITMAP_TYPE_PNG_RESOURCE);
404 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
405 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
409 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
410 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
411 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
414 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
415 _period = new wxSpinCtrl (_panel, wxID_ANY);
416 _period->SetRange (1, 60);
417 table->Add (_period, wxGBPosition(r, 1));
418 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
421 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
422 _duration = new wxSpinCtrl (_panel, wxID_ANY);
423 _duration->SetRange (100, 5000);
424 table->Add (_duration, wxGBPosition(r, 1));
425 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
428 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
429 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
430 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
433 void config_changed ()
435 Config* config = Config::instance ();
436 checked_set (_theatre, config->player_watermark_theatre());
437 checked_set (_duration, config->player_watermark_duration());
438 checked_set (_period, config->player_watermark_period());
441 void theatre_changed ()
443 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
446 void period_changed ()
448 Config::instance()->set_player_watermark_period(_period->GetValue());
451 void duration_changed ()
453 Config::instance()->set_player_watermark_duration(_duration->GetValue());
456 wxTextCtrl* _theatre;
458 wxSpinCtrl* _duration;
461 class DevicesPage : public StandardPage
464 DevicesPage (wxSize panel_size, int border)
465 : StandardPage (panel_size, border)
468 wxString GetName () const
474 wxBitmap GetLargeIcon () const
476 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
477 return wxBitmap ("devices", wxBITMAP_TYPE_PNG_RESOURCE);
484 vector<EditableListColumn> columns;
485 columns.push_back(EditableListColumn(wx_to_std(_("Manufacturer ID"))));
486 columns.push_back(EditableListColumn(wx_to_std(_("Product code"))));
487 columns.push_back(EditableListColumn(wx_to_std(_("Serial"))));
488 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture week"))));
489 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture year"))));
490 _monitor_list = new EditableList<Monitor, MonitorDialog> (
493 boost::bind (&Config::required_monitors, Config::instance()),
494 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
495 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
499 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
501 wxButton* get = new Button(_panel, _("Read current devices"));
502 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
503 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
508 Config::instance()->set_required_monitors(get_monitors());
509 _monitor_list->refresh ();
512 string monitor_column (Monitor m, int c)
516 return m.manufacturer_id;
518 return locale_convert<string>(m.manufacturer_product_code);
520 return locale_convert<string>(m.serial_number);
522 return locale_convert<string>(m.week_of_manufacture);
524 return locale_convert<string>(m.year_of_manufacture);
526 DCPOMATIC_ASSERT(false);
532 void config_changed ()
534 _monitor_list->refresh ();
538 EditableList<Monitor, MonitorDialog>* _monitor_list;
544 create_player_config_dialog ()
546 wxPreferencesEditor* e = new wxPreferencesEditor (_("DCP-o-matic Player Preferences"));
549 /* Width that we force some of the config panels to be on OSX so that
550 the containing window doesn't shrink too much when we select those panels.
551 This is obviously an unpleasant hack.
553 wxSize ps = wxSize (520, -1);
554 int const border = 16;
556 wxSize ps = wxSize (-1, -1);
557 int const border = 8;
560 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
561 e->AddPage (new SoundPage(ps, border));
562 e->AddPage (new LocationsPage(ps, border));
563 e->AddPage (new KeysPage(ps, border));
564 #ifdef DCPOMATIC_VARIANT_SWAROOP
565 e->AddPage (new WatermarkPage(ps, border));
566 e->AddPage (new DevicesPage(ps, border));
568 e->AddPage (new PlayerAdvancedPage(ps, border));