(target.platform == 'osx' and target.bits == 64) or
(target.platform == 'windows')) else {}
- deps.append(('libdcp', '184bdd2', cpp_lib_options))
- deps.append(('libsub', '72bf4fc', cpp_lib_options))
+ deps.append(('libdcp', '40f6f7d', cpp_lib_options))
+ deps.append(('libsub', 'c5b7a36', cpp_lib_options))
deps.append(('leqm-nrt', 'carl'))
deps.append(('rtaudio', 'carl'))
# We get our OpenSSL libraries from the environment, but we
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ viewBox="0 0 1000 1000"
+ sodipodi:docname="dcpomatic2_combine.svg"
+ inkscape:version="1.0 (4035a4f, 2020-05-01)"
+ version="1.1"
+ id="svg2"
+ height="1066.6666"
+ width="1066.6666">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Mstart"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow1Mstart">
+ <path
+ transform="scale(0.4) translate(10,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ id="path893" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible;"
+ id="marker1193"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="scale(0.8) rotate(180) translate(12.5,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ id="path1191" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker1189"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="scale(0.8) translate(12.5,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ id="path1187" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker1167"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="scale(0.8) translate(12.5,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ id="path1165" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible;"
+ id="Arrow1Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="scale(0.8) rotate(180) translate(12.5,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ id="path890" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lstart"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="scale(0.8) translate(12.5,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 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="27"
+ inkscape:window-x="0"
+ inkscape:window-height="986"
+ inkscape:window-width="1680"
+ showgrid="false"
+ inkscape:current-layer="layer1"
+ inkscape:document-units="px"
+ inkscape:cy="589.03894"
+ inkscape:cx="-138.64759"
+ inkscape:zoom="0.34926264"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <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" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="translate(0,-52.362188)"
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Layer 1">
+ <image
+ sodipodi:absref="/home/carl/src/dcpomatic/graphics/src/dcpomatic.png"
+ xlink:href="dcpomatic.png"
+ id="image4358"
+ preserveAspectRatio="none"
+ height="960.00006"
+ width="960.00006"
+ x="10.670144"
+ y="80.386467" />
+ <path
+ d="m 490.67101,280.27778 a 46.083593,46.083593 0 0 0 -46.08414,46.08418 V 514.30317 H 256.6457 a 46.083685,46.083685 0 0 0 -46.08423,46.08417 46.083685,46.083685 0 0 0 46.08423,46.08249 h 187.94117 v 187.94291 a 46.083593,46.083593 0 0 0 46.08414,46.08248 46.083593,46.083593 0 0 0 46.08256,-46.08248 V 606.46983 h 187.94284 a 46.083685,46.083685 0 0 0 46.08247,-46.08249 46.083685,46.083685 0 0 0 -46.08247,-46.08417 H 536.75357 V 326.36196 a 46.083593,46.083593 0 0 0 -46.08256,-46.08418 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#5e5e5e;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:15.5608;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;opacity:0.79289843"
+ id="path1288" />
+ </g>
+</svg>
fi
}
-svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk"
+svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner"
required_font "Libre Baskerville"
--- /dev/null
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Terminal=false
+Exec=@INSTALL_PREFIX@/bin/dcpomatic2_combiner
+Name=DCP-o-matic 2 Combiner
+Icon=dcpomatic2_combiner
+Comment=DCP combiner
+Categories=AudioVideo;Video
obj.VERSION = bld.env.VERSION
desktops.append(obj.target)
+ obj = bld(features='subst')
+ obj.source = 'dcpomatic_combiner.desktop.in'
+ obj.target = 'dcpomatic2_combiner.desktop'
+ obj.INSTALL_PREFIX = bld.env.INSTALL_PREFIX
+ obj.VERSION = bld.env.VERSION
+ desktops.append(obj.target)
+
bld.install_files('${PREFIX}/share/applications', desktops)
--- /dev/null
+<?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_combiner</string>
+ <key>CFBundleGetInfoString</key>
+ <string>DCP-o-matic 2 Combiner</string>
+ <key>CFBundleIconFile</key>
+ <string>dcpomatic2_combiner.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.dcpomatic.combiner</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>DCP-o-matic 2 Combiner</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>
cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_batch.icns "$dest"
cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_playlist.icns "$dest"
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/preferences/defaults.png "$dest"
cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults@2x.png "$dest"
cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email.png "$dest"
relink_relative "${rl[@]}"
make_dmg "$appdir" "" "DCP-o-matic Playlist Editor" com.dcpomatic.playlist
+# DCP-o-matic Combiner
+setup "DCP-o-matic 2 Combiner.app"
+copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_combiner "$approot/MacOS"
+copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
+cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_combiner.Info.plist "$approot/Info.plist"
+rl=("$approot/MacOS/dcpomatic2_combiner" "$approot/Frameworks/"*.dylib)
+relink_relative "${rl[@]}"
+make_dmg "$appdir" "" "DCP-o-matic Combiner" com.dcpomatic.combiner
+
# DCP-o-matic Disk Writer .app
setup "DCP-o-matic 2 Disk Writer.app"
copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_disk "$approot/MacOS"
obj = bld(features='subst', source='dcpomatic2_player.Info.plist.in', target='dcpomatic2_player.Info.plist', version=bld.env.VERSION)
obj = bld(features='subst', source='dcpomatic2_playlist.Info.plist.in', target='dcpomatic2_playlist.Info.plist', version=bld.env.VERSION)
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)
--- /dev/null
+gdb.exe -x gdb_script dcpomatic2_combiner.exe > %HOMEPATH%/Documents/dcpomatic_debug_log.txt
--- /dev/null
+id ICON "../../graphics/windows/dcpomatic2_combiner.ico"
+#include "wx-3.0/wx/msw/wx.rc"
('player', 'Player'),
('cli', 'CLI'),
('create', 'Creator'),
- ('playlist', 'Playlist Editor')
+ ('playlist', 'Playlist Editor'),
+ ('combiner', 'Combiner'),
]
if disk:
--- /dev/null
+#!/bin/bash
+
+export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:/home/c.hetherington/lib:$LD_LIBRARY_PATH
+export DYLD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:/Users/c.hetherington/osx-environment/64/lib
+if [ "$1" == "--debug" ]; then
+ shift
+ gdb --args build/src/tools/dcpomatic2_combiner $*
+elif [ "$1" == "--valgrind" ]; then
+ shift
+ valgrind --tool="memcheck" --suppressions=suppressions --track-fds=yes build/src/tools/dcpomatic2_combiner $*
+elif [ "$1" == "--callgrind" ]; then
+ shift
+ valgrind --tool="callgrind" build/src/tools/dcpomatic2_combiner $*
+elif [ "$1" == "--massif" ]; then
+ shift
+ valgrind --tool="massif" build/src/tools/dcpomatic2_combiner $*
+elif [ "$1" == "--i18n" ]; then
+ shift
+ LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 LC_ALL=fr_FR.UTF8 build/src/tools/dcpomatic2_combiner "$*"
+elif [ "$1" == "--perf" ]; then
+ shift
+ perf record build/src/tools/dcpomatic2_combiner $*
+else
+ build/src/tools/dcpomatic2_combiner $*
+fi
--- /dev/null
+/*
+ Copyright (C) 2020 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/>.
+
+*/
+
+
+#include "combine_dcp_job.h"
+#include <dcp/combine.h>
+#include <dcp/exceptions.h>
+
+#include "i18n.h"
+
+
+using std::string;
+using std::vector;
+using boost::shared_ptr;
+
+
+CombineDCPJob::CombineDCPJob (vector<boost::filesystem::path> inputs, boost::filesystem::path output)
+ : Job (shared_ptr<Film>())
+ , _inputs (inputs)
+ , _output (output)
+{
+
+}
+
+
+string
+CombineDCPJob::name () const
+{
+ return _("Combine DCPs");
+}
+
+
+string
+CombineDCPJob::json_name () const
+{
+ return N_("combine_dcps");
+}
+
+
+void
+CombineDCPJob::run ()
+{
+ try {
+ dcp::combine (_inputs, _output);
+ } catch (dcp::CombineError& e) {
+ set_state (FINISHED_ERROR);
+ set_error (e.what(), "");
+ return;
+ } catch (dcp::ReadError& e) {
+ set_state (FINISHED_ERROR);
+ set_error (e.what(), e.detail().get_value_or(""));
+ return;
+ }
+
+ set_progress (1);
+ set_state (FINISHED_OK);
+}
--- /dev/null
+/*
+ Copyright (C) 2020 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/>.
+
+*/
+
+
+#include "job.h"
+#include <boost/filesystem.hpp>
+
+
+class CombineDCPJob : public Job
+{
+public:
+ CombineDCPJob (std::vector<boost::filesystem::path> inputs, boost::filesystem::path output);
+
+ std::string name () const;
+ std::string json_name () const;
+ void run ();
+
+private:
+ std::vector<boost::filesystem::path> _inputs;
+ boost::filesystem::path _output;
+};
+
config.cc
content.cc
content_factory.cc
+ combine_dcp_job.cc
copy_dcp_details_to_film.cc
create_cli.cc
cross_common.cc
--- /dev/null
+/*
+ Copyright (C) 2020 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/>.
+
+*/
+
+
+#include "wx/dir_picker_ctrl.h"
+#include "wx/editable_list.h"
+#include "wx/wx_signal_manager.h"
+#include "lib/combine_dcp_job.h"
+#include "lib/config.h"
+#include "lib/cross.h"
+#include "lib/job_manager.h"
+#include "lib/util.h"
+#include <dcp/combine.h>
+DCPOMATIC_DISABLE_WARNINGS
+#include <wx/filepicker.h>
+DCPOMATIC_ENABLE_WARNINGS
+#include <wx/wx.h>
+#include <boost/bind.hpp>
+#include <boost/filesystem.hpp>
+#include <exception>
+
+
+using std::exception;
+using std::string;
+using std::vector;
+using boost::dynamic_pointer_cast;
+using boost::optional;
+using boost::shared_ptr;
+
+
+static string
+display_string (boost::filesystem::path p, int)
+{
+ return p.filename().string();
+}
+
+
+class DirDialogWrapper : public wxDirDialog
+{
+public:
+ DirDialogWrapper (wxWindow* parent)
+ : wxDirDialog (parent, _("Choose a DCP folder"), wxT(""), wxDD_DIR_MUST_EXIST)
+ {
+
+ }
+
+ boost::filesystem::path get () const
+ {
+ return boost::filesystem::path(wx_to_std(GetPath()));
+ }
+
+ void set (boost::filesystem::path)
+ {
+ /* Not used */
+ }
+};
+
+
+class DOMFrame : public wxFrame
+{
+public:
+ explicit DOMFrame (wxString const & title)
+ : wxFrame (0, -1, title)
+ {
+ /* Use a panel as the only child of the Frame so that we avoid
+ the dark-grey background on Windows.
+ */
+ wxPanel* overall_panel = new wxPanel (this);
+ wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ s->Add (overall_panel, 1, wxEXPAND);
+ SetSizer (s);
+
+ vector<EditableListColumn> columns;
+ columns.push_back(EditableListColumn(_("Input DCP"), 600, true));
+
+ _input = new EditableList<boost::filesystem::path, DirDialogWrapper>(
+ overall_panel,
+ columns,
+ boost::bind(&DOMFrame::inputs, this),
+ boost::bind(&DOMFrame::set_inputs, this, _1),
+ &display_string,
+ false,
+ true
+ );
+
+ wxBoxSizer* output = new wxBoxSizer (wxHORIZONTAL);
+ add_label_to_sizer (output, overall_panel, _("Output DCP folder"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
+ _output = new DirPickerCtrl (overall_panel);
+ output->Add (_output, 1, wxEXPAND);
+
+ _combine = new Button (overall_panel, _("Combine"));
+
+ wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
+ sizer->Add (_input, 1, wxALL | wxEXPAND, DCPOMATIC_DIALOG_BORDER);
+ sizer->Add (output, 0, wxALL | wxEXPAND, DCPOMATIC_DIALOG_BORDER);
+ sizer->Add (_combine, 0, wxALL | wxALIGN_RIGHT, DCPOMATIC_DIALOG_BORDER);
+ overall_panel->SetSizer (sizer);
+ Fit ();
+ SetSize (768, GetSize().GetHeight() + 32);
+
+ _combine->Bind (wxEVT_BUTTON, boost::bind(&DOMFrame::combine, this));
+ _output->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind(&DOMFrame::setup_sensitivity, this));
+
+ setup_sensitivity ();
+ }
+
+private:
+ void set_inputs (vector<boost::filesystem::path> inputs)
+ {
+ _inputs = inputs;
+ }
+
+ vector<boost::filesystem::path> inputs () const
+ {
+ return _inputs;
+ }
+
+ void combine ()
+ {
+ boost::filesystem::path const output = wx_to_std(_output->GetPath());
+
+ if (boost::filesystem::is_directory(output) && !boost::filesystem::is_empty(output)) {
+ if (!confirm_dialog (
+ this,
+ std_to_wx (
+ String::compose(wx_to_std(_("The directory %1 already exists and is not empty. "
+ "Are you sure you want to use it?")),
+ output.string())
+ )
+ )) {
+ return;
+ }
+ } else if (boost::filesystem::is_regular_file(output)) {
+ error_dialog (
+ this,
+ String::compose (wx_to_std(_("%1 already exists as a file, so you cannot use it for a DCP.")), output.string())
+ );
+ return;
+ }
+
+ JobManager* jm = JobManager::instance ();
+ jm->add (shared_ptr<Job>(new CombineDCPJob(_inputs, output)));
+ bool const ok = display_progress (_("DCP-o-matic Combine"), _("Combining DCPs"));
+ if (!ok) {
+ return;
+ }
+
+ DCPOMATIC_ASSERT (!jm->get().empty());
+ shared_ptr<CombineDCPJob> last = dynamic_pointer_cast<CombineDCPJob> (jm->get().back());
+ DCPOMATIC_ASSERT (last);
+
+ if (last->finished_ok()) {
+ message_dialog (this, _("DCPs combined successfully."));
+ } else {
+ wxString m = std_to_wx(last->error_summary());
+ if (!last->error_details().empty()) {
+ m += wxString::Format(" (%s)", std_to_wx(last->error_details()));
+ }
+ error_dialog (this, m);
+ }
+ }
+
+ void setup_sensitivity ()
+ {
+ _combine->Enable (!_output->GetPath().IsEmpty());
+ }
+
+ EditableList<boost::filesystem::path, DirDialogWrapper>* _input;
+ DirPickerCtrl* _output;
+ vector<boost::filesystem::path> _inputs;
+ Button* _combine;
+};
+
+
+class App : public wxApp
+{
+public:
+ App ()
+ : _frame (0)
+ {}
+
+ bool OnInit ()
+ {
+ try {
+ Config::FailedToLoad.connect (boost::bind (&App::config_failed_to_load, this));
+ Config::Warning.connect (boost::bind (&App::config_warning, this, _1));
+
+ SetAppName (_("DCP-o-matic Combiner"));
+
+ if (!wxApp::OnInit()) {
+ return false;
+ }
+
+#ifdef DCPOMATIC_LINUX
+ unsetenv ("UBUNTU_MENUPROXY");
+#endif
+
+#ifdef DCPOMATIC_OSX
+ make_foreground_application ();
+#endif
+
+ dcpomatic_setup_path_encoding ();
+
+ /* 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 DCP Combiner"));
+ SetTopWindow (_frame);
+
+ _frame->Show ();
+
+ signal_manager = new wxSignalManager (this);
+ Bind (wxEVT_IDLE, boost::bind(&App::idle, this, _1));
+ }
+ catch (exception& e)
+ {
+ error_dialog (0, wxString::Format ("DCP-o-matic DCP Combiner could not start."), std_to_wx(e.what()));
+ return false;
+ }
+
+ return true;
+ }
+
+ void config_failed_to_load ()
+ {
+ message_dialog (_frame, _("The existing configuration failed to load. Default values will be used instead. These may take a short time to create."));
+ }
+
+ void config_warning (string m)
+ {
+ message_dialog (_frame, std_to_wx(m));
+ }
+
+ void idle (wxIdleEvent& ev)
+ {
+ signal_manager->ui_idle ();
+ ev.Skip ();
+ }
+
+ void report_exception ()
+ {
+ try {
+ throw;
+ } catch (FileError& e) {
+ error_dialog (
+ 0,
+ 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 (exception& e) {
+ error_dialog (
+ 0,
+ wxString::Format (
+ _("An exception occurred: %s.\n\n") + REPORT_PROBLEM,
+ std_to_wx (e.what ())
+ )
+ );
+ } catch (...) {
+ error_dialog (0, _("An unknown exception occurred.") + " " + REPORT_PROBLEM);
+ }
+ }
+
+ bool OnExceptionInMainLoop ()
+ {
+ report_exception ();
+ /* This will terminate the program */
+ return false;
+ }
+
+ void OnUnhandledException ()
+ {
+ report_exception ();
+ }
+
+ DOMFrame* _frame;
+};
+
+IMPLEMENT_APP (App)
#
-# Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+# Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
#
# This file is part of DCP-o-matic.
#
elif bld.env.VARIANT == 'swaroop-studio':
gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'swaroop_dcpomatic_playlist']
else:
- gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist']
+ gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist', 'dcpomatic_combiner']
if bld.env.ENABLE_DISK:
gui_tools.append('dcpomatic_disk')