+ if (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 (true);
+ } 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_dkdms ()
+ {
+ if (!_film) {
+ return;
+ }
+
+ if (_dkdm_dialog) {
+ _dkdm_dialog->Destroy ();
+ _dkdm_dialog = 0;
+ }
+
+ _dkdm_dialog = new DKDMDialog (this, _film);
+ _dkdm_dialog->Show ();
+ }
+
+ /** @return false if we succeeded, true if not */
+ bool send_to_other_tool (int port, function<void()> start, string message)
+ {
+ /* i = 0; try to connect via socket
+ i = 1; try again, and then try to start the tool
+ 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> (port));
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query);
+ Socket socket (5);
+ socket.connect (*endpoint_iterator);
+ DCPOMATIC_ASSERT (_film->directory ());
+ socket.write (message.length() + 1);
+ socket.write ((uint8_t *) message.c_str(), message.length() + 1);
+ /* OK\0 */
+ uint8_t ok[3];
+ socket.read (ok, 3);
+ return false;
+ } catch (exception& e) {
+
+ }
+
+ if (i == 1) {
+ start ();
+ }
+
+ dcpomatic_sleep_seconds (1);
+ }
+
+ return true;
+ }
+
+ void jobs_make_dcp_batch ()
+ {
+ if (!_film) {
+ return;
+ }
+
+ if (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 ();
+
+ if (send_to_other_tool (BATCH_JOB_PORT, &start_batch_converter, _film->directory()->string())) {
+ error_dialog (this, _("Could not find batch converter."));
+ }
+ }
+
+ void jobs_open_dcp_in_player ()
+ {
+ if (!_film) {
+ return;
+ }
+
+ if (send_to_other_tool (PLAYER_PLAY_PORT, &start_player, _film->dir(_film->dcp_name(false)).string())) {
+ error_dialog (this, _("Could not find player."));
+ }
+ }
+
+ 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()
+ )
+ );
+
+
+ dcp::LocalTime from (Config::instance()->signer_chain()->leaf().not_before());
+ from.add_days (1);
+ dcp::LocalTime to (Config::instance()->signer_chain()->leaf().not_after());
+ to.add_days (-1);
+
+ optional<dcp::EncryptedKDM> kdm;
+ try {
+ kdm = _film->make_kdm (
+ Config::instance()->decryption_chain()->leaf(),
+ vector<string>(),
+ d->cpl (),
+ from, to,
+ dcp::MODIFIED_TRANSITIONAL_1,
+ true,
+ 0
+ );
+ } 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, _film->isdcf_name(true));
+ if (d->ShowModal() == wxID_OK) {
+ if (boost::filesystem::exists(d->path())) {
+ bool ok = confirm_dialog(
+ this,
+ wxString::Format (_("File %s already exists. Do you want to overwrite it?"), std_to_wx(d->path().string()).data())
+ );
+
+ if (!ok) {
+ d->Destroy ();
+ return;
+ }
+ }
+
+ shared_ptr<TranscodeJob> job (new TranscodeJob (_film));
+ if (d->format() == EXPORT_FORMAT_SUBTITLES_DCP) {
+ job->set_encoder (
+ shared_ptr<SubtitleEncoder>(new SubtitleEncoder(_film, job, d->path(), d->split_reels()))
+ );
+ } else {
+ job->set_encoder (
+ shared_ptr<FFmpegEncoder> (
+ new FFmpegEncoder (_film, job, d->path(), d->format(), d->mixdown_to_stereo(), d->split_reels(), d->x264_crf()
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ , optional<dcp::Key>(), optional<string>()
+#endif
+ )
+ )
+ );
+ }
+ JobManager::instance()->add (job);
+ }
+ d->Destroy ();
+ }
+
+ 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
+ int r = system ("which nautilus");
+ if (WEXITSTATUS (r) == 0) {
+ r = system (String::compose("nautilus \"%1\"", _film->directory()->string()).c_str());
+ if (WEXITSTATUS (r)) {
+ error_dialog (this, _("Could not show DCP."), _("Could not run nautilus"));
+ }
+ } else {
+ int r = system ("which konqueror");
+ if (WEXITSTATUS (r) == 0) {
+ r = system (String::compose ("konqueror \"%1\"", _film->directory()->string()).c_str());
+ if (WEXITSTATUS (r)) {
+ error_dialog (this, _("Could not show DCP"), _("Could not run konqueror"));
+ }
+ }
+ }
+#endif
+
+#ifdef DCPOMATIC_OSX
+ int r = system (String::compose ("open -R \"%1\"", _film->dir (_film->dcp_name(false)).string()).c_str());
+ if (WEXITSTATUS (r)) {
+ error_dialog (this, _("Could not show DCP"));
+ }
+#endif
+ }
+
+ void view_closed_captions ()
+ {
+ _film_viewer->show_closed_captions ();
+ }
+
+ void view_video_waveform ()
+ {
+ if (!_video_waveform_dialog) {
+ _video_waveform_dialog = new VideoWaveformDialog (this, _film, _film_viewer);
+ }
+
+ _video_waveform_dialog->Show ();
+ }
+
+ void tools_system_information ()
+ {
+ if (!_system_information_dialog) {
+ _system_information_dialog = new SystemInformationDialog (this, _film_viewer);
+ }
+
+ _system_information_dialog->Show ();
+ }
+
+ void tools_hints ()
+ {
+ if (!_hints_dialog) {
+ _hints_dialog = new HintsDialog (this, _film, true);
+ }
+
+ _hints_dialog->Show ();
+ }
+
+ void tools_encoding_servers ()
+ {
+ if (!_servers_list_dialog) {
+ _servers_list_dialog = new ServersListDialog (this);
+ }
+
+ _servers_list_dialog->Show ();
+ }
+
+ void tools_manage_templates ()
+ {
+ if (!_templates_dialog) {
+ _templates_dialog = new TemplatesDialog (this);
+ }
+
+ _templates_dialog->Show ();
+ }
+
+ void tools_check_for_updates ()
+ {
+ UpdateChecker::instance()->run ();
+ _update_news_requested = true;
+ }
+
+ void tools_send_translations ()
+ {
+ SendI18NDialog* d = new SendI18NDialog (this);
+ if (d->ShowModal() == wxID_OK) {
+ string body;
+ body += d->name() + "\n";
+ body += d->language() + "\n";
+ body += string(dcpomatic_version) + " " + string(dcpomatic_git_commit) + "\n";
+ body += "--\n";
+ map<string, string> translations = I18NHook::translations ();
+ for (map<string, string>::const_iterator i = translations.begin(); i != translations.end(); ++i) {
+ body += i->first + "\n" + i->second + "\n\n";
+ }
+ list<string> to;
+ to.push_back ("carl@dcpomatic.com");
+ Emailer emailer (d->email(), to, "DCP-o-matic translations", body);
+ emailer.send ("main.carlh.net", 2525, EMAIL_PROTOCOL_STARTTLS);
+ }
+
+ d->Destroy ();
+ }
+
+ void help_about ()
+ {
+ AboutDialog* d = new AboutDialog (this);
+ d->ShowModal ();
+ d->Destroy ();
+ }
+
+ void help_report_a_problem ()
+ {
+ ReportProblemDialog* d = new ReportProblemDialog (this, _film);
+ if (d->ShowModal () == wxID_OK) {
+ d->report ();
+ }
+ d->Destroy ();
+ }
+
+ bool should_close ()
+ {
+ if (!JobManager::instance()->work_to_do ()) {
+ return true;
+ }
+
+ wxMessageDialog* d = new wxMessageDialog (