#include <libdcp/exceptions.h>
#include "job.h"
#include "util.h"
+#include "cross.h"
+#include "ui_signaller.h"
+#include "exceptions.h"
#include "i18n.h"
using std::string;
using std::list;
+using std::cout;
using std::stringstream;
using boost::shared_ptr;
-/** @param s Film that we are operating on.
- */
-Job::Job (shared_ptr<Film> f)
+Job::Job (shared_ptr<const Film> f)
: _film (f)
, _thread (0)
, _state (NEW)
, _start_time (0)
- , _progress_unknown (false)
+ , _progress (0)
, _ran_for (0)
{
- descend (1);
+
}
/** Start the job in a separate thread, returning immediately */
set_state (FINISHED_ERROR);
string m = String::compose (_("An error occurred whilst handling the file %1."), boost::filesystem::path (e.filename()).leaf());
-
- boost::filesystem::space_info const s = boost::filesystem::space (e.filename());
- if (s.available < pow (1024, 3)) {
- m += N_("\n\n");
- m += _("The drive that the film is stored on is low in disc space. Free some more space and try again.");
+
+ try {
+ boost::filesystem::space_info const s = boost::filesystem::space (e.filename());
+ if (s.available < pow (1024, 3)) {
+ m += N_("\n\n");
+ m += _("The drive that the film is stored on is low in disc space. Free some more space and try again.");
+ }
+ } catch (...) {
+
}
set_error (e.what(), m);
+ } catch (OpenFileError& e) {
+
+ set_progress (1);
+ set_state (FINISHED_ERROR);
+
+ set_error (
+ String::compose (_("Could not open %1"), e.file().string()),
+ String::compose (_("DCP-o-matic could not open the file %1. Perhaps it does not exist or is in an unexpected format."), e.file().string())
+ );
+
} catch (boost::thread_interrupted &) {
set_state (FINISHED_CANCELLED);
-
+
} catch (std::exception& e) {
set_progress (1);
set_state (FINISHED_ERROR);
set_error (
e.what (),
- _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)")
+ _("It is not known what caused this error. The best idea is to report the problem to the DCP-o-matic mailing list (carl@dcpomatic.com)")
);
} catch (...) {
set_state (FINISHED_ERROR);
set_error (
_("Unknown error"),
- _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)")
+ _("It is not known what caused this error. The best idea is to report the problem to the DCP-o-matic mailing list (carl@dcpomatic.com)")
);
}
return _state == FINISHED_CANCELLED;
}
+bool
+Job::paused () const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _state == PAUSED;
+}
+
/** Set the state of this job.
* @param s New state.
*/
void
Job::set_state (State s)
{
- boost::mutex::scoped_lock lm (_state_mutex);
- _state = s;
+ bool finished = false;
+
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _state = s;
+
+ if (_state == FINISHED_OK || _state == FINISHED_ERROR || _state == FINISHED_CANCELLED) {
+ _ran_for = elapsed_time ();
+ finished = true;
+ _sub_name.clear ();
+ }
+ }
- if (_state == FINISHED_OK || _state == FINISHED_ERROR) {
- _ran_for = elapsed_time ();
+ if (finished && ui_signaller) {
+ ui_signaller->emit (boost::bind (boost::ref (Finished)));
}
}
-/** @return Time (in seconds) that this job has been running */
+/** @return DCPTime (in seconds) that this sub-job has been running */
int
Job::elapsed_time () const
{
* @param p Progress (from 0 to 1)
*/
void
-Job::set_progress (float p)
+Job::set_progress (float p, bool force)
{
- boost::mutex::scoped_lock lm (_progress_mutex);
- _progress_unknown = false;
- _stack.back().normalised = p;
- boost::this_thread::interruption_point ();
-}
+ if (!force && fabs (p - progress()) < 0.01) {
+ /* Calm excessive progress reporting */
+ return;
+ }
-/** @return fractional overall progress, or -1 if not known */
-float
-Job::overall_progress () const
-{
boost::mutex::scoped_lock lm (_progress_mutex);
- if (_progress_unknown) {
- return -1;
- }
+ _progress = p;
+ boost::this_thread::interruption_point ();
- float overall = 0;
- float factor = 1;
- for (list<Level>::const_iterator i = _stack.begin(); i != _stack.end(); ++i) {
- factor *= i->allocation;
- overall += i->normalised * factor;
+ if (paused ()) {
+ dcpomatic_sleep (1);
}
- if (overall > 1) {
- overall = 1;
+ if (ui_signaller) {
+ ui_signaller->emit (boost::bind (boost::ref (Progress)));
}
-
- return overall;
}
-/** Ascend up one level in terms of progress reporting; see descend() */
-void
-Job::ascend ()
+/** @return fractional progress of this sub-job, or -1 if not known */
+float
+Job::progress () const
{
boost::mutex::scoped_lock lm (_progress_mutex);
-
- assert (!_stack.empty ());
- float const a = _stack.back().allocation;
- _stack.pop_back ();
- _stack.back().normalised += a;
+ return _progress.get_value_or (-1);
}
-/** Descend down one level in terms of progress reporting; e.g. if
- * there is a task which is split up into N subtasks, each of which
- * report their progress from 0 to 100%, call descend() before executing
- * each subtask, and ascend() afterwards to ensure that overall progress
- * is reported correctly.
- *
- * @param a Fraction (from 0 to 1) of the current task to allocate to the subtask.
- */
void
-Job::descend (float a)
+Job::sub (string n)
{
- boost::mutex::scoped_lock lm (_progress_mutex);
- _stack.push_back (Level (a));
+ {
+ boost::mutex::scoped_lock lm (_progress_mutex);
+ _sub_name = n;
+ }
+
+ set_progress (0, true);
}
string
Job::set_progress_unknown ()
{
boost::mutex::scoped_lock lm (_progress_mutex);
- _progress_unknown = true;
+ _progress.reset ();
}
/** @return Human-readable status of this job */
string
Job::status () const
{
- float const p = overall_progress ();
+ float const p = progress ();
int const t = elapsed_time ();
int const r = remaining_time ();
return s.str ();
}
-/** @return An estimate of the remaining time for this job, in seconds */
+/** @return An estimate of the remaining time for this sub-job, in seconds */
int
Job::remaining_time () const
{
- return elapsed_time() / overall_progress() - elapsed_time();
+ return elapsed_time() / progress() - elapsed_time();
}
void
_thread->interrupt ();
_thread->join ();
}
+
+void
+Job::pause ()
+{
+ if (running ()) {
+ set_state (PAUSED);
+ }
+}
+
+void
+Job::resume ()
+{
+ if (paused ()) {
+ set_state (RUNNING);
+ }
+}