Use test_suite log level with --debug so we can see when tests take
[dcpomatic.git] / src / tools / dcpomatic_disk.cc
index baccdbce3c9f3fd5c94b17b40e67ff23d8d56f5d..b23f09d85ac9223f27e390987888c4ac7ea8b9fa 100644 (file)
@@ -22,6 +22,9 @@
 #include "wx/wx_util.h"
 #include "wx/job_manager_view.h"
 #include "wx/drive_wipe_warning_dialog.h"
+#include "wx/try_unmount_dialog.h"
+#include "wx/message_dialog.h"
+#include "wx/disk_warning_dialog.h"
 #include "lib/file_log.h"
 #include "lib/dcpomatic_log.h"
 #include "lib/util.h"
@@ -31,6 +34,7 @@
 #include "lib/copy_to_drive_job.h"
 #include "lib/job_manager.h"
 #include "lib/disk_writer_messages.h"
+#include "lib/version.h"
 #include <wx/wx.h>
 #include <boost/process.hpp>
 #ifdef DCPOMATIC_WINDOWS
 #endif
 #ifdef DCPOMATIC_OSX
 #include <ApplicationServices/ApplicationServices.h>
+#include <notify.h>
 #endif
 
 using std::string;
 using std::exception;
 using std::cout;
 using std::cerr;
-using std::runtime_error;
 using boost::shared_ptr;
+using boost::optional;
 
 class DOMFrame : public wxFrame
 {
@@ -109,11 +114,12 @@ public:
                 */
                dcpomatic_log.reset(new FileLog(config_path() / "disk.log"));
                dcpomatic_log->set_types (dcpomatic_log->types() | LogEntry::TYPE_DISK);
-               LOG_DISK_NC("dcpomatic_disk started");
+               LOG_DISK("dcpomatic_disk %1 started", dcpomatic_git_commit);
 
                drive_refresh ();
 
-               Bind (wxEVT_SIZE, boost::bind (&DOMFrame::sized, this, _1));
+               Bind (wxEVT_SIZE, boost::bind(&DOMFrame::sized, this, _1));
+               Bind (wxEVT_CLOSE_WINDOW, boost::bind(&DOMFrame::close, this, _1));
 
                JobManager::instance()->ActiveJobsChanged.connect(boost::bind(&DOMFrame::setup_sensitivity, this));
 
@@ -128,12 +134,15 @@ public:
                _writer = new boost::process::child (disk_writer_path());
 #endif
 
-               /* _writer is always running on macOS at the moment */
+#ifdef DCPOMATIC_OSX
+               LOG_DISK_NC("Sending notification to writer daemon");
+               notify_post ("com.dcpomatic.disk.writer.start");
+#endif
        }
 
        ~DOMFrame ()
        {
-               _nanomsg.blocking_send(DISK_WRITER_QUIT "\n");
+               _nanomsg.send(DISK_WRITER_QUIT "\n", 2000);
        }
 
 private:
@@ -143,6 +152,37 @@ private:
                ev.Skip ();
        }
 
+
+       bool should_close ()
+       {
+               if (!JobManager::instance()->work_to_do()) {
+                       return true;
+               }
+
+               wxMessageDialog* d = new wxMessageDialog (
+                       0,
+                       _("There are unfinished jobs; are you sure you want to quit?"),
+                       _("Unfinished jobs"),
+                       wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION
+                       );
+
+               bool const r = d->ShowModal() == wxID_YES;
+               d->Destroy ();
+               return r;
+       }
+
+
+       void close (wxCloseEvent& ev)
+       {
+               if (!should_close()) {
+                       ev.Veto ();
+                       return;
+               }
+
+               ev.Skip ();
+       }
+
+
        void open ()
        {
                wxDirDialog* d = new wxDirDialog (this, _("Choose a DCP folder"), wxT(""), wxDD_DIR_MUST_EXIST);
@@ -163,6 +203,37 @@ private:
        {
                DCPOMATIC_ASSERT (_drive->GetSelection() != wxNOT_FOUND);
                DCPOMATIC_ASSERT (static_cast<bool>(_dcp_path));
+
+               Drive const& drive = _drives[_drive->GetSelection()];
+               if (drive.mounted()) {
+                       TryUnmountDialog* d = new TryUnmountDialog(this, drive.description());
+                       int const r = d->ShowModal ();
+                       d->Destroy ();
+                       if (r != wxID_OK) {
+                               return;
+                       }
+
+                       LOG_DISK("Sending unmount request to disk writer for %1", drive.as_xml());
+                       if (!_nanomsg.send(DISK_WRITER_UNMOUNT "\n", 2000)) {
+                               throw CommunicationFailedError ();
+                       }
+                       if (!_nanomsg.send(drive.as_xml(), 2000)) {
+                               throw CommunicationFailedError ();
+                       }
+                       optional<string> reply = _nanomsg.receive (2000);
+                       if (!reply || *reply != DISK_WRITER_OK) {
+                               MessageDialog* m = new MessageDialog (
+                                               this,
+                                               _("DCP-o-matic Disk Writer"),
+                                               wxString::Format(_("The drive %s could not be unmounted.\nClose any application that is using it, then try again."), std_to_wx(drive.description()))
+                                               );
+                               m->ShowModal ();
+                               m->Destroy ();
+                               return;
+                       }
+               }
+
+
                DriveWipeWarningDialog* d = new DriveWipeWarningDialog (this, _drive->GetString(_drive->GetSelection()));
                int const r = d->ShowModal ();
                bool ok = r == wxID_OK && d->confirmed();
@@ -186,12 +257,7 @@ private:
                _drive->Clear ();
                int re_select = wxNOT_FOUND;
                int j = 0;
-               _drives.clear ();
-               BOOST_FOREACH (Drive i, get_drives()) {
-                       if (!i.mounted()) {
-                               _drives.push_back (i);
-                       }
-               }
+               _drives = Drive::get ();
                BOOST_FOREACH (Drive i, _drives) {
                        wxString const s = std_to_wx(i.description());
                        if (s == current) {
@@ -217,7 +283,9 @@ private:
        JobManagerView* _jobs;
        boost::optional<boost::filesystem::path> _dcp_path;
        std::vector<Drive> _drives;
+#ifndef DCPOMATIC_OSX
        boost::process::child* _writer;
+#endif
        Nanomsg _nanomsg;
        wxSizer* _sizer;
 };
@@ -271,6 +339,13 @@ public:
                        */
                        Config::drop ();
 
+                       DiskWarningDialog* warning = new DiskWarningDialog ();
+                       warning->ShowModal ();
+                       if (!warning->confirmed()) {
+                               return false;
+                       }
+                       warning->Destroy ();
+
                        _frame = new DOMFrame (_("DCP-o-matic Disk Writer"));
                        SetTopWindow (_frame);
 
@@ -282,6 +357,7 @@ public:
                catch (exception& e)
                {
                        error_dialog (0, wxString::Format ("DCP-o-matic could not start."), std_to_wx(e.what()));
+                       return false;
                }
 
                return true;
@@ -303,6 +379,44 @@ public:
                ev.Skip ();
        }
 
+       void report_exception ()
+       {
+               try {
+                       throw;
+               } catch (FileError& e) {
+                       error_dialog (
+                               0,
+                               wxString::Format (
+                                       _("An exception occurred: %s (%s)\n\n") + REPORT_PROBLEM,
+                                       std_to_wx (e.what()),
+                                       std_to_wx (e.file().string().c_str ())
+                                       )
+                               );
+               } catch (exception& e) {
+                       error_dialog (
+                               0,
+                               wxString::Format (
+                                       _("An exception occurred: %s.\n\n") + REPORT_PROBLEM,
+                                       std_to_wx (e.what ())
+                                       )
+                               );
+               } catch (...) {
+                       error_dialog (0, _("An unknown exception occurred.") + "  " + REPORT_PROBLEM);
+               }
+       }
+
+       bool OnExceptionInMainLoop ()
+       {
+               report_exception ();
+               /* This will terminate the program */
+               return false;
+       }
+
+       void OnUnhandledException ()
+       {
+               report_exception ();
+       }
+
        DOMFrame* _frame;
 };