Don't set up Writer etc. until the job is run. This means that
[dcpomatic.git] / src / wx / config_dialog.cc
index 49a8a6849a0f1dd59d3dff56160e227c7ae31154..233766cbaddd27395ea77033f5c872441a01fb3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
-    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 
     This file is part of DCP-o-matic.
 
@@ -33,6 +33,7 @@
 #include "make_chain_dialog.h"
 #include "email_dialog.h"
 #include "name_format_editor.h"
 #include "make_chain_dialog.h"
 #include "email_dialog.h"
 #include "name_format_editor.h"
+#include "nag_dialog.h"
 #include "lib/config.h"
 #include "lib/ratio.h"
 #include "lib/filter.h"
 #include "lib/config.h"
 #include "lib/ratio.h"
 #include "lib/filter.h"
@@ -66,6 +67,13 @@ using boost::function;
 using boost::optional;
 using dcp::locale_convert;
 
 using boost::optional;
 using dcp::locale_convert;
 
+static
+void
+do_nothing ()
+{
+
+}
+
 class Page
 {
 public:
 class Page
 {
 public:
@@ -205,7 +213,7 @@ private:
                ++r;
 
                add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
                ++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;
 
                table->Add (_cinemas_file, wxGBPosition (r, 1));
                ++r;
 
@@ -321,21 +329,25 @@ private:
                checked_set (_preview_sound, config->preview_sound());
 
                 optional<string> const current_so = get_preview_sound_output ();
                checked_set (_preview_sound, config->preview_sound());
 
                 optional<string> const current_so = get_preview_sound_output ();
-                string configured_so;
+                optional<string> configured_so;
 
                 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);
 
                 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) {
+                if (configured_so && current_so != configured_so) {
                         /* Update _preview_sound_output with the configured value */
                         unsigned int i = 0;
                         while (i < _preview_sound_output->GetCount()) {
                         /* Update _preview_sound_output with the configured value */
                         unsigned int i = 0;
                         while (i < _preview_sound_output->GetCount()) {
-                                if (_preview_sound_output->GetString(i) == std_to_wx(configured_so)) {
+                                if (_preview_sound_output->GetString(i) == std_to_wx(*configured_so)) {
                                         _preview_sound_output->SetSelection (i);
                                         break;
                                 }
                                         _preview_sound_output->SetSelection (i);
                                         break;
                                 }
@@ -515,6 +527,10 @@ private:
                _container = new wxChoice (_panel, wxID_ANY);
                table->Add (_container);
 
                _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);
                add_label_to_sizer (table, _panel, _("Default content type"), true);
                _dcp_content_type = new wxChoice (_panel, wxID_ANY);
                table->Add (_dcp_content_type);
@@ -561,16 +577,22 @@ private:
 
                _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
 
 
                _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
 
-               vector<Ratio const *> 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));
 
                }
 
                _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
 
-               vector<DCPContentType const *> 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);
                }
 
                setup_audio_channels_choice (_dcp_audio_channels, 2);
@@ -593,13 +615,24 @@ private:
        {
                Config* config = Config::instance ();
 
        {
                Config* config = Config::instance ();
 
+               vector<Ratio const *> containers = Ratio::containers ();
+               for (size_t i = 0; i < containers.size(); ++i) {
+                       if (containers[i] == config->default_container ()) {
+                               _container->SetSelection (i);
+                       }
+               }
+
                vector<Ratio const *> ratios = Ratio::all ();
                for (size_t i = 0; i < ratios.size(); ++i) {
                vector<Ratio const *> 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<DCPContentType const *> const ct = DCPContentType::all ();
                for (size_t i = 0; i < ct.size(); ++i) {
                        if (ct[i] == config->default_dcp_content_type ()) {
                vector<DCPContentType const *> const ct = DCPContentType::all ();
                for (size_t i = 0; i < ct.size(); ++i) {
                        if (ct[i] == config->default_dcp_content_type ()) {
@@ -662,10 +695,21 @@ private:
 
        void container_changed ()
        {
 
        void container_changed ()
        {
-               vector<Ratio const *> ratio = Ratio::all ();
+               vector<Ratio const *> ratio = Ratio::containers ();
                Config::instance()->set_default_container (ratio[_container->GetSelection()]);
        }
 
                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 const *> ratio = Ratio::all ();
+                       Config::instance()->set_default_scale_to (ratio[s - 1]);
+               }
+       }
+
        void dcp_content_type_changed ()
        {
                vector<DCPContentType const *> ct = DCPContentType::all ();
        void dcp_content_type_changed ()
        {
                vector<DCPContentType const *> ct = DCPContentType::all ();
@@ -689,6 +733,7 @@ private:
        wxDirPickerCtrl* _kdm_directory;
 #endif
        wxChoice* _container;
        wxDirPickerCtrl* _kdm_directory;
 #endif
        wxChoice* _container;
+       wxChoice* _scale_to;
        wxChoice* _dcp_content_type;
        wxChoice* _dcp_audio_channels;
        wxChoice* _standard;
        wxChoice* _dcp_content_type;
        wxChoice* _dcp_audio_channels;
        wxChoice* _standard;
@@ -762,11 +807,13 @@ public:
                wxString title,
                int border,
                function<void (shared_ptr<dcp::CertificateChain>)> set,
                wxString title,
                int border,
                function<void (shared_ptr<dcp::CertificateChain>)> set,
-               function<shared_ptr<const dcp::CertificateChain> (void)> get
+               function<shared_ptr<const dcp::CertificateChain> (void)> get,
+               function<void (void)> nag_remake
                )
                : wxPanel (parent)
                , _set (set)
                , _get (get)
                )
                : wxPanel (parent)
                , _set (set)
                , _get (get)
+               , _nag_remake (nag_remake)
        {
                wxFont subheading_font (*wxNORMAL_FONT);
                subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
        {
                wxFont subheading_font (*wxNORMAL_FONT);
                subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
@@ -840,6 +887,13 @@ public:
                table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
                ++r;
 
                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));
                _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));
@@ -875,7 +929,15 @@ private:
                if (d->ShowModal() == wxID_OK) {
                        try {
                                dcp::Certificate c;
                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,
                                if (!extra.empty ()) {
                                        message_dialog (
                                                this,
@@ -884,8 +946,17 @@ private:
                                                );
                                }
                                _chain->add (c);
                                                );
                                }
                                _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 ()));
                        }
                        } catch (dcp::MiscError& e) {
                                error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
                        }
@@ -962,6 +1033,16 @@ private:
 
                        ++n;
                }
 
                        ++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 ()
        }
 
        void remake_certificates ()
@@ -995,6 +1076,8 @@ private:
                        intermediate_common_name = i->subject_common_name ();
                }
 
                        intermediate_common_name = i->subject_common_name ();
                }
 
+               _nag_remake ();
+
                MakeChainDialog* d = new MakeChainDialog (
                        this,
                        subject_organization_name,
                MakeChainDialog* d = new MakeChainDialog (
                        this,
                        subject_organization_name,
@@ -1026,7 +1109,8 @@ private:
 
        void update_sensitivity ()
        {
 
        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);
        }
 
                _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
        }
 
@@ -1097,11 +1181,13 @@ private:
        wxStaticText* _private_key;
        wxButton* _load_private_key;
        wxButton* _export_private_key;
        wxStaticText* _private_key;
        wxButton* _load_private_key;
        wxButton* _export_private_key;
+       wxStaticText* _private_key_bad;
        wxSizer* _sizer;
        wxBoxSizer* _button_sizer;
        shared_ptr<dcp::CertificateChain> _chain;
        boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
        boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
        wxSizer* _sizer;
        wxBoxSizer* _button_sizer;
        shared_ptr<dcp::CertificateChain> _chain;
        boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
        boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
+       boost::function<void (void)> _nag_remake;
 };
 
 class KeysPage : public StandardPage
 };
 
 class KeysPage : public StandardPage
@@ -1130,22 +1216,24 @@ private:
                _signer = new CertificateChainEditor (
                        _panel, _("Signing DCPs and KDMs"), _border,
                        boost::bind (&Config::set_signer_chain, Config::instance (), _1),
                _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->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::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);
 
                        );
 
                _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);
                _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));
                _decryption->add_button (_export_decryption_chain);
 
                _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
@@ -1198,6 +1286,15 @@ private:
                _decryption->config_changed ();
        }
 
                _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;
        CertificateChainEditor* _signer;
        CertificateChainEditor* _decryption;
        wxButton* _export_decryption_certificate;