Use of gcsDebug instead of qDebug
[meego-garage:garage-client-services.git] / src / jobtypes.h
1 #ifndef JOBTYPES_H
2 #define JOBTYPES_H
3
4 #include <QList>
5 #include <QStringList>
6 #include <QTimer>
7 #include <QDebug>
8 #include "job.h"
9 #include "types.h"
10 #include "attica/metadata.h"
11
12 namespace MeeGoGarage {
13
14 /**
15     Job to retrieve category list from a catalog.
16   */
17 class CategoryListJob : public Job<CategoryList>
18 {
19 public:
20     CategoryListJob(Catalog * catalog = 0) : m_catalog(catalog) {}
21     Catalog *catalog() { return m_catalog; }
22 protected:
23     void setCatalog(Catalog * catalog = 0) { m_catalog = catalog; }
24     Catalog *m_catalog;
25 };
26
27
28 /**
29     Job to retrieve application list from a catalog.
30   */
31 class ApplicationListJob : public PageBasedJob<ApplicationList>
32 {
33 public:
34     ApplicationListJob(Catalog * catalog = 0, /*Category * category = 0, */int pageNumber = 0, int itemsPerPage = 0) :
35             PageBasedJob<ApplicationList>(pageNumber, itemsPerPage),
36             m_catalog(catalog)
37             //m_category(category
38             {}
39     Catalog *catalog() { return m_catalog; }
40     //Category *category() { return m_category; }
41 protected:
42     void setCatalog(Catalog * catalog) { m_catalog = catalog; }
43     //void setCategory(Category * category) { m_category = category; }
44     Catalog *m_catalog;
45     //Category *m_category;
46 };
47
48 /**
49     Job to retrieve application list from a catalog.
50   */
51 class ApplicationSearchJob : public ApplicationListJob
52 {
53 public:
54     ApplicationSearchJob(Catalog * catalog = 0,
55                          const QString & searchText = QString(),
56                          ApplicationListSortType sortType = SortByName,
57                          const CategoryList & categoryList = CategoryList(),
58                          int pageNumber = 0,
59                          int itemsPerPage = 0) :
60             ApplicationListJob(catalog, pageNumber, itemsPerPage),
61             m_searchText(searchText),
62             m_sortType(sortType),
63             m_categoryList(categoryList)  {}
64     ApplicationListSortType sortType() { return m_sortType; }
65     CategoryList categoryList() { return m_categoryList; }
66     QString searchText()  { return m_searchText; }
67     virtual ApplicationSearchJob *requestNextPage() = 0;
68 protected:
69     void setSearchText(const QString & searchText)  { m_searchText = searchText; }
70     void setCategoryList(const CategoryList & categoryList) { m_categoryList = categoryList; }
71     void setSortType(ApplicationListSortType sortType) { m_sortType = sortType; }
72     QString m_searchText;
73     ApplicationListSortType m_sortType;
74     CategoryList m_categoryList;
75 };
76
77 /**
78     Job for login operations
79   */
80 class LoginJob : public Job<bool>
81 {
82 Q_OBJECT
83 public:
84     LoginJob(Catalog * catalog, const QString & userName, const QString & password) :
85             m_catalog(catalog),
86             m_userName(userName),
87             m_password(password) {}
88 protected slots:
89     void loginDone(void);
90 protected:
91     friend class Catalog;
92     virtual bool doStart();
93     Catalog * m_catalog;
94     QString m_userName;
95     QString m_password;
96 };
97
98
99 /**
100     Job for parallel jobs. It is used to handle a list of jobs running concurrently.
101     The job is not considered finished until all jobs in the list are finished.
102     Jobs are executed in parallel and the results are combined.
103   */
104 template <class SuperClass, class JobClass>
105 class ParallelJob : public SuperClass {
106 public:
107     ParallelJob(const QList<JobClass*> &jobs) :
108             m_jobs(jobs),
109             m_overJobs(0),
110             m_canceledJobs(0),
111             m_errorJobs(0)
112     {
113     }
114
115 protected:
116
117     void onJobOver()
118     {
119         JobClass *job = static_cast<JobClass *> (JobClass::sender());
120         m_overJobs++;
121         if (job->isSuccessful()) {
122             processResult(job);
123         } else if (job->isError()) {
124             m_errorJobs++;
125             setErrorString(job->errorString());
126         } else if (job->isCanceled()) {
127             m_canceledJobs++;
128         }
129
130         if (m_overJobs == m_jobs.count()) {
131             if (m_errorJobs > 0) {
132                 setState(JobClass::ErrorState);
133             } else if (m_canceledJobs > 0) {
134                 setState(JobClass::CanceledState);
135             } else {
136                 setState(JobClass::SuccessfulState);
137             }
138         }
139
140         job->deleteLater();
141     }
142
143 protected:
144
145     virtual bool doStart()
146     {
147         bool ret = true;
148
149         if (m_jobs.count() > 0) {
150             JobClass *job;
151             foreach(job, m_jobs) {
152                 connect(job, SIGNAL(jobOver()), SLOT(onJobOver()));
153                 if (job->isInactive()) {
154                     ret &= job->start();
155                 }
156             }
157         } else {
158             // no jobs -> just terminate
159             setState(JobClass::SuccessfulState);
160         }
161
162         return ret;
163     }
164
165     virtual bool doCancel() {
166         bool ret = true;
167         JobClass *job;
168         foreach(job, m_jobs) {
169             ret &= job->cancel();
170         }
171         return ret;
172     }
173
174     virtual void processResult(JobClass * /*job*/)
175     {
176         // do something with the result, for example append to list, but not necessarily
177         //JobClass::m_result.append(job->results);
178     }
179
180     QList<JobClass*> m_jobs;
181     // number of jobs over
182     int m_overJobs;
183     // number of jobs finished with error
184     int m_errorJobs;
185     // number of jobs canceled
186     int m_canceledJobs;
187 };
188
189 /**
190     Job for sequential jobs, the job is executed after first job is finished.
191     Once finished the SequentialJob might want to access results
192   */
193 template <class SuperClass, class JobClass>
194 class SequentialJob : public SuperClass {
195 public:
196
197     SequentialJob(const QList<JobClass*> &jobs) :
198             m_jobs(jobs),
199             m_current(0)
200     {
201     }
202
203 protected:
204
205     void onJobOver()
206     {
207         JobClass *job = static_cast<JobClass *> (JobClass::sender());
208
209         if (job->isSuccessful()) {
210             processResult(job);
211             m_current++;
212             if (m_current < m_jobs.count()) {
213                 runNextJob();
214             } else {
215                 setState(JobClass::SuccessfulState);
216             }
217         } else if (job->isError()) {
218             setErrorString(job->errorString());
219             cancelPendingJobs();
220             setState(JobClass::ErrorState);
221         } else if (job->isCanceled()) {
222             cancelPendingJobs();
223             setState(JobClass::CanceledState);
224         }
225
226         job->deleteLater();
227     }
228
229 protected:
230
231     virtual bool doStart()
232     {
233         return runNextJob();
234     }
235
236     bool runNextJob()
237     {
238         if (m_current > 0 && m_current < m_jobs.count()) {
239             JobClass * job = m_jobs.at(m_current);
240             m_current++;
241             connect(job, SIGNAL(jobOver()), SLOT(onJobOver()));
242             if (job->isInactive()) {
243                 return job->start();
244             }
245         }
246
247         return false;
248     }
249
250     void cancelPendingJobs()
251     {
252         while(m_current < m_jobs.count()) {
253             JobClass * job = m_jobs.at(m_current);
254             m_current++;
255             job->cancel();
256             job->deleteLater();
257         }
258     }
259
260     virtual bool doCancel() {
261         if (m_current >= 0 && m_current < m_jobs.count()) {
262             JobClass *job = m_jobs.at(m_current);
263             if (job->isActive()) {
264                 return job->cancel();
265             }
266         }
267         return false;
268     }
269
270     virtual void processResult(JobClass * /*job*/)
271     {
272         // do something with the result
273     }
274
275 protected:
276
277     QList<JobClass*> m_jobs;
278     int m_current;
279 };
280
281 /**
282     Job that just is finished after N seconds
283   */
284 template <class JobClass>
285 class TimerJob : public JobClass
286 {
287 public:
288     TimerJob(int miliseconds) : JobClass(), m_miliseconds(miliseconds) {}
289
290 protected:
291
292     virtual void onJobOver()
293     {
294         setState(JobClass::SuccessfulState);
295     }
296
297 protected:
298     virtual bool doStart() {
299         QTimer::singleShot(m_miliseconds, this, SLOT(onJobOver()));
300         return true;
301     }
302
303     int m_miliseconds;
304 };
305
306 /**
307   Job that finishes just when started. Results must be provided on the constructor.
308   */
309 template <class JobClass>
310 class LightSpeedJob : public JobClass
311 {
312 public:
313     LightSpeedJob(typename JobClass::ResultType result) : JobClass()
314     {
315         JobClass::setResult(result);
316     }
317
318 protected:
319     virtual bool doStart() {
320         setState(JobClass::SuccessfulState);
321         return true;
322     }
323 };
324
325 /**
326   Job controlled externally from another class.
327   Basically to have it easier to keep legacy code, but being able to use interface.
328   */
329 template <class JobClass>
330 class ExternalJob : public JobClass
331 {
332 public:
333     void setStateFinished(const typename JobClass::ResultType & result)
334     {
335         //JobClass::setResult(result);
336         JobClass::setState(JobClass::SuccessfulState);
337     }
338
339     void setStateError(const QString & errorString)
340     {
341         JobClass::setErrorString(errorString);
342         JobClass::setState(JobClass::ErrorState);
343     }
344 };
345
346 /**
347   Wraps an Attica job.
348   */
349 template <class JobClass, class AtticaJob>
350 class AtticaWrapperJob : public JobClass
351 {
352 public:
353     AtticaWrapperJob(AtticaJob * atticaJob) :
354             m_atticaJob(atticaJob)
355     {
356         connect(m_atticaJob, SIGNAL(finished(Attica::BaseJob*)), SLOT(onJobOver()));
357     }
358
359 protected:
360
361     virtual void onJobOver()
362     {
363         if (m_atticaJob->metadata().error() != Attica::Metadata::NoError) {
364             JobClass::setErrorString(m_atticaJob->metadata().statusString() + m_atticaJob->metadata().message());
365             JobClass::setState(JobClass::ErrorState);
366         } else {
367             processResult(m_atticaJob);
368             JobClass::setState(JobClass::SuccessfulState);
369         }
370     }
371
372 protected:
373     virtual bool doStart()
374     {
375         m_atticaJob->start();
376         if (m_atticaJob->metadata().error() != Attica::Metadata::NoError) {
377             qWarning() << "Attica job failed with " << m_atticaJob->metadata().statusString();
378             return false;
379         }
380
381         return true;
382     }
383
384     virtual bool doCancel()
385     {
386         m_atticaJob->abort();
387         JobClass::setState(JobClass::CanceledState);
388         return true;
389     }
390
391     virtual void processResult(AtticaJob * /*atticaJob*/)
392     {
393     }
394
395     AtticaJob * m_atticaJob;
396 };
397
398 /**
399   WrapperJob wraps another job. Useful to run some code before or after the wrapped job is executed.
400   */
401 template <class JobClass, class WrappedJob>
402 class WrapperJob : public JobClass
403 {
404 public:
405     WrapperJob(WrappedJob * wrappedJob) :
406             m_wrappedJob(wrappedJob)
407     {
408         connect(m_wrappedJob, SIGNAL(jobOver(WrappedJob*)), SLOT(onJobOver()));
409     }
410
411 protected:
412
413     virtual void onJobOver()
414     {
415         if (m_wrappedJob->isSuccessful()) {
416             processResult(m_wrappedJob);
417             JobClass::setState(JobClass::SuccessfulState);
418         } else if (m_wrappedJob->isError()) {
419             JobClass::setErrorString(m_wrappedJob->errorString());
420             JobClass::setState(JobClass::ErrorState);
421         } else if (m_wrappedJob->isCanceled()) {
422             JobClass::setState(JobClass::CanceledState);
423         } else {
424             Q_ASSERT(true);
425         }
426     }
427
428 protected:
429     virtual bool doStart()
430     {
431         return m_wrappedJob->start();
432     }
433
434     virtual bool doCancel()
435     {
436         int ret = m_wrappedJob->cancel();
437         return ret;
438     }
439
440     virtual void processResult(WrappedJob * wrappedJob)
441     {
442     }
443
444     WrappedJob * m_wrappedJob;
445 };
446
447 /**
448     Job to retrieve review list from an application.
449   */
450 class ReviewListJob : public PageBasedJob<ReviewList>
451 {
452 public:
453     ReviewListJob(Catalog * catalog = 0, Application * application = 0, int pageNumber = 0, int itemsPerPage = 10) :
454             PageBasedJob<ReviewList>(pageNumber, itemsPerPage),
455             m_catalog(catalog),
456             m_application(application) {}
457     Catalog *catalog() { return m_catalog; }
458     Application *application() { return m_application; }
459 protected:
460     void setCatalog(Catalog * catalog) { m_catalog = catalog; }
461     //void setCategory(Category * category) { m_category = category; }
462     Catalog *m_catalog;
463     Application *m_application;
464 };
465
466 /**
467   Maybe useful to implement someday jobs to wrap:
468     - network requests
469     - QFuture
470   */
471
472
473 } // namespace MeeGoGarage
474
475 #endif // JOBTYPES_H