X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Fwx%2Fconfig_dialog.cc;h=e0effec53eafb90a25d2ff2e966f9d92f90406d7;hp=b5490f05a663a1b30feb64443df7a57dac2008fc;hb=01e979c79f7d0aa20fac1bb24c699e0636168294;hpb=b8cd038b2f5e6d521b3593c4f6024bf1cd287670 diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index b5490f05a..e0effec53 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2019 Carl Hetherington + Copyright (C) 2012-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -23,6 +23,8 @@ #include "check_box.h" #include "nag_dialog.h" #include "dcpomatic_button.h" +#include "audio_mapping_view.h" +#include #include using std::string; @@ -30,10 +32,14 @@ using std::vector; using std::pair; using std::make_pair; using std::map; +using std::make_shared; using boost::bind; using boost::optional; -using boost::shared_ptr; -using boost::function; +using std::shared_ptr; +using std::function; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif static bool @@ -51,11 +57,19 @@ Page::Page (wxSize panel_size, int border) _config_connection = Config::instance()->Changed.connect (bind (&Page::config_changed_wrapper, this)); } + +wxWindow* +Page::CreateWindow (wxWindow* parent) +{ + return create_window (parent); +} + + wxWindow* Page::create_window (wxWindow* parent) { _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size); - wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + auto s = new wxBoxSizer (wxVERTICAL); _panel->SetSizer (s); setup (); @@ -82,66 +96,49 @@ Page::window_destroyed () } -StockPage::StockPage (Kind kind, wxSize panel_size, int border) - : wxStockPreferencesPage (kind) - , Page (panel_size, border) -{ - -} - -wxWindow* -StockPage::CreateWindow (wxWindow* parent) -{ - return create_window (parent); -} - -StandardPage::StandardPage (wxSize panel_size, int border) +GeneralPage::GeneralPage (wxSize panel_size, int border) : Page (panel_size, border) { } -wxWindow* -StandardPage::CreateWindow (wxWindow* parent) -{ - return create_window (parent); -} -GeneralPage::GeneralPage (wxSize panel_size, int border) - : StockPage (Kind_General, panel_size, border) +wxString +GeneralPage::GetName () const { - + return _("General"); } + void GeneralPage::add_language_controls (wxGridBagSizer* table, int& r) { _set_language = new CheckBox (_panel, _("Set language")); table->Add (_set_language, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); _language = new wxChoice (_panel, wxID_ANY); - vector > languages; - languages.push_back (make_pair ("Čeština", "cs_CZ")); - languages.push_back (make_pair ("汉语/漢語", "zh_CN")); - languages.push_back (make_pair ("Dansk", "da_DK")); - languages.push_back (make_pair ("Deutsch", "de_DE")); - languages.push_back (make_pair ("English", "en_GB")); - languages.push_back (make_pair ("Español", "es_ES")); - languages.push_back (make_pair ("Français", "fr_FR")); - languages.push_back (make_pair ("Italiano", "it_IT")); - languages.push_back (make_pair ("Nederlands", "nl_NL")); - languages.push_back (make_pair ("Русский", "ru_RU")); - languages.push_back (make_pair ("Polski", "pl_PL")); - languages.push_back (make_pair ("Português europeu", "pt_PT")); - languages.push_back (make_pair ("Português do Brasil", "pt_BR")); - languages.push_back (make_pair ("Svenska", "sv_SE")); - languages.push_back (make_pair ("Slovenský jazyk", "sk_SK")); - languages.push_back (make_pair ("Türkçe", "tr_TR")); - languages.push_back (make_pair ("українська мова", "uk_UA")); + vector> languages; + languages.push_back (make_pair("Čeština", "cs_CZ")); + languages.push_back (make_pair("汉语/漢語", "zh_CN")); + languages.push_back (make_pair("Dansk", "da_DK")); + languages.push_back (make_pair("Deutsch", "de_DE")); + languages.push_back (make_pair("English", "en_GB")); + languages.push_back (make_pair("Español", "es_ES")); + languages.push_back (make_pair("Français", "fr_FR")); + languages.push_back (make_pair("Italiano", "it_IT")); + languages.push_back (make_pair("Nederlands", "nl_NL")); + languages.push_back (make_pair("Русский", "ru_RU")); + languages.push_back (make_pair("Polski", "pl_PL")); + languages.push_back (make_pair("Português europeu", "pt_PT")); + languages.push_back (make_pair("Português do Brasil", "pt_BR")); + languages.push_back (make_pair("Svenska", "sv_SE")); + languages.push_back (make_pair("Slovenský jazyk", "sk_SK")); + languages.push_back (make_pair("Türkçe", "tr_TR")); + languages.push_back (make_pair("українська мова", "uk_UA")); checked_set (_language, languages); table->Add (_language, wxGBPosition (r, 1)); ++r; - wxStaticText* restart = add_label_to_sizer ( + auto restart = add_label_to_sizer ( table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2) ); wxFont font = restart->GetFont(); @@ -154,36 +151,6 @@ GeneralPage::add_language_controls (wxGridBagSizer* table, int& r) _language->Bind (wxEVT_CHOICE, bind (&GeneralPage::language_changed, this)); } -void -GeneralPage::add_play_sound_controls (wxGridBagSizer* table, int& r) -{ - _sound = new CheckBox (_panel, _("Play sound via")); - table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _sound_output = new wxChoice (_panel, wxID_ANY); - s->Add (_sound_output, 0); - _sound_output_details = new wxStaticText (_panel, wxID_ANY, wxT("")); - s->Add (_sound_output_details, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, DCPOMATIC_SIZER_X_GAP); - table->Add (s, wxGBPosition(r, 1)); - ++r; - - wxFont font = _sound_output_details->GetFont(); - font.SetStyle (wxFONTSTYLE_ITALIC); - font.SetPointSize (font.GetPointSize() - 1); - _sound_output_details->SetFont (font); - - RtAudio audio (DCPOMATIC_RTAUDIO_API); - 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)); - } - } - - _sound->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::sound_changed, this)); - _sound_output->Bind (wxEVT_CHOICE, bind (&GeneralPage::sound_output_changed, this)); -} - void GeneralPage::add_update_controls (wxGridBagSizer* table, int& r) { @@ -202,7 +169,7 @@ GeneralPage::add_update_controls (wxGridBagSizer* table, int& r) void GeneralPage::config_changed () { - Config* config = Config::instance (); + auto config = Config::instance (); checked_set (_set_language, static_cast(config->language())); @@ -223,8 +190,8 @@ GeneralPage::config_changed () compat_map["cs"] = "cs_CZ"; compat_map["uk"] = "uk_UA"; - string lang = config->language().get_value_or ("en_GB"); - if (compat_map.find (lang) != compat_map.end ()) { + auto lang = config->language().get_value_or("en_GB"); + if (compat_map.find(lang) != compat_map.end ()) { lang = compat_map[lang]; } @@ -233,62 +200,6 @@ GeneralPage::config_changed () checked_set (_check_for_updates, config->check_for_updates ()); checked_set (_check_for_test_updates, config->check_for_test_updates ()); - checked_set (_sound, config->sound ()); - - optional const current_so = get_sound_output (); - optional configured_so; - - if (config->sound_output()) { - configured_so = config->sound_output().get(); - } else { - /* No configured output means we should use the default */ - RtAudio audio (DCPOMATIC_RTAUDIO_API); - try { - configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name; - } catch (RtAudioError& e) { - /* Probably no audio devices at all */ - } - } - - if (configured_so && current_so != configured_so) { - /* Update _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); - break; - } - ++i; - } - } - - RtAudio audio (DCPOMATIC_RTAUDIO_API); - - map apis; - apis[RtAudio::MACOSX_CORE] = _("CoreAudio"); - apis[RtAudio::WINDOWS_ASIO] = _("ASIO"); - apis[RtAudio::WINDOWS_DS] = _("Direct Sound"); - apis[RtAudio::WINDOWS_WASAPI] = _("WASAPI"); - apis[RtAudio::UNIX_JACK] = _("JACK"); - apis[RtAudio::LINUX_ALSA] = _("ALSA"); - apis[RtAudio::LINUX_PULSE] = _("Pulseaudio"); - apis[RtAudio::LINUX_OSS] = _("OSS"); - apis[RtAudio::RTAUDIO_DUMMY] = _("Dummy"); - - int channels = 0; - if (configured_so) { - for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) { - RtAudio::DeviceInfo info = audio.getDeviceInfo(i); - if (info.name == *configured_so && info.outputChannels > 0) { - channels = info.outputChannels; - } - } - } - - _sound_output_details->SetLabel ( - wxString::Format(_("%d channels on %s"), channels, apis[audio.getCurrentApi()]) - ); - setup_sensitivity (); } @@ -297,19 +208,6 @@ GeneralPage::setup_sensitivity () { _language->Enable (_set_language->GetValue ()); _check_for_test_updates->Enable (_check_for_updates->GetValue ()); - _sound_output->Enable (_sound->GetValue ()); -} - -/** @return Currently-selected preview sound output in the dialogue */ -optional -GeneralPage::get_sound_output () -{ - int const sel = _sound_output->GetSelection (); - if (sel == wxNOT_FOUND) { - return optional (); - } - - return wx_to_std (_sound_output->GetString (sel)); } void @@ -346,24 +244,6 @@ GeneralPage::check_for_test_updates_changed () Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ()); } -void -GeneralPage::sound_changed () -{ - Config::instance()->set_sound (_sound->GetValue ()); -} - -void -GeneralPage::sound_output_changed () -{ - RtAudio audio (DCPOMATIC_RTAUDIO_API); - optional const so = get_sound_output(); - if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) { - Config::instance()->unset_sound_output (); - } else { - Config::instance()->set_sound_output (*so); - } -} - CertificateChainEditor::CertificateChainEditor ( wxWindow* parent, wxString title, @@ -377,19 +257,10 @@ CertificateChainEditor::CertificateChainEditor ( , _get (get) , _nag_alter (nag_alter) { - wxFont subheading_font (*wxNORMAL_FONT); - subheading_font.SetWeight (wxFONTWEIGHT_BOLD); - _sizer = new wxBoxSizer (wxVERTICAL); - { - wxStaticText* m = new StaticText (this, title); - m->SetFont (subheading_font); - _sizer->Add (m, 0, wxALL, border); - } - - wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL); - _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border); + auto certificates_sizer = new wxBoxSizer (wxHORIZONTAL); + _sizer->Add (certificates_sizer, 0, wxALL, border); _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL); @@ -417,17 +288,19 @@ CertificateChainEditor::CertificateChainEditor ( certificates_sizer->Add (_certificates, 1, wxEXPAND); { - wxSizer* s = new wxBoxSizer (wxVERTICAL); + auto s = new wxBoxSizer (wxVERTICAL); _add_certificate = new Button (this, _("Add...")); - s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); + s->Add (_add_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP); _remove_certificate = new Button (this, _("Remove")); - s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); - _export_certificate = new Button (this, _("Export")); - s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); + s->Add (_remove_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP); + _export_certificate = new Button (this, _("Export certificate...")); + s->Add (_export_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP); + _export_chain = new Button (this, _("Export chain...")); + s->Add (_export_chain, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP); certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP); } - wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); _sizer->Add (table, 1, wxALL | wxEXPAND, border); int r = 0; @@ -446,8 +319,6 @@ CertificateChainEditor::CertificateChainEditor ( _button_sizer = new wxBoxSizer (wxHORIZONTAL); _remake_certificates = new Button (this, _("Re-make certificates and key...")); _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border); - _export_chain = new Button (this, _("Export chain...")); - _button_sizer->Add (_export_chain, 1, wxRIGHT, border); table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4)); ++r; @@ -468,7 +339,7 @@ CertificateChainEditor::CertificateChainEditor ( _import_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::import_private_key, this)); _export_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_private_key, this)); - wxSizer* buttons = CreateSeparatedButtonSizer (wxCLOSE); + auto buttons = CreateSeparatedButtonSizer (wxCLOSE); if (buttons) { _sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); } @@ -490,7 +361,7 @@ CertificateChainEditor::add_button (wxWindow* button) void CertificateChainEditor::add_certificate () { - wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File")); + auto d = new wxFileDialog (this, _("Select Certificate File")); if (d->ShowModal() == wxID_OK) { try { @@ -511,7 +382,7 @@ CertificateChainEditor::add_certificate () "Only the first certificate will be used.") ); } - shared_ptr chain(new dcp::CertificateChain(*_get().get())); + auto chain = make_shared(*_get().get()); chain->add (c); if (!chain->chain_valid ()) { error_dialog ( @@ -548,11 +419,12 @@ CertificateChainEditor::remove_certificate () } _certificates->DeleteItem (i); - shared_ptr chain(new dcp::CertificateChain(*_get().get())); + auto chain = make_shared(*_get().get()); chain->remove (i); _set (chain); update_sensitivity (); + update_certificate_list (); } void @@ -563,22 +435,35 @@ CertificateChainEditor::export_certificate () return; } - wxFileDialog* d = new wxFileDialog ( - this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"), + auto all = _get()->root_to_leaf(); + + wxString default_name; + if (i == 0) { + default_name = "root.pem"; + } else if (i == static_cast(all.size() - 1)) { + default_name = "leaf.pem"; + } else { + default_name = "intermediate.pem"; + } + + auto d = new wxFileDialog( + this, _("Select Certificate File"), wxEmptyString, default_name, wxT ("PEM files (*.pem)|*.pem"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - dcp::CertificateChain::List all = _get()->root_to_leaf (); - dcp::CertificateChain::List::iterator j = all.begin (); + auto j = all.begin (); for (int k = 0; k < i; ++k) { ++j; } if (d->ShowModal () == wxID_OK) { boost::filesystem::path path (wx_to_std(d->GetPath())); - FILE* f = fopen_boost (path, "w"); + if (path.extension() != ".pem") { + path += ".pem"; + } + auto f = fopen_boost (path, "w"); if (!f) { - throw OpenFileError (path, errno, false); + throw OpenFileError (path, errno, OpenFileError::WRITE); } string const s = j->certificate (true); @@ -591,19 +476,22 @@ CertificateChainEditor::export_certificate () void CertificateChainEditor::export_chain () { - wxFileDialog* d = new wxFileDialog ( - this, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT("PEM files (*.pem)|*.pem"), + auto d = new wxFileDialog ( + this, _("Select Chain File"), wxEmptyString, wxT("certificate_chain.pem"), wxT("PEM files (*.pem)|*.pem"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if (d->ShowModal () == wxID_OK) { boost::filesystem::path path (wx_to_std(d->GetPath())); - FILE* f = fopen_boost (path, "w"); + if (path.extension() != ".pem") { + path += ".pem"; + } + auto f = fopen_boost (path, "w"); if (!f) { - throw OpenFileError (path, errno, false); + throw OpenFileError (path, errno, OpenFileError::WRITE); } - string const s = _get()->chain(); + auto const s = _get()->chain(); checked_fwrite (s.c_str(), s.length(), f, path); fclose (f); } @@ -616,8 +504,8 @@ CertificateChainEditor::update_certificate_list () { _certificates->DeleteAllItems (); size_t n = 0; - dcp::CertificateChain::List certs = _get()->root_to_leaf (); - BOOST_FOREACH (dcp::Certificate const & i, certs) { + auto certs = _get()->root_to_leaf(); + for (auto const& i: certs) { wxListItem item; item.SetId (n); _certificates->InsertItem (item); @@ -648,7 +536,7 @@ CertificateChainEditor::update_certificate_list () void CertificateChainEditor::remake_certificates () { - shared_ptr chain = _get(); + auto chain = _get(); string subject_organization_name; string subject_organizational_unit_name; @@ -656,7 +544,7 @@ CertificateChainEditor::remake_certificates () string intermediate_common_name; string leaf_common_name; - dcp::CertificateChain::List all = chain->root_to_leaf (); + auto all = chain->root_to_leaf (); if (all.size() >= 1) { /* Have a root */ @@ -682,7 +570,7 @@ CertificateChainEditor::remake_certificates () return; } - MakeChainDialog* d = new MakeChainDialog ( + auto d = new MakeChainDialog ( this, subject_organization_name, subject_organizational_unit_name, @@ -693,15 +581,13 @@ CertificateChainEditor::remake_certificates () if (d->ShowModal () == wxID_OK) { _set ( - shared_ptr ( - new dcp::CertificateChain ( - openssl_path (), - d->organisation (), - d->organisational_unit (), - d->root_common_name (), - d->intermediate_common_name (), - d->leaf_common_name () - ) + make_shared ( + openssl_path (), + d->organisation (), + d->organisational_unit (), + d->root_common_name (), + d->intermediate_common_name (), + d->leaf_common_name () ) ); @@ -716,8 +602,8 @@ void CertificateChainEditor::update_sensitivity () { /* 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); + _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); } void @@ -730,7 +616,7 @@ CertificateChainEditor::update_private_key () void CertificateChainEditor::import_private_key () { - wxFileDialog* d = new wxFileDialog (this, _("Select Key File")); + auto d = new wxFileDialog (this, _("Select Key File")); if (d->ShowModal() == wxID_OK) { try { @@ -743,11 +629,11 @@ CertificateChainEditor::import_private_key () return; } - shared_ptr chain(new dcp::CertificateChain(*_get().get())); + auto chain = make_shared(*_get().get()); chain->set_key (dcp::file_to_string (p)); _set (chain); update_private_key (); - } catch (dcp::MiscError& e) { + } catch (std::exception& e) { error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what())); } } @@ -760,24 +646,27 @@ CertificateChainEditor::import_private_key () void CertificateChainEditor::export_private_key () { - optional key = _get()->key(); + auto key = _get()->key(); if (!key) { return; } - wxFileDialog* d = new wxFileDialog ( - this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"), + auto d = new wxFileDialog ( + this, _("Select Key File"), wxEmptyString, wxT("private_key.pem"), wxT("PEM files (*.pem)|*.pem"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if (d->ShowModal () == wxID_OK) { boost::filesystem::path path (wx_to_std(d->GetPath())); - FILE* f = fopen_boost (path, "w"); + if (path.extension() != ".pem") { + path += ".pem"; + } + auto f = fopen_boost (path, "w"); if (!f) { - throw OpenFileError (path, errno, false); + throw OpenFileError (path, errno, OpenFileError::WRITE); } - string const s = _get()->key().get (); + auto const s = _get()->key().get (); checked_fwrite (s.c_str(), s.length(), f, path); fclose (f); } @@ -796,22 +685,26 @@ KeysPage::setup () wxFont subheading_font (*wxNORMAL_FONT); subheading_font.SetWeight (wxFONTWEIGHT_BOLD); - wxSizer* sizer = _panel->GetSizer(); + auto sizer = _panel->GetSizer(); { - wxStaticText* m = new StaticText (_panel, _("Decrypting KDMs")); + auto m = new StaticText (_panel, _("Decrypting KDMs")); m->SetFont (subheading_font); - sizer->Add (m, 0, wxALL, _border); + sizer->Add (m, 0, wxALL | wxEXPAND, _border); } - wxButton* export_decryption_certificate = new Button (_panel, _("Export KDM decryption certificate...")); - sizer->Add (export_decryption_certificate, 0, wxLEFT, _border); - wxButton* export_settings = new Button (_panel, _("Export all KDM decryption settings...")); - sizer->Add (export_settings, 0, wxLEFT, _border); - wxButton* import_settings = new Button (_panel, _("Import all KDM decryption settings...")); - sizer->Add (import_settings, 0, wxLEFT, _border); - wxButton* decryption_advanced = new Button (_panel, _("Advanced...")); - sizer->Add (decryption_advanced, 0, wxALL, _border); + auto buttons = new wxBoxSizer (wxVERTICAL); + + auto export_decryption_certificate = new Button (_panel, _("Export KDM decryption leaf certificate...")); + buttons->Add (export_decryption_certificate, 0, wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); + auto export_settings = new Button (_panel, _("Export all KDM decryption settings...")); + buttons->Add (export_settings, 0, wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); + auto import_settings = new Button (_panel, _("Import all KDM decryption settings...")); + buttons->Add (import_settings, 0, wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); + auto decryption_advanced = new Button (_panel, _("Advanced...")); + buttons->Add (decryption_advanced, 0); + + sizer->Add (buttons, 0, wxLEFT, _border); export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this)); export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this)); @@ -819,24 +712,24 @@ KeysPage::setup () decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this)); { - wxStaticText* m = new StaticText (_panel, _("Signing DCPs and KDMs")); + auto m = new StaticText (_panel, _("Signing DCPs and KDMs")); m->SetFont (subheading_font); - sizer->Add (m, 0, wxALL, _border); + sizer->Add (m, 0, wxALL | wxEXPAND, _border); } - wxButton* signing_advanced = new Button (_panel, _("Advanced...")); - sizer->Add (signing_advanced, 0, wxLEFT, _border); + auto signing_advanced = new Button (_panel, _("Advanced...")); + sizer->Add (signing_advanced, 0, wxLEFT | wxBOTTOM, _border); signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this)); } void KeysPage::decryption_advanced () { - CertificateChainEditor* c = new CertificateChainEditor ( + auto c = new CertificateChainEditor ( _panel, _("Decrypting KDMs"), _border, - bind (&Config::set_decryption_chain, Config::instance (), _1), - bind (&Config::decryption_chain, Config::instance ()), - bind (&KeysPage::nag_alter_decryption_chain, this) + bind(&Config::set_decryption_chain, Config::instance(), _1), + bind(&Config::decryption_chain, Config::instance()), + bind(&KeysPage::nag_alter_decryption_chain, this) ); c->ShowModal(); @@ -845,11 +738,11 @@ KeysPage::decryption_advanced () void KeysPage::signing_advanced () { - CertificateChainEditor* c = new CertificateChainEditor ( + auto c = new CertificateChainEditor ( _panel, _("Signing DCPs and KDMs"), _border, - bind (&Config::set_signer_chain, Config::instance (), _1), - bind (&Config::signer_chain, Config::instance ()), - bind (&do_nothing) + bind(&Config::set_signer_chain, Config::instance(), _1), + bind(&Config::signer_chain, Config::instance()), + bind(&do_nothing) ); c->ShowModal(); @@ -858,19 +751,19 @@ KeysPage::signing_advanced () void KeysPage::export_decryption_chain_and_key () { - wxFileDialog* d = new wxFileDialog ( + auto d = new wxFileDialog ( _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if (d->ShowModal () == wxID_OK) { boost::filesystem::path path (wx_to_std(d->GetPath())); - FILE* f = fopen_boost (path, "w"); + auto f = fopen_boost (path, "w"); if (!f) { - throw OpenFileError (path, errno, false); + throw OpenFileError (path, errno, OpenFileError::WRITE); } - string const chain = Config::instance()->decryption_chain()->chain(); + auto const chain = Config::instance()->decryption_chain()->chain(); checked_fwrite (chain.c_str(), chain.length(), f, path); optional const key = Config::instance()->decryption_chain()->key(); DCPOMATIC_ASSERT (key); @@ -893,16 +786,16 @@ KeysPage::import_decryption_chain_and_key () return; } - wxFileDialog* d = new wxFileDialog ( + auto d = new wxFileDialog ( _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom") ); if (d->ShowModal () == wxID_OK) { - shared_ptr new_chain(new dcp::CertificateChain()); + auto new_chain = make_shared(); FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r"); if (!f) { - throw OpenFileError (wx_to_std (d->GetPath ()), errno, false); + throw OpenFileError (wx_to_std (d->GetPath ()), errno, OpenFileError::WRITE); } string current; @@ -945,22 +838,311 @@ KeysPage::nag_alter_decryption_chain () void KeysPage::export_decryption_certificate () { - wxFileDialog* d = new wxFileDialog ( - _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"), + auto config = Config::instance(); + wxString default_name = "dcpomatic"; + if (!config->dcp_creator().empty()) { + default_name += "_" + std_to_wx(careful_string_filter(config->dcp_creator())); + } + if (!config->dcp_issuer().empty()) { + default_name += "_" + std_to_wx(careful_string_filter(config->dcp_issuer())); + } + default_name += wxT("_kdm_decryption_cert.pem"); + + auto d = new wxFileDialog ( + _panel, _("Select Certificate File"), wxEmptyString, default_name, wxT("PEM files (*.pem)|*.pem"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if (d->ShowModal () == wxID_OK) { boost::filesystem::path path (wx_to_std(d->GetPath())); - FILE* f = fopen_boost (path, "w"); + if (path.extension() != ".pem") { + path += ".pem"; + } + auto f = fopen_boost (path, "w"); if (!f) { - throw OpenFileError (path, errno, false); + throw OpenFileError (path, errno, OpenFileError::WRITE); } - string const s = Config::instance()->decryption_chain()->leaf().certificate (true); + auto const s = Config::instance()->decryption_chain()->leaf().certificate (true); checked_fwrite (s.c_str(), s.length(), f, path); fclose (f); } d->Destroy (); } + +wxString +SoundPage::GetName () const +{ + return _("Sound"); +} + +void +SoundPage::setup () +{ + auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border); + + int r = 0; + + _sound = new CheckBox (_panel, _("Play sound via")); + table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _sound_output = new wxChoice (_panel, wxID_ANY); + s->Add (_sound_output, 0); + _sound_output_details = new wxStaticText (_panel, wxID_ANY, wxT("")); + s->Add (_sound_output_details, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, DCPOMATIC_SIZER_X_GAP); + table->Add (s, wxGBPosition(r, 1)); + ++r; + + add_label_to_sizer (table, _panel, _("Mapping"), true, wxGBPosition(r, 0)); + _map = new AudioMappingView (_panel, _("DCP"), _("DCP"), _("Output"), _("output")); + _map->SetSize (-1, 600); + table->Add (_map, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND); + ++r; + + _reset_to_default = new Button (_panel, _("Reset to default")); + table->Add (_reset_to_default, wxGBPosition(r, 1)); + ++r; + + wxFont font = _sound_output_details->GetFont(); + font.SetStyle (wxFONTSTYLE_ITALIC); + font.SetPointSize (font.GetPointSize() - 1); + _sound_output_details->SetFont (font); + + RtAudio audio (DCPOMATIC_RTAUDIO_API); + for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) { + try { + auto dev = audio.getDeviceInfo (i); + if (dev.probed && dev.outputChannels > 0) { + _sound_output->Append (std_to_wx (dev.name)); + } + } catch (RtAudioError&) { + /* Something went wrong so let's just ignore that device */ + } + } + + _sound->Bind (wxEVT_CHECKBOX, bind(&SoundPage::sound_changed, this)); + _sound_output->Bind (wxEVT_CHOICE, bind(&SoundPage::sound_output_changed, this)); + _map->Changed.connect (bind(&SoundPage::map_changed, this, _1)); + _reset_to_default->Bind (wxEVT_BUTTON, bind(&SoundPage::reset_to_default, this)); +} + +void +SoundPage::reset_to_default () +{ + Config::instance()->set_audio_mapping_to_default (); +} + +void +SoundPage::map_changed (AudioMapping m) +{ + Config::instance()->set_audio_mapping (m); +} + +void +SoundPage::sound_changed () +{ + Config::instance()->set_sound (_sound->GetValue ()); +} + +void +SoundPage::sound_output_changed () +{ + RtAudio audio (DCPOMATIC_RTAUDIO_API); + auto const so = get_sound_output(); + string default_device; + try { + default_device = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name; + } catch (RtAudioError&) { + /* Never mind */ + } + if (!so || *so == default_device) { + Config::instance()->unset_sound_output (); + } else { + Config::instance()->set_sound_output (*so); + } +} + +void +SoundPage::config_changed () +{ + auto config = Config::instance (); + + checked_set (_sound, config->sound ()); + + auto const current_so = get_sound_output (); + optional configured_so; + + if (config->sound_output()) { + configured_so = config->sound_output().get(); + } else { + /* No configured output means we should use the default */ + RtAudio audio (DCPOMATIC_RTAUDIO_API); + try { + configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name; + } catch (RtAudioError&) { + /* Probably no audio devices at all */ + } + } + + if (configured_so && current_so != configured_so) { + /* Update _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); + break; + } + ++i; + } + } + + RtAudio audio (DCPOMATIC_RTAUDIO_API); + + map apis; + apis[RtAudio::MACOSX_CORE] = _("CoreAudio"); + apis[RtAudio::WINDOWS_ASIO] = _("ASIO"); + apis[RtAudio::WINDOWS_DS] = _("Direct Sound"); + apis[RtAudio::WINDOWS_WASAPI] = _("WASAPI"); + apis[RtAudio::UNIX_JACK] = _("JACK"); + apis[RtAudio::LINUX_ALSA] = _("ALSA"); + apis[RtAudio::LINUX_PULSE] = _("PulseAudio"); + apis[RtAudio::LINUX_OSS] = _("OSS"); + apis[RtAudio::RTAUDIO_DUMMY] = _("Dummy"); + + int channels = 0; + if (configured_so) { + for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) { + try { + auto info = audio.getDeviceInfo(i); + if (info.name == *configured_so && info.outputChannels > 0) { + channels = info.outputChannels; + } + } catch (RtAudioError&) { + /* Never mind */ + } + } + } + + _sound_output_details->SetLabel ( + wxString::Format(_("%d channels on %s"), channels, apis[audio.getCurrentApi()]) + ); + + _map->set (Config::instance()->audio_mapping(channels)); + + vector input; + for (int i = 0; i < MAX_DCP_AUDIO_CHANNELS; ++i) { + input.push_back (NamedChannel(short_audio_channel_name(i), i)); + } + _map->set_input_channels (input); + + vector output; + for (int i = 0; i < channels; ++i) { + output.push_back (NamedChannel(dcp::raw_convert(i), i)); + } + _map->set_output_channels (output); + + setup_sensitivity (); +} + +void +SoundPage::setup_sensitivity () +{ + _sound_output->Enable (_sound->GetValue()); +} + +/** @return Currently-selected preview sound output in the dialogue */ +optional +SoundPage::get_sound_output () +{ + int const sel = _sound_output->GetSelection (); + if (sel == wxNOT_FOUND) { + return optional (); + } + + return wx_to_std (_sound_output->GetString (sel)); +} + + +LocationsPage::LocationsPage (wxSize panel_size, int border) + : Page (panel_size, border) +{ + +} + +wxString +LocationsPage::GetName () const +{ + return _("Locations"); +} + +#ifdef DCPOMATIC_OSX +wxBitmap +LocationsPage::GetLargeIcon () const +{ + return wxBitmap(bitmap_path("locations"), wxBITMAP_TYPE_PNG); +} +#endif + +void +LocationsPage::setup () +{ + int r = 0; + + auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border); + + add_label_to_sizer (table, _panel, _("Content directory"), true, wxGBPosition (r, 0)); + _content_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1)); + table->Add (_content_directory, wxGBPosition (r, 1)); + ++r; + + add_label_to_sizer (table, _panel, _("Playlist directory"), true, wxGBPosition (r, 0)); + _playlist_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1)); + table->Add (_playlist_directory, wxGBPosition (r, 1)); + ++r; + + add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0)); + _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1)); + table->Add (_kdm_directory, wxGBPosition (r, 1)); + ++r; + + _content_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::content_directory_changed, this)); + _playlist_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::playlist_directory_changed, this)); + _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this)); +} + +void +LocationsPage::config_changed () +{ + auto config = Config::instance (); + + if (config->player_content_directory()) { + checked_set (_content_directory, *config->player_content_directory()); + } + if (config->player_playlist_directory()) { + checked_set (_playlist_directory, *config->player_playlist_directory()); + } + if (config->player_kdm_directory()) { + checked_set (_kdm_directory, *config->player_kdm_directory()); + } +} + +void +LocationsPage::content_directory_changed () +{ + Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath())); +} + +void +LocationsPage::playlist_directory_changed () +{ + Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath())); +} + +void +LocationsPage::kdm_directory_changed () +{ + Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath())); +}