swaroop: progress dialogue when loading SPL.
[dcpomatic.git] / src / wx / swaroop_controls.cc
1 /*
2     Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "swaroop_controls.h"
22 #include "film_viewer.h"
23 #include "wx_util.h"
24 #include "content_view.h"
25 #include "dcpomatic_button.h"
26 #include "lib/player_video.h"
27 #include "lib/dcp_content.h"
28 #include <wx/listctrl.h>
29 #include <wx/progdlg.h>
30
31 using std::string;
32 using std::cout;
33 using std::exception;
34 using boost::shared_ptr;
35 using boost::dynamic_pointer_cast;
36 using boost::optional;
37
38 SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr<FilmViewer> viewer)
39         : Controls (parent, viewer, false)
40         , _play_button (new Button(this, _("Play")))
41         , _pause_button (new Button(this, _("Pause")))
42         , _stop_button (new Button(this, _("Stop")))
43         , _current_disable_timeline (false)
44 {
45         _button_sizer->Add (_play_button, 0, wxEXPAND);
46         _button_sizer->Add (_pause_button, 0, wxEXPAND);
47         _button_sizer->Add (_stop_button, 0, wxEXPAND);
48
49         _spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
50         _spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 740);
51
52         wxBoxSizer* left_sizer = new wxBoxSizer (wxVERTICAL);
53         wxBoxSizer* e_sizer = new wxBoxSizer (wxHORIZONTAL);
54
55         left_sizer->Add (_spl_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
56
57         _content_view = new ContentView (this);
58         left_sizer->Add (_content_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
59
60         _current_spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
61         _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 500);
62         _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
63         e_sizer->Add (left_sizer, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
64         e_sizer->Add (_current_spl_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
65
66         _v_sizer->Add (e_sizer, 1, wxEXPAND);
67
68         _log = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(-1, 200), wxTE_READONLY | wxTE_MULTILINE);
69         _v_sizer->Add (_log, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
70
71         _play_button->Bind  (wxEVT_BUTTON, boost::bind(&SwaroopControls::play_clicked,  this));
72         _pause_button->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::pause_clicked, this));
73         _stop_button->Bind  (wxEVT_BUTTON, boost::bind(&SwaroopControls::stop_clicked,  this));
74         _spl_view->Bind     (wxEVT_LIST_ITEM_SELECTED,   boost::bind(&SwaroopControls::spl_selection_changed, this));
75         _spl_view->Bind     (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&SwaroopControls::spl_selection_changed, this));
76         _viewer->ImageChanged.connect (boost::bind(&SwaroopControls::image_changed, this, _1));
77
78         _content_view->update ();
79         update_playlist_directory ();
80 }
81
82 void
83 SwaroopControls::started ()
84 {
85         Controls::started ();
86         _play_button->Enable (false);
87         _pause_button->Enable (true);
88 }
89
90 void
91 SwaroopControls::stopped ()
92 {
93         Controls::stopped ();
94         _play_button->Enable (true);
95         _pause_button->Enable (false);
96 }
97
98 void
99 SwaroopControls::play_clicked ()
100 {
101         _viewer->start ();
102 }
103
104 void
105 SwaroopControls::setup_sensitivity ()
106 {
107         Controls::setup_sensitivity ();
108         bool const active_job = _active_job && *_active_job != "examine_content";
109         bool const c = _film && !_film->content().empty() && !active_job;
110         _play_button->Enable (c && !_viewer->playing());
111         _pause_button->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT) && _viewer->playing());
112         _stop_button->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT));
113         _slider->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT) && !_current_disable_timeline);
114         _spl_view->Enable (!_viewer->playing());
115 }
116
117 void
118 SwaroopControls::pause_clicked ()
119 {
120         _viewer->stop ();
121 }
122
123 void
124 SwaroopControls::stop_clicked ()
125 {
126         _viewer->stop ();
127         _viewer->seek (DCPTime(), true);
128 }
129
130 void
131 SwaroopControls::log (wxString s)
132 {
133         struct timeval time;
134         gettimeofday (&time, 0);
135         char buffer[64];
136         time_t const sec = time.tv_sec;
137         struct tm* t = localtime (&sec);
138         strftime (buffer, 64, "%c", t);
139         wxString ts = std_to_wx(string(buffer)) + N_(": ");
140         _log->SetValue(_log->GetValue() + ts + s + "\n");
141 }
142
143 void
144 SwaroopControls::image_changed (boost::weak_ptr<PlayerVideo> weak_pv)
145 {
146         shared_ptr<PlayerVideo> pv = weak_pv.lock ();
147         if (!pv) {
148                 return;
149         }
150
151         shared_ptr<Content> c = pv->content().lock();
152         if (!c) {
153                 return;
154         }
155
156         if (c == _current_content.lock()) {
157                 return;
158         }
159
160         _current_content = c;
161
162         if (_selected_playlist) {
163                 BOOST_FOREACH (SPLEntry i, _playlists[*_selected_playlist].get()) {
164                         if (i.content == c) {
165                                 _current_disable_timeline = i.disable_timeline;
166                                 setup_sensitivity ();
167                         }
168                 }
169         }
170
171         shared_ptr<DCPContent> dc = dynamic_pointer_cast<DCPContent> (c);
172         if (!dc) {
173                 return;
174         }
175
176         if (!_current_kind || *_current_kind != dc->content_kind()) {
177                 _current_kind = dc->content_kind ();
178                 setup_sensitivity ();
179         }
180 }
181
182 void
183 SwaroopControls::add_playlist_to_list (SPL spl)
184 {
185         int const N = _spl_view->GetItemCount();
186
187         wxListItem it;
188         it.SetId(N);
189         it.SetColumn(0);
190         it.SetText (std_to_wx(spl.name()));
191         _spl_view->InsertItem (it);
192 }
193
194 void
195 SwaroopControls::update_playlist_directory ()
196 {
197         using namespace boost::filesystem;
198
199         _spl_view->DeleteAllItems ();
200         optional<path> dir = Config::instance()->player_playlist_directory();
201         if (!dir) {
202                 return;
203         }
204
205         _playlists.clear ();
206
207         for (directory_iterator i = directory_iterator(*dir); i != directory_iterator(); ++i) {
208                 try {
209                         if (is_regular_file(i->path()) && i->path().extension() == ".xml") {
210                                 SPL spl;
211                                 spl.read (i->path(), _content_view);
212                                 _playlists.push_back (spl);
213                                 add_playlist_to_list (spl);
214                         }
215                 } catch (exception& e) {
216                         /* Never mind */
217                 }
218         }
219 }
220
221 void
222 SwaroopControls::spl_selection_changed ()
223 {
224         _current_spl_view->DeleteAllItems ();
225
226         long int selected = _spl_view->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
227         if (selected == -1) {
228                 _selected_playlist = boost::none;
229                 return;
230         }
231
232         wxProgressDialog progress (_("DCP-o-matic"), _("Loading playlist"));
233
234         shared_ptr<Film> film (new Film(optional<boost::filesystem::path>()));
235
236         int N = 0;
237         BOOST_FOREACH (SPLEntry i, _playlists[selected].get()) {
238                 wxListItem it;
239                 it.SetId (N);
240                 it.SetColumn (0);
241                 it.SetText (std_to_wx(i.name));
242                 _current_spl_view->InsertItem (it);
243                 film->add_content (i.content);
244                 ++N;
245                 if (!progress.Pulse()) {
246                         /* user pressed cancel */
247                         return;
248                 }
249         }
250
251         _selected_playlist = selected;
252         ResetFilm (film);
253 }
254
255 void
256 SwaroopControls::config_changed (int property)
257 {
258         Controls::config_changed (property);
259
260         if (property == Config::PLAYER_CONTENT_DIRECTORY) {
261                 _content_view->update ();
262         } else if (property == Config::PLAYER_PLAYLIST_DIRECTORY) {
263                 update_playlist_directory ();
264         }
265 }
266
267 void
268 SwaroopControls::set_film (shared_ptr<Film> film)
269 {
270         Controls::set_film (film);
271         setup_sensitivity ();
272 }