Separate GUI verifier with basic reporting (#1823).
authorCarl Hetherington <cth@carlh.net>
Tue, 9 Apr 2024 00:02:28 +0000 (02:02 +0200)
committerCarl Hetherington <cth@carlh.net>
Wed, 17 Apr 2024 07:36:45 +0000 (09:36 +0200)
43 files changed:
cscript
graphics/linux/128/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/16/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/22/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/256/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/32/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/48/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/512/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/linux/64/dcpomatic2_verifier.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.icns [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png [new file with mode: 0644]
graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png [new file with mode: 0644]
graphics/src/dcpomatic2_verifier.svg [new file with mode: 0644]
graphics/update
graphics/windows/dcpomatic2_verifier.ico [new file with mode: 0644]
graphics/wscript
platform/linux/dcpomatic_verifier.desktop.in [new file with mode: 0644]
platform/linux/wscript
platform/osx/dcpomatic2_verifier.Info.plist.in [new file with mode: 0644]
platform/osx/make_dmg.sh
platform/osx/wscript
platform/windows/dcpomatic2_verifier.bat [new file with mode: 0644]
platform/windows/dcpomatic_verifier.rc [new file with mode: 0644]
platform/windows/wscript
run/dcpomatic_verifier [new file with mode: 0755]
src/lib/config.cc
src/lib/verify_dcp_job.cc
src/lib/verify_dcp_job.h
src/tools/dcpomatic_verifier.cc [new file with mode: 0644]
src/tools/wscript
src/wx/verify_dcp_result_dialog.cc
src/wx/verify_dcp_result_panel.cc
src/wx/verify_dcp_result_panel.h
test/reels_test.cc
test/test.cc

diff --git a/cscript b/cscript
index 4bef0f3d7be9ae8473032eb2603d394c3d2aa477..5d931f471de0f35a446c506a87d8af7ec691ce09 100644 (file)
--- a/cscript
+++ b/cscript
@@ -431,6 +431,7 @@ def make_spec(filename, version, target, options, requires=None):
     print('%{_bindir}/dcpomatic2_openssl', file=f)
     print('%{_bindir}/dcpomatic2_combiner', file=f)
     print('%{_bindir}/dcpomatic2_verify_cli', file=f)
+    print('%{_bindir}/dcpomatic2_verifier', file=f)
     print('%{_bindir}/dcpomatic2_kdm_inspect', file=f)
     print('%{_bindir}/dcpomatic2_map', file=f)
     if can_build_disk(target):
@@ -439,6 +440,7 @@ def make_spec(filename, version, target, options, requires=None):
     print('%{_datadir}/applications/dcpomatic2.desktop', file=f)
     print('%{_datadir}/applications/dcpomatic2_batch.desktop', file=f)
     print('%{_datadir}/applications/dcpomatic2_editor.desktop', file=f)
+    print('%{_datadir}/applications/dcpomatic2_verifier.desktop', file=f)
     print('%{_datadir}/applications/dcpomatic2_server.desktop', file=f)
     print('%{_datadir}/applications/dcpomatic2_kdm.desktop', file=f)
     print('%{_datadir}/applications/dcpomatic2_player.desktop', file=f)
@@ -472,6 +474,7 @@ def make_spec(filename, version, target, options, requires=None):
         print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2.png' % r, file=f)
         print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_batch.png' % r, file=f)
         print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_editor.png' % r, file=f)
+        print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_verifier.png' % r, file=f)
         print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_kdm.png' % r, file=f)
         print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_server.png' % r, file=f)
         print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_player.png' % r, file=f)
@@ -535,7 +538,7 @@ def dependencies(target, options):
         # Use distro-provided FFmpeg on Arch
         deps = []
 
-    deps.append(('libdcp', '56b3586247d76b2d07911018ccba63d4b05f4995', {'c++17': target.platform == 'osx'}))
+    deps.append(('libdcp', 'v1.9.5', {'c++17': target.platform == 'osx'}))
     deps.append(('libsub', 'v1.6.47'))
     deps.append(('leqm-nrt', '30dcaea1373ac62fba050e02ce5b0c1085797a23'))
     deps.append(('rtaudio', 'f619b76'))
@@ -874,6 +877,7 @@ def package(target, version, options):
             out.append(make_appimage(target, 'DCP-o-matic Encode Server', 'dcpomatic2_server', version))
             out.append(make_appimage(target, 'DCP-o-matic Combiner', 'dcpomatic2_combiner', version))
             out.append(make_appimage(target, 'DCP-o-matic Editor', 'dcpomatic2_editor', version))
+            out.append(make_appimage(target, 'DCP-o-matic Verifier', 'dcpomatic2_verifier', version))
             return out
         else:
             if target.bits == 32:
diff --git a/graphics/linux/128/dcpomatic2_verifier.png b/graphics/linux/128/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..d28ceb2
Binary files /dev/null and b/graphics/linux/128/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/16/dcpomatic2_verifier.png b/graphics/linux/16/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..9ad2929
Binary files /dev/null and b/graphics/linux/16/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/22/dcpomatic2_verifier.png b/graphics/linux/22/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..dbe6cbd
Binary files /dev/null and b/graphics/linux/22/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/256/dcpomatic2_verifier.png b/graphics/linux/256/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..f5198a7
Binary files /dev/null and b/graphics/linux/256/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/32/dcpomatic2_verifier.png b/graphics/linux/32/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..61afb5f
Binary files /dev/null and b/graphics/linux/32/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/48/dcpomatic2_verifier.png b/graphics/linux/48/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..5f5188e
Binary files /dev/null and b/graphics/linux/48/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/512/dcpomatic2_verifier.png b/graphics/linux/512/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..b8417ed
Binary files /dev/null and b/graphics/linux/512/dcpomatic2_verifier.png differ
diff --git a/graphics/linux/64/dcpomatic2_verifier.png b/graphics/linux/64/dcpomatic2_verifier.png
new file mode 100644 (file)
index 0000000..b17249b
Binary files /dev/null and b/graphics/linux/64/dcpomatic2_verifier.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.icns b/graphics/osx/dcpomatic2_verifier.icns
new file mode 100644 (file)
index 0000000..ffd2336
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.icns differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png
new file mode 100644 (file)
index 0000000..d28ceb2
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png
new file mode 100644 (file)
index 0000000..d28ceb2
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png
new file mode 100644 (file)
index 0000000..9ad2929
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png
new file mode 100644 (file)
index 0000000..9ad2929
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png
new file mode 100644 (file)
index 0000000..f5198a7
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png
new file mode 100644 (file)
index 0000000..f5198a7
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png
new file mode 100644 (file)
index 0000000..61afb5f
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png
new file mode 100644 (file)
index 0000000..61afb5f
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png
new file mode 100644 (file)
index 0000000..b8417ed
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png
new file mode 100644 (file)
index 0000000..b8417ed
Binary files /dev/null and b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png differ
diff --git a/graphics/src/dcpomatic2_verifier.svg b/graphics/src/dcpomatic2_verifier.svg
new file mode 100644 (file)
index 0000000..5572f0a
--- /dev/null
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   viewBox="0 0 960.00004 960.00004"
+   sodipodi:docname="dcpomatic2_verifier.svg"
+   inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+   version="1.1"
+   id="svg2"
+   height="1024"
+   width="1024"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="Arrow1Mstart"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mstart">
+      <path
+         transform="matrix(0.4,0,0,0.4,4,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path893" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1193"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path1191" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1189"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path1187" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1167"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path1165" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="Arrow1Lend"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path890" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="Arrow1Lstart"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path887" />
+    </marker>
+    <linearGradient
+       id="linearGradient3594"
+       y2="742.5"
+       gradientUnits="userSpaceOnUse"
+       x2="-886.76001"
+       gradientTransform="matrix(-0.84033,-0.84033,-0.84033,0.84033,136.32259,-691.39649)"
+       y1="742.5"
+       x1="-772.01001">
+      <stop
+         id="stop4687"
+         stop-color="#fff"
+         offset="0" />
+      <stop
+         id="stop4689"
+         stop-color="#fff"
+         stop-opacity="0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3601"
+       y2="613.94"
+       gradientUnits="userSpaceOnUse"
+       x2="385.04001"
+       gradientTransform="matrix(0.70711,-0.70711,0.70711,0.70711,-203.97741,756.21351)"
+       y1="63.870998"
+       x1="386.39001">
+      <stop
+         id="stop3797"
+         stop-color="#ffe800"
+         offset="0" />
+      <stop
+         id="stop3799"
+         stop-color="#dfb300"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3609"
+       y2="161.84"
+       gradientUnits="userSpaceOnUse"
+       x2="212.92999"
+       y1="358.29999"
+       x1="409.38"
+       gradientTransform="translate(-77.797413,384.00351)">
+      <stop
+         id="stop4034"
+         stop-color="#dfb300"
+         offset="0" />
+      <stop
+         id="stop3374"
+         stop-color="#dfb300"
+         offset=".5" />
+      <stop
+         id="stop3376"
+         stop-color="#dfb300"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3632"
+       y2="448.35001"
+       gradientUnits="userSpaceOnUse"
+       x2="382.89999"
+       gradientTransform="matrix(0.70711,-0.70711,0.70711,0.70711,-203.97741,756.21351)"
+       y1="448.35001"
+       x1="403.63">
+      <stop
+         id="stop3636"
+         stop-color="#ffe800"
+         stop-opacity=".39216"
+         offset="0" />
+      <stop
+         id="stop3638"
+         stop-color="#dfb300"
+         stop-opacity=".39216"
+         offset="1" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     inkscape:snap-midpoints="true"
+     inkscape:document-rotation="0"
+     inkscape:window-maximized="1"
+     inkscape:window-y="0"
+     inkscape:window-x="1920"
+     inkscape:window-height="1048"
+     inkscape:window-width="1920"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:document-units="px"
+     inkscape:cy="799.70529"
+     inkscape:cx="784.52101"
+     inkscape:zoom="0.49393196"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:pagecheckerboard="0"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-bbox="true"
+     inkscape:snap-bbox-midpoints="true"
+     inkscape:snap-global="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     transform="translate(0,-52.362188)"
+     id="layer1"
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1">
+    <g
+       id="g1445"
+       transform="translate(-10.670155,-28.024289)">
+      <image
+         xlink:href="dcpomatic.png"
+         id="image4358"
+         preserveAspectRatio="none"
+         height="960.00006"
+         width="960.00006"
+         x="10.670144"
+         y="80.386467" />
+      <rect
+         style="font-variation-settings:normal;opacity:0.792898;vector-effect:none;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:14.2122;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000"
+         id="rect1581"
+         width="232.89954"
+         height="83.860855"
+         x="797.59167"
+         y="-15.120205"
+         transform="matrix(0.69206236,0.72183772,-0.69206236,0.72183772,0,0)" />
+      <circle
+         style="font-variation-settings:normal;opacity:0.792898;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:23.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
+         id="path1076"
+         cx="424.06757"
+         cy="478.95279"
+         r="167.43817" />
+    </g>
+  </g>
+</svg>
index 46964470ba039c7f11852143ba6ab6b6c731920d..f04ce3fea3794bbd31c0cc3eab08a8d3ab3831ff 100755 (executable)
@@ -25,7 +25,7 @@ function required_font()
     fi
 }
 
-svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner dcpomatic2_editor"
+svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner dcpomatic2_editor dcpomatic2_verifier"
 
 
 if [ `uname -s` == "Darwin" ]; then
diff --git a/graphics/windows/dcpomatic2_verifier.ico b/graphics/windows/dcpomatic2_verifier.ico
new file mode 100644 (file)
index 0000000..2a85de4
Binary files /dev/null and b/graphics/windows/dcpomatic2_verifier.ico differ
index 663e282875d0275d92cea7e48157ad5e5ea3d2b0..287a6dec43e82644254b7055e92e25744b5c7b06 100644 (file)
@@ -32,7 +32,8 @@ def build(bld):
                 'dcpomatic2_playlist',
                 'dcpomatic2_disk',
                 'dcpomatic2_combiner',
-                'dcpomatic2_editor']:
+                'dcpomatic2_editor',
+                'dcpomatic2_verifier']:
                 bld.install_files('${PREFIX}/share/icons/hicolor/%dx%d/apps' % (r, r), 'linux/%d/%s.png' % (r, p))
 
     # Install stuff for POSIX systems
diff --git a/platform/linux/dcpomatic_verifier.desktop.in b/platform/linux/dcpomatic_verifier.desktop.in
new file mode 100644 (file)
index 0000000..b52a6fc
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Terminal=false
+Exec=@INSTALL_PREFIX@/bin/dcpomatic2_verifier
+Name=DCP-o-matic 2 Verifier
+Icon=dcpomatic2_verifier
+Comment=DCP generator
+Categories=AudioVideo;Video
index 98aff905d9c8fb6d2bec8b1dbf422c014e32f125..4a3516fd00e36f5cc7652206873fa0a3be2161e4 100644 (file)
@@ -16,6 +16,7 @@ def build(bld):
             desktop(bld, '_playlist'),
             desktop(bld, '_combiner'),
             desktop(bld, '_editor'),
+            desktop(bld, '_verifier'),
         ]
 
     if bld.env.ENABLE_DISK:
diff --git a/platform/osx/dcpomatic2_verifier.Info.plist.in b/platform/osx/dcpomatic2_verifier.Info.plist.in
new file mode 100644 (file)
index 0000000..d88a8ce
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>dcpomatic2_verifier</string>
+       <key>CFBundleGetInfoString</key>
+       <string>DCP-o-matic 2 Verifier</string>
+       <key>CFBundleIconFile</key>
+       <string>dcpomatic2_verifier.icns</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.dcpomatic.verifier</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>DCP-o-matic 2 Verifier</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersions</key>
+       <string>@VERSION@</string>
+       <key>CFBundleSignature</key>
+       <string>DOMC</string>
+       <key>CFBundleVersion</key>
+       <string>@VERSION@</string>
+       <key>CFBundleAllowMixedLocalizations</key>
+       <true/>
+       <key>LSUIElement</key>
+       <string>0</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
index be4394649a2862f820b1c14d17406d7d0bbcff5c..a223556af3376ee7b957e81e9aad24dd56265bdb 100644 (file)
@@ -7,7 +7,7 @@ SYNTAX="make_dmg.sh -e <environment> -r <builddir> -i <apple-id> -p <apple-passw
 # Don't set -e here as egrep (used a few times) returns 1 if no matches
 # were found.
 
-BUILD="main kdm server batch player playlist combiner editor disk"
+BUILD="main kdm server batch player playlist combiner editor disk verifier"
 while getopts "e:r:i:p:a:b:" o; do
        case "${o}" in
                e)
@@ -227,6 +227,7 @@ function copy_resources {
     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_disk.icns "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_combiner.icns "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_editor.icns "$dest"
+    cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_verifier.icns "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults*.png "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email*.png "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/preferences/email*.png "$dest"
@@ -592,6 +593,19 @@ if [[ "$BUILD" == *editor* ]]; then
        make_dmg "$appdir" "" "DCP-o-matic Editor" "dcpomatic2_verify_cli dcpomatic2_kdm_inspect openssl dcpomatic2_editor"
 fi
 
+if [[ "$BUILD" == *verifier* ]]; then
+       # DCP-o-matic Verifier
+       setup "DCP-o-matic 2 Verifier.app"
+       copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_verifier "$approot/MacOS"
+       copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
+       copy_verify
+       copy_kdm
+       cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_verifier.Info.plist "$approot/Info.plist"
+       rl=("$approot/MacOS/dcpomatic2_verifier" "$approot/Frameworks/"*.dylib)
+       relink_relative "${rl[@]}"
+       make_dmg "$appdir" "" "DCP-o-matic Verifier" "dcpomatic2_verify_cli dcpomatic2_kdm_inspect openssl dcpomatic2_verifier"
+fi
+
 if [[ "$BUILD" == *disk* ]]; then 
        # DCP-o-matic Disk Writer .app
        setup "DCP-o-matic 2 Disk Writer.app"
index fd6733a66f987e5e6438b7d8ed29409df1f8062f..cdb018473f53632341d65ad811ccc9ac9fa2437a 100644 (file)
@@ -8,3 +8,4 @@ def build(bld):
     obj = bld(features='subst', source='dcpomatic2_disk.Info.plist.in', target='dcpomatic2_disk.Info.plist', version=bld.env.VERSION)
     obj = bld(features='subst', source='dcpomatic2_combiner.Info.plist.in', target='dcpomatic2_combiner.Info.plist', version=bld.env.VERSION)
     obj = bld(features='subst', source='dcpomatic2_editor.Info.plist.in', target='dcpomatic2_editor.Info.plist', version=bld.env.VERSION)
+    obj = bld(features='subst', source='dcpomatic2_verifier.Info.plist.in', target='dcpomatic2_verifier.Info.plist', version=bld.env.VERSION)
diff --git a/platform/windows/dcpomatic2_verifier.bat b/platform/windows/dcpomatic2_verifier.bat
new file mode 100644 (file)
index 0000000..d8850d9
--- /dev/null
@@ -0,0 +1 @@
+gdb.exe -x gdb_script dcpomatic2_verifier.exe > %HOMEPATH%/Documents/dcpomatic_debug_log.txt
diff --git a/platform/windows/dcpomatic_verifier.rc b/platform/windows/dcpomatic_verifier.rc
new file mode 100644 (file)
index 0000000..8f1ba07
--- /dev/null
@@ -0,0 +1,2 @@
+id ICON "../../graphics/windows/dcpomatic2_verifier.ico"
+#include "wx-3.1/wx/msw/wx.rc"
index 13927f1705931e0f9f5f7b6615b2936782f97520..c6718db41e0391044a09517e360e566634ee1de8 100644 (file)
@@ -22,6 +22,7 @@ def write_installer(bits, dcpomatic_version, debug, disk):
         ('combiner', 'Combiner'),
         ('editor', 'Editor'),
         ('map', 'Map'),
+        ('verifier', 'Verifier'),
     ]
 
     if disk:
diff --git a/run/dcpomatic_verifier b/run/dcpomatic_verifier
new file mode 100755 (executable)
index 0000000..a87c3d4
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+source $DIR/environment
+binary=$build/src/tools/dcpomatic2_verifier
+
+if [[ "$(uname -m)" == arm64 ]]; then
+    env=arm64/11.0
+else
+    env=x86_64/10.10
+fi
+
+export DYLD_LIBRARY_PATH=/Users/cah/osx-environment/$env/lib:/usr/local/lib
+
+if [ "$1" == "--debug" ]; then
+    shift
+    if [[ "$(uname)" == Darwin ]]; then
+        /Applications/Xcode.app/Contents/Developer/usr/bin/lldb $binary $*
+    else
+        gdb --args $binary $*
+    fi
+else
+    $binary $* 2> >(grep -v Gtk-CRITICAL | grep -v Gtk-WARNING)
+fi
index c80ef224e922391c142014fe909f3e5b08732030..21192ad30ce3078772dde7441ce297c8f8354fa4 100644 (file)
@@ -200,6 +200,7 @@ Config::set_defaults ()
        _initial_paths["CinemaDatabasePath"] = boost::none;
        _initial_paths["ConfigFilePath"] = boost::none;
        _initial_paths["Preferences"] = boost::none;
+       _initial_paths["SaveVerificationReport"] = boost::none;
        _use_isdcf_name_by_default = true;
        _write_kdms_to_disk = true;
        _email_kdms = false;
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..d7ac21d412204e72bb0d5c5270d38713f0038153 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::VerificationResult const& 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::VerificationResult _result;
 };
diff --git a/src/tools/dcpomatic_verifier.cc b/src/tools/dcpomatic_verifier.cc
new file mode 100644 (file)
index 0000000..382516a
--- /dev/null
@@ -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)
index c3b2b5fe03b850228ec3bf74f07724c9858a71f7..65e4d0e4c5fa10c5029549068747416b08b8bc9a 100644 (file)
@@ -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')
 
index 9617878c581aecaf5135b6919776406ceba06db2..806eac85a9d8889317a6e8f06190fc034a1b7936 100644 (file)
@@ -44,5 +44,4 @@ VerifyDCPResultDialog::VerifyDCPResultDialog(wxWindow* parent, shared_ptr<Verify
        SetSizer (sizer);
        sizer->Layout ();
        sizer->SetSizeHints (this);
-
 }
index 4920ab350965534615ba021a1218d09eef98576b..bfeb14640ade6fec95514b44eedc843bd2949225 100644 (file)
 */
 
 
+#include "dcpomatic_button.h"
+#include "file_dialog.h"
 #include "verify_dcp_result_panel.h"
 #include "wx_util.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>
@@ -56,6 +59,13 @@ VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
        _summary = new wxStaticText(this, wxID_ANY, wxT(""));
        sizer->Add(_summary, 0, wxALL, DCPOMATIC_DIALOG_BORDER);
 
+       auto save_sizer = new wxBoxSizer(wxHORIZONTAL);
+       _save_text_report = new Button(this, _("Save report as text..."));
+       save_sizer->Add(_save_text_report, 0, wxALL, DCPOMATIC_SIZER_GAP);
+       _save_html_report = new Button(this, _("Save report as HTML..."));
+       save_sizer->Add(_save_html_report, 0, wxALL, DCPOMATIC_SIZER_GAP);
+       sizer->Add(save_sizer);
+
        SetSizer(sizer);
        sizer->Layout();
        sizer->SetSizeHints(this);
@@ -63,13 +73,19 @@ VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
        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);
+
+       _save_text_report->Enable(false);
+       _save_html_report->Enable(false);
 }
 
 
 void
 VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
 {
-       if (job->finished_ok() && job->notes().empty()) {
+       if (job->finished_ok() && job->result().notes.empty()) {
                _summary->SetLabel(_("DCP validates OK."));
                return;
        }
@@ -132,7 +148,7 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
                ++counts[dcp::VerificationNote::Type::ERROR];
        }
 
-       for (auto i: job->notes()) {
+       for (auto i: job->result().notes) {
                switch (i.code()) {
                case dcp::VerificationNote::Code::FAILED_READ:
                        add(i, _("Could not read DCP (%n)"));
@@ -448,6 +464,19 @@ VerifyDCPResultPanel::fill(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::MATCHING_CPL_HASHES:
+               case dcp::VerificationNote::Code::CORRECT_PICTURE_HASH:
+               case dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES:
+               case dcp::VerificationNote::Code::VALID_RELEASE_TERRITORY:
+               case dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT:
+               case dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL:
+               case dcp::VerificationNote::Code::ALL_ENCRYPTED:
+               case dcp::VerificationNote::Code::NONE_ENCRYPTED:
+               case dcp::VerificationNote::Code::VALID_CONTENT_KIND:
+               case dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA:
+               case dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT:
+                       /* These are all "OK" messages which we don't report here */
+                       break;
                }
        }
 
@@ -490,5 +519,39 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
        if (counts[dcp::VerificationNote::Type::WARNING] == 0) {
                add_bullet(dcp::VerificationNote::Type::WARNING, _("No warnings found."));
        }
+
+       _job = job;
+       _save_text_report->Enable(true);
+       _save_html_report->Enable(true);
+}
+
+
+template <class T>
+void save(wxWindow* parent, wxString filter, dcp::VerificationResult const& result)
+{
+       FileDialog dialog(parent, _("Verification report"), filter, wxFD_SAVE | wxFD_OVERWRITE_PROMPT, "SaveVerificationReport");
+       if (!dialog.show()) {
+               return;
+       }
+
+       T formatter(dialog.path());
+       dcp::verify_report(result, formatter);
 }
 
+
+void
+VerifyDCPResultPanel::save_text_report()
+{
+       if (_job) {
+               save<dcp::TextFormatter>(this, wxT("Text files (*.txt)|*.txt"), _job->result());
+       }
+}
+
+
+void
+VerifyDCPResultPanel::save_html_report()
+{
+       if (_job) {
+               save<dcp::HTMLFormatter>(this, wxT("HTML files (*.htm;*html)|*.htm;*.html"), _job->result());
+       }
+}
index f0a502064c58329e5fcebb430825dc5897a48a76..8cf92118b6acdd7ea559430bbac4d7065211cc1f 100644 (file)
@@ -25,6 +25,7 @@
 #include <memory>
 
 
+class Button;
 class VerifyDCPJob;
 class wxRichTextCtrl;
 
@@ -37,6 +38,13 @@ public:
        void fill(std::shared_ptr<VerifyDCPJob> job);
 
 private:
+       void save_text_report();
+       void save_html_report();
+
        wxStaticText* _summary;
        std::map<dcp::VerificationNote::Type, wxRichTextCtrl*> _pages;
+       Button* _save_text_report;
+       Button* _save_html_report;
+
+       std::shared_ptr<VerifyDCPJob> _job;
 };
index d4a783f91a72a30acd2e08b5ec8385f2d4d5995e..df4bbbbe6dc1a44e699c98229a78b33455231d51 100644 (file)
@@ -54,6 +54,14 @@ using std::vector;
 using namespace dcpomatic;
 
 
+static
+void
+filter_ok(std::vector<dcp::VerificationNote>& notes)
+{
+       notes.erase(std::remove_if(notes.begin(), notes.end(), [](dcp::VerificationNote const& note) { return note.type() == dcp::VerificationNote::Type::OK; }), notes.end());
+}
+
+
 /** Test Film::reels() */
 BOOST_AUTO_TEST_CASE (reels_test1)
 {
@@ -508,9 +516,10 @@ 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());
-       dump_notes (notes);
-       BOOST_REQUIRE (notes.empty());
+       auto result = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       filter_ok(result.notes);
+       dump_notes(result.notes);
+       BOOST_REQUIRE(result.notes.empty());
 }
 
 
@@ -533,9 +542,10 @@ 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());
-       dump_notes (notes);
-       BOOST_REQUIRE (notes.empty());
+       auto result = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       filter_ok(result.notes);
+       dump_notes(result.notes);
+       BOOST_REQUIRE(result.notes.empty());
 }
 
 
@@ -554,9 +564,10 @@ 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());
-       dump_notes (notes);
-       BOOST_REQUIRE (notes.empty());
+       auto result = dcp::verify({}, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       filter_ok(result.notes);
+       dump_notes(result.notes);
+       BOOST_REQUIRE(result.notes.empty());
 }
 
 
@@ -584,9 +595,10 @@ 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());
-       dump_notes (notes);
-       BOOST_REQUIRE (notes.empty());
+       auto result = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+       filter_ok(result.notes);
+       dump_notes(result.notes);
+       BOOST_REQUIRE(result.notes.empty());
 }
 
 
index ff4a3c9c0cafd8f223796c35bd5d36df0ddd05d4..4064f9b0ef0f900a6ededf913e08171f713c7c79 100644 (file)
@@ -965,10 +965,10 @@ 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 result = dcp::verify({dir}, {}, &stage, &progress, {}, TestPaths::xsd());
        bool ok = true;
-       for (auto i: notes) {
-               if (find(ignore.begin(), ignore.end(), i.code()) == ignore.end()) {
+       for (auto i: result.notes) {
+               if (i.type() != dcp::VerificationNote::Type::OK && find(ignore.begin(), ignore.end(), i.code()) == ignore.end()) {
                        std::cout << "\t" << dcp::note_to_string(i) << "\n";
                        ok = false;
                }