X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_playlist.cc;h=636a50f8ab9d6a3daafd36e564ba8d2ef65c871e;hp=261f0897267d9fc834f4daadf9ab6f832cbc6232;hb=5c444b35b60c34654ccef73c47e1e1bdda1f44ee;hpb=dd9be86db6cde0afa5da0d1d1ac43b42e05dca26 diff --git a/src/tools/dcpomatic_playlist.cc b/src/tools/dcpomatic_playlist.cc index 261f08972..636a50f8a 100644 --- a/src/tools/dcpomatic_playlist.cc +++ b/src/tools/dcpomatic_playlist.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2020 Carl Hetherington + Copyright (C) 2018-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,41 +18,57 @@ */ -#include "../wx/wx_util.h" -#include "../wx/wx_signal_manager.h" -#include "../wx/content_view.h" -#include "../wx/dcpomatic_button.h" -#include "../wx/about_dialog.h" -#include "../wx/playlist_editor_config_dialog.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 "wx/about_dialog.h" +#include "wx/content_view.h" +#include "wx/dcpomatic_button.h" +#include "wx/playlist_editor_config_dialog.h" +#include "wx/wx_signal_manager.h" +#include "wx/wx_util.h" +#include "lib/config.h" +#include "lib/cross.h" +#include "lib/dcp_content.h" +#include "lib/film.h" +#include "lib/spl.h" +#include "lib/spl_entry.h" +#include "lib/util.h" +#include +LIBDCP_DISABLE_WARNINGS #include -#include +#include #include -#include +#include +#include +LIBDCP_ENABLE_WARNINGS + -using std::exception; using std::cout; -using std::string; -using std::map; +using std::exception; using std::make_pair; -using std::vector; -using boost::optional; +using std::make_shared; +using std::map; using std::shared_ptr; +using std::string; +using std::vector; using std::weak_ptr; using boost::bind; +using boost::optional; using std::dynamic_pointer_cast; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif + +static +void +save_playlist(shared_ptr playlist) +{ + if (auto dir = Config::instance()->player_playlist_directory()) { + playlist->write(*dir / (playlist->id() + ".xml")); + } +} + + class ContentDialog : public wxDialog, public ContentStore { public: @@ -62,12 +78,12 @@ public: { _content_view->update (); - wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + auto overall_sizer = new wxBoxSizer (wxVERTICAL); SetSizer (overall_sizer); overall_sizer->Add (_content_view, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); if (buttons) { overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); } @@ -82,7 +98,7 @@ public: return _content_view->selected (); } - shared_ptr get (string digest) const + shared_ptr get (string digest) const override { return _content_view->get (digest); } @@ -100,8 +116,9 @@ public: PlaylistList (wxPanel* parent, ContentStore* content_store) : _sizer (new wxBoxSizer(wxVERTICAL)) , _content_store (content_store) + , _parent(parent) { - wxStaticText* label = new wxStaticText (parent, wxID_ANY, wxEmptyString); + auto label = new wxStaticText (parent, wxID_ANY, wxEmptyString); label->SetLabelMarkup (_("Playlists")); _sizer->Add (label, 0, wxTOP | wxLEFT, DCPOMATIC_SIZER_GAP * 2); @@ -112,13 +129,13 @@ public: _list->AppendColumn (_("Name"), wxLIST_FORMAT_LEFT, 840); _list->AppendColumn (_("Length"), wxLIST_FORMAT_LEFT, 100); - wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL); + auto button_sizer = new wxBoxSizer (wxVERTICAL); _new = new Button (parent, _("New")); button_sizer->Add (_new, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); _delete = new Button (parent, _("Delete")); button_sizer->Add (_delete, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP); - wxSizer* list = new wxBoxSizer (wxHORIZONTAL); + auto list = new wxBoxSizer (wxHORIZONTAL); list->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP); list->Add (button_sizer, 0, wxALL, DCPOMATIC_SIZER_GAP); @@ -130,6 +147,8 @@ public: _list->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, bind(&PlaylistList::selection_changed, this)); _new->Bind (wxEVT_BUTTON, bind(&PlaylistList::new_playlist, this)); _delete->Bind (wxEVT_BUTTON, bind(&PlaylistList::delete_playlist, this)); + + setup_sensitivity(); } wxSizer* sizer () @@ -140,7 +159,7 @@ public: shared_ptr first_playlist () const { if (_playlists.empty()) { - return shared_ptr(); + return {}; } return _playlists.front (); @@ -149,6 +168,11 @@ public: boost::signals2::signal)> Edit; private: + void setup_sensitivity() + { + _delete->Enable(static_cast(selected())); + } + void add_playlist_to_view (shared_ptr playlist) { wxListItem item; @@ -160,72 +184,97 @@ private: void add_playlist_to_model (shared_ptr playlist) { _playlists.push_back (playlist); - playlist->NameChanged.connect (bind(&PlaylistList::name_changed, this, weak_ptr(playlist))); + playlist->Changed.connect(bind(&PlaylistList::changed, this, weak_ptr(playlist), _1)); } - void name_changed (weak_ptr wp) + void changed(weak_ptr wp, SignalSPL::Change change) { - shared_ptr playlist = wp.lock (); + auto playlist = wp.lock (); if (!playlist) { return; } - int N = 0; - BOOST_FOREACH (shared_ptr i, _playlists) { - if (i == playlist) { - _list->SetItem (N, 0, std_to_wx(i->name())); + switch (change) { + case SignalSPL::Change::NAME: + { + int N = 0; + for (auto i: _playlists) { + if (i == playlist) { + _list->SetItem (N, 0, std_to_wx(i->name())); + } + ++N; } - ++N; + break; + } + case SignalSPL::Change::CONTENT: + save_playlist(playlist); + break; } } void load_playlists () { - optional path = Config::instance()->player_playlist_directory(); + auto path = Config::instance()->player_playlist_directory(); if (!path) { return; } _list->DeleteAllItems (); _playlists.clear (); - for (boost::filesystem::directory_iterator i(*path); i != boost::filesystem::directory_iterator(); ++i) { - shared_ptr spl(new SignalSPL); + for (auto i: boost::filesystem::directory_iterator(*path)) { + auto spl = make_shared(); try { - spl->read (*i, _content_store); + spl->read (i, _content_store); add_playlist_to_model (spl); } catch (...) {} } - BOOST_FOREACH (shared_ptr i, _playlists) { + for (auto i: _playlists) { add_playlist_to_view (i); } } void new_playlist () { + auto dir = Config::instance()->player_playlist_directory(); + if (!dir) { + error_dialog(_parent, _("No playlist folder is specified in preferences. Please set one and then try again.")); + return; + } + shared_ptr spl (new SignalSPL(wx_to_std(_("New Playlist")))); add_playlist_to_model (spl); add_playlist_to_view (spl); _list->SetItemState (_list->GetItemCount() - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); } - void delete_playlist () + boost::optional selected() const { - long int selected = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + long int selected = _list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (selected < 0 || selected >= int(_playlists.size())) { + return {}; + } + + return selected; + } + + void delete_playlist () + { + auto index = selected(); + if (!index) { return; } - optional dir = Config::instance()->player_playlist_directory(); + auto dir = Config::instance()->player_playlist_directory(); if (!dir) { return; } - boost::filesystem::remove (*dir / (_playlists[selected]->id() + ".xml")); - _list->DeleteItem (selected); - _playlists.erase (_playlists.begin() + selected); + boost::filesystem::remove(*dir / (_playlists[*index]->id() + ".xml")); + _list->DeleteItem(*index); + _playlists.erase(_playlists.begin() + *index); - Edit (shared_ptr()); + Edit(shared_ptr()); } void selection_changed () @@ -236,14 +285,17 @@ private: } else { Edit (_playlists[selected]); } + + setup_sensitivity(); } wxBoxSizer* _sizer; wxListCtrl* _list; wxButton* _new; wxButton* _delete; - vector > _playlists; + vector> _playlists; ContentStore* _content_store; + wxWindow* _parent; }; @@ -254,15 +306,15 @@ public: : _content_dialog (content_dialog) , _sizer (new wxBoxSizer(wxVERTICAL)) { - wxBoxSizer* title = new wxBoxSizer (wxHORIZONTAL); - wxStaticText* label = new wxStaticText (parent, wxID_ANY, wxEmptyString); + auto title = new wxBoxSizer (wxHORIZONTAL); + auto label = new wxStaticText (parent, wxID_ANY, wxEmptyString); label->SetLabelMarkup (_("Playlist:")); title->Add (label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, DCPOMATIC_SIZER_GAP); _name = new wxTextCtrl (parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1)); title->Add (_name, 0, wxRIGHT, DCPOMATIC_SIZER_GAP); _sizer->Add (title, 0, wxTOP | wxLEFT, DCPOMATIC_SIZER_GAP * 2); - wxBoxSizer* list = new wxBoxSizer (wxHORIZONTAL); + auto list = new wxBoxSizer (wxHORIZONTAL); _list = new wxListCtrl ( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL @@ -273,11 +325,11 @@ public: _list->AppendColumn (_("Type"), wxLIST_FORMAT_LEFT, 100); _list->AppendColumn (_("Encrypted"), wxLIST_FORMAT_CENTRE, 90); - wxImageList* images = new wxImageList (16, 16); + auto images = new wxImageList (16, 16); wxIcon tick_icon; wxIcon no_tick_icon; - tick_icon.LoadFile (bitmap_path("tick"), wxBITMAP_TYPE_PNG); - no_tick_icon.LoadFile (bitmap_path("no_tick"), wxBITMAP_TYPE_PNG); + tick_icon.LoadFile (bitmap_path("tick.png"), wxBITMAP_TYPE_PNG); + no_tick_icon.LoadFile (bitmap_path("no_tick.png"), wxBITMAP_TYPE_PNG); images->Add (tick_icon); images->Add (no_tick_icon); @@ -285,7 +337,7 @@ public: list->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP); - wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL); + auto button_sizer = new wxBoxSizer (wxVERTICAL); _up = new Button (parent, _("Up")); _down = new Button (parent, _("Down")); _add = new Button (parent, _("Add")); @@ -306,6 +358,8 @@ public: _down->Bind (wxEVT_BUTTON, bind(&PlaylistContent::down_clicked, this)); _add->Bind (wxEVT_BUTTON, bind(&PlaylistContent::add_clicked, this)); _remove->Bind (wxEVT_BUTTON, bind(&PlaylistContent::remove_clicked, this)); + + setup_sensitivity(); } wxSizer* sizer () @@ -318,7 +372,7 @@ public: _playlist = playlist; _list->DeleteAllItems (); if (_playlist) { - BOOST_FOREACH (SPLEntry i, _playlist->get()) { + for (auto i: _playlist->get()) { add (i); } _name->SetValue (std_to_wx(_playlist->name())); @@ -354,7 +408,7 @@ private: { _list->SetItem (N, 0, std_to_wx(e.name)); _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, 2, std_to_wx(e.kind->name())); _list->SetItem (N, 3, e.encrypted ? S_("Question|Y") : S_("Question|N")); } @@ -375,7 +429,7 @@ private: { int const r = _content_dialog->ShowModal (); if (r == wxID_OK) { - shared_ptr content = _content_dialog->selected (); + auto content = _content_dialog->selected (); if (content) { SPLEntry e (content); add (e); @@ -394,9 +448,7 @@ private: DCPOMATIC_ASSERT (_playlist); - SPLEntry tmp = (*_playlist)[s]; - (*_playlist)[s] = (*_playlist)[s-1]; - (*_playlist)[s-1] = tmp; + _playlist->swap(s, s - 1); set_item (s - 1, (*_playlist)[s-1]); set_item (s, (*_playlist)[s]); @@ -411,9 +463,7 @@ private: DCPOMATIC_ASSERT (_playlist); - SPLEntry tmp = (*_playlist)[s]; - (*_playlist)[s] = (*_playlist)[s+1]; - (*_playlist)[s+1] = tmp; + _playlist->swap(s, s + 1); set_item (s + 1, (*_playlist)[s+1]); set_item (s, (*_playlist)[s]); @@ -447,19 +497,19 @@ class DOMFrame : public wxFrame { public: explicit DOMFrame (wxString const & title) - : wxFrame (0, -1, title) + : wxFrame (nullptr, wxID_ANY, title) , _content_dialog (new ContentDialog(this)) - , _config_dialog (0) + , _config_dialog (nullptr) { - wxMenuBar* bar = new wxMenuBar; + auto bar = new wxMenuBar; setup_menu (bar); SetMenuBar (bar); /* 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* sizer = new wxBoxSizer (wxVERTICAL); + auto overall_panel = new wxPanel (this, wxID_ANY); + auto sizer = new wxBoxSizer (wxVERTICAL); _playlist_list = new PlaylistList (overall_panel, _content_dialog); _playlist_content = new PlaylistContent (overall_panel, _content_dialog); @@ -471,8 +521,6 @@ public: _playlist_list->Edit.connect (bind(&DOMFrame::change_playlist, this, _1)); - _playlist_content->set (_playlist_list->first_playlist()); - Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT); Bind (wxEVT_MENU, boost::bind (&DOMFrame::help_about, this), wxID_ABOUT); Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES); @@ -490,7 +538,7 @@ private: void help_about () { - AboutDialog* d = new AboutDialog (this); + auto d = new AboutDialog (this); d->ShowModal (); d->Destroy (); } @@ -505,26 +553,16 @@ private: void change_playlist (shared_ptr playlist) { - shared_ptr old = _playlist_content->playlist (); + auto old = _playlist_content->playlist (); if (old) { save_playlist (old); } _playlist_content->set (playlist); } - void save_playlist (shared_ptr playlist) - { - optional dir = Config::instance()->player_playlist_directory(); - if (!dir) { - error_dialog (this, _("No playlist folder is specified in preferences. Please set one and then try again.")); - return; - } - playlist->write (*dir / (playlist->id() + ".xml")); - } - void setup_menu (wxMenuBar* m) { - wxMenu* file = new wxMenu; + auto file = new wxMenu; #ifdef __WXOSX__ file->Append (wxID_EXIT, _("&Exit")); #else @@ -532,11 +570,11 @@ private: #endif #ifndef __WXOSX__ - wxMenu* edit = new wxMenu; + auto edit = new wxMenu; edit->Append (wxID_PREFERENCES, _("&Preferences...\tCtrl-P")); #endif - wxMenu* help = new wxMenu; + auto help = new wxMenu; #ifdef __WXOSX__ help->Append (wxID_ABOUT, _("About DCP-o-matic")); #else @@ -566,7 +604,6 @@ private: } } - ContentDialog* _content_dialog; PlaylistList* _playlist_list; PlaylistContent* _playlist_content; @@ -574,6 +611,7 @@ private: boost::signals2::scoped_connection _config_changed_connection; }; + /** @class App * @brief The magic App class for wxWidgets. */ @@ -582,12 +620,12 @@ class App : public wxApp public: App () : wxApp () - , _frame (0) + , _frame (nullptr) {} private: - bool OnInit () + bool OnInit () override try { wxInitAllImageHandlers (); @@ -642,7 +680,7 @@ private: } /* An unhandled exception has occurred inside the main event loop */ - bool OnExceptionInMainLoop () + bool OnExceptionInMainLoop () override { try { throw; @@ -671,7 +709,7 @@ private: return false; } - void OnUnhandledException () + void OnUnhandledException () override { error_dialog (0, _("An unknown exception occurred.") + " " + REPORT_PROBLEM); }