X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_playlist.cc;h=c9ceadb2658eb99df5132356f4343b19ba721a8a;hb=69f9e9881aa6f8036e93b8a1dba0a5bd1df1f901;hp=ec8c1efd8ed8c2d79bde8d608e5cc27569be29d9;hpb=e3321029d7c57d4a0a7e72e9c0aa69eb1e124016;p=dcpomatic.git diff --git a/src/tools/dcpomatic_playlist.cc b/src/tools/dcpomatic_playlist.cc index ec8c1efd8..c9ceadb26 100644 --- a/src/tools/dcpomatic_playlist.cc +++ b/src/tools/dcpomatic_playlist.cc @@ -20,40 +20,71 @@ #include "../wx/wx_util.h" #include "../wx/wx_signal_manager.h" +#include "../wx/content_view.h" #include "../lib/util.h" #include "../lib/config.h" #include "../lib/cross.h" +#include "../lib/film.h" +#include "../lib/dcp_content.h" +#include "../lib/spl_entry.h" +#include "../lib/spl.h" #include #include #include using std::exception; using std::cout; +using std::string; using boost::optional; +using boost::shared_ptr; +using boost::weak_ptr; +using boost::bind; +using boost::dynamic_pointer_cast; -class PlaylistEntry +class ContentDialog : public wxDialog, public ContentStore { public: - std::string name; - std::string cpl_id; - dcp::ContentKind kind; - enum Type { - DCP, - ECINEMA - }; - Type type; - bool encrypted; - bool skippable; - bool disable_timeline; - bool stop_after_play; -}; + ContentDialog (wxWindow* parent, weak_ptr film) + : wxDialog (parent, wxID_ANY, _("Add content"), wxDefaultPosition, wxSize(800, 640)) + , _content_view (new ContentView(this)) + { + _content_view->update (); + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + overall_sizer->Add (_content_view, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + overall_sizer->Layout (); + } + + shared_ptr selected () const + { + return _content_view->selected (); + } + + shared_ptr get (string digest) const + { + return _content_view->get (digest); + } + +private: + ContentView* _content_view; +}; class DOMFrame : public wxFrame { public: explicit DOMFrame (wxString const & title) : wxFrame (0, -1, title) + /* XXX: this is a bit of a hack, but we need it to be able to use the Content class hierarchy */ + , _film (new Film(optional())) + , _content_dialog (new ContentDialog(this, _film)) { /* Use a panel as the only child of the Frame so that we avoid the dark-grey background on Windows. @@ -66,8 +97,8 @@ public: ); _list->AppendColumn (_("Name"), wxLIST_FORMAT_LEFT, 400); - _list->AppendColumn (_("CPL"), wxLIST_FORMAT_LEFT, 400); - _list->AppendColumn (_("Type"), wxLIST_FORMAT_CENTRE, 75); + _list->AppendColumn (_("CPL"), wxLIST_FORMAT_LEFT, 350); + _list->AppendColumn (_("Type"), wxLIST_FORMAT_CENTRE, 100); _list->AppendColumn (_("Format"), wxLIST_FORMAT_CENTRE, 75); _list->AppendColumn (_("Encrypted"), wxLIST_FORMAT_CENTRE, 90); _list->AppendColumn (_("Skippable"), wxLIST_FORMAT_CENTRE, 90); @@ -111,37 +142,40 @@ public: overall_panel->SetSizer (main_sizer); _list->Bind (wxEVT_LEFT_DOWN, bind(&DOMFrame::list_left_click, this, _1)); - - PlaylistEntry pe; - pe.name = "Shit"; - pe.cpl_id = "sh-1t"; - pe.kind = dcp::FEATURE; - pe.type = PlaylistEntry::ECINEMA; - pe.encrypted = true; - pe.disable_timeline = false; - pe.stop_after_play = true; - add (pe); + _list->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&DOMFrame::selection_changed, this)); + _list->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&DOMFrame::selection_changed, this)); + _up->Bind (wxEVT_BUTTON, bind(&DOMFrame::up_clicked, this)); + _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 (); } private: - void add (PlaylistEntry e) + void add (SPLEntry e) { wxListItem item; - item.SetId (0); + item.SetId (_list->GetItemCount()); long const N = _list->InsertItem (item); set_item (N, e); - _playlist.push_back (e); + _playlist.add (e); } - void set_item (long N, PlaylistEntry e) + void selection_changed () + { + setup_sensitivity (); + } + + void set_item (long N, SPLEntry 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, 3, e.type == SPLEntry::DCP ? _("DCP") : _("E-cinema")); _list->SetItem (N, 4, e.encrypted ? _("Y") : _("N")); _list->SetItem (N, COLUMN_SKIPPABLE, wxEmptyString, e.skippable ? 0 : 1); _list->SetItem (N, COLUMN_DISABLE_TIMELINE, wxEmptyString, e.disable_timeline ? 0 : 1); @@ -150,10 +184,11 @@ private: void setup_sensitivity () { - int const selected = _list->GetSelectedItemCount (); + int const num_selected = _list->GetSelectedItemCount (); + long int selected = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); _up->Enable (selected > 0); - _down->Enable (selected > 0); - _remove->Enable (selected > 0); + _down->Enable (selected != -1 && selected < (_list->GetItemCount() - 1)); + _remove->Enable (num_selected > 0); } void list_left_click (wxMouseEvent& ev) @@ -190,6 +225,85 @@ private: } } + void add_clicked () + { + int const r = _content_dialog->ShowModal (); + if (r == wxID_OK) { + shared_ptr content = _content_dialog->selected (); + if (content) { + add (SPLEntry(content)); + } + } + } + + void up_clicked () + { + long int s = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s < 1) { + return; + } + + SPLEntry tmp = _playlist[s]; + _playlist[s] = _playlist[s-1]; + _playlist[s-1] = tmp; + + set_item (s - 1, _playlist[s-1]); + set_item (s, _playlist[s]); + } + + void down_clicked () + { + long int s = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s > (_list->GetItemCount() - 1)) { + return; + } + + SPLEntry tmp = _playlist[s]; + _playlist[s] = _playlist[s+1]; + _playlist[s+1] = tmp; + + set_item (s + 1, _playlist[s+1]); + set_item (s, _playlist[s]); + } + + void remove_clicked () + { + long int s = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s == -1) { + return; + } + + _playlist.remove (s); + _list->DeleteItem (s); + } + + void save_clicked () + { + Config* c = Config::instance (); + wxString default_dir = c->player_playlist_directory() ? std_to_wx(c->player_playlist_directory()->string()) : wxString(wxEmptyString); + wxFileDialog* d = new wxFileDialog (this, _("Select playlist file"), default_dir, wxEmptyString, wxT("XML files (*.xml)|*.xml"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (d->ShowModal() == wxID_OK) { + _playlist.write (wx_to_std(d->GetPath())); + } + } + + void load_clicked () + { + Config* c = Config::instance (); + wxString default_dir = c->player_playlist_directory() ? std_to_wx(c->player_playlist_directory()->string()) : wxString(wxEmptyString); + wxFileDialog* d = new wxFileDialog (this, _("Select playlist file"), default_dir, wxEmptyString, wxT("XML files (*.xml)|*.xml")); + if (d->ShowModal() == wxID_OK) { + _list->DeleteAllItems (); + if (!_playlist.read (wx_to_std(d->GetPath()), _content_dialog)) { + BOOST_FOREACH (SPLEntry i, _playlist.get()) { + add (i); + } + } else { + error_dialog (this, _("Some content in this playlist was not found.")); + } + } + } + wxListCtrl* _list; wxButton* _up; wxButton* _down; @@ -197,7 +311,9 @@ private: wxButton* _remove; wxButton* _save; wxButton* _load; - std::vector _playlist; + boost::shared_ptr _film; + SPL _playlist; + ContentDialog* _content_dialog; enum { COLUMN_SKIPPABLE = 5, @@ -258,7 +374,7 @@ private: */ Config::drop (); - _frame = new DOMFrame (_("DCP-o-matic KDM Creator")); + _frame = new DOMFrame (_("DCP-o-matic Playlist Editor")); SetTopWindow (_frame); _frame->Maximize (); _frame->Show ();