summaryrefslogtreecommitdiff
path: root/src/wx
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-02-20 23:10:50 +0100
committerCarl Hetherington <cth@carlh.net>2025-02-23 01:47:38 +0100
commit81d8c747c7a04be10821223dea69faf058b05b1d (patch)
tree98f58e45012c3133e719024fe8c84d7b9c691811 /src/wx
parent6628b2573f601b7448da169453d5f113534e525e (diff)
Allow verification of multiple DCPs in one go (#2843).
Diffstat (limited to 'src/wx')
-rw-r--r--src/wx/verify_dcp_progress_dialog.cc4
-rw-r--r--src/wx/verify_dcp_progress_dialog.h4
-rw-r--r--src/wx/verify_dcp_progress_panel.cc23
-rw-r--r--src/wx/verify_dcp_progress_panel.h6
-rw-r--r--src/wx/verify_dcp_result_dialog.cc2
-rw-r--r--src/wx/verify_dcp_result_panel.cc180
-rw-r--r--src/wx/verify_dcp_result_panel.h11
7 files changed, 144 insertions, 86 deletions
diff --git a/src/wx/verify_dcp_progress_dialog.cc b/src/wx/verify_dcp_progress_dialog.cc
index 5e3a7be62..cdca99603 100644
--- a/src/wx/verify_dcp_progress_dialog.cc
+++ b/src/wx/verify_dcp_progress_dialog.cc
@@ -23,8 +23,8 @@
#include "verify_dcp_progress_panel.h"
#include "wx_util.h"
#include "lib/cross.h"
-#include "lib/job.h"
#include "lib/job_manager.h"
+#include "lib/verify_dcp_job.h"
#include <dcp/warnings.h>
LIBDCP_DISABLE_WARNINGS
#include <wx/evtloop.h>
@@ -66,7 +66,7 @@ VerifyDCPProgressDialog::cancel ()
bool
-VerifyDCPProgressDialog::run (shared_ptr<Job> job)
+VerifyDCPProgressDialog::run(shared_ptr<VerifyDCPJob> job)
{
Show ();
diff --git a/src/wx/verify_dcp_progress_dialog.h b/src/wx/verify_dcp_progress_dialog.h
index 1ae3336e8..5120b309b 100644
--- a/src/wx/verify_dcp_progress_dialog.h
+++ b/src/wx/verify_dcp_progress_dialog.h
@@ -26,7 +26,7 @@ LIBDCP_ENABLE_WARNINGS
#include <memory>
-class Job;
+class VerifyDCPJob;
class VerifyDCPProgressPanel;
@@ -35,7 +35,7 @@ class VerifyDCPProgressDialog : public wxDialog
public:
VerifyDCPProgressDialog (wxWindow* parent, wxString title);
- bool run (std::shared_ptr<Job> job);
+ bool run(std::shared_ptr<VerifyDCPJob> job);
private:
void cancel ();
diff --git a/src/wx/verify_dcp_progress_panel.cc b/src/wx/verify_dcp_progress_panel.cc
index a99791911..2b0455ca1 100644
--- a/src/wx/verify_dcp_progress_panel.cc
+++ b/src/wx/verify_dcp_progress_panel.cc
@@ -19,7 +19,7 @@
*/
-#include "lib/job.h"
+#include "lib/verify_dcp_job.h"
#include "verify_dcp_progress_panel.h"
#include "wx_util.h"
@@ -37,6 +37,12 @@ VerifyDCPProgressPanel::VerifyDCPProgressPanel(wxWindow* parent)
{
auto overall_sizer = new wxBoxSizer(wxVERTICAL);
+ _directory_name = new wxStaticText(this, wxID_ANY, {});
+ wxFont directory_name_font(*wxNORMAL_FONT);
+ directory_name_font.SetFamily(wxFONTFAMILY_MODERN);
+ _directory_name->SetFont(directory_name_font);
+ overall_sizer->Add(_directory_name, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP);
+
_job_name = new wxStaticText(this, wxID_ANY, {});
overall_sizer->Add(_job_name, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP);
@@ -61,8 +67,11 @@ VerifyDCPProgressPanel::VerifyDCPProgressPanel(wxWindow* parent)
void
-VerifyDCPProgressPanel::update(shared_ptr<Job> job)
+VerifyDCPProgressPanel::update(shared_ptr<const VerifyDCPJob> job)
{
+ DCPOMATIC_ASSERT(!job->directories().empty());
+ checked_set(_directory_name, std_to_wx(job->directories()[0].filename().string()));
+
auto const progress = job->progress();
if (progress) {
_progress->SetValue(*progress * 100);
@@ -85,3 +94,13 @@ VerifyDCPProgressPanel::update(shared_ptr<Job> job)
}
}
+
+void
+VerifyDCPProgressPanel::clear()
+{
+ _directory_name->SetLabel(wxT(""));
+ _job_name->SetLabel(wxT(""));
+ _file_name->SetLabel(wxT(""));
+ _progress->SetValue(0);
+}
+
diff --git a/src/wx/verify_dcp_progress_panel.h b/src/wx/verify_dcp_progress_panel.h
index 3fde50827..52ef221cb 100644
--- a/src/wx/verify_dcp_progress_panel.h
+++ b/src/wx/verify_dcp_progress_panel.h
@@ -26,7 +26,7 @@ LIBDCP_ENABLE_WARNINGS
#include <memory>
-class Job;
+class VerifyDCPJob;
class VerifyDCPProgressPanel : public wxPanel
@@ -34,9 +34,11 @@ class VerifyDCPProgressPanel : public wxPanel
public:
VerifyDCPProgressPanel(wxWindow* parent);
- void update(std::shared_ptr<Job> job);
+ void update(std::shared_ptr<const VerifyDCPJob> job);
+ void clear();
private:
+ wxStaticText* _directory_name;
wxStaticText* _job_name;
wxStaticText* _file_name;
wxGauge* _progress;
diff --git a/src/wx/verify_dcp_result_dialog.cc b/src/wx/verify_dcp_result_dialog.cc
index 806eac85a..c61ed19ea 100644
--- a/src/wx/verify_dcp_result_dialog.cc
+++ b/src/wx/verify_dcp_result_dialog.cc
@@ -33,7 +33,7 @@ VerifyDCPResultDialog::VerifyDCPResultDialog(wxWindow* parent, shared_ptr<Verify
auto sizer = new wxBoxSizer (wxVERTICAL);
auto panel = new VerifyDCPResultPanel(this);
- panel->fill(job);
+ panel->add({ job });
sizer->Add(panel, 1, wxEXPAND);
auto buttons = CreateStdDialogButtonSizer(0);
diff --git a/src/wx/verify_dcp_result_panel.cc b/src/wx/verify_dcp_result_panel.cc
index 4cf44431c..6f8b1f53a 100644
--- a/src/wx/verify_dcp_result_panel.cc
+++ b/src/wx/verify_dcp_result_panel.cc
@@ -28,8 +28,8 @@
#include <dcp/verify_report.h>
#include <dcp/warnings.h>
LIBDCP_DISABLE_WARNINGS
-#include <wx/richtext/richtextctrl.h>
#include <wx/notebook.h>
+#include <wx/treectrl.h>
LIBDCP_ENABLE_WARNINGS
#include <fmt/format.h>
#include <boost/algorithm/string.hpp>
@@ -44,17 +44,30 @@ using std::vector;
VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
+ , _types{
+ dcp::VerificationNote::Type::ERROR,
+ dcp::VerificationNote::Type::BV21_ERROR,
+ dcp::VerificationNote::Type::WARNING
+ }
{
auto sizer = new wxBoxSizer(wxVERTICAL);
- auto notebook = new wxNotebook(this, wxID_ANY);
+ auto notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 400));
sizer->Add(notebook, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
- _pages[dcp::VerificationNote::Type::ERROR] = new wxRichTextCtrl(notebook, wxID_ANY, wxEmptyString, wxDefaultPosition, {400, 300}, wxRE_READONLY);
- notebook->AddPage(_pages[dcp::VerificationNote::Type::ERROR], _("Errors"));
- _pages[dcp::VerificationNote::Type::BV21_ERROR] = new wxRichTextCtrl(notebook, wxID_ANY, wxEmptyString, wxDefaultPosition, {400, 300}, wxRE_READONLY);
- notebook->AddPage(_pages[dcp::VerificationNote::Type::BV21_ERROR], _("SMPTE Bv2.1 errors"));
- _pages[dcp::VerificationNote::Type::WARNING] = new wxRichTextCtrl(notebook, wxID_ANY, wxEmptyString, wxDefaultPosition, {400, 300}, wxRE_READONLY);
- notebook->AddPage(_pages[dcp::VerificationNote::Type::WARNING], _("Warnings"));
+ auto names = map<dcp::VerificationNote::Type, wxString>{
+ { dcp::VerificationNote::Type::ERROR, _("Errors") },
+ { dcp::VerificationNote::Type::BV21_ERROR, _("SMPTE Bv2.1 errors") },
+ { dcp::VerificationNote::Type::WARNING, _("Warnings") }
+ };
+
+ for (auto const type: _types) {
+ auto panel = new wxPanel(notebook, wxID_ANY);
+ _pages[type] = new wxTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS | wxTR_NO_LINES);
+ auto sizer = new wxBoxSizer(wxHORIZONTAL);
+ sizer->Add(_pages[type], 1, wxEXPAND);
+ panel->SetSizer(sizer);
+ notebook->AddPage(panel, names[type]);
+ }
_summary = new wxStaticText(this, wxID_ANY, {});
sizer->Add(_summary, 0, wxALL, DCPOMATIC_DIALOG_BORDER);
@@ -70,10 +83,6 @@ VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
sizer->Layout();
sizer->SetSizeHints(this);
- for (auto const& i: _pages) {
- i.second->GetCaret()->Hide();
- }
-
_save_text_report->bind(&VerifyDCPResultPanel::save_text_report, this);
_save_html_report->bind(&VerifyDCPResultPanel::save_html_report, this);
@@ -83,24 +92,82 @@ VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
void
-VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
+VerifyDCPResultPanel::add(vector<shared_ptr<const VerifyDCPJob>> jobs)
{
- if (job->finished_ok() && job->result().notes.empty()) {
- _summary->SetLabel(_("DCP validates OK."));
- return;
+ _jobs = jobs;
+
+ for (auto const type: _types) {
+ _pages[type]->DeleteAllItems();
+ _pages[type]->AddRoot(wxT(""));
}
- vector<dcp::VerificationNote::Type> const types = {
- dcp::VerificationNote::Type::WARNING,
- dcp::VerificationNote::Type::BV21_ERROR,
- dcp::VerificationNote::Type::ERROR
- };
+ map<dcp::VerificationNote::Type, int> counts;
+ for (auto type: _types) {
+ counts[type] = 0;
+ }
+
+ for (auto job: jobs) {
+ auto job_counts = add(job, jobs.size() > 1);
+ for (auto const type: _types) {
+ counts[type] += job_counts[type];
+ }
+ }
+
+ wxString summary_text;
+
+ if (counts[dcp::VerificationNote::Type::ERROR] == 1) {
+ /// TRANSLATORS: this will be used at the start of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
+ summary_text = _("1 error, ");
+ } else {
+ /// TRANSLATORS: this will be used at the start of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
+ summary_text = wxString::Format(_("%d errors, "), counts[dcp::VerificationNote::Type::ERROR]);
+ }
+
+ if (counts[dcp::VerificationNote::Type::BV21_ERROR] == 1) {
+ /// TRANSLATORS: this will be used in the middle of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
+ summary_text += _("1 Bv2.1 error, ");
+ } else {
+ /// TRANSLATORS: this will be used in the middle of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
+ summary_text += wxString::Format(_("%d Bv2.1 errors, "), counts[dcp::VerificationNote::Type::BV21_ERROR]);
+ }
+
+ if (counts[dcp::VerificationNote::Type::WARNING] == 1) {
+ /// TRANSLATORS: this will be used at the end of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
+ summary_text += _("and 1 warning.");
+ } else {
+ /// TRANSLATORS: this will be used at the end of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
+ summary_text += wxString::Format(_("and %d warnings."), counts[dcp::VerificationNote::Type::WARNING]);
+ }
+
+ _summary->SetLabel(summary_text);
+ _save_text_report->Enable(true);
+ _save_html_report->Enable(true);
+
+ for (auto type: _types) {
+ _pages[type]->ExpandAll();
+ }
+}
+
+
+map<dcp::VerificationNote::Type, int>
+VerifyDCPResultPanel::add(shared_ptr<const VerifyDCPJob> job, bool many)
+{
map<dcp::VerificationNote::Type, int> counts;
- for (auto type: types) {
+ for (auto type: _types) {
counts[type] = 0;
}
+ map<dcp::VerificationNote::Type, wxTreeItemId> root;
+
+ for (auto type: _types) {
+ root[type] = _pages[type]->GetRootItem();
+ if (many) {
+ DCPOMATIC_ASSERT(!job->directories().empty());
+ root[type] = _pages[type]->AppendItem(root[type], std_to_wx(job->directories()[0].filename().string()));
+ }
+ }
+
int constexpr limit_per_type = 20;
auto substitute = [](wxString message, dcp::VerificationNote const& note) {
@@ -146,25 +213,22 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
return message;
};
- auto add_bullet = [this](dcp::VerificationNote::Type type, wxString message) {
- _pages[type]->BeginStandardBullet(char_to_wx("standard/diamond"), 1, 50);
- _pages[type]->WriteText(message);
- _pages[type]->Newline();
- _pages[type]->EndStandardBullet();
+ auto add_line = [this, &root](dcp::VerificationNote::Type type, wxString message) {
+ _pages[type]->AppendItem(root[type], message);
};
- auto add = [&add_bullet, &substitute](vector<dcp::VerificationNote> const& notes, wxString message, wxString more_message = {}) {
+ auto add = [&add_line, &substitute](vector<dcp::VerificationNote> const& notes, wxString message, wxString more_message = {}) {
for (auto const& note: notes) {
- add_bullet(note.type(), substitute(message, note));
+ add_line(note.type(), substitute(message, note));
}
if (notes.size() == limit_per_type && !more_message.IsEmpty()) {
- add_bullet(notes[0].type(), more_message);
+ add_line(notes[0].type(), more_message);
}
};
if (job->finished_in_error() && job->error_summary() != "") {
/* We have an error that did not come from dcp::verify */
- add_bullet(dcp::VerificationNote::Type::ERROR, std_to_wx(job->error_summary()));
+ add_line(dcp::VerificationNote::Type::ERROR, std_to_wx(job->error_summary()));
}
/* Gather notes by code, discarding more than limit_per_type so we don't get overwhelmed if
@@ -603,54 +667,24 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
}
}
- wxString summary_text;
-
- if (counts[dcp::VerificationNote::Type::ERROR] == 1) {
- /// TRANSLATORS: this will be used at the start of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
- summary_text = _("1 error, ");
- } else {
- /// TRANSLATORS: this will be used at the start of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
- summary_text = wxString::Format(_("%d errors, "), counts[dcp::VerificationNote::Type::ERROR]);
- }
-
- if (counts[dcp::VerificationNote::Type::BV21_ERROR] == 1) {
- /// TRANSLATORS: this will be used in the middle of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
- summary_text += _("1 Bv2.1 error, ");
- } else {
- /// TRANSLATORS: this will be used in the middle of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
- summary_text += wxString::Format(_("%d Bv2.1 errors, "), counts[dcp::VerificationNote::Type::BV21_ERROR]);
- }
-
- if (counts[dcp::VerificationNote::Type::WARNING] == 1) {
- /// TRANSLATORS: this will be used at the end of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
- summary_text += _("and 1 warning.");
- } else {
- /// TRANSLATORS: this will be used at the end of a string like "1 error, 2 Bv2.1 errors and 3 warnings."
- summary_text += wxString::Format(_("and %d warnings."), counts[dcp::VerificationNote::Type::WARNING]);
- }
-
- _summary->SetLabel(summary_text);
-
if (counts[dcp::VerificationNote::Type::ERROR] == 0) {
- add_bullet(dcp::VerificationNote::Type::ERROR, _("No errors found."));
+ add_line(dcp::VerificationNote::Type::ERROR, _("No errors found."));
}
if (counts[dcp::VerificationNote::Type::BV21_ERROR] == 0) {
- add_bullet(dcp::VerificationNote::Type::BV21_ERROR, _("No SMPTE Bv2.1 errors found."));
+ add_line(dcp::VerificationNote::Type::BV21_ERROR, _("No SMPTE Bv2.1 errors found."));
}
if (counts[dcp::VerificationNote::Type::WARNING] == 0) {
- add_bullet(dcp::VerificationNote::Type::WARNING, _("No warnings found."));
+ add_line(dcp::VerificationNote::Type::WARNING, _("No warnings found."));
}
- _job = job;
- _save_text_report->Enable(true);
- _save_html_report->Enable(true);
+ return counts;
}
template <class T>
-void save(wxWindow* parent, wxString filter, dcp::VerificationResult const& result)
+void save(wxWindow* parent, wxString filter, vector<shared_ptr<const VerifyDCPJob>> jobs)
{
FileDialog dialog(parent, _("Verification report"), filter, wxFD_SAVE | wxFD_OVERWRITE_PROMPT, "SaveVerificationReport");
if (!dialog.show()) {
@@ -658,23 +692,23 @@ void save(wxWindow* parent, wxString filter, dcp::VerificationResult const& resu
}
T formatter(dialog.path());
- dcp::verify_report(result, formatter);
+ auto results = std::vector<dcp::VerificationResult>();
+ for (auto job: jobs) {
+ results.push_back(job->result());
+ }
+ dcp::verify_report(results, formatter);
}
void
VerifyDCPResultPanel::save_text_report()
{
- if (_job) {
- save<dcp::TextFormatter>(this, char_to_wx("Text files (*.txt)|*.txt"), _job->result());
- }
+ save<dcp::TextFormatter>(this, char_to_wx("Text files (*.txt)|*.txt"), _jobs);
}
void
VerifyDCPResultPanel::save_html_report()
{
- if (_job) {
- save<dcp::HTMLFormatter>(this, char_to_wx("HTML files (*.htm;*html)|*.htm;*.html"), _job->result());
- }
+ save<dcp::HTMLFormatter>(this, char_to_wx("HTML files (*.htm;*html)|*.htm;*.html"), _jobs);
}
diff --git a/src/wx/verify_dcp_result_panel.h b/src/wx/verify_dcp_result_panel.h
index 8cf92118b..fe75bfe35 100644
--- a/src/wx/verify_dcp_result_panel.h
+++ b/src/wx/verify_dcp_result_panel.h
@@ -27,7 +27,7 @@
class Button;
class VerifyDCPJob;
-class wxRichTextCtrl;
+class wxTreeCtrl;
class VerifyDCPResultPanel : public wxPanel
@@ -35,16 +35,19 @@ class VerifyDCPResultPanel : public wxPanel
public:
VerifyDCPResultPanel(wxWindow* parent);
- void fill(std::shared_ptr<VerifyDCPJob> job);
+ void add(std::vector<std::shared_ptr<const VerifyDCPJob>> job);
private:
+ std::map<dcp::VerificationNote::Type, int> add(std::shared_ptr<const VerifyDCPJob> job, bool many);
void save_text_report();
void save_html_report();
wxStaticText* _summary;
- std::map<dcp::VerificationNote::Type, wxRichTextCtrl*> _pages;
+ std::map<dcp::VerificationNote::Type, wxTreeCtrl*> _pages;
Button* _save_text_report;
Button* _save_html_report;
- std::shared_ptr<VerifyDCPJob> _job;
+ std::vector<std::shared_ptr<const VerifyDCPJob>> _jobs;
+
+ std::vector<dcp::VerificationNote::Type> _types;
};