diff options
| author | Carl Hetherington <cth@carlh.net> | 2024-04-09 02:02:28 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2024-04-17 09:36:45 +0200 |
| commit | af20e21e2363f7c4d5f7031c444984f383c26914 (patch) | |
| tree | 072277c1a9c48d81367384d0c0f4a3ae356ce54e /src/tools | |
| parent | 39960bc88eee794ade1a73b00523e749945b9eab (diff) | |
Separate GUI verifier with basic reporting (#1823).
Diffstat (limited to 'src/tools')
| -rw-r--r-- | src/tools/dcpomatic_verifier.cc | 247 | ||||
| -rw-r--r-- | src/tools/wscript | 10 |
2 files changed, 256 insertions, 1 deletions
diff --git a/src/tools/dcpomatic_verifier.cc b/src/tools/dcpomatic_verifier.cc new file mode 100644 index 000000000..382516acc --- /dev/null +++ b/src/tools/dcpomatic_verifier.cc @@ -0,0 +1,247 @@ +/* + Copyright (C) 2024 Carl Hetherington <cth@carlh.net> + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +/** @file src/tools/dcpomatic_verify.cc + * @brief A DCP verify GUI. + */ + + +#include "wx/check_box.h" +#include "wx/dcpomatic_button.h" +#include "wx/dir_picker_ctrl.h" +#include "wx/verify_dcp_progress_panel.h" +#include "wx/verify_dcp_result_panel.h" +#include "wx/wx_util.h" +#include "lib/constants.h" +#include "lib/cross.h" +#include "lib/job_manager.h" +#include "lib/verify_dcp_job.h" +#include "lib/util.h" +#include <dcp/verify_report.h> +LIBDCP_DISABLE_WARNINGS +#include <wx/evtloop.h> +#include <wx/wx.h> +LIBDCP_ENABLE_WARNINGS +#ifdef __WXGTK__ +#include <X11/Xlib.h> +#endif + + +using std::exception; +using std::make_shared; + + +class DOMFrame : public wxFrame +{ +public: + explicit DOMFrame(wxString const& title) + : wxFrame(nullptr, -1, title) + { +#ifdef DCPOMATIC_WINDOWS + SetIcon(wxIcon(std_to_wx("id"))); +#endif + auto overall_sizer = new wxBoxSizer(wxVERTICAL); + + auto dcp_sizer = new wxBoxSizer(wxHORIZONTAL); + add_label_to_sizer(dcp_sizer, this, _("DCP"), true, 0, wxALIGN_CENTER_VERTICAL); + _dcp = new DirPickerCtrl(this, true); + dcp_sizer->Add(_dcp, 1, wxEXPAND); + overall_sizer->Add(dcp_sizer, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + auto options_sizer = new wxBoxSizer(wxVERTICAL); + _write_log = new CheckBox(this, _("Write log to DCP folder")); + options_sizer->Add(_write_log, 0, wxBOTTOM, DCPOMATIC_SIZER_GAP); + overall_sizer->Add(options_sizer, 0, wxLEFT, DCPOMATIC_DIALOG_BORDER); + + _verify = new Button(this, _("Verify")); + overall_sizer->Add(_verify, 0, wxEXPAND | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER); + + _progress_panel = new VerifyDCPProgressPanel(this); + overall_sizer->Add(_progress_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + _result_panel = new VerifyDCPResultPanel(this); + overall_sizer->Add(_result_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + SetSizerAndFit(overall_sizer); + + _dcp->Changed.connect(boost::bind(&DOMFrame::setup_sensitivity, this)); + _verify->bind(&DOMFrame::verify_clicked, this); + + setup_sensitivity(); + } + +private: + void setup_sensitivity() + { + _verify->Enable(!_dcp->GetPath().IsEmpty()); + } + + void verify_clicked() + { + auto dcp = boost::filesystem::path(wx_to_std(_dcp->GetPath())); + if (dcp.empty()) { + return; + } + + auto job_manager = JobManager::instance(); + auto job = make_shared<VerifyDCPJob>(std::vector<boost::filesystem::path>{dcp}, std::vector<boost::filesystem::path>()); + job_manager->add(job); + + while (job_manager->work_to_do()) { + wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT); + dcpomatic_sleep_seconds(1); + + _progress_panel->update(job); + } + + _result_panel->fill(job); + if (_write_log->get()) { + dcp::TextFormatter formatter(dcp / "REPORT.txt"); + dcp::verify_report(job->result(), formatter); + } + } + + DirPickerCtrl* _dcp; + CheckBox* _write_log; + Button* _verify; + VerifyDCPProgressPanel* _progress_panel; + VerifyDCPResultPanel* _result_panel; +}; + + +/** @class App + * @brief The magic App class for wxWidgets. + */ +class App : public wxApp +{ +public: + App() + : wxApp() + { + dcpomatic_setup_path_encoding(); +#ifdef DCPOMATIC_LINUX + XInitThreads(); +#endif + } + +private: + bool OnInit() override + { + try { + SetAppName(_("DCP-o-matic Verifier")); + + if (!wxApp::OnInit()) { + return false; + } + +#ifdef DCPOMATIC_LINUX + unsetenv("UBUNTU_MENUPROXY"); +#endif + +#ifdef DCPOMATIC_OSX + dcpomatic_sleep_seconds(1); + make_foreground_application(); +#endif + + /* Enable i18n; this will create a Config object + to look for a force-configured language. This Config + object will be wrong, however, because dcpomatic_setup + hasn't yet been called and there aren't any filters etc. + set up yet. + */ + dcpomatic_setup_i18n(); + + /* Set things up, including filters etc. + which will now be internationalised correctly. + */ + dcpomatic_setup(); + + /* Force the configuration to be re-loaded correctly next + time it is needed. + */ + Config::drop(); + + _frame = new DOMFrame(_("DCP-o-matic Verifier")); + SetTopWindow(_frame); + _frame->SetSize({480, 640}); + _frame->Show(); + } + catch (exception& e) + { + error_dialog(nullptr, wxString::Format("DCP-o-matic Verifier could not start."), std_to_wx(e.what())); + } + + return true; + } + + void report_exception() + { + try { + throw; + } catch (FileError& e) { + error_dialog( + nullptr, + 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 (boost::filesystem::filesystem_error& e) { + error_dialog( + nullptr, + wxString::Format( + _("An exception occurred: %s (%s) (%s)\n\n") + REPORT_PROBLEM, + std_to_wx(e.what()), + std_to_wx(e.path1().string()), + std_to_wx(e.path2().string()) + ) + ); + } catch (exception& e) { + error_dialog( + nullptr, + wxString::Format( + _("An exception occurred: %s.\n\n") + REPORT_PROBLEM, + std_to_wx(e.what()) + ) + ); + } catch (...) { + error_dialog(nullptr, _("An unknown exception occurred.") + " " + REPORT_PROBLEM); + } + } + + /* An unhandled exception has occurred inside the main event loop */ + bool OnExceptionInMainLoop() override + { + report_exception(); + return false; + } + + void OnUnhandledException() override + { + report_exception(); + } + + DOMFrame* _frame = nullptr; +}; + + +IMPLEMENT_APP(App) diff --git a/src/tools/wscript b/src/tools/wscript index c3b2b5fe0..65e4d0e4c 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -62,7 +62,15 @@ def build(bld): gui_tools = [] if not bld.env.DISABLE_GUI: - gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist', 'dcpomatic_combiner', 'dcpomatic_editor'] + gui_tools = ['dcpomatic', + 'dcpomatic_batch', + 'dcpomatic_server', + 'dcpomatic_kdm', + 'dcpomatic_player', + 'dcpomatic_playlist', + 'dcpomatic_combiner', + 'dcpomatic_editor', + 'dcpomatic_verifier'] if bld.env.ENABLE_DISK: gui_tools.append('dcpomatic_disk') |
