+2017-01-28 Carl Hetherington <cth@carlh.net>
+
+ * Add priority control buttons to batch converter (#961).
+
2017-01-18 Carl Hetherington <cth@carlh.net>
* Updated uk_UA translation from Igor Voytovich.
}
bool
-Job::paused () const
+Job::paused_by_user () const
{
boost::mutex::scoped_lock lm (_state_mutex);
- return _state == PAUSED;
+ return _state == PAUSED_BY_USER;
+}
+
+bool
+Job::paused_by_priority () const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _state == PAUSED_BY_PRIORITY;
}
/** Set the state of this job.
boost::this_thread::interruption_point ();
boost::mutex::scoped_lock lm (_state_mutex);
- while (_state == PAUSED) {
+ while (_state == PAUSED_BY_USER || _state == PAUSED_BY_PRIORITY) {
emit (boost::bind (boost::ref (Progress)));
_pause_changed.wait (lm);
}
return N_("new");
case RUNNING:
return N_("running");
- case PAUSED:
+ case PAUSED_BY_USER:
+ case PAUSED_BY_PRIORITY:
return N_("paused");
case FINISHED_OK:
return N_("finished_ok");
return;
}
- if (paused ()) {
+ if (paused_by_user() || paused_by_priority()) {
resume ();
}
}
void
-Job::pause ()
+Job::pause_by_user ()
+{
+ if (running ()) {
+ set_state (PAUSED_BY_USER);
+ _pause_changed.notify_all ();
+ }
+}
+
+void
+Job::pause_by_priority ()
{
if (running ()) {
- set_state (PAUSED);
+ set_state (PAUSED_BY_PRIORITY);
_pause_changed.notify_all ();
}
}
void
Job::resume ()
{
- if (paused ()) {
+ if (paused_by_user() || paused_by_priority()) {
set_state (RUNNING);
_pause_changed.notify_all ();
}
virtual void run () = 0;
void start ();
- void pause ();
+ void pause_by_user ();
+ void pause_by_priority ();
void resume ();
void cancel ();
bool finished_ok () const;
bool finished_in_error () const;
bool finished_cancelled () const;
- bool paused () const;
+ bool paused_by_user () const;
+ bool paused_by_priority () const;
std::string error_summary () const;
std::string error_details () const;
enum State {
NEW, ///< the job hasn't been started yet
RUNNING, ///< the job is running
- PAUSED, ///< the job has been paused
+ PAUSED_BY_USER, ///< the job has been paused
+ PAUSED_BY_PRIORITY, ///< the job has been paused
FINISHED_OK, ///< the job has finished successfully
FINISHED_ERROR, ///< the job has finished in error
FINISHED_CANCELLED ///< the job was cancelled
emit (boost::bind (boost::ref (JobAdded), weak_ptr<Job> (job)));
}
+
+void
+JobManager::increase_priority (shared_ptr<Job> job)
+{
+ bool changed = false;
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ list<shared_ptr<Job> >::iterator last = _jobs.end ();
+ for (list<shared_ptr<Job> >::iterator i = _jobs.begin(); i != _jobs.end(); ++i) {
+ if (*i == job && last != _jobs.end()) {
+ swap (*i, *last);
+ changed = true;
+ break;
+ }
+ last = i;
+ }
+ }
+
+ if (changed) {
+ priority_changed ();
+ }
+}
+
+void
+JobManager::priority_changed ()
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+
+ bool first = true;
+ BOOST_FOREACH (shared_ptr<Job> i, _jobs) {
+ if (first) {
+ if (i->is_new ()) {
+ i->start ();
+ } else if (i->paused_by_priority ()) {
+ i->resume ();
+ }
+ first = false;
+ } else {
+ if (i->running ()) {
+ i->pause_by_priority ();
+ }
+ }
+ }
+ }
+
+ emit (boost::bind (boost::ref (JobsReordered)));
+}
+
+void
+JobManager::decrease_priority (shared_ptr<Job> job)
+{
+ bool changed = false;
+
+ for (list<shared_ptr<Job> >::iterator i = _jobs.begin(); i != _jobs.end(); ++i) {
+ list<shared_ptr<Job> >::iterator next = i;
+ ++next;
+ if (*i == job && next != _jobs.end()) {
+ swap (*i, *next);
+ changed = true;
+ break;
+ }
+ }
+
+ if (changed) {
+ priority_changed ();
+ }
+}
class JobManager : public Signaller, public boost::noncopyable
{
public:
-
boost::shared_ptr<Job> add (boost::shared_ptr<Job>);
std::list<boost::shared_ptr<Job> > get () const;
bool work_to_do () const;
bool errors () const;
+ void increase_priority (boost::shared_ptr<Job>);
+ void decrease_priority (boost::shared_ptr<Job>);
void analyse_audio (
boost::shared_ptr<const Film> film,
);
boost::signals2::signal<void (boost::weak_ptr<Job>)> JobAdded;
+ boost::signals2::signal<void ()> JobsReordered;
boost::signals2::signal<void (boost::optional<std::string>, boost::optional<std::string>)> ActiveJobsChanged;
static JobManager* instance ();
~JobManager ();
void scheduler ();
void start ();
+ void priority_changed ();
mutable boost::mutex _mutex;
+ /** List of jobs in the order that they will be executed */
std::list<boost::shared_ptr<Job> > _jobs;
bool _terminate;
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
#include "batch_job_view.h"
+#include "lib/job_manager.h"
#include <wx/sizer.h>
+#include <wx/button.h>
+using std::list;
using boost::shared_ptr;
BatchJobView::BatchJobView (shared_ptr<Job> job, wxWindow* parent, wxWindow* container, wxFlexGridSizer* table)
{
return _table->GetEffectiveRowsCount() * _table->GetEffectiveColsCount();
}
+
+void
+BatchJobView::finish_setup (wxWindow* parent, wxSizer* sizer)
+{
+ _higher_priority = new wxButton (parent, wxID_ANY, _("Higher prioirity"));
+ _higher_priority->Bind (wxEVT_BUTTON, boost::bind (&BatchJobView::higher_priority_clicked, this));
+ sizer->Add (_higher_priority, 1, wxALIGN_CENTER_VERTICAL);
+ _lower_priority = new wxButton (parent, wxID_ANY, _("Lower prioirity"));
+ _lower_priority->Bind (wxEVT_BUTTON, boost::bind (&BatchJobView::lower_priority_clicked, this));
+ sizer->Add (_lower_priority, 1, wxALIGN_CENTER_VERTICAL);
+}
+void
+BatchJobView::higher_priority_clicked ()
+{
+ JobManager::instance()->increase_priority (_job);
+}
+
+void
+BatchJobView::lower_priority_clicked ()
+{
+ JobManager::instance()->decrease_priority (_job);
+}
+
+void
+BatchJobView::job_list_changed ()
+{
+ bool high = false;
+ bool low = false;
+ list<shared_ptr<Job> > jobs = JobManager::instance()->get();
+ if (!jobs.empty ()) {
+ if (_job != jobs.front()) {
+ high = true;
+ }
+ if (_job != jobs.back()) {
+ low = true;
+ }
+ }
+
+ _higher_priority->Enable (high);
+ _lower_priority->Enable (low);
+}
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
private:
int insert_position () const;
+ void job_list_changed ();
+
+ void finish_setup (wxWindow* parent, wxSizer* sizer);
+ void higher_priority_clicked ();
+ void lower_priority_clicked ();
+
+ wxButton* _higher_priority;
+ wxButton* _lower_priority;
};
/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "lib/util.h"
#include "lib/exceptions.h"
#include "lib/compose.hpp"
+#include <boost/foreach.hpp>
#include <iostream>
using std::string;
using std::cout;
using boost::shared_ptr;
using boost::weak_ptr;
+using boost::bind;
/** @param parent Parent window.
* @param batch true to use BatchJobView, false to use NormalJobView.
_timer->Start (1000);
JobManager::instance()->JobAdded.connect (bind (&JobManagerView::job_added, this, _1));
+ JobManager::instance()->JobsReordered.connect (bind (&JobManagerView::replace, this));
}
void
}
FitInside();
+ job_list_changed ();
}
void
(*i)->maybe_pulse ();
}
}
+
+void
+JobManagerView::replace ()
+{
+ /* Make a new version of _job_records which reflects the order in JobManager's job list */
+
+ list<shared_ptr<JobView> > new_job_records;
+
+ BOOST_FOREACH (shared_ptr<Job> i, JobManager::instance()->get()) {
+ /* Find this job's JobView */
+ BOOST_FOREACH (shared_ptr<JobView> j, _job_records) {
+ if (j->job() == i) {
+ new_job_records.push_back (j);
+ break;
+ }
+ }
+ }
+
+ BOOST_FOREACH (shared_ptr<JobView> i, _job_records) {
+ i->detach ();
+ }
+
+ _job_records = new_job_records;
+
+ BOOST_FOREACH (shared_ptr<JobView> i, _job_records) {
+ i->insert (i->insert_position ());
+ }
+
+ job_list_changed ();
+}
+
+void
+JobManagerView::job_list_changed ()
+{
+ BOOST_FOREACH (shared_ptr<JobView> i, _job_records) {
+ i->job_list_changed ();
+ }
+}
private:
void job_added (boost::weak_ptr<Job>);
void periodic ();
+ void replace ();
+ void job_list_changed ();
wxPanel* _panel;
wxFlexGridSizer* _table;
_table->Insert (n, _gauge_message, 1, wxEXPAND | wxLEFT | wxRIGHT);
++n;
- wxBoxSizer* buttons = new wxBoxSizer (wxHORIZONTAL);
+ _buttons = new wxBoxSizer (wxHORIZONTAL);
_cancel = new wxButton (_container, wxID_ANY, _("Cancel"));
_cancel->Bind (wxEVT_BUTTON, &JobView::cancel_clicked, this);
- buttons->Add (_cancel, 1, wxALIGN_CENTER_VERTICAL);
+ _buttons->Add (_cancel, 1, wxALIGN_CENTER_VERTICAL);
_details = new wxButton (_container, wxID_ANY, _("Details..."));
_details->Bind (wxEVT_BUTTON, &JobView::details_clicked, this);
_details->Enable (false);
- buttons->Add (_details, 1, wxALIGN_CENTER_VERTICAL);
+ _buttons->Add (_details, 1, wxALIGN_CENTER_VERTICAL);
- finish_setup (_container, buttons);
+ finish_setup (_container, _buttons);
- _table->Insert (n, buttons, 1, wxALIGN_CENTER_VERTICAL | wxALL, 3);
+ _table->Insert (n, _buttons, 1, wxALIGN_CENTER_VERTICAL | wxALL, 3);
_progress_connection = _job->Progress.connect (boost::bind (&JobView::progress, this));
_finished_connection = _job->Finished.connect (boost::bind (&JobView::finished, this));
_job->cancel ();
}
}
+
+void
+JobView::insert (int pos)
+{
+ _table->Insert (pos, _gauge_message, 1, wxEXPAND | wxLEFT | wxRIGHT);
+ _table->Insert (pos + 1, _buttons, 1, wxALIGN_CENTER_VERTICAL | wxALL, 3);
+ _table->Layout ();
+}
+
+void
+JobView::detach ()
+{
+ _table->Detach (_gauge_message);
+ _table->Detach (_buttons);
+}
/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
JobView (boost::shared_ptr<Job> job, wxWindow* parent, wxWindow* container, wxFlexGridSizer* table);
virtual ~JobView () {}
- void setup ();
+ virtual int insert_position () const = 0;
+ virtual void job_list_changed () {}
+ void setup ();
void maybe_pulse ();
+ void insert (int pos);
+ void detach ();
+
+ boost::shared_ptr<Job> job () const {
+ return _job;
+ }
protected:
virtual void finished ();
boost::shared_ptr<Job> _job;
wxFlexGridSizer* _table;
+ wxBoxSizer* _buttons;
+ wxBoxSizer* _gauge_message;
private:
- virtual int insert_position () const = 0;
virtual void finish_setup (wxWindow *, wxSizer *) {}
void progress ();
wxWindow* _parent;
wxWindow* _container;
- wxBoxSizer* _gauge_message;
wxGauge* _gauge;
wxStaticText* _message;
wxButton* _cancel;
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
void
NormalJobView::pause_clicked ()
{
- if (_job->paused()) {
+ if (_job->paused_by_user()) {
_job->resume ();
_pause->SetLabel (_("Pause"));
} else {
- _job->pause ();
+ _job->pause_by_user ();
_pause->SetLabel (_("Resume"));
}
}