X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_playlist.cc;h=bc1f78dc36432935ca539bc2010ba3df3f514212;hp=b2b5c458a915b96dd263bf0882658009757f1ff1;hb=76e340c36a7c0da70b145c0437b5758eaa7134dc;hpb=2da4caba7871455c097c0ed940dd6f2332dbda5d diff --git a/src/tools/dcpomatic_playlist.cc b/src/tools/dcpomatic_playlist.cc index b2b5c458a..bc1f78dc3 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,37 +18,46 @@ */ -#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::make_shared; +using std::map; +using std::shared_ptr; +using std::string; using std::vector; -using boost::optional; -using boost::shared_ptr; -using boost::weak_ptr; +using std::weak_ptr; using boost::bind; -using boost::dynamic_pointer_cast; +using boost::optional; +using std::dynamic_pointer_cast; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif + class ContentDialog : public wxDialog, public ContentStore { @@ -59,17 +68,19 @@ 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()); } overall_sizer->Layout (); + + _config_changed_connection = Config::instance()->Changed.connect(boost::bind(&ContentView::update, _content_view)); } shared_ptr selected () const @@ -77,13 +88,14 @@ public: return _content_view->selected (); } - shared_ptr get (string digest) const + shared_ptr get (string digest) const override { return _content_view->get (digest); } private: ContentView* _content_view; + boost::signals2::scoped_connection _config_changed_connection; }; @@ -95,7 +107,7 @@ public: : _sizer (new wxBoxSizer(wxVERTICAL)) , _content_store (content_store) { - 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); @@ -106,13 +118,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); @@ -134,7 +146,7 @@ public: shared_ptr first_playlist () const { if (_playlists.empty()) { - return shared_ptr(); + return {}; } return _playlists.front (); @@ -154,43 +166,54 @@ 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: + if (auto dir = Config::instance()->player_playlist_directory()) { + playlist->write(*dir / (playlist->id() + ".xml")); + } + 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); } } @@ -210,7 +233,7 @@ private: return; } - optional dir = Config::instance()->player_playlist_directory(); + auto dir = Config::instance()->player_playlist_directory(); if (!dir) { return; } @@ -236,7 +259,7 @@ private: wxListCtrl* _list; wxButton* _new; wxButton* _delete; - vector > _playlists; + vector> _playlists; ContentStore* _content_store; }; @@ -248,15 +271,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 @@ -267,18 +290,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; -#ifdef DCPOMATIC_OSX - tick_icon.LoadFile ("tick.png", wxBITMAP_TYPE_PNG_RESOURCE); - no_tick_icon.LoadFile ("no_tick.png", wxBITMAP_TYPE_PNG_RESOURCE); -#else - boost::filesystem::path tick_path = shared_path() / "tick.png"; - tick_icon.LoadFile (std_to_wx(tick_path.string()), wxBITMAP_TYPE_PNG); - boost::filesystem::path no_tick_path = shared_path() / "no_tick.png"; - no_tick_icon.LoadFile (std_to_wx(no_tick_path.string()), wxBITMAP_TYPE_PNG); -#endif + 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); @@ -286,7 +302,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")); @@ -319,7 +335,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())); @@ -355,7 +371,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")); } @@ -376,7 +392,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); @@ -395,9 +411,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]); @@ -412,9 +426,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]); @@ -448,19 +460,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); @@ -472,11 +484,11 @@ 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); + + _config_changed_connection = Config::instance()->Changed.connect(boost::bind(&DOMFrame::config_changed, this)); } private: @@ -489,7 +501,7 @@ private: void help_about () { - AboutDialog* d = new AboutDialog (this); + auto d = new AboutDialog (this); d->ShowModal (); d->Destroy (); } @@ -504,7 +516,7 @@ private: void change_playlist (shared_ptr playlist) { - shared_ptr old = _playlist_content->playlist (); + auto old = _playlist_content->playlist (); if (old) { save_playlist (old); } @@ -513,9 +525,9 @@ private: void save_playlist (shared_ptr playlist) { - optional dir = Config::instance()->player_playlist_directory(); + auto dir = Config::instance()->player_playlist_directory(); if (!dir) { - error_dialog (this, _("No playlist folder is specified in preferences. Please set on and then try again.")); + error_dialog (this, _("No playlist folder is specified in preferences. Please set one and then try again.")); return; } playlist->write (*dir / (playlist->id() + ".xml")); @@ -523,7 +535,7 @@ private: void setup_menu (wxMenuBar* m) { - wxMenu* file = new wxMenu; + auto file = new wxMenu; #ifdef __WXOSX__ file->Append (wxID_EXIT, _("&Exit")); #else @@ -531,11 +543,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 @@ -549,12 +561,30 @@ private: m->Append (help, _("&Help")); } + + void config_changed () + { + try { + Config::instance()->write_config(); + } catch (exception& e) { + error_dialog ( + this, + wxString::Format ( + _("Could not write to config file at %s. Your changes have not been saved."), + std_to_wx (Config::instance()->cinemas_file().string()).data() + ) + ); + } + } + ContentDialog* _content_dialog; PlaylistList* _playlist_list; PlaylistContent* _playlist_content; wxPreferencesEditor* _config_dialog; + boost::signals2::scoped_connection _config_changed_connection; }; + /** @class App * @brief The magic App class for wxWidgets. */ @@ -563,12 +593,12 @@ class App : public wxApp public: App () : wxApp () - , _frame (0) + , _frame (nullptr) {} private: - bool OnInit () + bool OnInit () override try { wxInitAllImageHandlers (); @@ -623,7 +653,7 @@ private: } /* An unhandled exception has occurred inside the main event loop */ - bool OnExceptionInMainLoop () + bool OnExceptionInMainLoop () override { try { throw; @@ -652,7 +682,7 @@ private: return false; } - void OnUnhandledException () + void OnUnhandledException () override { error_dialog (0, _("An unknown exception occurred.") + " " + REPORT_PROBLEM); }