Basic save/load of playlists.
authorCarl Hetherington <cth@carlh.net>
Thu, 15 Nov 2018 22:07:13 +0000 (22:07 +0000)
committerCarl Hetherington <cth@carlh.net>
Thu, 22 Nov 2018 23:26:18 +0000 (23:26 +0000)
src/tools/dcpomatic_playlist.cc
src/wx/content_view.cc
src/wx/content_view.h

index 04beb0250f2962cd55d10c4c284f25d9bed86835..43cb70550c73a0ec4861aa0ce606dc5b06728639 100644 (file)
@@ -32,6 +32,7 @@
 
 using std::exception;
 using std::cout;
+using std::string;
 using boost::optional;
 using boost::shared_ptr;
 using boost::weak_ptr;
@@ -45,22 +46,49 @@ public:
                : skippable (false)
                , disable_timeline (false)
                , stop_after_play (false)
+       {
+               construct (content);
+       }
+
+       PlaylistEntry (boost::shared_ptr<Content> content, cxml::ConstNodePtr node)
+               : skippable (node->bool_child("Skippable"))
+               , disable_timeline (node->bool_child("DisableTimeline"))
+               , stop_after_play (node->bool_child("StopAfterPlay"))
+       {
+               construct (content);
+       }
+
+       void construct (shared_ptr<Content> content)
        {
                shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent> (content);
+               digest = content->digest ();
                if (dcp) {
                        name = dcp->name ();
-                       cpl_id = dcp->cpl().get_value_or("");
+                       DCPOMATIC_ASSERT (dcp->cpl());
+                       id = *dcp->cpl();
                        kind = dcp->content_kind().get_value_or(dcp::FEATURE);
                        type = DCP;
                        encrypted = dcp->encrypted ();
                } else {
                        name = content->path(0).filename().string();
                        type = ECINEMA;
+                       kind = dcp::FEATURE;
                }
        }
 
+       void as_xml (xmlpp::Element* e)
+       {
+               e->add_child("Digest")->add_child_text(digest);
+               e->add_child("Skippable")->add_child_text(skippable ? "1" : "0");
+               e->add_child("DisableTimeline")->add_child_text(disable_timeline ? "1" : "0");
+               e->add_child("StopAfterPlay")->add_child_text(stop_after_play ? "1" : "0");
+       }
+
        std::string name;
-       std::string cpl_id;
+       /** Digest of this content */
+       std::string digest;
+       /** CPL ID or something else for MP4 (?) */
+       std::string id;
        dcp::ContentKind kind;
        enum Type {
                DCP,
@@ -100,6 +128,11 @@ public:
                return _content_view->selected ();
        }
 
+       shared_ptr<Content> get (string digest) const
+       {
+               return _content_view->get (digest);
+       }
+
 private:
        ContentView* _content_view;
 };
@@ -175,6 +208,8 @@ public:
                _down->Bind (wxEVT_BUTTON, bind(&DOMFrame::down_clicked, this));
                _add->Bind (wxEVT_BUTTON, bind(&DOMFrame::add_clicked, this));
                _remove->Bind (wxEVT_BUTTON, bind(&DOMFrame::remove_clicked, this));
+               _save->Bind (wxEVT_BUTTON, bind(&DOMFrame::save_clicked, this));
+               _load->Bind (wxEVT_BUTTON, bind(&DOMFrame::load_clicked, this));
 
                setup_sensitivity ();
        }
@@ -198,7 +233,7 @@ private:
        void set_item (long N, PlaylistEntry e)
        {
                _list->SetItem (N, 0, std_to_wx(e.name));
-               _list->SetItem (N, 1, std_to_wx(e.cpl_id));
+               _list->SetItem (N, 1, std_to_wx(e.id));
                _list->SetItem (N, 2, std_to_wx(dcp::content_kind_to_string(e.kind)));
                _list->SetItem (N, 3, e.type == PlaylistEntry::DCP ? _("DCP") : _("E-cinema"));
                _list->SetItem (N, 4, e.encrypted ? _("Y") : _("N"));
@@ -302,6 +337,42 @@ private:
                _list->DeleteItem (s);
        }
 
+       void save_clicked ()
+       {
+               wxFileDialog* d = new wxFileDialog (this, _("Select playlist file"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+               if (d->ShowModal() == wxID_OK) {
+                       xmlpp::Document doc;
+                       xmlpp::Element* root = doc.create_root_node ("SPL");
+                       BOOST_FOREACH (PlaylistEntry i, _playlist) {
+                               i.as_xml (root->add_child("Entry"));
+                       }
+                       doc.write_to_file_formatted (wx_to_std(d->GetPath()));
+               }
+       }
+
+       void load_clicked ()
+       {
+               wxFileDialog* d = new wxFileDialog (this, _("Select playlist file"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"));
+               if (d->ShowModal() == wxID_OK) {
+                       _list->DeleteAllItems ();
+                       _playlist.clear ();
+                       cxml::Document doc ("SPL");
+                       doc.read_file (wx_to_std(d->GetPath()));
+                       bool missing = false;
+                       BOOST_FOREACH (cxml::ConstNodePtr i, doc.node_children("Entry")) {
+                               shared_ptr<Content> c = _content_dialog->get(i->string_child("Digest"));
+                               if (c) {
+                                       add (PlaylistEntry(c, i));
+                               } else {
+                                       missing = true;
+                               }
+                       }
+                       if (missing) {
+                               error_dialog (this, _("Some content in this playlist was not found."));
+                       }
+               }
+       }
+
        wxListCtrl* _list;
        wxButton* _up;
        wxButton* _down;
index 4eab80339ec09fcbf509c2d2a77d0231122810e3..aeefb65df7cdc20e963f49f53fb476043c1cd70d 100644 (file)
@@ -32,6 +32,7 @@
 #include <boost/optional.hpp>
 #include <wx/progdlg.h>
 
+using std::string;
 using boost::shared_ptr;
 using boost::weak_ptr;
 using boost::optional;
@@ -145,3 +146,15 @@ ContentView::add (shared_ptr<Content> content)
        it.SetText(std_to_wx(content->summary()));
        SetItem(it);
 }
+
+shared_ptr<Content>
+ContentView::get (string digest) const
+{
+       BOOST_FOREACH (shared_ptr<Content> i, _content) {
+               if (i->digest() == digest) {
+                       return i;
+               }
+       }
+
+       return shared_ptr<Content>();
+}
index 0da53f636f139ff0d1838ec1793ad011bc1c821a..ac64600e10a95feba9dc4cfd647e855b95eb4c78 100644 (file)
@@ -34,6 +34,8 @@ public:
        boost::shared_ptr<Content> selected () const;
        void update ();
 
+       boost::shared_ptr<Content> get (std::string digest) const;
+
 private:
        void add (boost::shared_ptr<Content> content);