2013-07-06 05:20:07 +05:30
|
|
|
#pragma once
|
|
|
|
#include <QtCore>
|
2013-07-09 04:22:03 +05:30
|
|
|
#include "libutil_config.h"
|
2013-07-06 05:20:07 +05:30
|
|
|
|
|
|
|
enum JobStatus
|
|
|
|
{
|
|
|
|
Job_NotStarted,
|
|
|
|
Job_InProgress,
|
|
|
|
Job_Finished,
|
|
|
|
Job_Failed
|
|
|
|
};
|
|
|
|
|
|
|
|
class JobList;
|
|
|
|
|
2013-08-26 06:23:29 +05:30
|
|
|
class Job : public QObject
|
2013-07-06 05:20:07 +05:30
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
protected:
|
|
|
|
explicit Job(): QObject(0){};
|
|
|
|
public:
|
|
|
|
virtual ~Job() {};
|
|
|
|
signals:
|
|
|
|
void finish();
|
|
|
|
void fail();
|
|
|
|
void progress(qint64 current, qint64 total);
|
|
|
|
public slots:
|
|
|
|
virtual void start() = 0;
|
|
|
|
};
|
|
|
|
typedef QSharedPointer<Job> JobPtr;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A list of jobs, to be processed one by one.
|
|
|
|
*/
|
2013-08-26 06:23:29 +05:30
|
|
|
class JobList : public QObject
|
2013-07-06 05:20:07 +05:30
|
|
|
{
|
|
|
|
friend class JobListQueue;
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
|
|
|
|
JobList() : QObject(0)
|
|
|
|
{
|
|
|
|
m_status = Job_NotStarted;
|
|
|
|
current_job_idx = 0;
|
|
|
|
}
|
|
|
|
JobStatus getStatus()
|
|
|
|
{
|
|
|
|
return m_status;
|
|
|
|
}
|
|
|
|
void add(JobPtr dlable)
|
|
|
|
{
|
|
|
|
if(m_status == Job_NotStarted)
|
|
|
|
m_jobs.append(dlable);
|
|
|
|
//else there's a bug. TODO: catch the bugs
|
|
|
|
}
|
|
|
|
JobPtr getFirstJob()
|
|
|
|
{
|
|
|
|
if(m_jobs.size())
|
|
|
|
return m_jobs[0];
|
|
|
|
else
|
|
|
|
return JobPtr();
|
|
|
|
}
|
|
|
|
void start()
|
|
|
|
{
|
|
|
|
current_job_idx = 0;
|
|
|
|
auto job = m_jobs[current_job_idx];
|
|
|
|
|
|
|
|
connect(job.data(), SIGNAL(progress(qint64,qint64)), SLOT(currentJobProgress(qint64,qint64)));
|
|
|
|
connect(job.data(), SIGNAL(finish()), SLOT(currentJobFinished()));
|
|
|
|
connect(job.data(), SIGNAL(fail()), SLOT(currentJobFailed()));
|
|
|
|
job->start();
|
|
|
|
emit started();
|
|
|
|
}
|
|
|
|
private slots:
|
|
|
|
void currentJobFinished()
|
|
|
|
{
|
|
|
|
if(current_job_idx == m_jobs.size() - 1)
|
|
|
|
{
|
|
|
|
m_status = Job_Finished;
|
|
|
|
emit finished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
current_job_idx++;
|
|
|
|
auto job = m_jobs[current_job_idx];
|
|
|
|
connect(job.data(), SIGNAL(progress(qint64,qint64)), SLOT(currentJobProgress(qint64,qint64)));
|
|
|
|
connect(job.data(), SIGNAL(finish()), SLOT(currentJobFinished()));
|
|
|
|
connect(job.data(), SIGNAL(fail()), SLOT(currentJobFailed()));
|
|
|
|
job->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void currentJobFailed()
|
|
|
|
{
|
|
|
|
m_status = Job_Failed;
|
|
|
|
emit failed();
|
|
|
|
}
|
|
|
|
void currentJobProgress(qint64 current, qint64 total)
|
|
|
|
{
|
|
|
|
if(!total)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int total_jobs = m_jobs.size();
|
|
|
|
|
|
|
|
if(!total_jobs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
float job_chunk = 1000.0 / float(total_jobs);
|
|
|
|
float cur = current;
|
|
|
|
float tot = total;
|
|
|
|
float last_chunk = (cur / tot) * job_chunk;
|
|
|
|
|
|
|
|
float list_total = job_chunk * current_job_idx + last_chunk;
|
|
|
|
emit progress(qint64(list_total), 1000LL);
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
QVector<JobPtr> m_jobs;
|
|
|
|
/// The overall status of this job list
|
|
|
|
JobStatus m_status;
|
|
|
|
int current_job_idx;
|
|
|
|
signals:
|
|
|
|
void progress(qint64 current, qint64 total);
|
|
|
|
void started();
|
|
|
|
void finished();
|
|
|
|
void failed();
|
|
|
|
};
|
|
|
|
typedef QSharedPointer<JobList> JobListPtr;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A queue of job lists! The job lists fail or finish as units.
|
|
|
|
*/
|
2013-08-26 06:23:29 +05:30
|
|
|
class JobListQueue : public QObject
|
2013-07-06 05:20:07 +05:30
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
JobListQueue(QObject *p = 0):
|
|
|
|
QObject(p),
|
|
|
|
currentIndex(0),
|
|
|
|
is_running(false){}
|
|
|
|
|
|
|
|
void enqueue(JobListPtr job)
|
|
|
|
{
|
|
|
|
jobs.enqueue(job);
|
|
|
|
|
|
|
|
// finish or fail, we should catch that and start the next one
|
|
|
|
connect(job.data(),SIGNAL(finished()), SLOT(startNextJob()));
|
|
|
|
connect(job.data(),SIGNAL(failed()), SLOT(startNextJob()));
|
|
|
|
|
|
|
|
if(!is_running)
|
|
|
|
{
|
|
|
|
QTimer::singleShot(0, this, SLOT(startNextJob()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void startNextJob()
|
|
|
|
{
|
|
|
|
if (jobs.isEmpty())
|
|
|
|
{
|
|
|
|
currentJobList.clear();
|
|
|
|
currentIndex = 0;
|
|
|
|
is_running = false;
|
|
|
|
emit finishedAllJobs();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentJobList = jobs.dequeue();
|
|
|
|
is_running = true;
|
|
|
|
currentIndex = 0;
|
|
|
|
currentJobList->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void finishedAllJobs();
|
|
|
|
|
|
|
|
private:
|
|
|
|
JobListPtr currentJobList;
|
|
|
|
QQueue<JobListPtr> jobs;
|
|
|
|
unsigned currentIndex;
|
|
|
|
bool is_running;
|
|
|
|
};
|