2 Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 /** @file src/tools/dcpomatic_verify.cc
23 * @brief A DCP verify GUI.
27 #include "wx/check_box.h"
28 #include "wx/dcpomatic_button.h"
29 #include "wx/dir_picker_ctrl.h"
30 #include "wx/verify_dcp_progress_panel.h"
31 #include "wx/verify_dcp_result_panel.h"
32 #include "wx/wx_util.h"
33 #include "lib/constants.h"
34 #include "lib/cross.h"
35 #include "lib/job_manager.h"
36 #include "lib/verify_dcp_job.h"
38 #include <dcp/verify_report.h>
39 LIBDCP_DISABLE_WARNINGS
40 #include <wx/evtloop.h>
42 LIBDCP_ENABLE_WARNINGS
49 using std::make_shared;
52 class DOMFrame : public wxFrame
55 explicit DOMFrame(wxString const& title)
56 : wxFrame(nullptr, -1, title)
58 #ifdef DCPOMATIC_WINDOWS
59 SetIcon(wxIcon(std_to_wx("id")));
61 auto overall_sizer = new wxBoxSizer(wxVERTICAL);
63 auto dcp_sizer = new wxBoxSizer(wxHORIZONTAL);
64 add_label_to_sizer(dcp_sizer, this, _("DCP"), true, 0, wxALIGN_CENTER_VERTICAL);
65 _dcp = new DirPickerCtrl(this, true);
66 dcp_sizer->Add(_dcp, 1, wxEXPAND);
67 overall_sizer->Add(dcp_sizer, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
69 auto options_sizer = new wxBoxSizer(wxVERTICAL);
70 _write_log = new CheckBox(this, _("Write log to DCP folder"));
71 options_sizer->Add(_write_log, 0, wxBOTTOM, DCPOMATIC_SIZER_GAP);
72 overall_sizer->Add(options_sizer, 0, wxLEFT, DCPOMATIC_DIALOG_BORDER);
74 _verify = new Button(this, _("Verify"));
75 overall_sizer->Add(_verify, 0, wxEXPAND | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER);
77 _progress_panel = new VerifyDCPProgressPanel(this);
78 overall_sizer->Add(_progress_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
80 _result_panel = new VerifyDCPResultPanel(this);
81 overall_sizer->Add(_result_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
83 SetSizerAndFit(overall_sizer);
85 _dcp->Changed.connect(boost::bind(&DOMFrame::setup_sensitivity, this));
86 _verify->bind(&DOMFrame::verify_clicked, this);
92 void setup_sensitivity()
94 _verify->Enable(!_dcp->GetPath().IsEmpty());
99 auto dcp = boost::filesystem::path(wx_to_std(_dcp->GetPath()));
104 auto job_manager = JobManager::instance();
105 auto job = make_shared<VerifyDCPJob>(std::vector<boost::filesystem::path>{dcp}, std::vector<boost::filesystem::path>());
106 job_manager->add(job);
108 while (job_manager->work_to_do()) {
109 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
110 dcpomatic_sleep_seconds(1);
112 _progress_panel->update(job);
115 _result_panel->fill(job);
116 if (_write_log->get()) {
117 dcp::TextFormatter formatter(dcp / "REPORT.txt");
118 dcp::verify_report(job->result(), formatter);
123 CheckBox* _write_log;
125 VerifyDCPProgressPanel* _progress_panel;
126 VerifyDCPResultPanel* _result_panel;
131 * @brief The magic App class for wxWidgets.
133 class App : public wxApp
139 dcpomatic_setup_path_encoding();
140 #ifdef DCPOMATIC_LINUX
146 bool OnInit() override
149 SetAppName(_("DCP-o-matic Verifier"));
151 if (!wxApp::OnInit()) {
155 #ifdef DCPOMATIC_LINUX
156 unsetenv("UBUNTU_MENUPROXY");
160 dcpomatic_sleep_seconds(1);
161 make_foreground_application();
164 /* Enable i18n; this will create a Config object
165 to look for a force-configured language. This Config
166 object will be wrong, however, because dcpomatic_setup
167 hasn't yet been called and there aren't any filters etc.
170 dcpomatic_setup_i18n();
172 /* Set things up, including filters etc.
173 which will now be internationalised correctly.
177 /* Force the configuration to be re-loaded correctly next
182 _frame = new DOMFrame(_("DCP-o-matic Verifier"));
183 SetTopWindow(_frame);
184 _frame->SetSize({480, 640});
189 error_dialog(nullptr, wxString::Format("DCP-o-matic Verifier could not start."), std_to_wx(e.what()));
195 void report_exception()
199 } catch (FileError& e) {
203 _("An exception occurred: %s (%s)\n\n") + REPORT_PROBLEM,
205 std_to_wx(e.file().string().c_str())
208 } catch (boost::filesystem::filesystem_error& e) {
212 _("An exception occurred: %s (%s) (%s)\n\n") + REPORT_PROBLEM,
214 std_to_wx(e.path1().string()),
215 std_to_wx(e.path2().string())
218 } catch (exception& e) {
222 _("An exception occurred: %s.\n\n") + REPORT_PROBLEM,
227 error_dialog(nullptr, _("An unknown exception occurred.") + " " + REPORT_PROBLEM);
231 /* An unhandled exception has occurred inside the main event loop */
232 bool OnExceptionInMainLoop() override
238 void OnUnhandledException() override
243 DOMFrame* _frame = nullptr;