WIP: Allow export of a verification report (#1823).
authorCarl Hetherington <cth@carlh.net>
Sun, 25 Dec 2022 23:30:25 +0000 (00:30 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 5 Jan 2024 23:44:44 +0000 (00:44 +0100)
src/lib/verify_dcp_job.cc
src/lib/verify_dcp_job.h
src/wx/verify_dcp_dialog.cc
src/wx/verify_dcp_dialog.h
test/reels_test.cc
test/test.cc

index 5e50ec51db3bd3873c99de004d7ae6be01e48758..668b1eab49f42dc392fb7285fa70f467004571c3 100644 (file)
@@ -86,7 +86,7 @@ VerifyDCPJob::run ()
                }
        }
 
-       _notes = dcp::verify(
+       _result = dcp::verify(
                _directories,
                decrypted_kdms,
                bind(&VerifyDCPJob::update_stage, this, _1, _2),
@@ -96,7 +96,7 @@ VerifyDCPJob::run ()
                );
 
        bool failed = false;
-       for (auto i: _notes) {
+       for (auto i: _result.notes) {
                if (i.type() == dcp::VerificationNote::Type::ERROR) {
                        failed = true;
                }
index 61a34750717879a288cd22c886c9a1d3bb2cad91..be7dcb717360291f2a6dca02d9a797764d5b5b03 100644 (file)
@@ -36,8 +36,8 @@ public:
        std::string json_name () const override;
        void run () override;
 
-       std::vector<dcp::VerificationNote> notes () const {
-               return _notes;
+       dcp::VerifyResult result() const {
+               return _result;
        }
 
 private:
@@ -45,5 +45,5 @@ private:
 
        std::vector<boost::filesystem::path> _directories;
        std::vector<boost::filesystem::path> _kdms;
-       std::vector<dcp::VerificationNote> _notes;
+       dcp::VerifyResult _result;
 };
index 2f43f3c8f9d1b24dd1de7fd37d1f7b896fd8dcae..89a5da0beffb6070cea60afb48e61ba01fc81192 100644 (file)
 */
 
 
+#include "dcpomatic_button.h"
 #include "verify_dcp_dialog.h"
 #include "wx_util.h"
+#include "lib/scope_guard.h"
 #include "lib/verify_dcp_job.h"
 #include <dcp/raw_convert.h>
 #include <dcp/verify.h>
+#include <dcp/verify_report.h>
 #include <dcp/warnings.h>
 LIBDCP_DISABLE_WARNINGS
 #include <wx/richtext/richtextctrl.h>
@@ -41,6 +44,7 @@ using std::vector;
 
 VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job)
        : wxDialog (parent, wxID_ANY, _("DCP verification"), wxDefaultPosition, {600, 400})
+       , _result(job->result())
 {
        auto sizer = new wxBoxSizer (wxVERTICAL);
        auto notebook = new wxNotebook (this, wxID_ANY);
@@ -57,6 +61,10 @@ VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job
        auto summary = new wxStaticText (this, wxID_ANY, wxT(""));
        sizer->Add (summary, 0, wxALL, DCPOMATIC_DIALOG_BORDER);
 
+       auto save_report = new Button(this, _("Save report..."));
+       sizer->Add(save_report, 0, wxLEFT, DCPOMATIC_DIALOG_BORDER);
+       save_report->bind(&VerifyDCPDialog::save_report, this);
+
        auto buttons = CreateStdDialogButtonSizer (0);
        sizer->Add (CreateSeparatedSizer(buttons), wxSizerFlags().Expand().DoubleBorder());
        buttons->SetAffirmativeButton (new wxButton (this, wxID_OK));
@@ -70,7 +78,7 @@ VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job
                i.second->GetCaret()->Hide();
        }
 
-       if (job->finished_ok() && job->notes().empty()) {
+       if (job->finished_ok() && _result.notes.empty()) {
                summary->SetLabel (_("DCP validates OK."));
                return;
        }
@@ -81,10 +89,12 @@ VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job
        counts[dcp::VerificationNote::Type::ERROR] = 0;
 
        auto add_bullet = [&pages](dcp::VerificationNote::Type type, wxString message) {
-               pages[type]->BeginStandardBullet(N_("standard/diamond"), 1, 50);
-               pages[type]->WriteText (message);
-               pages[type]->Newline ();
-               pages[type]->EndStandardBullet ();
+               if (pages.find(type) != pages.end()) {
+                       pages[type]->BeginStandardBullet(N_("standard/diamond"), 1, 50);
+                       pages[type]->WriteText(message);
+                       pages[type]->Newline();
+                       pages[type]->EndStandardBullet();
+               }
        };
 
        auto add = [&counts, &add_bullet](dcp::VerificationNote note, wxString message) {
@@ -121,7 +131,7 @@ VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job
                add_bullet (dcp::VerificationNote::Type::ERROR, std_to_wx(job->error_summary()));
        }
 
-       for (auto i: job->notes()) {
+       for (auto i: job->result().notes) {
                switch (i.code()) {
                case dcp::VerificationNote::Code::FAILED_READ:
                        add (i, std_to_wx(*i.note()));
@@ -437,6 +447,13 @@ VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job
                case dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT:
                        add(i, _("The <LabelText> in a <ContentVersion> in CPL %id is empty"));
                        break;
+               case dcp::VerificationNote::Code::ALL_ENCRYPTED:
+               case dcp::VerificationNote::Code::NONE_ENCRYPTED:
+               case dcp::VerificationNote::Code::MATCHING_CPL_HASHES:
+               case dcp::VerificationNote::Code::CORRECT_PICTURE_HASH:
+               case dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES:
+                       /* We don't make our own messages for "OK" notes, i.e. things that are used in verification reports */
+                       break;
                }
        }
 
@@ -480,3 +497,20 @@ VerifyDCPDialog::VerifyDCPDialog (wxWindow* parent, shared_ptr<VerifyDCPJob> job
                add_bullet (dcp::VerificationNote::Type::WARNING, _("No warnings found."));
        }
 }
+
+
+void
+VerifyDCPDialog::save_report()
+{
+       auto d = new wxFileDialog(
+               this, _("Select report file"), wxEmptyString, wxT("report.html"), wxT("HTML files (*.htm,*.html)|*.htm,*.html"),
+               wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+               );
+
+       ScopeGuard sg = [d]() { d->Destroy(); };
+
+       if (d->ShowModal() == wxID_OK) {
+               dcp::verify_report(_result, wx_to_std(d->GetPath()));
+       }
+}
+
index 076217b1f9678c4db79698b252f87414f016421c..2fa539ed3edab9cc57221f619025d10e76e387d1 100644 (file)
@@ -34,4 +34,9 @@ class VerifyDCPDialog : public wxDialog
 {
 public:
        VerifyDCPDialog (wxWindow* parent, std::shared_ptr<VerifyDCPJob> job);
+
+private:
+       void save_report();
+
+       dcp::VerifyResult _result;
 };
index 2a87ef6b64bec37cb62be23228f47646104f4536..5de9cd1312afa466bea3f3382380251ebd9b1958 100644 (file)
@@ -503,7 +503,7 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short1)
        make_and_verify_dcp (film);
 
        vector<boost::filesystem::path> dirs = { film->dir(film->dcp_name(false)) };
-       auto notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       auto notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd()).notes;
        dump_notes (notes);
        BOOST_REQUIRE (notes.empty());
 }
@@ -528,7 +528,7 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short2)
        make_and_verify_dcp (film);
 
        vector<boost::filesystem::path> dirs = { film->dir(film->dcp_name(false)) };
-       auto const notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       auto const notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd()).notes;
        dump_notes (notes);
        BOOST_REQUIRE (notes.empty());
 }
@@ -549,7 +549,7 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short3)
 
        make_and_verify_dcp (film);
 
-       auto const notes = dcp::verify({}, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       auto const notes = dcp::verify({}, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd()).notes;
        dump_notes (notes);
        BOOST_REQUIRE (notes.empty());
 }
@@ -579,7 +579,7 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short4)
        BOOST_REQUIRE (!wait_for_jobs());
 
        vector<boost::filesystem::path> dirs = { film->dir(film->dcp_name(false)) };
-       auto const notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       auto const notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd()).notes;
        dump_notes (notes);
        BOOST_REQUIRE (notes.empty());
 }
index 8ca103a6bdedb9800c97ef94f3f14509ac5253ee..d9c7bf15dc4525c2b2640d0e9a8345d9077ab989 100644 (file)
@@ -948,7 +948,7 @@ void progress (float) {}
 void
 verify_dcp(boost::filesystem::path dir, vector<dcp::VerificationNote::Code> ignore)
 {
-       auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, TestPaths::xsd());
+       auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, TestPaths::xsd()).notes;
        bool ok = true;
        for (auto i: notes) {
                if (find(ignore.begin(), ignore.end(), i.code()) == ignore.end()) {