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 wxBitmap GetLargeIcon () const
292 return wxBitmap ("advanced", wxBITMAP_TYPE_PNG_RESOURCE);
297 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
299 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
301 flags |= wxALIGN_RIGHT;
304 wxStaticText* m = new StaticText (parent, text);
305 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
310 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
311 table->AddGrowableCol (1, 1);
312 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
315 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
316 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
317 _log_general = new CheckBox (_panel, _("General"));
318 t->Add (_log_general, 1, wxEXPAND | wxALL);
319 _log_warning = new CheckBox (_panel, _("Warnings"));
320 t->Add (_log_warning, 1, wxEXPAND | wxALL);
321 _log_error = new CheckBox (_panel, _("Errors"));
322 t->Add (_log_error, 1, wxEXPAND | wxALL);
323 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
324 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
325 t->Add (_log_timing, 1, wxEXPAND | wxALL);
326 table->Add (t, 0, wxALL, 6);
329 #ifdef DCPOMATIC_WINDOWS
330 _win32_console = new CheckBox (_panel, _("Open console window"));
331 table->Add (_win32_console, 1, wxEXPAND | wxALL);
332 table->AddSpacer (0);
335 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
336 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
337 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
338 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
339 #ifdef DCPOMATIC_WINDOWS
340 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::win32_console_changed, this));
344 void config_changed ()
346 Config* config = Config::instance ();
348 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
349 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
350 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
351 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
352 #ifdef DCPOMATIC_WINDOWS
353 checked_set (_win32_console, config->win32_console());
360 if (_log_general->GetValue ()) {
361 types |= LogEntry::TYPE_GENERAL;
363 if (_log_warning->GetValue ()) {
364 types |= LogEntry::TYPE_WARNING;
366 if (_log_error->GetValue ()) {
367 types |= LogEntry::TYPE_ERROR;
369 if (_log_timing->GetValue ()) {
370 types |= LogEntry::TYPE_TIMING;
372 Config::instance()->set_log_types (types);
375 #ifdef DCPOMATIC_WINDOWS
376 void win32_console_changed ()
378 Config::instance()->set_win32_console (_win32_console->GetValue ());
382 wxCheckBox* _log_general;
383 wxCheckBox* _log_warning;
384 wxCheckBox* _log_error;
385 wxCheckBox* _log_timing;
386 #ifdef DCPOMATIC_WINDOWS
387 wxCheckBox* _win32_console;
392 #ifdef DCPOMATIC_VARIANT_SWAROOP
393 class WatermarkPage : public StandardPage
396 WatermarkPage (wxSize panel_size, int border)
397 : StandardPage (panel_size, border)
400 wxString GetName () const
402 return _("Watermark");
406 wxBitmap GetLargeIcon () const
408 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
409 return wxBitmap ("watermark", wxBITMAP_TYPE_PNG_RESOURCE);
416 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
417 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
421 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
422 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
423 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
426 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
427 _period = new wxSpinCtrl (_panel, wxID_ANY);
428 _period->SetRange (1, 60);
429 table->Add (_period, wxGBPosition(r, 1));
430 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
433 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
434 _duration = new wxSpinCtrl (_panel, wxID_ANY);
435 _duration->SetRange (100, 5000);
436 table->Add (_duration, wxGBPosition(r, 1));
437 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
440 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
441 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
442 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
445 void config_changed ()
447 Config* config = Config::instance ();
448 checked_set (_theatre, config->player_watermark_theatre());
449 checked_set (_duration, config->player_watermark_duration());
450 checked_set (_period, config->player_watermark_period());
453 void theatre_changed ()
455 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
458 void period_changed ()
460 Config::instance()->set_player_watermark_period(_period->GetValue());
463 void duration_changed ()
465 Config::instance()->set_player_watermark_duration(_duration->GetValue());
468 wxTextCtrl* _theatre;
470 wxSpinCtrl* _duration;
473 class DevicesPage : public StandardPage
476 DevicesPage (wxSize panel_size, int border)
477 : StandardPage (panel_size, border)
480 wxString GetName () const
486 wxBitmap GetLargeIcon () const
488 /* XXX: this icon doesn't exist; this is just to make the swaroop variant build on OS X */
489 return wxBitmap ("devices", wxBITMAP_TYPE_PNG_RESOURCE);
496 vector<EditableListColumn> columns;
497 columns.push_back(EditableListColumn(wx_to_std(_("Manufacturer ID"))));
498 columns.push_back(EditableListColumn(wx_to_std(_("Product code"))));
499 columns.push_back(EditableListColumn(wx_to_std(_("Serial"))));
500 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture week"))));
501 columns.push_back(EditableListColumn(wx_to_std(_("Manufacture year"))));
502 _monitor_list = new EditableList<Monitor, MonitorDialog> (
505 boost::bind (&Config::required_monitors, Config::instance()),
506 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
507 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
511 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
513 wxButton* get = new Button(_panel, _("Read current devices"));
514 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
515 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
520 Config::instance()->set_required_monitors(get_monitors());
521 _monitor_list->refresh ();
524 string monitor_column (Monitor m, int c)
528 return m.manufacturer_id;
530 return locale_convert<string>(m.manufacturer_product_code);
532 return locale_convert<string>(m.serial_number);
534 return locale_convert<string>(m.week_of_manufacture);
536 return locale_convert<string>(m.year_of_manufacture);
538 DCPOMATIC_ASSERT(false);
544 void config_changed ()
546 _monitor_list->refresh ();
550 EditableList<Monitor, MonitorDialog>* _monitor_list;
556 create_player_config_dialog ()
558 wxPreferencesEditor* e = new wxPreferencesEditor (_("DCP-o-matic Player Preferences"));
561 /* Width that we force some of the config panels to be on OSX so that
562 the containing window doesn't shrink too much when we select those panels.
563 This is obviously an unpleasant hack.
565 wxSize ps = wxSize (520, -1);
566 int const border = 16;
568 wxSize ps = wxSize (-1, -1);
569 int const border = 8;
572 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
573 e->AddPage (new SoundPage(ps, border));
574 e->AddPage (new LocationsPage(ps, border));
575 e->AddPage (new KeysPage(ps, border));
576 #ifdef DCPOMATIC_VARIANT_SWAROOP
577 e->AddPage (new WatermarkPage(ps, border));
578 e->AddPage (new DevicesPage(ps, border));
580 e->AddPage (new PlayerAdvancedPage(ps, border));