X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Fconfig_dialog.cc;h=f41d5146cb503d928143853f50d12751f28d297c;hb=e1093a718c15e1c9ca98abbf514ec54293f0723a;hp=3410948431005356c966f91c4f24929c4a05e7a3;hpb=6a4e591bde05d9700c1751105f7244e43ec72702;p=dcpomatic.git diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 341094843..f41d5146c 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington + Copyright (C) 2012-2017 Carl Hetherington This file is part of DCP-o-matic. @@ -33,6 +33,8 @@ #include "make_chain_dialog.h" #include "email_dialog.h" #include "name_format_editor.h" +#include "nag_dialog.h" +#include "config_move_dialog.h" #include "lib/config.h" #include "lib/ratio.h" #include "lib/filter.h" @@ -66,6 +68,13 @@ using boost::function; using boost::optional; using dcp::locale_convert; +static +void +do_nothing () +{ + +} + class Page { public: @@ -194,19 +203,30 @@ private: restart->SetFont (font); ++r; - add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0)); - _num_local_encoding_threads = new wxSpinCtrl (_panel); - table->Add (_num_local_encoding_threads, wxGBPosition (r, 1)); + add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0)); + _master_encoding_threads = new wxSpinCtrl (_panel); + table->Add (_master_encoding_threads, wxGBPosition (r, 1)); + ++r; + + add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0)); + _server_encoding_threads = new wxSpinCtrl (_panel); + table->Add (_server_encoding_threads, wxGBPosition (r, 1)); + ++r; + + add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0)); + _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true); + table->Add (_config_file, wxGBPosition (r, 1)); ++r; add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0)); - _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml"); + _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true); table->Add (_cinemas_file, wxGBPosition (r, 1)); ++r; - add_label_to_sizer (table, _panel, _("Sound output"), true, wxGBPosition (r, 0)); - _sound_output = new wxChoice (_panel, wxID_ANY); - table->Add (_sound_output, wxGBPosition (r, 1)); + _preview_sound = new wxCheckBox (_panel, wxID_ANY, _("Play sound in the preview via")); + table->Add (_preview_sound, wxGBPosition (r, 0)); + _preview_sound_output = new wxChoice (_panel, wxID_ANY); + table->Add (_preview_sound_output, wxGBPosition (r, 1)); ++r; #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG @@ -245,17 +265,21 @@ private: for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) { RtAudio::DeviceInfo dev = audio.getDeviceInfo (i); if (dev.probed && dev.outputChannels > 0) { - _sound_output->Append (std_to_wx (dev.name)); + _preview_sound_output->Append (std_to_wx (dev.name)); } } - _set_language->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::set_language_changed, this)); - _language->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::language_changed, this)); - _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this)); - _sound_output->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::sound_output_changed, this)); + _set_language->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::set_language_changed, this)); + _language->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::language_changed, this)); + _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&GeneralPage::config_file_changed, this)); + _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this)); + _preview_sound->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::preview_sound_changed, this)); + _preview_sound_output->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::preview_sound_output_changed, this)); - _num_local_encoding_threads->SetRange (1, 128); - _num_local_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this)); + _master_encoding_threads->SetRange (1, 128); + _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::master_encoding_threads_changed, this)); + _server_encoding_threads->SetRange (1, 128); + _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::server_encoding_threads_changed, this)); #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::analyse_ebur128_changed, this)); @@ -298,7 +322,8 @@ private: checked_set (_language, lang); - checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ()); + checked_set (_master_encoding_threads, config->master_encoding_threads ()); + checked_set (_server_encoding_threads, config->server_encoding_threads ()); #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG checked_set (_analyse_ebur128, config->analyse_ebur128 ()); #endif @@ -307,25 +332,31 @@ private: checked_set (_check_for_test_updates, config->check_for_test_updates ()); checked_set (_issuer, config->dcp_issuer ()); checked_set (_creator, config->dcp_creator ()); + checked_set (_config_file, config->config_file()); checked_set (_cinemas_file, config->cinemas_file()); + checked_set (_preview_sound, config->preview_sound()); - optional const current_so = get_sound_output (); - string configured_so; + optional const current_so = get_preview_sound_output (); + optional configured_so; - if (config->sound_output()) { - configured_so = config->sound_output().get(); + if (config->preview_sound_output()) { + configured_so = config->preview_sound_output().get(); } else { /* No configured output means we should use the default */ RtAudio audio (DCPOMATIC_RTAUDIO_API); - configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name; + try { + configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name; + } catch (RtAudioError& e) { + /* Probably no audio devices at all */ + } } - if (!current_so || *current_so != configured_so) { - /* Update _sound_output with the configured value */ + if (configured_so && current_so != configured_so) { + /* Update _preview_sound_output with the configured value */ unsigned int i = 0; - while (i < _sound_output->GetCount()) { - if (_sound_output->GetString(i) == std_to_wx(configured_so)) { - _sound_output->SetSelection (i); + while (i < _preview_sound_output->GetCount()) { + if (_preview_sound_output->GetString(i) == std_to_wx(*configured_so)) { + _preview_sound_output->SetSelection (i); break; } ++i; @@ -335,21 +366,22 @@ private: setup_sensitivity (); } - /** @return Currently-selected sound output in the dialogue */ - optional get_sound_output () + /** @return Currently-selected preview sound output in the dialogue */ + optional get_preview_sound_output () { - int const sel = _sound_output->GetSelection (); + int const sel = _preview_sound_output->GetSelection (); if (sel == wxNOT_FOUND) { return optional (); } - return wx_to_std (_sound_output->GetString (sel)); + return wx_to_std (_preview_sound_output->GetString (sel)); } void setup_sensitivity () { _language->Enable (_set_language->GetValue ()); _check_for_test_updates->Enable (_check_for_updates->GetValue ()); + _preview_sound_output->Enable (_preview_sound->GetValue ()); } void set_language_changed () @@ -394,9 +426,14 @@ private: Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ()); } - void num_local_encoding_threads_changed () + void master_encoding_threads_changed () { - Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ()); + Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue ()); + } + + void server_encoding_threads_changed () + { + Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue ()); } void issuer_changed () @@ -409,27 +446,61 @@ private: Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ())); } + void config_file_changed () + { + Config* config = Config::instance(); + boost::filesystem::path new_file = wx_to_std(_config_file->GetPath()); + if (new_file == config->config_file()) { + return; + } + bool copy_and_link = true; + if (boost::filesystem::exists(new_file)) { + ConfigMoveDialog* d = new ConfigMoveDialog (_panel, new_file); + if (d->ShowModal() == wxID_OK) { + copy_and_link = false; + } + d->Destroy (); + } + + if (copy_and_link) { + config->write (); + if (new_file != config->config_file()) { + config->copy_and_link (new_file); + } + } else { + config->link (new_file); + } + } + void cinemas_file_changed () { Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ())); } - void sound_output_changed () + void preview_sound_changed () + { + Config::instance()->set_preview_sound (_preview_sound->GetValue ()); + } + + void preview_sound_output_changed () { RtAudio audio (DCPOMATIC_RTAUDIO_API); - optional const so = get_sound_output(); + optional const so = get_preview_sound_output(); if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) { - Config::instance()->unset_sound_output (); + Config::instance()->unset_preview_sound_output (); } else { - Config::instance()->set_sound_output (*so); + Config::instance()->set_preview_sound_output (*so); } } wxCheckBox* _set_language; wxChoice* _language; - wxSpinCtrl* _num_local_encoding_threads; + wxSpinCtrl* _master_encoding_threads; + wxSpinCtrl* _server_encoding_threads; + FilePickerCtrl* _config_file; FilePickerCtrl* _cinemas_file; - wxChoice* _sound_output; + wxCheckBox* _preview_sound; + wxChoice* _preview_sound_output; #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG wxCheckBox* _analyse_ebur128; #endif @@ -491,6 +562,10 @@ private: _container = new wxChoice (_panel, wxID_ANY); table->Add (_container); + add_label_to_sizer (table, _panel, _("Default scale-to"), true); + _scale_to = new wxChoice (_panel, wxID_ANY); + table->Add (_scale_to); + add_label_to_sizer (table, _panel, _("Default content type"), true); _dcp_content_type = new wxChoice (_panel, wxID_ANY); table->Add (_dcp_content_type); @@ -537,16 +612,22 @@ private: _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this)); - vector ratios = Ratio::all (); - for (size_t i = 0; i < ratios.size(); ++i) { - _container->Append (std_to_wx (ratios[i]->nickname ())); + BOOST_FOREACH (Ratio const * i, Ratio::containers()) { + _container->Append (std_to_wx(i->container_nickname())); } _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this)); - vector const ct = DCPContentType::all (); - for (size_t i = 0; i < ct.size(); ++i) { - _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ())); + _scale_to->Append (_("Guess from content")); + + BOOST_FOREACH (Ratio const * i, Ratio::all()) { + _scale_to->Append (std_to_wx(i->image_nickname())); + } + + _scale_to->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::scale_to_changed, this)); + + BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) { + _dcp_content_type->Append (std_to_wx (i->pretty_name ())); } setup_audio_channels_choice (_dcp_audio_channels, 2); @@ -569,13 +650,24 @@ private: { Config* config = Config::instance (); + vector containers = Ratio::containers (); + for (size_t i = 0; i < containers.size(); ++i) { + if (containers[i] == config->default_container ()) { + _container->SetSelection (i); + } + } + vector ratios = Ratio::all (); for (size_t i = 0; i < ratios.size(); ++i) { - if (ratios[i] == config->default_container ()) { - _container->SetSelection (i); + if (ratios[i] == config->default_scale_to ()) { + _scale_to->SetSelection (i + 1); } } + if (!config->default_scale_to()) { + _scale_to->SetSelection (0); + } + vector const ct = DCPContentType::all (); for (size_t i = 0; i < ct.size(); ++i) { if (ct[i] == config->default_dcp_content_type ()) { @@ -638,10 +730,21 @@ private: void container_changed () { - vector ratio = Ratio::all (); + vector ratio = Ratio::containers (); Config::instance()->set_default_container (ratio[_container->GetSelection()]); } + void scale_to_changed () + { + int const s = _scale_to->GetSelection (); + if (s == 0) { + Config::instance()->set_default_scale_to (0); + } else { + vector ratio = Ratio::all (); + Config::instance()->set_default_scale_to (ratio[s - 1]); + } + } + void dcp_content_type_changed () { vector ct = DCPContentType::all (); @@ -665,6 +768,7 @@ private: wxDirPickerCtrl* _kdm_directory; #endif wxChoice* _container; + wxChoice* _scale_to; wxChoice* _dcp_content_type; wxChoice* _dcp_audio_channels; wxChoice* _standard; @@ -738,11 +842,13 @@ public: wxString title, int border, function)> set, - function (void)> get + function (void)> get, + function nag_remake ) : wxPanel (parent) , _set (set) , _get (get) + , _nag_remake (nag_remake) { wxFont subheading_font (*wxNORMAL_FONT); subheading_font.SetWeight (wxFONTWEIGHT_BOLD); @@ -816,6 +922,13 @@ public: table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4)); ++r; + _private_key_bad = new wxStaticText (this, wxID_ANY, _("Leaf private key does not match leaf certificate!")); + font = *wxSMALL_FONT; + font.SetWeight (wxFONTWEIGHT_BOLD); + _private_key_bad->SetFont (font); + table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3)); + ++r; + _add_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::add_certificate, this)); _remove_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remove_certificate, this)); _export_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_certificate, this)); @@ -851,7 +964,15 @@ private: if (d->ShowModal() == wxID_OK) { try { dcp::Certificate c; - string const extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ()))); + string extra; + try { + extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ()))); + } catch (boost::filesystem::filesystem_error& e) { + error_dialog (this, wxString::Format (_("Could not load certificate (%s)"), d->GetPath().data())); + d->Destroy (); + return; + } + if (!extra.empty ()) { message_dialog ( this, @@ -860,8 +981,17 @@ private: ); } _chain->add (c); - _set (_chain); - update_certificate_list (); + if (!_chain->chain_valid ()) { + error_dialog ( + this, + _("Adding this certificate would make the chain inconsistent, so it will not be added. " + "Add certificates in order from root to intermediate to leaf.") + ); + _chain->remove (c); + } else { + _set (_chain); + update_certificate_list (); + } } catch (dcp::MiscError& e) { error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ())); } @@ -938,6 +1068,16 @@ private: ++n; } + + static wxColour normal = _private_key_bad->GetForegroundColour (); + + if (_chain->private_key_valid ()) { + _private_key_bad->Hide (); + _private_key_bad->SetForegroundColour (normal); + } else { + _private_key_bad->Show (); + _private_key_bad->SetForegroundColour (wxColour (255, 0, 0)); + } } void remake_certificates () @@ -971,6 +1111,8 @@ private: intermediate_common_name = i->subject_common_name (); } + _nag_remake (); + MakeChainDialog* d = new MakeChainDialog ( this, subject_organization_name, @@ -1002,7 +1144,8 @@ private: void update_sensitivity () { - _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1); + /* We can only remove the leaf certificate */ + _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1)); _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1); } @@ -1073,11 +1216,13 @@ private: wxStaticText* _private_key; wxButton* _load_private_key; wxButton* _export_private_key; + wxStaticText* _private_key_bad; wxSizer* _sizer; wxBoxSizer* _button_sizer; shared_ptr _chain; boost::function)> _set; boost::function (void)> _get; + boost::function _nag_remake; }; class KeysPage : public StandardPage @@ -1106,22 +1251,24 @@ private: _signer = new CertificateChainEditor ( _panel, _("Signing DCPs and KDMs"), _border, boost::bind (&Config::set_signer_chain, Config::instance (), _1), - boost::bind (&Config::signer_chain, Config::instance ()) + boost::bind (&Config::signer_chain, Config::instance ()), + boost::bind (&do_nothing) ); _panel->GetSizer()->Add (_signer); _decryption = new CertificateChainEditor ( - _panel, _("Decrypting DCPs"), _border, + _panel, _("Decrypting KDMs"), _border, boost::bind (&Config::set_decryption_chain, Config::instance (), _1), - boost::bind (&Config::decryption_chain, Config::instance ()) + boost::bind (&Config::decryption_chain, Config::instance ()), + boost::bind (&KeysPage::nag_remake_decryption_chain, this) ); _panel->GetSizer()->Add (_decryption); - _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate...")); + _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\ncertificate...")); _decryption->add_button (_export_decryption_certificate); - _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain...")); + _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\nchain...")); _decryption->add_button (_export_decryption_chain); _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this)); @@ -1174,6 +1321,15 @@ private: _decryption->config_changed (); } + void nag_remake_decryption_chain () + { + NagDialog::maybe_nag ( + _panel, + Config::NAG_REMAKE_DECRYPTION_CHAIN, + _("If you continue with this operation you will no longer be able to use any DKDMs that you have created. Also, any KDMs that have been sent to you will become useless. Proceed with caution!") + ); + } + CertificateChainEditor* _signer; CertificateChainEditor* _decryption; wxButton* _export_decryption_certificate; @@ -1458,6 +1614,71 @@ private: wxButton* _reset_kdm_email; }; +class CoverSheetPage : public StandardPage +{ +public: + + CoverSheetPage (wxSize panel_size, int border) +#ifdef DCPOMATIC_OSX + /* We have to force both width and height of this one */ + : StandardPage (wxSize (480, 128), border) +#else + : StandardPage (panel_size, border) +#endif + {} + + wxString GetName () const + { + return _("Cover Sheet"); + } + +#ifdef DCPOMATIC_OSX + wxBitmap GetLargeIcon () const + { + return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE); + } +#endif + +private: + void setup () + { + _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE); + _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border); + + _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text")); + _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border); + + _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this)); + _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this)); + } + + void config_changed () + { + checked_set (_cover_sheet, Config::instance()->cover_sheet ()); + } + + void cover_sheet_changed () + { + if (_cover_sheet->GetValue().IsEmpty ()) { + /* Sometimes we get sent an erroneous notification that the cover sheet + is empty; I don't know why. + */ + return; + } + Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ())); + } + + void reset_cover_sheet () + { + Config::instance()->reset_cover_sheet (); + checked_set (_cover_sheet, Config::instance()->cover_sheet ()); + } + + wxTextCtrl* _cover_sheet; + wxButton* _reset_cover_sheet; +}; + + /** @class AdvancedPage * @brief Advanced page of the preferences dialog. */ @@ -1706,6 +1927,7 @@ create_config_dialog () e->AddPage (new KeysPage (ps, border)); e->AddPage (new TMSPage (ps, border)); e->AddPage (new KDMEmailPage (ps, border)); + e->AddPage (new CoverSheetPage (ps, border)); e->AddPage (new AdvancedPage (ps, border)); return e; }