Rename SafeStringStream -> locked_stringstream. Bump deps for removal of stringstream.
[dcpomatic.git] / src / tools / dcpomatic.cc
index acdae692dad4a61b7fe0286c24bf5fec920c9741..ac5b8a5448c15c91dd1b19264f5551f805893d92 100644 (file)
@@ -58,6 +58,7 @@
 #include "lib/compose.hpp"
 #include "lib/cinema_kdms.h"
 #include "lib/dcpomatic_socket.h"
+#include "lib/hints.h"
 #include <dcp/exceptions.h>
 #include <wx/generic/aboutdlgg.h>
 #include <wx/stdpaths.h>
@@ -92,6 +93,7 @@ using std::list;
 using std::exception;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
+using boost::optional;
 
 class FilmChangedDialog : public boost::noncopyable
 {
@@ -104,7 +106,11 @@ public:
                        /// TRANSLATORS: this is the heading for a dialog box, which tells the user that the current
                        /// project (Film) has been changed since it was last saved.
                        _("Film changed"),
-                       wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION
+                       wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_QUESTION
+                       );
+
+               _dialog->SetYesNoCancelLabels (
+                       _("Save film and close"), _("Close without saving film"), _("Don't close")
                        );
        }
 
@@ -279,8 +285,6 @@ public:
        void load_film (boost::filesystem::path file)
        try
        {
-               maybe_save_then_delete_film ();
-
                shared_ptr<Film> film (new Film (file));
                list<string> const notes = film->read_metadata ();
 
@@ -355,8 +359,9 @@ private:
                                return;
                        }
 
-                       maybe_save_then_delete_film ();
-                       new_film (d->get_path ());
+                       if (maybe_save_then_delete_film ()) {
+                               new_film (d->get_path ());
+                       }
                }
 
                d->Destroy ();
@@ -381,7 +386,7 @@ private:
                        }
                }
 
-               if (r == wxID_OK) {
+               if (r == wxID_OK && maybe_save_then_delete_film()) {
                        load_film (wx_to_std (c->GetPath ()));
                }
 
@@ -397,7 +402,7 @@ private:
        {
                vector<boost::filesystem::path> history = Config::instance()->history ();
                int n = event.GetId() - ID_file_history;
-               if (n >= 0 && n < static_cast<int> (history.size ())) {
+               if (n >= 0 && n < static_cast<int> (history.size ()) && maybe_save_then_delete_film()) {
                        load_film (history[n]);
                }
        }
@@ -451,6 +456,15 @@ private:
                        }
                }
 
+               if (!get_hints(_film).empty() && Config::instance()->show_hints_before_make_dcp()) {
+                       HintsDialog* hints = new HintsDialog (this, _film, false);
+                       int const r = hints->ShowModal();
+                       hints->Destroy ();
+                       if (r == wxID_CANCEL) {
+                               return;
+                       }
+               }
+
                try {
                        /* It seems to make sense to auto-save metadata here, since the make DCP may last
                           a long time, and crashes/power failures are moderately likely.
@@ -513,6 +527,15 @@ private:
                        return;
                }
 
+               if (!get_hints(_film).empty() && Config::instance()->show_hints_before_make_dcp()) {
+                       HintsDialog* hints = new HintsDialog (this, _film, false);
+                       int const r = hints->ShowModal();
+                       hints->Destroy ();
+                       if (r == wxID_CANCEL) {
+                               return;
+                       }
+               }
+
                _film->write_metadata ();
 
                /* i = 0; try to connect via socket
@@ -560,20 +583,16 @@ private:
                        return;
                }
 
+               optional<dcp::EncryptedKDM> kdm;
                try {
-                       vector<dcp::EncryptedKDM> dkdms = Config::instance()->dkdms ();
-                       dkdms.push_back (
-                               _film->make_kdm (
-                                       Config::instance()->decryption_chain()->leaf(),
-                                       vector<dcp::Certificate> (),
-                                       d->cpl (),
-                                       dcp::LocalTime ("2012-01-01T01:00:00+00:00"),
-                                       dcp::LocalTime ("2112-01-01T01:00:00+00:00"),
-                                       dcp::MODIFIED_TRANSITIONAL_1
-                                       )
+                       kdm = _film->make_kdm (
+                               Config::instance()->decryption_chain()->leaf(),
+                               vector<dcp::Certificate> (),
+                               d->cpl (),
+                               dcp::LocalTime ("2012-01-01T01:00:00+00:00"),
+                               dcp::LocalTime ("2112-01-01T01:00:00+00:00"),
+                               dcp::MODIFIED_TRANSITIONAL_1
                                );
-
-                       Config::instance()->set_dkdms (dkdms);
                } catch (dcp::NotEncryptedError& e) {
                        error_dialog (this, _("CPL's content is not encrypted."));
                } catch (exception& e) {
@@ -582,6 +601,17 @@ private:
                        error_dialog (this, _("An unknown exception occurred."));
                }
 
+               if (kdm) {
+                       if (d->internal ()) {
+                               vector<dcp::EncryptedKDM> dkdms = Config::instance()->dkdms ();
+                               dkdms.push_back (kdm.get());
+                               Config::instance()->set_dkdms (dkdms);
+                       } else {
+                               boost::filesystem::path path = d->directory() / (_film->dcp_name(false) + "_DKDM.xml");
+                               kdm->as_xml (path);
+                       }
+               }
+
                d->Destroy ();
        }
 
@@ -652,7 +682,7 @@ private:
        void tools_hints ()
        {
                if (!_hints_dialog) {
-                       _hints_dialog = new HintsDialog (this, _film);
+                       _hints_dialog = new HintsDialog (this, _film, true);
                }
 
                _hints_dialog->Show ();
@@ -716,21 +746,9 @@ private:
 
                if (_film && _film->dirty ()) {
 
-                       wxMessageDialog* dialog = new wxMessageDialog (
-                               0,
-                               wxString::Format (_("Save changes to film \"%s\" before closing?"), std_to_wx (_film->name()).data()),
-                               /// TRANSLATORS: this is the heading for a dialog box, which tells the user that the current
-                               /// project (Film) has been changed since it was last saved.
-                               _("Film changed"),
-                               wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_QUESTION
-                               );
-
-                       dialog->SetYesNoCancelLabels (
-                               _("Save film and close"), _("Close without saving film"), _("Don't close")
-                               );
-
-                       int const r = dialog->ShowModal ();
-                       dialog->Destroy ();
+                       FilmChangedDialog* dialog = new FilmChangedDialog (_film->name ());
+                       int const r = dialog->run ();
+                       delete dialog;
 
                        switch (r) {
                        case wxID_NO:
@@ -791,10 +809,13 @@ private:
                }
        }
 
-       void maybe_save_then_delete_film ()
+       /** @return true if the operation that called this method
+        *  should continue, false to abort it.
+        */
+       bool maybe_save_then_delete_film ()
        {
                if (!_film) {
-                       return;
+                       return true;
                }
 
                if (_film->dirty ()) {
@@ -805,10 +826,13 @@ private:
                        case wxID_YES:
                                _film->write_metadata ();
                                break;
+                       case wxID_CANCEL:
+                               return false;
                        }
                }
 
                _film.reset ();
+               return true;
        }
 
        void add_item (wxMenu* menu, wxString text, int id, int sens)
@@ -903,7 +927,7 @@ private:
                }
 
                for (size_t i = 0; i < history.size(); ++i) {
-                       SafeStringStream s;
+                       locked_stringstream s;
                        if (i < 9) {
                                s << "&" << (i + 1) << " ";
                        }
@@ -982,6 +1006,8 @@ private:
        {
                wxInitAllImageHandlers ();
 
+               Config::FailedToLoad.connect (boost::bind (&App::config_failed_to_load, this));
+
                wxSplashScreen* splash = 0;
                try {
                        if (!Config::have_existing ("config.xml")) {
@@ -1151,6 +1177,11 @@ private:
                }
        }
 
+       void config_failed_to_load ()
+       {
+               message_dialog (_frame, _("The existing configuration failed to load.  Default values will be used instead.  These may take a short time to create."));
+       }
+
        DOMFrame* _frame;
        shared_ptr<wxTimer> _timer;
        string _film_to_load;