+ double required;
+ double available;
+ bool can_hard_link;
+
+ if (!_film->should_be_enough_disk_space (required, available, can_hard_link)) {
+ wxString message;
+ if (can_hard_link) {
+ message = wxString::Format (_("The DCP for this film will take up about %.1f Gb, and the disk that you are using only has %.1f Gb available. Do you want to continue anyway?"), required, available);
+ } else {
+ message = wxString::Format (_("The DCP and intermediate files for this film will take up about %.1f Gb, and the disk that you are using only has %.1f Gb available. You would need half as much space if the filesystem supported hard links, but it does not. Do you want to continue anyway?"), required, available);
+ }
+ if (!confirm_dialog (this, message)) {
+ return;
+ }
+ }
+
+ if (!get_hints(_film).empty() && Config::instance()->show_hints_before_make_dcp()) {
+ HintsDialog* hints = new HintsDialog (this, _film, false);
+ int const r = hints->ShowModal();
+ hints->Destroy ();
+ if (r == wxID_CANCEL) {
+ return;
+ }
+ }
+
+ if (_film->encrypted ()) {
+ NagDialog::maybe_nag (
+ this,
+ Config::NAG_ENCRYPTED_METADATA,
+ _("You are making an encrypted DCP. It will not be possible to make KDMs for this DCP unless you have copies of "
+ "the <tt>metadata.xml</tt> file within the film and the metadata files within the DCP.\n\n"
+ "You should ensure that these files are <span weight=\"bold\" size=\"larger\">BACKED UP</span> "
+ "if you want to make KDMs for this film.")
+ );
+ }
+
+ /* Remove any existing DCP if the user agrees */
+ boost::filesystem::path const dcp_dir = _film->dir (_film->dcp_name(), false);
+ if (boost::filesystem::exists (dcp_dir)) {
+ if (!confirm_dialog (this, wxString::Format (_("Do you want to overwrite the existing DCP %s?"), std_to_wx(dcp_dir.string()).data()))) {
+ return;
+ }
+ boost::filesystem::remove_all (dcp_dir);
+ }
+
+ try {
+ /* It seems to make sense to auto-save metadata here, since the make DCP may last
+ a long time, and crashes/power failures are moderately likely.
+ */
+ _film->write_metadata ();
+ _film->make_dcp ();
+ } catch (BadSettingError& e) {
+ error_dialog (this, wxString::Format (_("Bad setting for %s."), std_to_wx(e.setting()).data()), std_to_wx(e.what()));
+ } catch (std::exception& e) {
+ error_dialog (this, wxString::Format (_("Could not make DCP.")), std_to_wx(e.what()));
+ }
+ }
+
+ void jobs_make_kdms ()
+ {
+ if (!_film) {
+ return;
+ }
+
+ if (_kdm_dialog) {
+ _kdm_dialog->Destroy ();
+ _kdm_dialog = 0;
+ }
+
+ _kdm_dialog = new KDMDialog (this, _film);
+ _kdm_dialog->Show ();
+ }
+
+ void jobs_make_dcp_batch ()
+ {
+ if (!_film) {
+ return;
+ }
+
+ if (!get_hints(_film).empty() && Config::instance()->show_hints_before_make_dcp()) {
+ HintsDialog* hints = new HintsDialog (this, _film, false);
+ int const r = hints->ShowModal();
+ hints->Destroy ();
+ if (r == wxID_CANCEL) {
+ return;
+ }
+ }
+
+ _film->write_metadata ();
+
+ /* i = 0; try to connect via socket
+ i = 1; try again, and then try to start the batch converter
+ i = 2 onwards; try again.
+ */
+ for (int i = 0; i < 8; ++i) {
+ try {
+ boost::asio::io_service io_service;
+ boost::asio::ip::tcp::resolver resolver (io_service);
+ boost::asio::ip::tcp::resolver::query query ("127.0.0.1", raw_convert<string> (BATCH_JOB_PORT));
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query);
+ Socket socket (5);
+ socket.connect (*endpoint_iterator);
+ DCPOMATIC_ASSERT (_film->directory ());
+ string s = _film->directory()->string ();
+ socket.write (s.length() + 1);
+ socket.write ((uint8_t *) s.c_str(), s.length() + 1);
+ /* OK\0 */
+ uint8_t ok[3];
+ socket.read (ok, 3);
+ return;
+ } catch (exception& e) {
+
+ }
+
+ if (i == 1) {
+ start_batch_converter (wx_to_std (wxStandardPaths::Get().GetExecutablePath()));
+ }
+
+ dcpomatic_sleep (1);
+ }
+
+ error_dialog (this, _("Could not find batch converter."));
+ }
+
+ void jobs_make_self_dkdm ()
+ {
+ if (!_film) {
+ return;
+ }
+
+ SelfDKDMDialog* d = new SelfDKDMDialog (this, _film);
+ if (d->ShowModal () != wxID_OK) {
+ d->Destroy ();
+ return;
+ }
+
+ NagDialog::maybe_nag (
+ this,
+ Config::NAG_DKDM_CONFIG,
+ wxString::Format (
+ _("You are making a DKDM which is encrypted by a private key held in"
+ "\n\n<tt>%s</tt>\n\nIt is <span weight=\"bold\" size=\"larger\">VITALLY IMPORTANT</span> "
+ "that you <span weight=\"bold\" size=\"larger\">BACK UP THIS FILE</span> since if it is lost "
+ "your DKDMs (and the DCPs they protect) will become useless."), std_to_wx(Config::config_file().string()).data()
+ )
+ );
+
+ optional<dcp::EncryptedKDM> kdm;
+ try {
+ kdm = _film->make_kdm (
+ Config::instance()->decryption_chain()->leaf(),
+ vector<dcp::Certificate> (),
+ d->cpl (),
+ dcp::LocalTime ("2012-01-01T01:00:00+00:00"),
+ dcp::LocalTime ("2112-01-01T01:00:00+00:00"),
+ dcp::MODIFIED_TRANSITIONAL_1
+ );
+ } catch (dcp::NotEncryptedError& e) {
+ error_dialog (this, _("CPL's content is not encrypted."));
+ } catch (exception& e) {
+ error_dialog (this, e.what ());
+ } catch (...) {
+ error_dialog (this, _("An unknown exception occurred."));
+ }
+
+ if (kdm) {
+ if (d->internal ()) {
+ shared_ptr<DKDMGroup> dkdms = Config::instance()->dkdms ();
+ dkdms->add (shared_ptr<DKDM> (new DKDM (kdm.get())));
+ Config::instance()->changed ();
+ } else {
+ boost::filesystem::path path = d->directory() / (_film->dcp_name(false) + "_DKDM.xml");
+ kdm->as_xml (path);
+ }
+ }
+
+ d->Destroy ();
+ }
+
+ void jobs_export ()
+ {
+ ExportDialog* d = new ExportDialog (this);
+ if (d->ShowModal() == wxID_OK) {
+ shared_ptr<TranscodeJob> job (new TranscodeJob (_film));
+ job->set_encoder (shared_ptr<FFmpegEncoder> (new FFmpegEncoder (_film, job, d->path(), d->format(), d->mixdown_to_stereo())));
+ JobManager::instance()->add (job);
+ }
+ d->Destroy ();
+ }
+
+ void content_scale_to_fit_width ()
+ {
+ ContentList vc = _film_editor->content_panel()->selected_video ();
+ for (ContentList::iterator i = vc.begin(); i != vc.end(); ++i) {
+ (*i)->video->scale_and_crop_to_fit_width ();
+ }
+ }
+
+ void content_scale_to_fit_height ()
+ {
+ ContentList vc = _film_editor->content_panel()->selected_video ();
+ for (ContentList::iterator i = vc.begin(); i != vc.end(); ++i) {
+ (*i)->video->scale_and_crop_to_fit_height ();
+ }
+ }
+
+ void jobs_send_dcp_to_tms ()
+ {
+ _film->send_dcp_to_tms ();
+ }
+
+ void jobs_show_dcp ()
+ {
+ DCPOMATIC_ASSERT (_film->directory ());
+#ifdef DCPOMATIC_WINDOWS
+ wstringstream args;
+ args << "/select," << _film->dir (_film->dcp_name(false));
+ ShellExecute (0, L"open", L"explorer.exe", args.str().c_str(), 0, SW_SHOWDEFAULT);
+#endif
+
+#ifdef DCPOMATIC_LINUX