Use Film/Playlist for SPL management rather than special classes.
authorCarl Hetherington <cth@carlh.net>
Thu, 25 Oct 2018 23:09:34 +0000 (00:09 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 25 Oct 2018 23:09:34 +0000 (00:09 +0100)
src/lib/film.cc
src/lib/film.h
src/lib/spl.cc [deleted file]
src/lib/spl.h [deleted file]
src/lib/spl_entry.h [deleted file]
src/lib/wscript
src/tools/dcpomatic_player.cc
src/wx/controls.cc
src/wx/controls.h
src/wx/wx_util.cc
src/wx/wx_util.h

index bd57248..807aeaf 100644 (file)
@@ -403,6 +403,13 @@ Film::metadata (bool with_content_paths) const
        return doc;
 }
 
+void
+Film::write_metadata (boost::filesystem::path path) const
+{
+       shared_ptr<xmlpp::Document> doc = metadata ();
+       doc->write_to_file_formatted (path.string());
+}
+
 /** Write state to our `metadata' file */
 void
 Film::write_metadata () const
index 44e84dc..273077f 100644 (file)
@@ -94,6 +94,7 @@ public:
        void use_template (std::string name);
        std::list<std::string> read_metadata (boost::optional<boost::filesystem::path> path = boost::optional<boost::filesystem::path> ());
        void write_metadata () const;
+       void write_metadata (boost::filesystem::path path) const;
        void write_template (boost::filesystem::path path) const;
        boost::shared_ptr<xmlpp::Document> metadata (bool with_content_paths = true) const;
 
diff --git a/src/lib/spl.cc b/src/lib/spl.cc
deleted file mode 100644 (file)
index d7c0944..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-    Copyright (C) 2018 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 "spl.h"
-#include "spl_entry.h"
-#include <dcp/cpl.h>
-#include <dcp/dcp.h>
-#include <libxml++/libxml++.h>
-#include <boost/foreach.hpp>
-
-using boost::shared_ptr;
-
-SPL::SPL (boost::filesystem::path file)
-{
-       cxml::Document f ("DCPPlaylist");
-       f.read_file (file);
-
-       name = f.string_attribute ("Name");
-       BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("DCP")) {
-               boost::filesystem::path dir(i->content());
-               dcp::DCP dcp (dir);
-               dcp.read ();
-               BOOST_FOREACH (shared_ptr<dcp::CPL> j, dcp.cpls()) {
-                       if (j->id() == i->string_attribute("CPL")) {
-                               playlist.push_back (SPLEntry(j, dir));
-                       }
-               }
-       }
-}
-
-void
-SPL::as_xml (boost::filesystem::path file) const
-{
-       xmlpp::Document doc;
-       xmlpp::Element* root = doc.create_root_node ("DCPPlaylist");
-       root->set_attribute ("Name", name);
-
-       BOOST_FOREACH (SPLEntry i, playlist) {
-               xmlpp::Element* d = root->add_child ("DCP");
-               d->set_attribute ("CPL", i.cpl->id());
-               d->add_child_text (i.directory.string());
-       }
-
-       doc.write_to_file_formatted(file.string());
-}
diff --git a/src/lib/spl.h b/src/lib/spl.h
deleted file mode 100644 (file)
index 25e8ac4..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-    Copyright (C) 2018 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/>.
-
-*/
-
-#ifndef DCPOMATIC_SPL_H
-#define DCPOMATIC_SPL_H
-
-#include "spl_entry.h"
-#include <boost/filesystem.hpp>
-
-
-class SPL
-{
-public:
-       SPL () {}
-       SPL (boost::filesystem::path file);
-
-       void as_xml (boost::filesystem::path file) const;
-
-       std::string name;
-       std::list<SPLEntry> playlist;
-};
-
-#endif
diff --git a/src/lib/spl_entry.h b/src/lib/spl_entry.h
deleted file mode 100644 (file)
index e79d89a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-    Copyright (C) 2018 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/>.
-
-*/
-
-#ifndef DCPOMATIC_SPL_ENTRY_H
-#define DCPOMATIC_SPL_ENTRY_H
-
-#include "dcpomatic_time.h"
-
-namespace dcp {
-       class CPL;
-}
-
-class SPLEntry
-{
-public:
-       SPLEntry (boost::shared_ptr<dcp::CPL> cpl_, boost::filesystem::path directory_)
-               : cpl (cpl_)
-               , directory (directory_)
-       {}
-
-       /* Length of black before this DCP */
-       DCPTime black_before;
-       boost::shared_ptr<dcp::CPL> cpl;
-       boost::filesystem::path directory;
-};
-
-#endif
index bbe51a8..e78227b 100644 (file)
@@ -138,7 +138,6 @@ sources = """
           send_problem_report_job.cc
           server.cc
           shuffler.cc
-          spl.cc
           string_log_entry.cc
           string_text_file.cc
           string_text_file_content.cc
index a4333db..8601814 100644 (file)
@@ -36,8 +36,6 @@
 #include "lib/compose.hpp"
 #include "lib/dcp_content.h"
 #include "lib/job_manager.h"
-#include "lib/spl.h"
-#include "lib/spl_entry.h"
 #include "lib/job.h"
 #include "lib/film.h"
 #include "lib/video_content.h"
@@ -201,8 +199,9 @@ public:
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::back_frame, this), ID_back_frame);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::forward_frame, this), ID_forward_frame);
 
+               reset_film ();
+
                UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this));
-               _controls->SPLChanged.connect (boost::bind(&DOMFrame::set_spl, this, _1));
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                MonitorChecker::instance()->StateChanged.connect(boost::bind(&DOMFrame::monitor_checker_state_changed, this));
                MonitorChecker::instance()->run ();
@@ -214,7 +213,9 @@ public:
                        boost::filesystem::is_regular_file(Config::path("position")) &&
                        boost::filesystem::is_regular_file(Config::path("spl.xml"))) {
 
-                       set_spl (SPL(Config::path("spl.xml")));
+                       shared_ptr<Film> film (new Film(boost::optional<boost::filesystem::path>()));
+                       film->read_metadata (Config::path("spl.xml"));
+                       reset_film (film);
                        FILE* f = fopen_boost (Config::path("position"), "r");
                        if (f) {
                                char buffer[64];
@@ -362,14 +363,15 @@ public:
 
        void load_dcp (boost::filesystem::path dir)
        {
+               DCPOMATIC_ASSERT (_film);
+
                try {
-                       dcp::DCP dcp (dir);
-                       dcp.read ();
-                       SPL spl;
-                       BOOST_FOREACH (shared_ptr<dcp::CPL> j, dcp.cpls()) {
-                               spl.playlist.push_back (SPLEntry(j, dir));
+                       shared_ptr<DCPContent> dcp (new DCPContent(_film, dir));
+                       _film->examine_and_add_content (dcp);
+                       bool const ok = display_progress (_("DCP-o-matic Player"), _("Loading DCP"));
+                       if (!ok || !report_errors_from_last_job(this)) {
+                               return;
                        }
-                       set_spl (spl);
                        Config::instance()->add_to_player_history (dir);
                } catch (dcp::DCPReadError& e) {
                        error_dialog (this, wxString::Format(_("Could not load a DCP from %s"), std_to_wx(dir.string())), std_to_wx(e.what()));
@@ -419,55 +421,33 @@ public:
                return optional<dcp::EncryptedKDM>();
        }
 
-       void set_spl (SPL spl)
+       void reset_film (shared_ptr<Film> film = shared_ptr<Film>(new Film(optional<boost::filesystem::path>())))
        {
-#ifdef DCPOMATIC_VARIANT_SWAROOP
-               spl.as_xml (Config::path("spl.xml"));
-#endif
+               _film = film;
+               _viewer->set_film (_film);
+               _film->Change.connect (bind(&DOMFrame::film_changed, this, _1, _2));
+       }
 
-               if (_viewer->playing ()) {
-                       _viewer->stop ();
+       void film_changed (ChangeType type, Film::Property property)
+       {
+               if (type != CHANGE_TYPE_DONE || property != Film::CONTENT) {
+                       return;
                }
 
-               _film.reset (new Film (optional<boost::filesystem::path>()));
+               _film->write_metadata (Config::path("spl.xml"));
 
-               if (spl.playlist.empty ()) {
-                       _viewer->set_film (_film);
-                       _info->triggered_update ();
-                       return;
+               if (_viewer->playing ()) {
+                       _viewer->stop ();
                }
 
                /* Start off as Flat */
                _film->set_container (Ratio::from_id("185"));
 
-               /* Put 1 frame of black at the start so when we seek to 0 we don't see anything */
-               DCPTime position = DCPTime::from_frames(1, _film->video_frame_rate());
-               shared_ptr<DCPContent> first;
-
-               BOOST_FOREACH (SPLEntry i, spl.playlist) {
-                       shared_ptr<DCPContent> dcp;
-                       try {
-                               dcp.reset (new DCPContent (_film, i.directory));
-                       } catch (boost::filesystem::filesystem_error& e) {
-                               error_dialog (this, _("Could not load DCP"), std_to_wx (e.what()));
-                               return;
-                       }
-
-                       if (!first) {
-                               first = dcp;
-                       }
-
-                       _film->examine_and_add_content (dcp, true);
-                       bool const ok = progress (_("Loading DCP"));
-                       if (!ok || !report_errors_from_last_job()) {
-                               return;
-                       }
-
-                       dcp->set_position (position + i.black_before);
-                       position += dcp->length_after_trim() + i.black_before;
-
+               BOOST_FOREACH (shared_ptr<Content> i, _film->content()) {
                        /* This DCP has been examined and loaded */
 
+                       shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent>(i);
+                       DCPOMATIC_ASSERT (dcp);
                        if (dcp->needs_kdm()) {
                                optional<dcp::EncryptedKDM> kdm;
 #ifdef DCPOMATIC_VARIANT_SWAROOP
@@ -499,11 +479,8 @@ public:
                        if (dcp->three_d()) {
                                _film->set_three_d (true);
                        }
-
-                       _controls->log (wxString::Format(_("Load DCP %s"), i.directory.filename().string().c_str()));
                }
 
-               _viewer->set_film (_film);
                _viewer->seek (DCPTime(), true);
                _info->triggered_update ();
 
@@ -514,8 +491,10 @@ public:
                        _cpl_menu->Remove (*i);
                }
 
-               if (spl.playlist.size() == 1) {
+               if (_film->content().size() == 1) {
                        /* Offer a CPL menu */
+                       shared_ptr<DCPContent> first = dynamic_pointer_cast<DCPContent>(_film->content().front());
+                       DCPOMATIC_ASSERT (first);
                        DCPExaminer ex (first);
                        int id = ID_view_cpl;
                        BOOST_FOREACH (shared_ptr<dcp::CPL> i, ex.cpls()) {
@@ -653,8 +632,8 @@ private:
                        DCPOMATIC_ASSERT (dcp);
                        dcp->add_ov (wx_to_std(c->GetPath()));
                        JobManager::instance()->add(shared_ptr<Job>(new ExamineContentJob (_film, dcp)));
-                       bool const ok = progress (_("Loading DCP"));
-                       if (!ok || !report_errors_from_last_job()) {
+                       bool const ok = display_progress (_("DCP-o-matic Player"), _("Loading DCP"));
+                       if (!ok || !report_errors_from_last_job(this)) {
                                return;
                        }
                        BOOST_FOREACH (shared_ptr<TextContent> i, dcp->text) {
@@ -705,8 +684,7 @@ private:
 
        void file_close ()
        {
-               _viewer->set_film (shared_ptr<Film>());
-               _film.reset ();
+               reset_film ();
                _info->triggered_update ();
                set_menu_sensitivity ();
        }
@@ -829,7 +807,7 @@ private:
 
                JobManager* jm = JobManager::instance ();
                jm->add (shared_ptr<Job> (new VerifyDCPJob (dcp->directories())));
-               bool const ok = progress (_("Verifying DCP"));
+               bool const ok = display_progress (_("DCP-o-matic Player"), _("Verifying DCP"));
                if (!ok) {
                        return;
                }
@@ -980,46 +958,6 @@ private:
 
 private:
 
-       /** @return false if the task was cancelled */
-       bool progress (wxString task)
-       {
-               JobManager* jm = JobManager::instance ();
-
-               wxProgressDialog* progress = new wxProgressDialog (_("DCP-o-matic Player"), task, 100, 0, wxPD_CAN_ABORT);
-
-               bool ok = true;
-
-               while (jm->work_to_do() || signal_manager->ui_idle()) {
-                       dcpomatic_sleep (1);
-                       if (!progress->Pulse()) {
-                               /* user pressed cancel */
-                               BOOST_FOREACH (shared_ptr<Job> i, jm->get()) {
-                                       i->cancel();
-                               }
-                               ok = false;
-                               break;
-                       }
-               }
-
-               progress->Destroy ();
-               return ok;
-       }
-
-       bool report_errors_from_last_job ()
-       {
-               JobManager* jm = JobManager::instance ();
-
-               DCPOMATIC_ASSERT (!jm->get().empty());
-
-               shared_ptr<Job> last = jm->get().back();
-               if (last->finished_in_error()) {
-                       error_dialog(this, std_to_wx(last->error_summary()) + ".\n", std_to_wx(last->error_details()));
-                       return false;
-               }
-
-               return true;
-       }
-
        wxFrame* _dual_screen;
        bool _update_news_requested;
        PlayerInformation* _info;
index 074aa82..8c24a0d 100644 (file)
@@ -26,7 +26,9 @@
 #include "lib/job_manager.h"
 #include "lib/player_video.h"
 #include "lib/dcp_content.h"
-#include "lib/spl_entry.h"
+#include "lib/job.h"
+#include "lib/examine_content_job.h"
+#include "lib/cross.h"
 #include <dcp/dcp.h>
 #include <dcp/cpl.h>
 #include <dcp/reel.h>
@@ -34,6 +36,7 @@
 #include <wx/wx.h>
 #include <wx/tglbtn.h>
 #include <wx/listctrl.h>
+#include <wx/progdlg.h>
 
 using std::string;
 using std::list;
@@ -85,14 +88,14 @@ Controls::Controls (wxWindow* parent, shared_ptr<FilmViewer> viewer, bool editor
 
        wxBoxSizer* e_sizer = new wxBoxSizer (wxHORIZONTAL);
 
-       _cpl = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
+       _content_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
        /* time */
-       _cpl->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
+       _content_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
        /* type */
-       _cpl->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
+       _content_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
        /* annotation text */
-       _cpl->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 580);
-       e_sizer->Add (_cpl, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
+       _content_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 580);
+       e_sizer->Add (_content_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
 
        _spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
        _spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
@@ -114,7 +117,7 @@ Controls::Controls (wxWindow* parent, shared_ptr<FilmViewer> viewer, bool editor
        _log = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(-1, 200), wxTE_READONLY | wxTE_MULTILINE);
        _v_sizer->Add (_log, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
 
-       _cpl->Show (false);
+       _content_view->Show (false);
        _spl_view->Show (false);
        _add_button->Show (false);
        _save_button->Show (false);
@@ -168,8 +171,8 @@ Controls::Controls (wxWindow* parent, shared_ptr<FilmViewer> viewer, bool editor
        _forward_button->Bind   (wxEVT_LEFT_DOWN,            boost::bind(&Controls::forward_clicked, this, _1));
        _frame_number->Bind     (wxEVT_LEFT_DOWN,            boost::bind(&Controls::frame_number_clicked, this));
        _timecode->Bind         (wxEVT_LEFT_DOWN,            boost::bind(&Controls::timecode_clicked, this));
-       _cpl->Bind              (wxEVT_LIST_ITEM_SELECTED,   boost::bind(&Controls::setup_sensitivity, this));
-       _cpl->Bind              (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&Controls::setup_sensitivity, this));
+       _content_view->Bind     (wxEVT_LIST_ITEM_SELECTED,   boost::bind(&Controls::setup_sensitivity, this));
+       _content_view->Bind     (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&Controls::setup_sensitivity, this));
        if (_jump_to_selected) {
                _jump_to_selected->Bind (wxEVT_CHECKBOX, boost::bind (&Controls::jump_to_selected_clicked, this));
                _jump_to_selected->SetValue (Config::instance()->jump_to_selected ());
@@ -200,11 +203,18 @@ Controls::Controls (wxWindow* parent, shared_ptr<FilmViewer> viewer, bool editor
 void
 Controls::add_clicked ()
 {
-       optional<CPL> sel = selected_cpl ();
+       shared_ptr<Content> sel = selected_content ();
        DCPOMATIC_ASSERT (sel);
-       _spl.playlist.push_back (SPLEntry(sel->first, sel->second));
-       add_cpl_to_list (sel->first, _spl_view);
-       SPLChanged (_spl);
+       _film->examine_and_add_content (sel);
+       bool const ok = display_progress (_("DCP-o-matic"), _("Loading DCP"));
+       if (!ok || !report_errors_from_last_job(this)) {
+               return;
+       }
+       if (_film->content().size() == 1) {
+               /* Put 1 frame of black at the start so when we seek to 0 we don't see anything */
+               sel->set_position (DCPTime::from_frames(1, _film->video_frame_rate()));
+       }
+       add_content_to_list (sel, _spl_view);
        setup_sensitivity ();
 }
 
@@ -217,7 +227,7 @@ Controls::save_clicked ()
                );
 
        if (d->ShowModal() == wxID_OK) {
-               _spl.as_xml (boost::filesystem::path(wx_to_std(d->GetPath())));
+               _film->write_metadata(wx_to_std(d->GetPath()));
        }
 
        d->Destroy ();
@@ -231,12 +241,12 @@ Controls::load_clicked ()
                );
 
        if (d->ShowModal() == wxID_OK) {
-               _spl = SPL (boost::filesystem::path(wx_to_std(d->GetPath())));
+               _film->read_metadata (boost::filesystem::path(wx_to_std(d->GetPath())));
                _spl_view->DeleteAllItems ();
-               BOOST_FOREACH (SPLEntry i, _spl.playlist) {
-                       add_cpl_to_list (i.cpl, _spl_view);
+               BOOST_FOREACH (shared_ptr<Content> i, _film->content()) {
+                       shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent>(i);
+                       add_content_to_list (dcp, _spl_view);
                }
-               SPLChanged (_spl);
        }
 
        d->Destroy ();
@@ -462,7 +472,7 @@ Controls::setup_sensitivity ()
 {
        /* examine content is the only job which stops the viewer working */
        bool const active_job = _active_job && *_active_job != "examine_content";
-       bool const c = ((_film && !_film->content().empty()) || !_spl.playlist.empty()) && !active_job;
+       bool const c = _film && !_film->content().empty() && !active_job;
 
        _slider->Enable (c);
        _rewind_button->Enable (c);
@@ -489,20 +499,20 @@ Controls::setup_sensitivity ()
                _eye->Enable (c && _film->three_d ());
        }
 
-       _add_button->Enable (Config::instance()->allow_spl_editing() && static_cast<bool>(selected_cpl()));
+       _add_button->Enable (Config::instance()->allow_spl_editing() && static_cast<bool>(selected_content()));
        _save_button->Enable (Config::instance()->allow_spl_editing());
 }
 
-optional<Controls::CPL>
-Controls::selected_cpl () const
+shared_ptr<Content>
+Controls::selected_content () const
 {
-       long int s = _cpl->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+       long int s = _content_view->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if (s == -1) {
-               return optional<CPL>();
+               return shared_ptr<Content>();
        }
 
-       DCPOMATIC_ASSERT (s < int(_cpls.size()));
-       return _cpls[s];
+       DCPOMATIC_ASSERT (s < int(_content.size()));
+       return _content[s];
 }
 
 void
@@ -561,7 +571,7 @@ Controls::film () const
 void
 Controls::show_extended_player_controls (bool s)
 {
-       _cpl->Show (s);
+       _content_view->Show (s);
        if (s) {
                update_dcp_directory ();
        }
@@ -574,61 +584,73 @@ Controls::show_extended_player_controls (bool s)
 }
 
 void
-Controls::add_cpl_to_list (shared_ptr<dcp::CPL> cpl, wxListCtrl* ctrl)
+Controls::add_content_to_list (shared_ptr<Content> content, wxListCtrl* ctrl)
 {
-       list<shared_ptr<dcp::Reel> > reels = cpl->reels ();
-
        int const N = ctrl->GetItemCount();
 
        wxListItem it;
-       if (!reels.empty() && reels.front()->main_picture()) {
+       it.SetId(N);
+       it.SetColumn(0);
+       DCPTime length = content->length_after_trim ();
+       int seconds = length.seconds();
+       int minutes = seconds / 60;
+       seconds -= minutes * 60;
+       int hours = minutes / 60;
+       minutes -= hours * 60;
+       it.SetText(wxString::Format("%02d:%02d:%02d", hours, minutes, seconds));
+       ctrl->InsertItem(it);
+
+       shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent>(content);
+       if (dcp && dcp->content_kind()) {
                it.SetId(N);
-               it.SetColumn(0);
-               int seconds = rint(double(cpl->duration()) / reels.front()->main_picture()->frame_rate().as_float());
-               int minutes = seconds / 60;
-               seconds -= minutes * 60;
-               int hours = minutes / 60;
-               minutes -= hours * 60;
-               it.SetText(wxString::Format("%02d:%02d:%02d", hours, minutes, seconds));
-               ctrl->InsertItem(it);
+               it.SetColumn(1);
+               it.SetText(std_to_wx(dcp::content_kind_to_string(*dcp->content_kind())));
+               ctrl->SetItem(it);
        }
 
-       it.SetId(N);
-       it.SetColumn(1);
-       it.SetText(std_to_wx(dcp::content_kind_to_string(cpl->content_kind())));
-       ctrl->SetItem(it);
-
        it.SetId(N);
        it.SetColumn(2);
-       it.SetText(std_to_wx(cpl->annotation_text()));
+       it.SetText(std_to_wx(content->summary()));
        ctrl->SetItem(it);
 }
 
 void
 Controls::update_dcp_directory ()
 {
-       if (!_cpl->IsShown()) {
+       if (!_content_view->IsShown()) {
                return;
        }
 
        using namespace boost::filesystem;
 
-       _cpl->DeleteAllItems ();
-       _cpls.clear ();
+       _content_view->DeleteAllItems ();
+       _content.clear ();
        optional<path> dir = Config::instance()->player_content_directory();
        if (!dir) {
                return;
        }
 
+       wxProgressDialog progress (_("DCP-o-matic"), _("Reading DCP directory"));
+       JobManager* jm = JobManager::instance ();
+
        for (directory_iterator i = directory_iterator(*dir); i != directory_iterator(); ++i) {
                try {
                        if (is_directory(*i) && (is_regular_file(*i / "ASSETMAP") || is_regular_file(*i / "ASSETMAP.xml"))) {
-                               string const x = i->path().string().substr(dir->string().length() + 1);
-                               dcp::DCP dcp (*i);
-                               dcp.read ();
-                               BOOST_FOREACH (shared_ptr<dcp::CPL> j, dcp.cpls()) {
-                                       add_cpl_to_list (j, _cpl);
-                                       _cpls.push_back (make_pair(j, *i));
+                               shared_ptr<DCPContent> content (new DCPContent(_film, *i));
+                               jm->add (shared_ptr<Job>(new ExamineContentJob(_film, content)));
+                               while (jm->work_to_do()) {
+                                       if (!progress.Pulse()) {
+                                               /* user pressed cancel */
+                                               BOOST_FOREACH (shared_ptr<Job> i, jm->get()) {
+                                                       i->cancel();
+                                               }
+                                               return;
+                                       }
+                                       dcpomatic_sleep (1);
+                               }
+                               if (report_errors_from_last_job (this)) {
+                                       add_content_to_list (content, _content_view);
+                                       _content.push_back (content);
                                }
                        }
                } catch (boost::filesystem::filesystem_error& e) {
index 09e942e..dba981d 100644 (file)
@@ -21,7 +21,6 @@
 #include "lib/dcpomatic_time.h"
 #include "lib/types.h"
 #include "lib/film.h"
-#include "lib/spl.h"
 #include <wx/wx.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/signals2.hpp>
@@ -54,8 +53,6 @@ public:
        void show_extended_player_controls (bool s);
        void log (wxString s);
 
-       boost::signals2::signal<void (SPL)> SPLChanged;
-
 private:
        void update_position_label ();
        void update_position_slider ();
@@ -88,7 +85,7 @@ private:
 
        typedef std::pair<boost::shared_ptr<dcp::CPL>, boost::filesystem::path> CPL;
 
-       boost::optional<CPL> selected_cpl () const;
+       boost::shared_ptr<Content> selected_content () const;
 #ifdef DCPOMATIC_VARIANT_SWAROOP
        void pause_clicked ();
        void stop_clicked ();
@@ -96,7 +93,7 @@ private:
        void add_clicked ();
        void save_clicked ();
        void load_clicked ();
-       void add_cpl_to_list (boost::shared_ptr<dcp::CPL> cpl, wxListCtrl* list);
+       void add_content_to_list (boost::shared_ptr<Content> content, wxListCtrl* list);
 
        boost::shared_ptr<Film> _film;
        boost::shared_ptr<FilmViewer> _viewer;
@@ -108,13 +105,13 @@ private:
        wxCheckBox* _outline_content;
        wxChoice* _eye;
        wxCheckBox* _jump_to_selected;
-       wxListCtrl* _cpl;
+       wxListCtrl* _content_view;
        wxListCtrl* _spl_view;
        wxTextCtrl* _log;
        wxButton* _add_button;
        wxButton* _save_button;
        wxButton* _load_button;
-       std::vector<CPL> _cpls;
+       std::vector<boost::shared_ptr<Content> > _content;
        wxSlider* _slider;
        wxButton* _rewind_button;
        wxButton* _back_button;
@@ -129,7 +126,6 @@ private:
        wxToggleButton* _play_button;
 #endif
        boost::optional<std::string> _active_job;
-       SPL _spl;
 
        ClosedCaptionsDialog* _closed_captions_dialog;
 
index 0b1c683..98d69e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 #include "wx_util.h"
 #include "file_picker_ctrl.h"
 #include "lib/config.h"
+#include "lib/job_manager.h"
 #include "lib/util.h"
 #include "lib/cross.h"
+#include "lib/job.h"
 #include <dcp/locale_convert.h>
 #include <wx/spinctrl.h>
 #include <wx/splash.h>
+#include <wx/progdlg.h>
 #include <wx/filepicker.h>
 #include <boost/thread.hpp>
 
-using namespace std;
-using namespace boost;
+using std::string;
+using std::vector;
+using std::pair;
+using boost::shared_ptr;
+using boost::optional;
 using dcp::locale_convert;
 
 wxStaticText *
@@ -485,3 +491,45 @@ calculate_mark_interval (double mark_interval)
 
        return mark_interval;
 }
+
+
+/** @return false if the task was cancelled */
+bool
+display_progress (wxString title, wxString task)
+{
+       JobManager* jm = JobManager::instance ();
+
+       wxProgressDialog progress (title, task, 100, 0, wxPD_CAN_ABORT);
+
+       bool ok = true;
+
+       while (jm->work_to_do()) {
+               dcpomatic_sleep (1);
+               if (!progress.Pulse()) {
+                       /* user pressed cancel */
+                       BOOST_FOREACH (shared_ptr<Job> i, jm->get()) {
+                               i->cancel();
+                       }
+                       ok = false;
+                       break;
+               }
+       }
+
+       return ok;
+}
+
+bool
+report_errors_from_last_job (wxWindow* parent)
+{
+       JobManager* jm = JobManager::instance ();
+
+       DCPOMATIC_ASSERT (!jm->get().empty());
+
+       shared_ptr<Job> last = jm->get().back();
+       if (last->finished_in_error()) {
+               error_dialog(parent, std_to_wx(last->error_summary()) + ".\n", std_to_wx(last->error_details()));
+               return false;
+       }
+
+       return true;
+}
index 0438fce..d6de3b4 100644 (file)
@@ -87,6 +87,8 @@ extern wxString time_to_timecode (DCPTime t, double fps);
 extern void setup_audio_channels_choice (wxChoice* choice, int minimum);
 extern wxSplashScreen* maybe_show_splash ();
 extern double calculate_mark_interval (double start);
+extern bool display_progress (wxString title, wxString task);
+extern bool report_errors_from_last_job (wxWindow* parent);
 
 extern void checked_set (FilePickerCtrl* widget, boost::filesystem::path value);
 extern void checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value);