2 Copyright (C) 2012-2018 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 "lib/config.h"
40 #include "lib/ratio.h"
41 #include "lib/filter.h"
42 #include "lib/dcp_content_type.h"
45 #include "lib/cross.h"
46 #include "lib/exceptions.h"
47 #include <dcp/locale_convert.h>
48 #include <dcp/exceptions.h>
49 #include <dcp/certificate_chain.h>
50 #include <wx/stdpaths.h>
51 #include <wx/preferences.h>
52 #include <wx/spinctrl.h>
53 #include <wx/filepicker.h>
55 #include <boost/filesystem.hpp>
56 #include <boost/foreach.hpp>
67 using boost::shared_ptr;
68 using boost::function;
69 using boost::optional;
70 using dcp::locale_convert;
72 class PlayerGeneralPage : public GeneralPage
75 PlayerGeneralPage (wxSize panel_size, int border)
76 : GeneralPage (panel_size, border)
82 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
83 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
86 add_language_controls (table, r);
87 add_play_sound_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 _respect_kdm = new CheckBox (_panel, _("Respect KDM validity periods"));
106 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
109 add_label_to_sizer (table, _panel, _("Log file"), true, wxGBPosition (r, 0));
110 _log_file = new FilePickerCtrl (_panel, _("Select log file"), "*", true);
111 table->Add (_log_file, wxGBPosition (r, 1));
114 #ifdef DCPOMATIC_VARIANT_SWAROOP
115 add_label_to_sizer (table, _panel, _("KDM server URL"), true, wxGBPosition(r, 0));
116 _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
117 table->Add (_kdm_server_url, wxGBPosition (r, 1));
120 add_label_to_sizer (table, _panel, _("Lock file"), true, wxGBPosition(r, 0));
121 _lock_file = new FilePickerCtrl (_panel, _("Select lock file"), "*", true);
122 table->Add (_lock_file, wxGBPosition (r, 1));
126 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
127 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
128 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
129 _log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::log_file_changed, this));
130 #ifdef DCPOMATIC_VARIANT_SWAROOP
131 _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
132 _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this));
136 void config_changed ()
138 GeneralPage::config_changed ();
140 Config* config = Config::instance ();
142 switch (config->player_mode()) {
143 case Config::PLAYER_MODE_WINDOW:
144 checked_set (_player_mode, 0);
146 case Config::PLAYER_MODE_FULL:
147 checked_set (_player_mode, 1);
149 case Config::PLAYER_MODE_DUAL:
150 checked_set (_player_mode, 2);
154 checked_set (_image_display, config->image_display());
155 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
156 if (config->player_log_file()) {
157 checked_set (_log_file, *config->player_log_file());
159 #ifdef DCPOMATIC_VARIANT_SWAROOP
160 checked_set (_kdm_server_url, config->kdm_server_url());
161 if (config->player_lock_file()) {
162 checked_set (_lock_file, config->player_lock_file().get());
168 void player_mode_changed ()
170 switch (_player_mode->GetSelection()) {
172 Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
175 Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
178 Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
183 void image_display_changed ()
185 Config::instance()->set_image_display(_image_display->GetSelection());
188 void respect_kdm_changed ()
190 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
193 void log_file_changed ()
195 Config::instance()->set_player_log_file(wx_to_std(_log_file->GetPath()));
198 #ifdef DCPOMATIC_VARIANT_SWAROOP
199 void kdm_server_url_changed ()
201 Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
204 void lock_file_changed ()
206 Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
210 wxChoice* _player_mode;
211 wxChoice* _image_display;
212 wxCheckBox* _respect_kdm;
213 FilePickerCtrl* _log_file;
214 #ifdef DCPOMATIC_VARIANT_SWAROOP
215 wxTextCtrl* _kdm_server_url;
216 FilePickerCtrl* _lock_file;
220 class LocationsPage : public StandardPage
223 LocationsPage (wxSize panel_size, int border)
224 : StandardPage (panel_size, border)
227 wxString GetName () const
229 return _("Locations");
233 wxBitmap GetLargeIcon () const
235 return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
245 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
246 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
248 add_label_to_sizer (table, _panel, _("Content directory"), true, wxGBPosition (r, 0));
249 _content_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
250 table->Add (_content_directory, wxGBPosition (r, 1));
253 add_label_to_sizer (table, _panel, _("Playlist directory"), true, wxGBPosition (r, 0));
254 _playlist_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
255 table->Add (_playlist_directory, wxGBPosition (r, 1));
258 add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0));
259 _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
260 table->Add (_kdm_directory, wxGBPosition (r, 1));
263 #ifdef DCPOMATIC_VARIANT_SWAROOP
264 add_label_to_sizer (table, _panel, _("Background image"), true, wxGBPosition (r, 0));
265 _background_image = new FilePickerCtrl (_panel, _("Select image file"), "*.png;*.jpg;*.jpeg;*.tif;*.tiff", true);
266 table->Add (_background_image, wxGBPosition (r, 1));
270 _content_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::content_directory_changed, this));
271 _playlist_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::playlist_directory_changed, this));
272 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this));
273 #ifdef DCPOMATIC_VARIANT_SWAROOP
274 _background_image->Bind (wxEVT_FILEPICKER_CHANGED, bind(&LocationsPage::background_image_changed, this));
278 void config_changed ()
280 Config* config = Config::instance ();
282 if (config->player_content_directory()) {
283 checked_set (_content_directory, *config->player_content_directory());
285 if (config->player_playlist_directory()) {
286 checked_set (_playlist_directory, *config->player_playlist_directory());
288 if (config->player_kdm_directory()) {
289 checked_set (_kdm_directory, *config->player_kdm_directory());
291 #ifdef DCPOMATIC_VARIANT_SWAROOP
292 if (config->player_background_image()) {
293 checked_set (_background_image, *config->player_background_image());
298 void content_directory_changed ()
300 Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath()));
303 void playlist_directory_changed ()
305 Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath()));
308 void kdm_directory_changed ()
310 Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
313 #ifdef DCPOMATIC_VARIANT_SWAROOP
314 void background_image_changed ()
316 Config::instance()->set_player_background_image(wx_to_std(_background_image->GetPath()));
320 wxDirPickerCtrl* _content_directory;
321 wxDirPickerCtrl* _playlist_directory;
322 wxDirPickerCtrl* _kdm_directory;
323 #ifdef DCPOMATIC_VARIANT_SWAROOP
324 FilePickerCtrl* _background_image;
328 #ifdef DCPOMATIC_VARIANT_SWAROOP
329 class WatermarkPage : public StandardPage
332 WatermarkPage (wxSize panel_size, int border)
333 : StandardPage (panel_size, border)
336 wxString GetName () const
338 return _("Watermark");
344 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
345 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
349 add_label_to_sizer (table, _panel, _("Theatre name"), true, wxGBPosition(r, 0));
350 _theatre = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1));
351 table->Add (_theatre, wxGBPosition(r, 1), wxGBSpan(1, 2));
354 add_label_to_sizer (table, _panel, _("Period"), true, wxGBPosition(r, 0));
355 _period = new wxSpinCtrl (_panel, wxID_ANY);
356 _period->SetRange (1, 60);
357 table->Add (_period, wxGBPosition(r, 1));
358 add_label_to_sizer (table, _panel, _("minutes"), false, wxGBPosition(r, 2));
361 add_label_to_sizer (table, _panel, _("Duration"), true, wxGBPosition(r, 0));
362 _duration = new wxSpinCtrl (_panel, wxID_ANY);
363 _duration->SetRange (100, 5000);
364 table->Add (_duration, wxGBPosition(r, 1));
365 add_label_to_sizer (table, _panel, _("milliseconds"), false, wxGBPosition(r, 2));
368 _theatre->Bind (wxEVT_TEXT, bind(&WatermarkPage::theatre_changed, this));
369 _duration->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::duration_changed, this));
370 _period->Bind (wxEVT_SPINCTRL, bind(&WatermarkPage::period_changed, this));
373 void config_changed ()
375 Config* config = Config::instance ();
376 checked_set (_theatre, config->player_watermark_theatre());
377 checked_set (_duration, config->player_watermark_duration());
378 checked_set (_period, config->player_watermark_period());
381 void theatre_changed ()
383 Config::instance()->set_player_watermark_theatre(wx_to_std(_theatre->GetValue()));
386 void period_changed ()
388 Config::instance()->set_player_watermark_period(_period->GetValue());
391 void duration_changed ()
393 Config::instance()->set_player_watermark_duration(_duration->GetValue());
396 wxTextCtrl* _theatre;
398 wxSpinCtrl* _duration;
401 class DevicesPage : public StandardPage
404 DevicesPage (wxSize panel_size, int border)
405 : StandardPage (panel_size, border)
408 wxString GetName () const
416 vector<string> columns;
417 columns.push_back(wx_to_std(_("Manufacturer ID")));
418 columns.push_back(wx_to_std(_("Product code")));
419 columns.push_back(wx_to_std(_("Serial")));
420 columns.push_back(wx_to_std(_("Manufacture week")));
421 columns.push_back(wx_to_std(_("Manufacture year")));
422 _monitor_list = new EditableList<Monitor, MonitorDialog> (
425 boost::bind (&Config::required_monitors, Config::instance()),
426 boost::bind (&Config::set_required_monitors, Config::instance(), _1),
427 boost::bind (&DevicesPage::monitor_column, this, _1, _2),
432 _panel->GetSizer()->Add(_monitor_list, 1, wxEXPAND | wxALL, _border);
434 Button* get = new wxButton(_panel, _("Read current devices"));
435 _panel->GetSizer()->Add(get, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
436 get->Bind(wxEVT_BUTTON, bind(&DevicesPage::get_clicked, this));
441 Config::instance()->set_required_monitors(get_monitors());
442 _monitor_list->refresh ();
445 string monitor_column (Monitor m, int c)
449 return m.manufacturer_id;
451 return locale_convert<string>(m.manufacturer_product_code);
453 return locale_convert<string>(m.serial_number);
455 return locale_convert<string>(m.week_of_manufacture);
457 return locale_convert<string>(m.year_of_manufacture);
459 DCPOMATIC_ASSERT(false);
465 void config_changed ()
467 _monitor_list->refresh ();
471 EditableList<Monitor, MonitorDialog>* _monitor_list;
477 create_player_config_dialog ()
479 wxPreferencesEditor* e = new wxPreferencesEditor ();
482 /* Width that we force some of the config panels to be on OSX so that
483 the containing window doesn't shrink too much when we select those panels.
484 This is obviously an unpleasant hack.
486 wxSize ps = wxSize (520, -1);
487 int const border = 16;
489 wxSize ps = wxSize (-1, -1);
490 int const border = 8;
493 e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
494 e->AddPage (new LocationsPage(ps, border));
495 e->AddPage (new KeysPage(ps, border));
496 #ifdef DCPOMATIC_VARIANT_SWAROOP
497 e->AddPage (new WatermarkPage(ps, border));
498 e->AddPage (new DevicesPage(ps, border));