Remove polling from JobManagerView and use signals instead (fixes #137).
[dcpomatic.git] / src / wx / job_manager_view.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /** @file src/job_manager_view.cc
21  *  @brief Class generating a GTK widget to show the progress of jobs.
22  */
23
24 #include "lib/job_manager.h"
25 #include "lib/job.h"
26 #include "lib/util.h"
27 #include "lib/exceptions.h"
28 #include "job_manager_view.h"
29 #include "wx_util.h"
30
31 using std::string;
32 using std::list;
33 using std::map;
34 using boost::shared_ptr;
35 using boost::weak_ptr;
36
37 /** Must be called in the GUI thread */
38 JobManagerView::JobManagerView (wxWindow* parent, Buttons buttons)
39         : wxScrolledWindow (parent)
40         , _buttons (buttons)
41 {
42         _panel = new wxPanel (this);
43         wxSizer* sizer = new wxBoxSizer (wxVERTICAL);
44         sizer->Add (_panel, 1, wxEXPAND);
45         SetSizer (sizer);
46
47         int N = 5;
48         if (buttons & PAUSE) {
49                 ++N;
50         }
51         
52         _table = new wxFlexGridSizer (N, 6, 6);
53         _table->AddGrowableCol (1, 1);
54         _panel->SetSizer (_table);
55
56         SetScrollRate (0, 32);
57
58         JobManager::instance()->JobAdded.connect (bind (&JobManagerView::job_added, this, _1));
59 }
60
61 void
62 JobManagerView::job_added (weak_ptr<Job> j)
63 {
64         shared_ptr<Job> job = j.lock ();
65         if (!job) {
66                 return;
67         }
68
69         wxStaticText* m = new wxStaticText (_panel, wxID_ANY, std_to_wx (job->name ()));
70         _table->Insert (0, m, 0, wxALIGN_CENTER_VERTICAL | wxALL, 6);
71         
72         JobRecord r;
73         int n = 1;
74         r.scroll_nudged = false;
75         r.gauge = new wxGauge (_panel, wxID_ANY, 100);
76         _table->Insert (n, r.gauge, 1, wxEXPAND | wxLEFT | wxRIGHT);
77         ++n;
78         
79         r.message = new wxStaticText (_panel, wxID_ANY, std_to_wx (""));
80         _table->Insert (n, r.message, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6);
81         ++n;
82         
83         r.cancel = new wxButton (_panel, wxID_ANY, _("Cancel"));
84         r.cancel->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (JobManagerView::cancel_clicked), 0, this);
85         _table->Insert (n, r.cancel, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6);
86         ++n;
87         
88         if (_buttons & PAUSE) {
89                 r.pause = new wxButton (_panel, wxID_ANY, _("Pause"));
90                 r.pause->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (JobManagerView::pause_clicked), 0, this);
91                 _table->Insert (n, r.pause, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6);
92                 ++n;
93         }
94         
95         r.details = new wxButton (_panel, wxID_ANY, _("Details..."));
96         r.details->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (JobManagerView::details_clicked), 0, this);
97         r.details->Enable (false);
98         _table->Insert (n, r.details, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6);
99         ++n;
100         
101         _job_records[job] = r;
102
103         job->Progress.connect (bind (&JobManagerView::progress, this, j));
104         job->Progress.connect (bind (&JobManagerView::finished, this, j));
105         
106         _table->Layout ();
107         FitInside ();
108 }
109
110 void
111 JobManagerView::progress (weak_ptr<Job> j)
112 {
113         shared_ptr<Job> job = j.lock ();
114         if (!job) {
115                 return;
116         }
117
118         float const p = job->overall_progress ();
119         if (p >= 0) {
120                 checked_set (_job_records[job].message, job->status ());
121                 _job_records[job].gauge->SetValue (p * 100);
122         } else {
123                 checked_set (_job_records[job].message, wx_to_std (_("Running")));
124                 _job_records[job].gauge->Pulse ();
125         }
126
127         if (!_job_records[job].scroll_nudged && (job->running () || job->finished())) {
128                 int x, y;
129                 _job_records[job].gauge->GetPosition (&x, &y);
130                 int px, py;
131                 GetScrollPixelsPerUnit (&px, &py);
132                 int vx, vy;
133                 GetViewStart (&vx, &vy);
134                 int sx, sy;
135                 GetClientSize (&sx, &sy);
136                 
137                 if (y > (vy * py + sy / 2)) {
138                         Scroll (-1, y / py);
139                         _job_records[job].scroll_nudged = true;
140                 }
141         }
142
143         _table->Layout ();
144         FitInside ();
145 }
146
147 void
148 JobManagerView::finished (weak_ptr<Job> j)
149 {
150         shared_ptr<Job> job = j.lock ();
151         if (!job) {
152                 return;
153         }
154         
155         checked_set (_job_records[job].message, job->status ());
156         if (!job->finished_cancelled ()) {
157                 _job_records[job].gauge->SetValue (100);
158         }
159         _job_records[job].cancel->Enable (false);
160         if (!job->error_details().empty ()) {
161                 _job_records[job].details->Enable (true);
162         }
163
164         _table->Layout ();
165         FitInside ();
166 }
167
168 void
169 JobManagerView::details_clicked (wxCommandEvent& ev)
170 {
171         wxObject* o = ev.GetEventObject ();
172
173         for (map<shared_ptr<Job>, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) {
174                 if (i->second.details == o) {
175                         string s = i->first->error_summary();
176                         s[0] = toupper (s[0]);
177                         error_dialog (this, std_to_wx (String::compose ("%1.\n\n%2", s, i->first->error_details())));
178                 }
179         }
180 }
181
182 void
183 JobManagerView::cancel_clicked (wxCommandEvent& ev)
184 {
185         wxObject* o = ev.GetEventObject ();
186
187         for (map<shared_ptr<Job>, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) {
188                 if (i->second.cancel == o) {
189                         i->first->cancel ();
190                 }
191         }
192 }
193
194 void
195 JobManagerView::pause_clicked (wxCommandEvent& ev)
196 {
197         wxObject* o = ev.GetEventObject ();
198         for (map<boost::shared_ptr<Job>, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) {
199                 if (i->second.pause == o) {
200                         if (i->first->paused()) {
201                                 i->first->resume ();
202                                 i->second.pause->SetLabel (_("Pause"));
203                         } else {
204                                 i->first->pause ();
205                                 i->second.pause->SetLabel (_("Resume"));
206                         }
207                 }
208         }
209 }
210