X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_playlist.cc;h=de6ae107b36883bdc05914a5c044ccf30482779e;hb=1d589b5c4765ec80e03914cc4cc4c0e39252512d;hp=04beb0250f2962cd55d10c4c284f25d9bed86835;hpb=a3f6e20d055cdf1697eab011622dc569010ad617;p=dcpomatic.git diff --git a/src/tools/dcpomatic_playlist.cc b/src/tools/dcpomatic_playlist.cc index 04beb0250..de6ae107b 100644 --- a/src/tools/dcpomatic_playlist.cc +++ b/src/tools/dcpomatic_playlist.cc @@ -21,64 +21,37 @@ #include "../wx/wx_util.h" #include "../wx/wx_signal_manager.h" #include "../wx/content_view.h" +#include "../wx/dcpomatic_button.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 +#include +#ifdef __WXOSX__ +#include +#endif 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: - PlaylistEntry (boost::shared_ptr content) - : skippable (false) - , disable_timeline (false) - , stop_after_play (false) - { - shared_ptr dcp = dynamic_pointer_cast (content); - if (dcp) { - name = dcp->name (); - cpl_id = dcp->cpl().get_value_or(""); - kind = dcp->content_kind().get_value_or(dcp::FEATURE); - type = DCP; - encrypted = dcp->encrypted (); - } else { - name = content->path(0).filename().string(); - type = ECINEMA; - } - } - - 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; -}; - -class ContentDialog : public wxDialog -{ -public: - ContentDialog (wxWindow* parent, weak_ptr film) + ContentDialog (wxWindow* parent) : wxDialog (parent, wxID_ANY, _("Add content"), wxDefaultPosition, wxSize(800, 640)) - , _content_view (new ContentView(this, film)) + , _content_view (new ContentView(this)) { _content_view->update (); @@ -100,6 +73,11 @@ public: return _content_view->selected (); } + shared_ptr get (string digest) const + { + return _content_view->get (digest); + } + private: ContentView* _content_view; }; @@ -109,15 +87,13 @@ 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)) + , _content_dialog (new ContentDialog(this)) { /* Use a panel as the only child of the Frame so that we avoid the dark-grey background on Windows. */ wxPanel* overall_panel = new wxPanel (this, wxID_ANY); - wxBoxSizer* main_sizer = new wxBoxSizer (wxHORIZONTAL); + wxBoxSizer* h_sizer = new wxBoxSizer (wxHORIZONTAL); _list = new wxListCtrl ( overall_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL @@ -149,15 +125,15 @@ public: _list->SetImageList (images, wxIMAGE_LIST_SMALL); - main_sizer->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP); + h_sizer->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP); wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL); - _up = new wxButton (overall_panel, wxID_ANY, _("Up")); - _down = new wxButton (overall_panel, wxID_ANY, _("Down")); - _add = new wxButton (overall_panel, wxID_ANY, _("Add")); - _remove = new wxButton (overall_panel, wxID_ANY, _("Remove")); - _save = new wxButton (overall_panel, wxID_ANY, _("Save playlist")); - _load = new wxButton (overall_panel, wxID_ANY, _("Load playlist")); + _up = new Button (overall_panel, _("Up")); + _down = new Button (overall_panel, _("Down")); + _add = new Button (overall_panel, _("Add")); + _remove = new Button (overall_panel, _("Remove")); + _save = new Button (overall_panel, _("Save playlist")); + _load = new Button (overall_panel, _("Load playlist")); button_sizer->Add (_up, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); button_sizer->Add (_down, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); button_sizer->Add (_add, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); @@ -165,8 +141,20 @@ public: button_sizer->Add (_save, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); button_sizer->Add (_load, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); - main_sizer->Add (button_sizer, 0, wxALL, DCPOMATIC_SIZER_GAP); - overall_panel->SetSizer (main_sizer); + h_sizer->Add (button_sizer, 0, wxALL, DCPOMATIC_SIZER_GAP); + + wxBoxSizer* v_sizer = new wxBoxSizer (wxVERTICAL); + + wxBoxSizer* allowed_shows_sizer = new wxBoxSizer (wxHORIZONTAL); + _allowed_shows_enable = new wxCheckBox (overall_panel, wxID_ANY, _("Limit number of shows with this playlist to")); + allowed_shows_sizer->Add (_allowed_shows_enable, 0, wxRIGHT, DCPOMATIC_SIZER_GAP); + _allowed_shows = new wxSpinCtrl (overall_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 65536, 100); + allowed_shows_sizer->Add (_allowed_shows); + + v_sizer->Add (allowed_shows_sizer, 0, wxALL, DCPOMATIC_SIZER_GAP); + v_sizer->Add (h_sizer); + + overall_panel->SetSizer (v_sizer); _list->Bind (wxEVT_LEFT_DOWN, bind(&DOMFrame::list_left_click, this, _1)); _list->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&DOMFrame::selection_changed, this)); @@ -175,19 +163,32 @@ 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)); + _allowed_shows_enable->Bind (wxEVT_CHECKBOX, bind(&DOMFrame::allowed_shows_changed, this)); + _allowed_shows->Bind (wxEVT_SPINCTRL, bind(&DOMFrame::allowed_shows_changed, this)); setup_sensitivity (); } private: - void add (PlaylistEntry e) + void allowed_shows_changed () + { + if (_allowed_shows_enable->GetValue()) { + _playlist.set_allowed_shows (_allowed_shows->GetValue()); + } else { + _playlist.unset_allowed_shows (); + } + setup_sensitivity (); + } + + void add (SPLEntry e) { wxListItem item; item.SetId (_list->GetItemCount()); long const N = _list->InsertItem (item); set_item (N, e); - _playlist.push_back (e); } void selection_changed () @@ -195,13 +196,13 @@ private: setup_sensitivity (); } - void set_item (long N, PlaylistEntry e) + 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, 4, e.encrypted ? _("Y") : _("N")); + _list->SetItem (N, 3, e.type == SPLEntry::DCP ? _("DCP") : _("E-cinema")); + _list->SetItem (N, 4, e.encrypted ? S_("Question|Y") : S_("Question|N")); _list->SetItem (N, COLUMN_SKIPPABLE, wxEmptyString, e.skippable ? 0 : 1); _list->SetItem (N, COLUMN_DISABLE_TIMELINE, wxEmptyString, e.disable_timeline ? 0 : 1); _list->SetItem (N, COLUMN_STOP_AFTER_PLAY, wxEmptyString, e.stop_after_play ? 0 : 1); @@ -214,6 +215,7 @@ private: _up->Enable (selected > 0); _down->Enable (selected != -1 && selected < (_list->GetItemCount() - 1)); _remove->Enable (num_selected > 0); + _allowed_shows->Enable (_allowed_shows_enable->GetValue()); } void list_left_click (wxMouseEvent& ev) @@ -256,7 +258,9 @@ private: if (r == wxID_OK) { shared_ptr content = _content_dialog->selected (); if (content) { - add (PlaylistEntry(content)); + SPLEntry e (content); + add (e); + _playlist.add (e); } } } @@ -268,7 +272,7 @@ private: return; } - PlaylistEntry tmp = _playlist[s]; + SPLEntry tmp = _playlist[s]; _playlist[s] = _playlist[s-1]; _playlist[s-1] = tmp; @@ -283,7 +287,7 @@ private: return; } - PlaylistEntry tmp = _playlist[s]; + SPLEntry tmp = _playlist[s]; _playlist[s] = _playlist[s+1]; _playlist[s+1] = tmp; @@ -298,10 +302,49 @@ private: return; } - _playlist.erase (_playlist.begin() + s); + _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) { + boost::filesystem::path file = wx_to_std (d->GetPath()); + file.replace_extension (".xml"); + _playlist.write (file); + } + } + + 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 (); + _playlist.read (wx_to_std(d->GetPath()), _content_dialog); + if (!_playlist.missing()) { + _list->DeleteAllItems (); + BOOST_FOREACH (SPLEntry i, _playlist.get()) { + add (i); + } + } else { + error_dialog (this, _("Some content in this playlist was not found.")); + } + optional allowed_shows = _playlist.allowed_shows (); + _allowed_shows_enable->SetValue (static_cast(allowed_shows)); + if (allowed_shows) { + _allowed_shows->SetValue (*allowed_shows); + } else { + _allowed_shows->SetValue (65536); + } + setup_sensitivity (); + } + } + wxListCtrl* _list; wxButton* _up; wxButton* _down; @@ -309,8 +352,9 @@ private: wxButton* _remove; wxButton* _save; wxButton* _load; - boost::shared_ptr _film; - std::vector _playlist; + wxCheckBox* _allowed_shows_enable; + wxSpinCtrl* _allowed_shows; + SPL _playlist; ContentDialog* _content_dialog; enum { @@ -346,7 +390,7 @@ private: unsetenv ("UBUNTU_MENUPROXY"); #endif - #ifdef __WXOSX__ +#ifdef __WXOSX__ ProcessSerialNumber serial; GetCurrentProcess (&serial); TransformProcessType (&serial, kProcessTransformToForegroundApplication);