Add Version File dialog.
[dcpomatic.git] / src / tools / dcpomatic.cc
index b53f39b451ab3aca2cede112d120e283ad135d75..3464a73d5ab10d74d793c3a82cd8c10e92911fcc 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "wx/about_dialog.h"
 #include "wx/content_panel.h"
+#include "wx/dcp_referencing_dialog.h"
 #include "wx/dkdm_dialog.h"
 #include "wx/export_subtitles_dialog.h"
 #include "wx/export_video_file_dialog.h"
@@ -75,6 +76,9 @@
 #include "lib/ffmpeg_encoder.h"
 #include "lib/film.h"
 #include "lib/font_config.h"
+#ifdef DCPOMATIC_GROK
+#include "lib/grok/context.h"
+#endif
 #include "lib/hints.h"
 #include "lib/job_manager.h"
 #include "lib/kdm_with_metadata.h"
@@ -91,6 +95,7 @@
 #include "lib/version.h"
 #include "lib/video_content.h"
 #include <dcp/exceptions.h>
+#include <dcp/filesystem.h>
 #include <dcp/raw_convert.h>
 #include <dcp/warnings.h>
 LIBDCP_DISABLE_WARNINGS
@@ -205,6 +210,7 @@ private:
 #define NEEDS_SELECTED_VIDEO_CONTENT  0x20
 #define NEEDS_CLIPBOARD               0x40
 #define NEEDS_ENCRYPTION              0x80
+#define NEEDS_DCP_CONTENT             0x100
 
 
 map<wxMenuItem*, int> menu_items;
@@ -234,6 +240,7 @@ enum {
        ID_jobs_open_dcp_in_player,
        ID_view_closed_captions,
        ID_view_video_waveform,
+       ID_tools_version_file,
        ID_tools_hints,
        ID_tools_encoding_servers,
        ID_tools_manage_templates,
@@ -306,25 +313,6 @@ public:
                , _right_panel(new wxPanel(_splitter, wxID_ANY))
                , _film_viewer(_right_panel)
        {
-#if defined(DCPOMATIC_WINDOWS)
-               if (Config::instance()->win32_console()) {
-                       AllocConsole();
-
-                       HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
-                       int hCrt = _open_osfhandle((intptr_t) handle_out, _O_TEXT);
-                       FILE* hf_out = _fdopen(hCrt, "w");
-                       setvbuf(hf_out, NULL, _IONBF, 1);
-                       *stdout = *hf_out;
-
-                       HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
-                       hCrt = _open_osfhandle((intptr_t) handle_in, _O_TEXT);
-                       FILE* hf_in = _fdopen(hCrt, "r");
-                       setvbuf(hf_in, NULL, _IONBF, 128);
-                       *stdin = *hf_in;
-
-                       cout << "DCP-o-matic is starting." << "\n";
-               }
-#endif
 
                auto bar = new wxMenuBar;
                setup_menu (bar);
@@ -364,6 +352,7 @@ public:
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_open_dcp_in_player, this), ID_jobs_open_dcp_in_player);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_closed_captions, this),    ID_view_closed_captions);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_video_waveform, this),     ID_view_video_waveform);
+               Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_version_file, this),      ID_tools_version_file);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_hints, this),             ID_tools_hints);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_encoding_servers, this),  ID_tools_encoding_servers);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_manage_templates, this),  ID_tools_manage_templates);
@@ -494,7 +483,7 @@ public:
        }
        catch (FileNotFoundError& e) {
                auto const dir = e.file().parent_path();
-               if (boost::filesystem::exists(dir / "ASSETMAP") || boost::filesystem::exists(dir / "ASSETMAP.xml")) {
+               if (dcp::filesystem::exists(dir / "ASSETMAP") || dcp::filesystem::exists(dir / "ASSETMAP.xml")) {
                        error_dialog (
                                this, _("Could not open this folder as a DCP-o-matic project."),
                                _("It looks like you are trying to open a DCP.  File -> Open is for loading DCP-o-matic projects, not DCPs.  To import a DCP, create a new project with File -> New and then click the \"Add DCP...\" button.")
@@ -707,13 +696,16 @@ private:
        void edit_copy ()
        {
                auto const sel = _film_editor->content_panel()->selected();
-               DCPOMATIC_ASSERT (sel.size() == 1);
-               _clipboard = sel.front()->clone();
+               if (sel.size() == 1) {
+                       _clipboard = sel.front()->clone();
+               }
        }
 
        void edit_paste ()
        {
-               DCPOMATIC_ASSERT (_clipboard);
+               if (!_clipboard) {
+                       return;
+               }
 
                PasteDialog dialog(this, static_cast<bool>(_clipboard->video), static_cast<bool>(_clipboard->audio), !_clipboard->text.empty());
                if (dialog.ShowModal() != wxID_OK) {
@@ -777,7 +769,17 @@ private:
                        );
 
                if (dialog.ShowModal() == wxID_OK) {
-                       save_all_config_as_zip(wx_to_std(dialog.GetPath()));
+                       auto const path = boost::filesystem::path(wx_to_std(dialog.GetPath()));
+                       if (boost::filesystem::exists(path)) {
+                               boost::system::error_code ec;
+                               boost::filesystem::remove(path, ec);
+                               if (ec) {
+                                       error_dialog(nullptr, _("Could not remove existing preferences file"), std_to_wx(path.string()));
+                                       return;
+                               }
+                       }
+
+                       save_all_config_as_zip(path);
                }
        }
 
@@ -819,11 +821,11 @@ private:
 
                /* Remove any existing DCP if the user agrees */
                auto const dcp_dir = _film->dir (_film->dcp_name(), false);
-               if (boost::filesystem::exists(dcp_dir)) {
+               if (dcp::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);
+                       dcp::filesystem::remove_all(dcp_dir);
                }
 
                try {
@@ -997,7 +999,7 @@ private:
                        return;
                }
 
-               if (boost::filesystem::exists(dialog.path())) {
+               if (dcp::filesystem::exists(dialog.path())) {
                        bool ok = confirm_dialog(
                                        this,
                                        wxString::Format(_("File %s already exists.  Do you want to overwrite it?"), std_to_wx(dialog.path().string()).data())
@@ -1067,6 +1069,17 @@ private:
                _system_information_dialog->Show ();
        }
 
+       void tools_version_file()
+       {
+               if (_dcp_referencing_dialog) {
+                       _dcp_referencing_dialog->Destroy();
+                       _dcp_referencing_dialog = nullptr;
+               }
+
+               _dcp_referencing_dialog = new DCPReferencingDialog(this, _film);
+               _dcp_referencing_dialog->Show();
+       }
+
        void tools_hints ()
        {
                if (!_hints_dialog) {
@@ -1195,6 +1208,7 @@ private:
                FontConfig::drop();
 
                ev.Skip ();
+               JobManager::drop ();
        }
 
        void active_jobs_changed()
@@ -1218,6 +1232,13 @@ private:
                bool const have_single_selected_content = _film_editor->content_panel()->selected().size() == 1;
                bool const have_selected_content = !_film_editor->content_panel()->selected().empty();
                bool const have_selected_video_content = !_film_editor->content_panel()->selected_video().empty();
+               vector<shared_ptr<Content>> content;
+               if (_film) {
+                       content = _film->content();
+               }
+               bool const have_dcp_content = std::find_if(content.begin(), content.end(), [](shared_ptr<const Content> content) {
+                       return static_cast<bool>(dynamic_pointer_cast<const DCPContent>(content));
+               }) != content.end();
 
                for (auto j: menu_items) {
 
@@ -1255,6 +1276,10 @@ private:
                                enabled = false;
                        }
 
+                       if ((j.second & NEEDS_DCP_CONTENT) && !have_dcp_content) {
+                               enabled = false;
+                       }
+
                        j.first->Enable (enabled);
                }
        }
@@ -1388,6 +1413,7 @@ private:
                add_item (view, _("Video waveform..."), ID_view_video_waveform, NEEDS_FILM);
 
                auto tools = new wxMenu;
+               add_item (tools, _("Version File (VF)..."), ID_tools_version_file, NEEDS_FILM | NEEDS_DCP_CONTENT);
                add_item (tools, _("Hints..."), ID_tools_hints, NEEDS_FILM);
                add_item (tools, _("Encoding servers..."), ID_tools_encoding_servers, 0);
                add_item (tools, _("Manage templates..."), ID_tools_manage_templates, 0);
@@ -1558,6 +1584,7 @@ private:
        StandardControls* _controls;
        wx_ptr<VideoWaveformDialog> _video_waveform_dialog;
        SystemInformationDialog* _system_information_dialog = nullptr;
+       DCPReferencingDialog* _dcp_referencing_dialog = nullptr;
        HintsDialog* _hints_dialog = nullptr;
        ServersListDialog* _servers_list_dialog = nullptr;
        wxPreferencesEditor* _config_dialog = nullptr;
@@ -1597,6 +1624,7 @@ public:
        App ()
                : wxApp ()
        {
+               dcpomatic_setup_path_encoding ();
 #ifdef DCPOMATIC_LINUX
                XInitThreads ();
 #endif
@@ -1607,6 +1635,26 @@ private:
        bool OnInit () override
        {
                try {
+
+#if defined(DCPOMATIC_WINDOWS)
+               if (Config::instance()->win32_console()) {
+                       AllocConsole();
+
+                       HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
+                       int hCrt = _open_osfhandle((intptr_t) handle_out, _O_TEXT);
+                       FILE* hf_out = _fdopen(hCrt, "w");
+                       setvbuf(hf_out, NULL, _IONBF, 1);
+                       *stdout = *hf_out;
+
+                       HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
+                       hCrt = _open_osfhandle((intptr_t) handle_in, _O_TEXT);
+                       FILE* hf_in = _fdopen(hCrt, "r");
+                       setvbuf(hf_in, NULL, _IONBF, 128);
+                       *stdin = *hf_in;
+
+                       cout << "DCP-o-matic is starting." << "\n";
+               }
+#endif
                        wxInitAllImageHandlers ();
 
                        Config::FailedToLoad.connect(boost::bind(&App::config_failed_to_load, this, _1));
@@ -1629,8 +1677,6 @@ private:
                        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
@@ -1672,7 +1718,7 @@ private:
                        signal_manager = new wxSignalManager (this);
                        Bind (wxEVT_IDLE, boost::bind (&App::idle, this, _1));
 
-                       if (!_film_to_load.empty() && boost::filesystem::is_directory(_film_to_load)) {
+                       if (!_film_to_load.empty() && dcp::filesystem::is_directory(_film_to_load)) {
                                try {
                                        _frame->load_film (_film_to_load);
                                } catch (exception& e) {
@@ -1706,6 +1752,10 @@ private:
                                notes.Centre();
                                notes.ShowModal();
                        }
+
+#ifdef DCPOMATIC_GROK
+                       grk_plugin::setMessengerLogger(new grk_plugin::GrokLogger("[GROK] "));
+#endif
                }
                catch (exception& e)
                {