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 Page
276 PlayerAdvancedPage (wxSize panel_size, int border)
277 : Page (panel_size, border)
284 wxString GetName () const
286 return _("Advanced");
290 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
292 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
294 flags |= wxALIGN_RIGHT;
297 wxStaticText* m = new StaticText (parent, text);
298 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
303 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
304 table->AddGrowableCol (1, 1);
305 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
308 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
309 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
310 _log_general = new CheckBox (_panel, _("General"));
311 t->Add (_log_general, 1, wxEXPAND | wxALL);
312 _log_warning = new CheckBox (_panel, _("Warnings"));
313 t->Add (_log_warning, 1, wxEXPAND | wxALL);
314 _log_error = new CheckBox (_panel, _("Errors"));
315 t->Add (_log_error, 1, wxEXPAND | wxALL);
316 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
317 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
318 t->Add (_log_timing, 1, wxEXPAND | wxALL);
319 table->Add (t, 0, wxALL, 6);
322 #ifdef DCPOMATIC_WINDOWS
323 _win32_console = new CheckBox (_panel, _("Open console window"));
324 table->Add (_win32_console, 1, wxEXPAND | wxALL);
325 table->AddSpacer (0);
328 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
329 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
330 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
331 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
332 #ifdef DCPOMATIC_WINDOWS
333 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::win32_console_changed, this));
337 void config_changed ()
339 Config* config = Config::instance ();
341 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
342 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
343 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
344 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
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 Config::instance()->set_log_types (types);
368 #ifdef DCPOMATIC_WINDOWS
369 void win32_console_changed ()
371 Config::instance()->set_win32_console (_win32_console->GetValue ());
375 wxCheckBox* _log_general;
376 wxCheckBox* _log_warning;
377 wxCheckBox* _log_error;
378 wxCheckBox* _log_timing;
379 #ifdef DCPOMATIC_WINDOWS
380 wxCheckBox* _win32_console;
385 #ifdef DCPOMATIC_VARIANT_SWAROOP
386 class WatermarkPage : public StandardPage
389 WatermarkPage (wxSize panel_size, int border)
390 : StandardPage (panel_size, border)
393 wxString GetName () const
395 return _("Watermark");
399 wxBitmap GetLargeIcon () const
401 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
402 return wxBitmap ("watermark", wxBITMAP_TYPE_PNG_RESOURCE);
409 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
410 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
414 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
415 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
416 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
419 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
420 _period = new wxSpinCtrl (_panel, wxID_ANY);
421 _period->SetRange (1, 60);
422 table->Add (_period, wxGBPosition(r, 1));
423 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
426 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
427 _duration = new wxSpinCtrl (_panel, wxID_ANY);
428 _duration->SetRange (100, 5000);
429 table->Add (_duration, wxGBPosition(r, 1));
430 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
433 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
434 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
435 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
438 void config_changed ()
440 Config* config = Config::instance ();
441 checked_set (_theatre, config->player_watermark_theatre());
442 checked_set (_duration, config->player_watermark_duration());
443 checked_set (_period, config->player_watermark_period());
446 void theatre_changed ()
448 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
451 void period_changed ()
453 Config::instance()->set_player_watermark_period(_period->GetValue());
456 void duration_changed ()
458 Config::instance()->set_player_watermark_duration(_duration->GetValue());
461 wxTextCtrl* _theatre;
463 wxSpinCtrl* _duration;
466 class DevicesPage : public StandardPage
469 DevicesPage (wxSize panel_size, int border)
470 : StandardPage (panel_size, border)
473 wxString GetName () const
479 wxBitmap GetLargeIcon () const
481 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
482 return wxBitmap ("devices", wxBITMAP_TYPE_PNG_RESOURCE);
489 vector<EditableListColumn> columns;
490 columns.push_back(EditableListColumn(wx_to_std(_("Manufacturer ID"))));
491 columns.push_back(EditableListColumn(wx_to_std(_("Product code"))));
492 columns.push_back(EditableListColumn(wx_to_std(_("Serial"))));
493 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture week"))));
494 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture year"))));
495 _monitor_list = new EditableList<Monitor, MonitorDialog> (
498 boost::bind (&Config::required_monitors, Config::instance()),
499 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
500 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
504 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
506 wxButton* get = new Button(_panel, _("Read current devices"));
507 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
508 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
513 Config::instance()->set_required_monitors(get_monitors());
514 _monitor_list->refresh ();
517 string monitor_column (Monitor m, int c)
521 return m.manufacturer_id;
523 return locale_convert<string>(m.manufacturer_product_code);
525 return locale_convert<string>(m.serial_number);
527 return locale_convert<string>(m.week_of_manufacture);
529 return locale_convert<string>(m.year_of_manufacture);
531 DCPOMATIC_ASSERT(false);
537 void config_changed ()
539 _monitor_list->refresh ();
543 EditableList<Monitor, MonitorDialog>* _monitor_list;
549 create_player_config_dialog ()
551 wxPreferencesEditor* e = new wxPreferencesEditor (_("DCP-o-matic Player Preferences"));
554 /* Width that we force some of the config panels to be on OSX so that
555 the containing window doesn't shrink too much when we select those panels.
556 This is obviously an unpleasant hack.
558 wxSize ps = wxSize (520, -1);
559 int const border = 16;
561 wxSize ps = wxSize (-1, -1);
562 int const border = 8;
565 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
566 e->AddPage (new SoundPage(ps, 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));
573 e->AddPage (new PlayerAdvancedPage(ps, border));