Merge lp:~ahayzen/ubuntu-ui-extras/job-model-split-update into lp:~phablet-team/ubuntu-ui-extras/printer-staging

Proposed by Andrew Hayzen
Status: Merged
Approved by: Jonas G. Drange
Approved revision: 158
Merged at revision: 148
Proposed branch: lp:~ahayzen/ubuntu-ui-extras/job-model-split-update
Merge into: lp:~phablet-team/ubuntu-ui-extras/printer-staging
Diff against target: 1894 lines (+750/-311)
23 files modified
modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt (+1/-0)
modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp (+15/-0)
modules/Ubuntu/Components/Extras/Printers/backend/backend.h (+5/-0)
modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp (+103/-24)
modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h (+10/-1)
modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp (+13/-2)
modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h (+2/-0)
modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp (+50/-0)
modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h (+47/-0)
modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp (+156/-100)
modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h (+31/-9)
modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp (+0/-16)
modules/Ubuntu/Components/Extras/Printers/models/printermodel.h (+0/-1)
modules/Ubuntu/Components/Extras/Printers/plugin.cpp (+1/-0)
modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp (+12/-2)
modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp (+80/-56)
modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h (+2/-1)
modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp (+34/-6)
tests/unittests/Printers/mockbackend.h (+82/-25)
tests/unittests/Printers/tst_jobfilter.cpp (+4/-2)
tests/unittests/Printers/tst_jobmodel.cpp (+77/-51)
tests/unittests/Printers/tst_printerjob.cpp (+2/-0)
tests/unittests/Printers/tst_printers.cpp (+23/-15)
To merge this branch: bzr merge lp:~ahayzen/ubuntu-ui-extras/job-model-split-update
Reviewer Review Type Date Requested Status
Jonas G. Drange (community) Approve
Review via email: mp+319676@code.launchpad.net

Commit message

* Add a JobLoader for loading a specific jobId for a printer and loading the extended attributes
* Move the loading of creationTime, completedTime, processingTime, size and user to extended attributes as signals don't give us those
* Add method for PrinterBackend for getting a specific job
* Split up JobModel::update so there is jobCreated, jobState and jobCompleted which then call addJob, removeJob and updateJob
* Improve Printer::updateFrom to not call loadAttributes as this results in a possible UI block
* Add missing comparisions for PrinterJob deepCompare and updateFrom
* Change PrinterJob::setPrinter to not call loadDefaults and instead explicitly call it
* Change Printers to trigger requestJobExtendedAttributes which triggers a background thread rather than doing in foreground

Description of the change

* Add a JobLoader for loading a specific jobId for a printer and loading the extended attributes
* Move the loading of creationTime, completedTime, processingTime, size and user to extended attributes as signals don't give us those
* Add method for PrinterBackend for getting a specific job
* Split up JobModel::update so there is jobCreated, jobState and jobCompleted which then call addJob, removeJob and updateJob
* Improve Printer::updateFrom to not call loadAttributes as this results in a possible UI block
* Add missing comparisions for PrinterJob deepCompare and updateFrom
* Change PrinterJob::setPrinter to not call loadDefaults and instead explicitly call it
* Change Printers to trigger requestJobExtendedAttributes which triggers a background thread rather than doing in foreground

To post a comment you must log in.
Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Looks good! A couple of requests for information.

review: Needs Information
149. By Andrew Hayzen

* Resolve failing tests with new JobLoader changes
* Add comments

150. By Andrew Hayzen

* Remove MockPrinters and use Printers directly

151. By Andrew Hayzen

* Rename m_activeRequests to m_activePrinterRequests
* Update JobModel::updateJob description

152. By Andrew Hayzen

* Pull of upstream

153. By Andrew Hayzen

* Fix missed renames
* Fix failing tests
* Actually set the printer from JobLoader to the PrinterJob in JobModel, even if it isn't loaded to keep the reference up to date
* Improve emulation to be closer to real

Revision history for this message
Andrew Hayzen (ahayzen) wrote :

1) I wonder if you could rename this to m_activePrinterRequests.

Yup, done

2) Could you inform me what will happen when a thread is locked out? Will it keep trying until it can get a lock? What's the behavior?

At the moment it will block the thread and keep trying. Do you think we should use tryLock? Note that the problem is not usually that the Ipp request blocks, it is that only one request should be done at a time. Otherwise if two requests done at the same one or both of them will fail with strange errors.

3) Maybe. For printer's we have this proxytype. Maybe you could introduce the same semantics?

I think this should be done in a future branch, also async cups requests would fix this.

4) Not entirely sure I understand this comment. Could you clarify?

JobLoader::load used to create it's own PrinterBackend to avoid threading issues that #2 resolved. This comment is now incorrect, I've updated it.

5) Good. I wonder why it wasn't like this in the first place.

Yeah exactly, this is probably one of the places that would cause the app to hang that we hadn't figured out :-)

Also are you able to test if we need to set the timezone information for creation/completion/processing times?

154. By Andrew Hayzen

* Use tryLock instead of lock and print a warning

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Is this a bug in the API or PrinterQueue? http://i.imgur.com/s8CBHJM.png

Still getting:

    QObject::connect: Cannot queue arguments of type 'QVector<int>'
    (Make sure 'QVector<int>' is registered using qRegisterMetaType().)

I think this is introduced by this branch?

Otherwise, I'm at UNI and have 30 printers showing up that may or may not be reachable, and this is really snappy and non-crashy.

review: Needs Information
Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Couple of minor nitpicks. Also, /* … */ should be used for multi lined comments, please (super small nitpick).

review: Needs Fixing
155. By Andrew Hayzen

* Change JobLoader to only respond with a QMap of attributes and not a PrinterJob
* Change Printers to directly call JobModel::updateJobPrinter
* Remove headers we don't need in JobLoader
* Change FIXME to TODO
* Update tests

Revision history for this message
Andrew Hayzen (ahayzen) wrote :

1) Not sure it needs this header?

Yup removed

2) s/FIXME/TODO :)

Fixed

3) Are you fixing this? Otherwise, could you rewrite it to be a TODO? Fixme's I associate with "fix before merging". :)
And in what cases aren't the newJob's printer fully loaded?

Changed, when in the Queue app it only uses the list of jobs and doesn't load any printers, so they are all proxytype.

4) Seems the timezone is set, but the time stamp does not it reflect it. E.g. time was 13:51 (UTC+1) and the time stamp in the job appeared as 12:51 GMT+0100.

Investigating on next commit...

Made the changes to JobLoader to return a QMap rather than a 'new' job.

156. By Andrew Hayzen

* Set timezone for completedTime, creationTime, processingTime in PrinterJob

Revision history for this message
Andrew Hayzen (ahayzen) wrote :

4) Timezone stuff

Tried setting a timezone for the datetime's let me know if this works.

157. By Andrew Hayzen

* Fix timezones, internally use UTC then when exposing to QML set as local timezone

158. By Andrew Hayzen

* Set timezone after time_t

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Very good, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt'
2--- modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt 2017-03-08 14:47:16 +0000
3+++ modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt 2017-03-16 15:26:32 +0000
4@@ -31,6 +31,7 @@
5
6 cups/devicesearcher.cpp
7 cups/ippclient.cpp
8+ cups/jobloader.cpp
9 cups/printerdriverloader.cpp
10 cups/printerloader.cpp
11
12
13=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp'
14--- modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp 2017-03-10 13:15:27 +0000
15+++ modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp 2017-03-16 15:26:32 +0000
16@@ -182,6 +182,14 @@
17 return QList<QSharedPointer<PrinterJob>>{};
18 }
19
20+QSharedPointer<PrinterJob> PrinterBackend::printerGetJob(
21+ const QString &printerName, const int jobId)
22+{
23+ Q_UNUSED(printerName);
24+ Q_UNUSED(jobId);
25+ return QSharedPointer<PrinterJob>(Q_NULLPTR);
26+}
27+
28 QMap<QString, QVariant> PrinterBackend::printerGetJobAttributes(
29 const QString &name, const int jobId)
30 {
31@@ -281,6 +289,13 @@
32 return QString();
33 }
34
35+void PrinterBackend::requestJobExtendedAttributes(
36+ QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job)
37+{
38+ Q_UNUSED(printer);
39+ Q_UNUSED(job);
40+}
41+
42 void PrinterBackend::requestPrinterDrivers()
43 {
44 }
45
46=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend.h'
47--- modules/Ubuntu/Components/Extras/Printers/backend/backend.h 2017-03-10 13:15:27 +0000
48+++ modules/Ubuntu/Components/Extras/Printers/backend/backend.h 2017-03-16 15:26:32 +0000
49@@ -86,6 +86,8 @@
50 const QString &title,
51 const cups_dest_t *dest);
52 virtual QList<QSharedPointer<PrinterJob>> printerGetJobs();
53+ virtual QSharedPointer<PrinterJob> printerGetJob(const QString &printerName,
54+ const int jobId);
55 virtual QMap<QString, QVariant> printerGetJobAttributes(
56 const QString &name, const int jobId);
57
58@@ -111,6 +113,8 @@
59 virtual QSharedPointer<Printer> getPrinter(const QString &printerName);
60 virtual QString defaultPrinterName();
61
62+ virtual void requestJobExtendedAttributes(QSharedPointer<Printer> printer,
63+ QSharedPointer<PrinterJob> job);
64 virtual void requestPrinterDrivers();
65 virtual void requestPrinter(const QString &printerName);
66
67@@ -125,6 +129,7 @@
68 void printerDriversLoaded(const QList<PrinterDriver> &drivers);
69 void printerDriversFailedToLoad(const QString &errorMessage);
70
71+ void jobLoaded(QString, int, QMap<QString, QVariant>);
72 void printerLoaded(QSharedPointer<Printer> printers);
73 void deviceFound(const Device &device);
74 void deviceSearchFinished();
75
76=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp'
77--- modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp 2017-03-13 13:21:01 +0000
78+++ modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp 2017-03-16 15:26:32 +0000
79@@ -16,6 +16,7 @@
80
81 #include "backend/backend_cups.h"
82 #include "cups/devicesearcher.h"
83+#include "cups/jobloader.h"
84 #include "cups/printerdriverloader.h"
85 #include "cups/printerloader.h"
86 #include "utils.h"
87@@ -468,6 +469,18 @@
88 map.insert("ColorModel", QVariant(""));
89 }
90
91+ if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-completed", QDateTime)) {
92+ map.insert("CompletedTime", rawMap.value("date-time-at-completed"));
93+ } else {
94+ map.insert("CompletedTime", QVariant(QDateTime()));
95+ }
96+
97+ if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-creation", QDateTime)) {
98+ map.insert("CreationTime", rawMap.value("date-time-at-creation"));
99+ } else {
100+ map.insert("CreationTime", QVariant(QDateTime()));
101+ }
102+
103 if (__CUPS_ATTR_EXISTS(rawMap, "Duplex", QString)) {
104 map.insert("Duplex", rawMap.value("Duplex"));
105 } else {
106@@ -493,6 +506,12 @@
107 map.insert("page-ranges", QVariant(QStringList()));
108 }
109
110+ if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-processing", QDateTime)) {
111+ map.insert("ProcessingTime", rawMap.value("date-time-at-processing"));
112+ } else {
113+ map.insert("ProcessingTime", QVariant(QDateTime()));
114+ }
115+
116 Q_FOREACH(QString qualityOption, m_knownQualityOptions) {
117 if (rawMap.contains(qualityOption)
118 && rawMap.value(qualityOption).canConvert<QString>()) {
119@@ -510,6 +529,18 @@
120 map.insert("OutputOrder", "Normal");
121 }
122
123+ if (__CUPS_ATTR_EXISTS(rawMap, "job-k-octets", int)) {
124+ map.insert("Size", rawMap.value("job-k-octets"));
125+ } else {
126+ map.insert("Size", QVariant(0));
127+ }
128+
129+ if (__CUPS_ATTR_EXISTS(rawMap, "job-originating-user-name", QString)) {
130+ map.insert("User", rawMap.value("job-originating-user-name"));
131+ } else {
132+ map.insert("User", QVariant(""));
133+ }
134+
135 // Generate a list of messages
136 // TODO: for now just using job-printer-state-message, are there others?
137 QStringList messages;
138@@ -530,31 +561,13 @@
139 QList<QSharedPointer<PrinterJob>> list;
140
141 Q_FOREACH(auto job, jobs) {
142+ // Note: extended attributes are not loaded here
143+ // they are loaded in JobLoader
144 auto newJob = QSharedPointer<PrinterJob>(
145 new PrinterJob(QString::fromUtf8(job->dest), this, job->id)
146 );
147-
148- // Extract the times
149- QDateTime completedTime;
150- completedTime.setTimeZone(QTimeZone::systemTimeZone());
151- completedTime.setTime_t(job->completed_time);
152-
153- QDateTime creationTime;
154- creationTime.setTimeZone(QTimeZone::systemTimeZone());
155- creationTime.setTime_t(job->creation_time);
156-
157- QDateTime processingTime;
158- processingTime.setTimeZone(QTimeZone::systemTimeZone());
159- processingTime.setTime_t(job->processing_time);
160-
161- // Load the information from the cups struct
162- newJob->setCompletedTime(completedTime);
163- newJob->setCreationTime(creationTime);
164- newJob->setProcessingTime(processingTime);
165- newJob->setSize(job->size);
166 newJob->setState(static_cast<PrinterEnum::JobState>(job->state));
167 newJob->setTitle(QString::fromLocal8Bit(job->title));
168- newJob->setUser(QString::fromLocal8Bit(job->user));
169
170 list.append(newJob);
171 }
172@@ -564,6 +577,35 @@
173 return list;
174 }
175
176+QSharedPointer<PrinterJob> PrinterCupsBackend::printerGetJob(
177+ const QString &printerName, const int jobId)
178+{
179+ auto jobs = getCupsJobs(printerName);
180+ cups_job_t *cupsJob = Q_NULLPTR;
181+ QSharedPointer<PrinterJob> job(Q_NULLPTR);
182+
183+ for (int i=0; i < jobs.size(); i++) {
184+ if (jobs.at(i)->id == jobId) {
185+ cupsJob = jobs.at(i);
186+ break;
187+ }
188+ }
189+
190+ if (cupsJob) {
191+ job = QSharedPointer<PrinterJob>(
192+ new PrinterJob(QString::fromUtf8(cupsJob->dest), this, cupsJob->id)
193+ );
194+
195+ job->setState(static_cast<PrinterEnum::JobState>(cupsJob->state));
196+ job->setTitle(QString::fromLocal8Bit(cupsJob->title));
197+ }
198+
199+ if (!jobs.size())
200+ cupsFreeJobs(jobs.size(), jobs.first());
201+
202+ return job;
203+}
204+
205 QString PrinterCupsBackend::printerName() const
206 {
207 return m_printerName;
208@@ -675,9 +717,35 @@
209 return QPrinterInfo::defaultPrinterName();
210 }
211
212+void PrinterCupsBackend::requestJobExtendedAttributes(
213+ QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job)
214+{
215+ QPair<QString, int> pair(printer->name(), job->jobId());
216+
217+ if (m_activeJobRequests.contains(pair)) {
218+ return;
219+ }
220+
221+ auto thread = new QThread;
222+ auto loader = new JobLoader(this, printer->name(), job->jobId());
223+ loader->moveToThread(thread);
224+ connect(thread, SIGNAL(started()), loader, SLOT(load()));
225+ connect(loader, SIGNAL(finished()), thread, SLOT(quit()));
226+ connect(loader, SIGNAL(finished()), loader, SLOT(deleteLater()));
227+ connect(loader, SIGNAL(loaded(QString, int, QMap<QString, QVariant>)),
228+ this, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>)));
229+ connect(loader, SIGNAL(loaded(QString, int, QMap<QString, QVariant>)),
230+ this, SLOT(onJobLoaded(QString, int, QMap<QString, QVariant>)));
231+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
232+
233+ m_activeJobRequests << pair;
234+
235+ thread->start();
236+}
237+
238 void PrinterCupsBackend::requestPrinter(const QString &printerName)
239 {
240- if (m_activeRequests.contains(printerName)) {
241+ if (m_activePrinterRequests.contains(printerName)) {
242 return;
243 }
244
245@@ -692,9 +760,10 @@
246 connect(loader, SIGNAL(loaded(QSharedPointer<Printer>)),
247 this, SLOT(onPrinterLoaded(QSharedPointer<Printer>)));
248 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
249+
250+ m_activePrinterRequests << printerName;
251+
252 thread->start();
253-
254- m_activeRequests << printerName;
255 }
256
257 void PrinterCupsBackend::requestPrinterDrivers()
258@@ -711,6 +780,7 @@
259 connect(loader, SIGNAL(loaded(const QList<PrinterDriver>&)),
260 this, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&)));
261 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
262+
263 thread->start();
264 }
265
266@@ -801,8 +871,17 @@
267 return m_extendedAttributeNames.contains(attributeName);
268 }
269
270+void PrinterCupsBackend::onJobLoaded(QString printerName, int jobId,
271+ QMap<QString, QVariant> attributes)
272+{
273+ Q_UNUSED(attributes);
274+
275+ QPair<QString, int> pair(printerName, jobId);
276+ m_activeJobRequests.remove(pair);
277+}
278+
279 void PrinterCupsBackend::onPrinterLoaded(QSharedPointer<Printer> printer)
280 {
281- m_activeRequests.remove(printer->name());
282+ m_activePrinterRequests.remove(printer->name());
283 }
284
285
286=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h'
287--- modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h 2017-03-10 13:15:27 +0000
288+++ modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h 2017-03-16 15:26:32 +0000
289@@ -81,6 +81,8 @@
290 const QString &title,
291 const cups_dest_t *dest) override;
292 virtual QList<QSharedPointer<PrinterJob>> printerGetJobs() override;
293+ virtual QSharedPointer<PrinterJob> printerGetJob(
294+ const QString &printerName, const int jobId) override;
295
296 virtual QString printerName() const override;
297 virtual QString description() const override;
298@@ -103,6 +105,10 @@
299 virtual QStringList availablePrinterNames() override;
300 virtual QSharedPointer<Printer> getPrinter(const QString &printerName) override;
301 virtual QString defaultPrinterName() override;
302+
303+ virtual void requestJobExtendedAttributes(
304+ QSharedPointer<Printer> printer,
305+ QSharedPointer<PrinterJob> job) override;
306 virtual void requestPrinterDrivers() override;
307 virtual void requestPrinter(const QString &printerName) override;
308 virtual QMap<QString, QVariant> printerGetJobAttributes(
309@@ -142,9 +148,12 @@
310 int m_cupsSubscriptionId;
311 mutable QMap<QString, cups_dest_t*> m_dests; // Printer name, dest.
312 mutable QMap<QString, ppd_file_t*> m_ppds; // Printer name, ppd.
313- QSet<QString> m_activeRequests;
314+ QSet<QString> m_activePrinterRequests;
315+ QSet<QPair<QString, int>> m_activeJobRequests;
316
317 private Q_SLOTS:
318+ void onJobLoaded(QString printerName, int jobId,
319+ QMap<QString, QVariant> attributes);
320 void onPrinterLoaded(QSharedPointer<Printer> printer);
321 };
322
323
324=== modified file 'modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp'
325--- modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp 2017-03-10 13:15:27 +0000
326+++ modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp 2017-03-16 15:26:32 +0000
327@@ -475,6 +475,14 @@
328 ipp_t *request;
329 QMap<QString, QVariant> map;
330
331+ // Try to get the lock, if we can't after 5 seconds then fail and return
332+ if (!m_thread_lock.tryLock(5000)) {
333+ qWarning() << "Unable to get lock for IppClient::printerGetJobAttributes."
334+ << "Unable to load attributes for job:" << jobId << " for "
335+ << printerName;
336+ return map;
337+ }
338+
339 // Construct request
340 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
341
342@@ -500,7 +508,8 @@
343 map.insert(ippGetName(attr), value);
344 }
345 } else {
346- qWarning() << "Not able to get attributes of job:" << jobId;
347+ qWarning() << "Not able to get attributes of job:" << jobId << " for "
348+ << printerName;
349 }
350
351 // Destruct the reply if valid
352@@ -508,6 +517,8 @@
353 ippDelete(reply);
354 }
355
356+ m_thread_lock.unlock();
357+
358 return map;
359 }
360
361@@ -1107,8 +1118,8 @@
362 case IPP_TAG_DATE: {
363 time_t time = ippDateToTime(ippGetDate(attr, index));
364 QDateTime datetime;
365- datetime.setTimeZone(QTimeZone::systemTimeZone());
366 datetime.setTime_t(time);
367+ datetime.setTimeZone(QTimeZone::utc());
368
369 var = QVariant::fromValue<QDateTime>(datetime);
370 break;
371
372=== modified file 'modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h'
373--- modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h 2017-03-14 13:35:58 +0000
374+++ modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h 2017-03-16 15:26:32 +0000
375@@ -25,6 +25,7 @@
376 #include <cups/ipp.h>
377 #include <cups/ppd.h>
378
379+#include <QMutex>
380 #include <QString>
381 #include <QStringList>
382
383@@ -125,6 +126,7 @@
384 http_t *m_connection;
385 ipp_status_t m_lastStatus = IPP_OK;
386 mutable QString m_internalStatus = QString::null;
387+ QMutex m_thread_lock;
388 };
389
390
391
392=== added file 'modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp'
393--- modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp 1970-01-01 00:00:00 +0000
394+++ modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp 2017-03-16 15:26:32 +0000
395@@ -0,0 +1,50 @@
396+/*
397+ * Copyright (C) 2017 Canonical, Ltd.
398+ *
399+ * This program is free software; you can redistribute it and/or modify
400+ * it under the terms of the GNU Lesser General Public License as published by
401+ * the Free Software Foundation; version 3.
402+ *
403+ * This program is distributed in the hope that it will be useful,
404+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
405+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
406+ * GNU Lesser General Public License for more details.
407+ *
408+ * You should have received a copy of the GNU Lesser General Public License
409+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
410+ */
411+
412+#include "jobloader.h"
413+
414+#include "backend/backend.h"
415+
416+#include "printers/printers.h"
417+
418+#include <QDBusConnection>
419+#include <QPrinterInfo>
420+
421+class PrinterCupsBackend;
422+JobLoader::JobLoader(PrinterBackend *backend,
423+ QString printerName,
424+ int jobId,
425+ QObject *parent)
426+ : QObject(parent)
427+ , m_backend(backend)
428+ , m_job_id(jobId)
429+ , m_printer_name(printerName)
430+{
431+}
432+
433+JobLoader::~JobLoader()
434+{
435+}
436+
437+void JobLoader::load()
438+{
439+ QMap<QString, QVariant> map = m_backend->printerGetJobAttributes(
440+ m_printer_name, m_job_id
441+ );
442+
443+ Q_EMIT loaded(m_printer_name, m_job_id, map);
444+ Q_EMIT finished();
445+}
446
447=== added file 'modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h'
448--- modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h 1970-01-01 00:00:00 +0000
449+++ modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h 2017-03-16 15:26:32 +0000
450@@ -0,0 +1,47 @@
451+/*
452+ * Copyright (C) 2017 Canonical, Ltd.
453+ *
454+ * This program is free software; you can redistribute it and/or modify
455+ * it under the terms of the GNU Lesser General Public License as published by
456+ * the Free Software Foundation; version 3.
457+ *
458+ * This program is distributed in the hope that it will be useful,
459+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
460+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
461+ * GNU Lesser General Public License for more details.
462+ *
463+ * You should have received a copy of the GNU Lesser General Public License
464+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
465+ */
466+
467+#ifndef USC_PRINTERS_CUPS_JOBLOADER_H
468+#define USC_PRINTERS_CUPS_JOBLOADER_H
469+
470+#include "printer/printer.h"
471+#include "printer/printerjob.h"
472+
473+#include <QList>
474+#include <QObject>
475+#include <QSharedPointer>
476+
477+class JobLoader : public QObject
478+{
479+ Q_OBJECT
480+ PrinterBackend *m_backend;
481+ int m_job_id;
482+ QString m_printer_name;
483+public:
484+ explicit JobLoader(PrinterBackend *backend,
485+ QString printerName, int jobId,
486+ QObject *parent = Q_NULLPTR);
487+ ~JobLoader();
488+
489+public Q_SLOTS:
490+ void load();
491+
492+Q_SIGNALS:
493+ void finished();
494+ void loaded(QString, int, QMap<QString, QVariant>);
495+};
496+
497+#endif // USC_PRINTERS_CUPS_JOBLOADER_H
498
499=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp'
500--- modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp 2017-03-06 13:19:08 +0000
501+++ modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp 2017-03-16 15:26:32 +0000
502@@ -31,113 +31,169 @@
503 : QAbstractListModel(parent)
504 , m_backend(backend)
505 {
506- update();
507-
508 QObject::connect(m_backend, &PrinterBackend::jobCreated,
509- this, &JobModel::jobSignalCatchAll);
510+ this, &JobModel::jobCreated);
511 QObject::connect(m_backend, &PrinterBackend::jobState,
512- this, &JobModel::jobSignalCatchAll);
513+ this, &JobModel::jobState);
514 QObject::connect(m_backend, &PrinterBackend::jobCompleted,
515- this, &JobModel::jobSignalCatchAll);
516+ this, &JobModel::jobCompleted);
517+
518+ connect(m_backend, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>)),
519+ this, SLOT(updateJob(QString, int, QMap<QString, QVariant>)));
520+
521+ // Add already existing jobs
522+ // TODO: even this should probably be in a background thread?
523+ // so that it doesn't block startup?
524+ Q_FOREACH(auto job, m_backend->printerGetJobs()) {
525+ addJob(job);
526+ }
527 }
528
529 JobModel::~JobModel()
530 {
531 }
532
533-void JobModel::jobSignalCatchAll(
534- const QString &text, const QString &printer_uri,
535- const QString &printer_name, uint printer_state,
536- const QString &printer_state_reasons, bool printer_is_accepting_jobs,
537- uint job_id, uint job_state, const QString &job_state_reasons,
538- const QString &job_name, uint job_impressions_completed)
539-{
540- Q_UNUSED(text);
541- Q_UNUSED(printer_uri);
542- Q_UNUSED(printer_name);
543- Q_UNUSED(printer_state);
544- Q_UNUSED(printer_state_reasons);
545- Q_UNUSED(printer_is_accepting_jobs);
546- Q_UNUSED(job_id);
547+void JobModel::jobCreated(
548+ const QString &text, const QString &printer_uri,
549+ const QString &printer_name, uint printer_state,
550+ const QString &printer_state_reasons, bool printer_is_accepting_jobs,
551+ uint job_id, uint job_state, const QString &job_state_reasons,
552+ const QString &job_name, uint job_impressions_completed)
553+{
554+ Q_UNUSED(text); // "Job Created"
555+ Q_UNUSED(printer_uri);
556+ Q_UNUSED(printer_state);
557+ Q_UNUSED(printer_state_reasons);
558+ Q_UNUSED(printer_is_accepting_jobs);
559+ Q_UNUSED(job_state_reasons);
560+
561+ QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(
562+ new PrinterJob(printer_name, m_backend, job_id)
563+ );
564+ job->setImpressionsCompleted(job_impressions_completed);
565+ job->setState(static_cast<PrinterEnum::JobState>(job_state));
566+ job->setTitle(job_name);
567+
568+ // Printers listens to rowInserted and spawns a JobLoader to set the
569+ // printer of the job, which triggers the extended attributes to be loaded
570+ // once complete this triggers JobModel::updateJob
571+ addJob(job);
572+}
573+
574+void JobModel::jobState(
575+ const QString &text, const QString &printer_uri,
576+ const QString &printer_name, uint printer_state,
577+ const QString &printer_state_reasons, bool printer_is_accepting_jobs,
578+ uint job_id, uint job_state, const QString &job_state_reasons,
579+ const QString &job_name, uint job_impressions_completed)
580+{
581+ Q_UNUSED(text);
582+ Q_UNUSED(printer_uri);
583+ Q_UNUSED(printer_state);
584+ Q_UNUSED(printer_state_reasons);
585+ Q_UNUSED(printer_is_accepting_jobs);
586+ Q_UNUSED(job_state_reasons);
587+ Q_UNUSED(job_name);
588+
589+ QSharedPointer<PrinterJob> job = getJob(printer_name, job_id);
590+
591+ if (job) {
592+ job->setImpressionsCompleted(job_impressions_completed);
593+ job->setState(static_cast<PrinterEnum::JobState>(job_state));
594+
595+ updateJob(job);
596+ } else {
597+ qWarning() << "JobModel::jobState for unknown job: " << job_name << " ("
598+ << job_id << ") for " << printer_name;
599+ }
600+}
601+
602+void JobModel::jobCompleted(
603+ const QString &text, const QString &printer_uri,
604+ const QString &printer_name, uint printer_state,
605+ const QString &printer_state_reasons, bool printer_is_accepting_jobs,
606+ uint job_id, uint job_state, const QString &job_state_reasons,
607+ const QString &job_name, uint job_impressions_completed)
608+{
609+ Q_UNUSED(text);
610+ Q_UNUSED(printer_uri);
611+ Q_UNUSED(printer_state);
612+ Q_UNUSED(printer_state_reasons);
613+ Q_UNUSED(printer_is_accepting_jobs);
614 Q_UNUSED(job_state);
615 Q_UNUSED(job_state_reasons);
616 Q_UNUSED(job_name);
617-
618- auto job = getJobById(job_id);
619- if (job)
620- job->setImpressionsCompleted(job_impressions_completed);
621-
622- update();
623-}
624-
625-void JobModel::update()
626-{
627- // Store the old count and get the new printers
628- int oldCount = m_jobs.size();
629- QList<QSharedPointer<PrinterJob>> newJobs = m_backend->printerGetJobs();
630-
631- // Go through the old model
632- for (int i=0; i < m_jobs.count(); i++) {
633- // Determine if the old printer exists in the new model
634- bool exists = false;
635-
636- Q_FOREACH(QSharedPointer<PrinterJob> p, newJobs) {
637- if (p->jobId() == m_jobs.at(i)->jobId()) {
638- exists = true;
639-
640- // Ensure the other properties of the job are up to date
641- if (!m_jobs.at(i)->deepCompare(p)) {
642- m_jobs.at(i)->updateFrom(p);
643-
644- Q_EMIT dataChanged(index(i), index(i));
645- }
646-
647- break;
648- }
649- }
650-
651- // If it doesn't exist then remove it from the old model
652- if (!exists) {
653- beginRemoveRows(QModelIndex(), i, i);
654- QSharedPointer<PrinterJob> p = m_jobs.takeAt(i);
655- endRemoveRows();
656-
657- i--; // as we have removed an item decrement
658- }
659- }
660-
661- // Go through the new model
662- for (int i=0; i < newJobs.count(); i++) {
663- // Determine if the new printer exists in the old model
664- bool exists = false;
665- int j;
666-
667- for (j=0; j < m_jobs.count(); j++) {
668- if (m_jobs.at(j)->jobId() == newJobs.at(i)->jobId()) {
669- exists = true;
670- break;
671- }
672- }
673-
674- if (exists) {
675- if (j == i) { // New printer exists and in correct position
676- continue;
677- } else {
678- // New printer does exist but needs to be moved in old model
679- beginMoveRows(QModelIndex(), j, 1, QModelIndex(), i);
680- m_jobs.move(j, i);
681- endMoveRows();
682- }
683- } else {
684- // New printer does not exist insert into model
685- beginInsertRows(QModelIndex(), i, i);
686- m_jobs.insert(i, newJobs.at(i));
687- endInsertRows();
688- }
689- }
690-
691- if (oldCount != m_jobs.size()) {
692- Q_EMIT countChanged();
693+ Q_UNUSED(job_impressions_completed);
694+
695+ auto job = getJob(printer_name, job_id);
696+ if (job) {
697+ removeJob(job);
698+ } else {
699+ qWarning() << "JobModel::jobCompleted for unknown job: " << job_name << " ("
700+ << job_id << ") for " << printer_name;
701+ }
702+}
703+
704+void JobModel::addJob(QSharedPointer<PrinterJob> job)
705+{
706+ int i = m_jobs.size();
707+
708+ beginInsertRows(QModelIndex(), i, i);
709+ m_jobs.append(job);
710+ endInsertRows();
711+
712+ Q_EMIT countChanged();
713+}
714+
715+void JobModel::removeJob(QSharedPointer<PrinterJob> job)
716+{
717+ int i = m_jobs.indexOf(job);
718+
719+ beginRemoveRows(QModelIndex(), i, i);
720+ m_jobs.removeAt(i);
721+ endRemoveRows();
722+
723+ Q_EMIT countChanged();
724+}
725+
726+// This is used by JobModel::jobState as it has modified an existing job
727+void JobModel::updateJob(QSharedPointer<PrinterJob> job)
728+{
729+ int i = m_jobs.indexOf(job);
730+ QModelIndex idx = index(i);
731+ Q_EMIT dataChanged(idx, idx);
732+}
733+
734+// This is used by JobLoader as it gives us the oldJob and a newJob which has
735+// the extended attributes loaded. We then load the data from this newJob.
736+void JobModel::updateJob(QString printerName, int jobId,
737+ QMap<QString, QVariant> attributes)
738+{
739+ QSharedPointer<PrinterJob> job = getJob(printerName, jobId);
740+
741+ int i = m_jobs.indexOf(job);
742+ QModelIndex idx = index(i);
743+
744+ if (i > -1) {
745+ job->loadAttributes(attributes);
746+
747+ Q_EMIT dataChanged(idx, idx);
748+ } else {
749+ qWarning() << "Tried to updateJob which doesn't exist:" << printerName << jobId;
750+ }
751+}
752+
753+void JobModel::updateJobPrinter(QSharedPointer<PrinterJob> job, QSharedPointer<Printer> printer)
754+{
755+ int i = m_jobs.indexOf(job);
756+ QModelIndex idx = index(i);
757+
758+ if (i > -1) {
759+ job->setPrinter(printer);
760+
761+ Q_EMIT dataChanged(idx, idx);
762+ } else {
763+ qWarning() << "Tried to updateJobPrinter which doesn't exist:" << printer->name() << job->jobId();
764 }
765 }
766
767@@ -175,13 +231,13 @@
768 break;
769 }
770 case CompletedTimeRole:
771- ret = job->completedTime();
772+ ret = job->completedTime().toLocalTime();
773 break;
774 case CopiesRole:
775 ret = job->copies();
776 break;
777 case CreationTimeRole:
778- ret = job->creationTime();
779+ ret = job->creationTime().toLocalTime();
780 break;
781 case DuplexRole: {
782 if (job->printer()) {
783@@ -217,7 +273,7 @@
784 ret = QVariant::fromValue<PrinterEnum::PrintRange>(job->printRangeMode());
785 break;
786 case ProcessingTimeRole:
787- ret = job->processingTime();
788+ ret = job->processingTime().toLocalTime();
789 break;
790 case QualityRole: {
791 if (job->printer()) {
792@@ -307,10 +363,10 @@
793 return result;
794 }
795
796-QSharedPointer<PrinterJob> JobModel::getJobById(const int &id)
797+QSharedPointer<PrinterJob> JobModel::getJob(const QString &printerName, const int &id)
798 {
799 Q_FOREACH(auto job, m_jobs) {
800- if (job->jobId() == id) {
801+ if (job->printerName() == printerName && job->jobId() == id) {
802 return job;
803 }
804 }
805
806=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h'
807--- modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h 2017-03-06 13:19:08 +0000
808+++ modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h 2017-03-16 15:26:32 +0000
809@@ -30,6 +30,8 @@
810 #include <QTimer>
811 #include <QVariant>
812
813+class PrinterBackend;
814+class PrinterJob;
815 class PRINTERS_DECL_EXPORT JobModel : public QAbstractListModel
816 {
817 Q_OBJECT
818@@ -76,20 +78,40 @@
819 int count() const;
820
821 Q_INVOKABLE QVariantMap get(const int row) const;
822- QSharedPointer<PrinterJob> getJobById(const int &id);
823+ QSharedPointer<PrinterJob> getJob(const QString &printerName, const int &id);
824+
825+ void updateJobPrinter(QSharedPointer<PrinterJob> job, QSharedPointer<Printer> printer);
826 private:
827+ void addJob(QSharedPointer<PrinterJob> job);
828+ void removeJob(QSharedPointer<PrinterJob> job);
829+ void updateJob(QSharedPointer<PrinterJob> Job);
830+
831 PrinterBackend *m_backend;
832
833 QList<QSharedPointer<PrinterJob>> m_jobs;
834 private Q_SLOTS:
835- void update();
836- void jobSignalCatchAll(const QString &text, const QString &printer_uri,
837- const QString &printer_name, uint printer_state,
838- const QString &printer_state_reasons,
839- bool printer_is_accepting_jobs, uint job_id,
840- uint job_state, const QString &job_state_reasons,
841- const QString &job_name,
842- uint job_impressions_completed);
843+ void jobCreated(const QString &text, const QString &printer_uri,
844+ const QString &printer_name, uint printer_state,
845+ const QString &printer_state_reasons,
846+ bool printer_is_accepting_jobs, uint job_id,
847+ uint job_state, const QString &job_state_reasons,
848+ const QString &job_name,
849+ uint job_impressions_completed);
850+ void jobState(const QString &text, const QString &printer_uri,
851+ const QString &printer_name, uint printer_state,
852+ const QString &printer_state_reasons,
853+ bool printer_is_accepting_jobs, uint job_id,
854+ uint job_state, const QString &job_state_reasons,
855+ const QString &job_name,
856+ uint job_impressions_completed);
857+ void jobCompleted(const QString &text, const QString &printer_uri,
858+ const QString &printer_name, uint printer_state,
859+ const QString &printer_state_reasons,
860+ bool printer_is_accepting_jobs, uint job_id,
861+ uint job_state, const QString &job_state_reasons,
862+ const QString &job_name,
863+ uint job_impressions_completed);
864+ void updateJob(QString printerName, int jobId, QMap<QString, QVariant> attributes);
865
866 Q_SIGNALS:
867 void countChanged();
868
869=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp'
870--- modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp 2017-03-10 13:15:27 +0000
871+++ modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp 2017-03-16 15:26:32 +0000
872@@ -127,22 +127,6 @@
873 return QSharedPointer<Printer>(Q_NULLPTR);
874 }
875
876-void PrinterModel::movePrinter(const int &from, const int &to)
877-{
878- int size = m_printers.size();
879- if (from < 0 || to < 0 || from >= size || to >= size) {
880- qWarning() << Q_FUNC_INFO << "Illegal move operation from"
881- << from << "to" << to << ". Size was" << size;
882- return;
883- }
884- if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), to)) {
885- qWarning() << Q_FUNC_INFO << "failed to move rows.";
886- return;
887- }
888- m_printers.move(from, to);
889- endMoveRows();
890-}
891-
892 void PrinterModel::removePrinter(QSharedPointer<Printer> printer, const CountChangeSignal &notify)
893 {
894 int idx = m_printers.indexOf(printer);
895
896=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/printermodel.h'
897--- modules/Ubuntu/Components/Extras/Printers/models/printermodel.h 2017-03-10 13:15:27 +0000
898+++ modules/Ubuntu/Components/Extras/Printers/models/printermodel.h 2017-03-16 15:26:32 +0000
899@@ -99,7 +99,6 @@
900 const CountChangeSignal &notify = CountChangeSignal::Defer);
901 void removePrinter(QSharedPointer<Printer> printer,
902 const CountChangeSignal &notify = CountChangeSignal::Defer);
903- void movePrinter(const int &from, const int &to);
904 void updatePrinter(QSharedPointer<Printer> old,
905 QSharedPointer<Printer> newPrinter);
906 PrinterBackend *m_backend;
907
908=== modified file 'modules/Ubuntu/Components/Extras/Printers/plugin.cpp'
909--- modules/Ubuntu/Components/Extras/Printers/plugin.cpp 2017-03-08 11:29:01 +0000
910+++ modules/Ubuntu/Components/Extras/Printers/plugin.cpp 2017-03-16 15:26:32 +0000
911@@ -54,6 +54,7 @@
912
913 qmlRegisterUncreatableType<PrinterEnum>(uri, 0, 1, "PrinterEnum", "Is an enum");
914 qRegisterMetaType<QList<PrinterDriver>>("QList<PrinterDriver>");
915+ qRegisterMetaType<QSharedPointer<PrinterJob>>("QSharedPointer<PrinterJob>");
916 qRegisterMetaType<QList<QSharedPointer<Printer>>>("QList<QSharedPointer<Printer>>");
917 qRegisterMetaType<Device>("Device");
918 }
919
920=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp'
921--- modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp 2017-03-10 13:15:27 +0000
922+++ modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp 2017-03-16 15:26:32 +0000
923@@ -403,10 +403,20 @@
924 void Printer::updateFrom(QSharedPointer<Printer> other)
925 {
926 PrinterBackend *tmp = m_backend;
927+
928+ // Copy values from other printer which has been loaded in another thread
929+ // Note: do not use loadAttributes otherwise can cause UI block
930+ m_acceptJobs = other->m_acceptJobs;
931 m_backend = other->m_backend;
932+ m_defaultColorModel = other->m_defaultColorModel;
933+ m_defaultPrintQuality = other->m_defaultPrintQuality;
934+ m_deviceUri = other->m_deviceUri;
935+ m_shared = other->m_shared;
936+ m_stateMessage = other->m_stateMessage;
937+ m_supportedColorModels = other->m_supportedColorModels;
938+ m_supportedPrintQualities = other->m_supportedPrintQualities;
939+
940 other->m_backend = tmp;
941-
942- loadAttributes();
943 }
944
945 void Printer::onPrinterStateChanged(
946
947=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp'
948--- modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp 2017-03-14 12:01:48 +0000
949+++ modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp 2017-03-16 15:26:32 +0000
950@@ -145,6 +145,62 @@
951 return m_landscape;
952 }
953
954+void PrinterJob::loadAttributes(const QMap<QString, QVariant> &attributes)
955+{
956+ // Load the extra attributes for the job
957+ // NOTE: we don't need to type check them as they have been filtered for us
958+
959+ setCollate(attributes.value("Collate").toBool());
960+ setCopies(attributes.value("copies").toInt());
961+
962+ // No colorModel will result in PrinterJob using defaultColorModel
963+ QString colorModel = attributes.value("ColorModel").toString();
964+ for (int i=0; i < m_printer->supportedColorModels().length(); i++) {
965+ if (m_printer->supportedColorModels().at(i).name == colorModel) {
966+ setColorModel(i);
967+ }
968+ }
969+
970+ setCompletedTime(attributes.value("CompletedTime").toDateTime());
971+ setCreationTime(attributes.value("CreationTime").toDateTime());
972+
973+ // No duplexMode will result in PrinterJob using defaultDuplexMode
974+ QString duplex = attributes.value("Duplex").toString();
975+ PrinterEnum::DuplexMode duplexMode = Utils::ppdChoiceToDuplexMode(duplex);
976+ for (int i=0; i < m_printer->supportedDuplexModes().length(); i++) {
977+ if (m_printer->supportedDuplexModes().at(i) == duplexMode) {
978+ setDuplexMode(i);
979+ }
980+ }
981+
982+ setLandscape(attributes.value("landscape").toBool());
983+ setMessages(attributes.value("messages").toStringList());
984+
985+ QStringList pageRanges = attributes.value("page-ranges").toStringList();
986+ if (pageRanges.isEmpty()) {
987+ setPrintRangeMode(PrinterEnum::PrintRange::AllPages);
988+ setPrintRange(QStringLiteral(""));
989+ } else {
990+ setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
991+ // Use groupSeparator as createSeparatedList adds "and" into the string
992+ setPrintRange(pageRanges.join(QLocale::system().groupSeparator()));
993+ }
994+
995+ setProcessingTime(attributes.value("ProcessingTime").toDateTime());
996+
997+ // No quality will result in PrinterJob using defaultPrintQuality
998+ QString quality = attributes.value("quality").toString();
999+ for (int i=0; i < m_printer->supportedPrintQualities().length(); i++) {
1000+ if (m_printer->supportedPrintQualities().at(i).name == quality) {
1001+ setQuality(i);
1002+ }
1003+ }
1004+
1005+ setReverse(attributes.value("OutputOrder").toString() == "Reverse");
1006+ setSize(attributes.value("Size").toInt());
1007+ setUser(attributes.value("User").toString());
1008+}
1009+
1010 void PrinterJob::loadDefaults()
1011 {
1012 if (!m_printer) {
1013@@ -152,62 +208,17 @@
1014 return;
1015 }
1016
1017- qWarning() << Q_FUNC_INFO << jobId();
1018-
1019 if (jobId() > 0) {
1020- // Load the extra attributes for the job
1021- // NOTE: we don't need to type check them as they have been filtered for us
1022-
1023- QMap<QString, QVariant> attributes = m_backend->printerGetJobAttributes(
1024- m_printer->name(), jobId());
1025-
1026- setCollate(attributes.value("Collate").toBool());
1027- setCopies(attributes.value("copies").toInt());
1028-
1029- // No colorModel will result in PrinterJob using defaultColorModel
1030- QString colorModel = attributes.value("ColorModel").toString();
1031- for (int i=0; i < m_printer->supportedColorModels().length(); i++) {
1032- if (m_printer->supportedColorModels().at(i).originalOption == colorModel) {
1033- setColorModel(i);
1034- }
1035- }
1036-
1037- // No duplexMode will result in PrinterJob using defaultDuplexMode
1038- QString duplex = attributes.value("Duplex").toString();
1039- PrinterEnum::DuplexMode duplexMode = Utils::ppdChoiceToDuplexMode(duplex);
1040- for (int i=0; i < m_printer->supportedDuplexModes().length(); i++) {
1041- if (m_printer->supportedDuplexModes().at(i) == duplexMode) {
1042- setDuplexMode(i);
1043- }
1044- }
1045-
1046- setLandscape(attributes.value("landscape").toBool());
1047- setMessages(attributes.value("messages").toStringList());
1048-
1049- QStringList pageRanges = attributes.value("page-ranges").toStringList();
1050- if (pageRanges.isEmpty()) {
1051- setPrintRangeMode(PrinterEnum::PrintRange::AllPages);
1052- setPrintRange(QStringLiteral(""));
1053- } else {
1054- setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
1055- // Use groupSeparator as createSeparatedList adds "and" into the string
1056- setPrintRange(pageRanges.join(QLocale::system().groupSeparator()));
1057- }
1058-
1059- // No quality will result in PrinterJob using defaultPrintQuality
1060- QString quality = attributes.value("quality").toString();
1061- for (int i=0; i < m_printer->supportedPrintQualities().length(); i++) {
1062- if (m_printer->supportedPrintQualities().at(i).name == quality) {
1063- setQuality(i);
1064- }
1065- }
1066-
1067- setReverse(attributes.value("OutputOrder").toString() == "Reverse");
1068+ loadAttributes(
1069+ m_backend->printerGetJobAttributes(
1070+ printerName(), jobId()
1071+ )
1072+ );
1073+ } else {
1074+ setColorModel(m_printer->supportedColorModels().indexOf(m_printer->defaultColorModel()));
1075+ setDuplexMode(m_printer->supportedDuplexModes().indexOf(m_printer->defaultDuplexMode()));
1076+ setQuality(m_printer->supportedPrintQualities().indexOf(m_printer->defaultPrintQuality()));
1077 }
1078-
1079- setColorModel(m_printer->supportedColorModels().indexOf(m_printer->defaultColorModel()));
1080- setDuplexMode(m_printer->supportedDuplexModes().indexOf(m_printer->defaultDuplexMode()));
1081- setQuality(m_printer->supportedPrintQualities().indexOf(m_printer->defaultPrintQuality()));
1082 }
1083
1084 QStringList PrinterJob::messages() const
1085@@ -385,7 +396,6 @@
1086
1087 Q_EMIT printerChanged();
1088 }
1089- loadDefaults();
1090 }
1091
1092 void PrinterJob::setPrintRange(const QString &printRange)
1093@@ -481,30 +491,44 @@
1094 // Return true if they are the same
1095 return collate() == other->collate()
1096 && colorModel() == other->colorModel()
1097+ && completedTime() == other->completedTime()
1098 && copies() == other->copies()
1099+ && creationTime() == other->creationTime()
1100 && duplexMode() == other->duplexMode()
1101+ && impressionsCompleted() == other->impressionsCompleted()
1102 && landscape() == other->landscape()
1103+ && messages() == other->messages()
1104 && printRange() == other->printRange()
1105 && printRangeMode() == other->printRangeMode()
1106+ && processingTime() == other->processingTime()
1107 && quality() == other->quality()
1108 && reverse() == other->reverse()
1109+ && size() == other->size()
1110 && state() == other->state()
1111- && title() == other->title();
1112+ && title() == other->title()
1113+ && user() == other->user();
1114 }
1115
1116 void PrinterJob::updateFrom(QSharedPointer<PrinterJob> other)
1117 {
1118 setCollate(other->collate());
1119 setColorModel(other->colorModel());
1120+ setCompletedTime(other->completedTime());
1121 setCopies(other->copies());
1122+ setCreationTime(other->creationTime());
1123 setDuplexMode(other->duplexMode());
1124+ setImpressionsCompleted(other->impressionsCompleted());
1125 setLandscape(other->landscape());
1126+ setMessages(other->messages());
1127 setPrintRange(other->printRange());
1128 setPrintRangeMode(other->printRangeMode());
1129+ setProcessingTime(other->processingTime());
1130 setQuality(other->quality());
1131 setReverse(other->reverse());
1132+ setSize(other->size());
1133 setState(other->state());
1134 setTitle(other->title());
1135+ setUser(other->user());
1136 }
1137
1138 QString PrinterJob::user() const
1139
1140=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h'
1141--- modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h 2017-03-10 13:06:04 +0000
1142+++ modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h 2017-03-16 15:26:32 +0000
1143@@ -95,6 +95,8 @@
1144 PrinterEnum::DuplexMode getDuplexMode() const;
1145 ColorModel getColorModel() const;
1146 PrintQuality getPrintQuality() const;
1147+ void loadAttributes(const QMap<QString, QVariant>& attributes);
1148+ void loadDefaults();
1149 Q_INVOKABLE void printFile(const QUrl &url);
1150 void setCollate(const bool collate);
1151 void setColorModel(const int colorModel);
1152@@ -119,7 +121,6 @@
1153
1154 void updateFrom(QSharedPointer<PrinterJob> other);
1155 private Q_SLOTS:
1156- void loadDefaults();
1157 void onPrinterAboutToChange(QSharedPointer<Printer> old,
1158 QSharedPointer<Printer> replacement);
1159 Q_SIGNALS:
1160
1161=== modified file 'modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp'
1162--- modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp 2017-03-09 14:34:05 +0000
1163+++ modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp 2017-03-16 15:26:32 +0000
1164@@ -58,7 +58,12 @@
1165 const QModelIndex &parent, int first, int) {
1166 int jobId = m_jobs.data(m_jobs.index(first, 0, parent),
1167 JobModel::Roles::IdRole).toInt();
1168- jobAdded(m_jobs.getJobById(jobId));
1169+ QString printerName = m_jobs.data(
1170+ m_jobs.index(first, 0, parent),
1171+ JobModel::Roles::PrinterNameRole
1172+ ).toString();
1173+
1174+ jobAdded(m_jobs.getJob(printerName, jobId));
1175 });
1176 connect(&m_model, &QAbstractItemModel::rowsInserted, [this](
1177 const QModelIndex &parent, int first, int) {
1178@@ -78,6 +83,17 @@
1179 );
1180 }
1181
1182+ // Ensure existing jobs have been added, incase some were added before
1183+ // the connect to rowsInserted was done
1184+ for (int i = 0; i < m_jobs.rowCount(); i++) {
1185+ jobAdded(
1186+ m_jobs.getJob(
1187+ m_jobs.data(m_jobs.index(i), JobModel::Roles::PrinterNameRole).toString(),
1188+ m_jobs.data(m_jobs.index(i), JobModel::IdRole).toInt()
1189+ )
1190+ );
1191+ }
1192+
1193 if (m_backend->type() == PrinterEnum::PrinterType::CupsType) {
1194 ((PrinterCupsBackend*) m_backend)->createSubscription();
1195 }
1196@@ -271,8 +287,21 @@
1197 void Printers::jobAdded(QSharedPointer<PrinterJob> job)
1198 {
1199 auto printer = m_model.getPrinterByName(job->printerName());
1200- if (printer && job)
1201- job->setPrinter(printer);
1202+
1203+ // Check if we have a valid printer, does not need to be loaded as JobLoader
1204+ // creates it's own Backend.
1205+ if (printer && job) {
1206+ // TODO: this printer may not be fully loaded
1207+ // Which has the side affect of colorModel, duplex, quality not working
1208+ // in PrinterJob as Printer::supportedColorModels etc fail
1209+ // Potentially trigger loadPrinter and listen for the new printer?
1210+
1211+ // Set the printer to the job
1212+ m_jobs.updateJobPrinter(job, printer);
1213+
1214+ // Trigger JobLoader to load extended attributes in the background
1215+ m_backend->requestJobExtendedAttributes(printer, job);
1216+ }
1217 }
1218
1219 void Printers::printerAdded(QSharedPointer<Printer> printer)
1220@@ -288,10 +317,9 @@
1221 ).toString();
1222
1223 int jobId = m_jobs.data(idx, JobModel::Roles::IdRole).toInt();
1224- auto job = m_jobs.getJobById(jobId);
1225+ auto job = m_jobs.getJob(printerName, jobId);
1226 if (printerName == printer->name() && !job->printer()) {
1227- job->setPrinter(printer);
1228- return;
1229+ jobAdded(job);
1230 }
1231 }
1232 }
1233
1234=== modified file 'tests/unittests/Printers/mockbackend.h'
1235--- tests/unittests/Printers/mockbackend.h 2017-03-10 13:15:27 +0000
1236+++ tests/unittests/Printers/mockbackend.h 2017-03-16 15:26:32 +0000
1237@@ -176,36 +176,30 @@
1238 }
1239 }
1240
1241- virtual void holdJob(const QString &name, const int jobId) override
1242+ virtual void holdJob(const QString &printerName, const int jobId) override
1243 {
1244- for (int i=0; i < m_jobs.count(); i++) {
1245- QSharedPointer<PrinterJob> job = m_jobs[i];
1246-
1247- if (job->printerName() == name && job->jobId() == jobId) {
1248- auto jobHeld = QSharedPointer<PrinterJob>(new PrinterJob(job->printerName(), this, jobId));
1249- jobHeld->setState(PrinterEnum::JobState::Held);
1250- m_jobs.replace(0, jobHeld);
1251-
1252- Q_EMIT jobState(job->title(), "", job->printerName(), 1, "", true, job->jobId(), 4, "", "", 1);
1253- break;
1254+ // Change the faked job state
1255+ Q_FOREACH(auto job, m_jobs) {
1256+ if (job->printerName() == printerName
1257+ && job->jobId() == jobId) {
1258+ job->setState(PrinterEnum::JobState::Held);
1259 }
1260 }
1261+
1262+ Q_EMIT jobState("", "", printerName, 1, "", true, jobId, static_cast<uint>(PrinterEnum::JobState::Held), "", "", 1);
1263 }
1264
1265- virtual void releaseJob(const QString &name, const int jobId) override
1266+ virtual void releaseJob(const QString &printerName, const int jobId) override
1267 {
1268- for (int i=0; i < m_jobs.count(); i++) {
1269- QSharedPointer<PrinterJob> job = m_jobs[i];
1270-
1271- if (job->printerName() == name && job->jobId() == jobId) {
1272- auto jobRelease = QSharedPointer<PrinterJob>(new PrinterJob(job->printerName(), this, jobId));
1273- jobRelease->setState(PrinterEnum::JobState::Pending);
1274- m_jobs.replace(0, jobRelease);
1275-
1276- Q_EMIT jobState(job->title(), "", job->printerName(), 1, "", true, job->jobId(), 4, "", "", 1);
1277- break;
1278+ // Change the faked job state
1279+ Q_FOREACH(auto job, m_jobs) {
1280+ if (job->printerName() == printerName
1281+ && job->jobId() == jobId) {
1282+ job->setState(PrinterEnum::JobState::Pending);
1283 }
1284 }
1285+
1286+ Q_EMIT jobState("", "", printerName, 1, "", true, jobId, static_cast<uint>(PrinterEnum::JobState::Pending), "", "", 1);
1287 }
1288
1289 virtual int printFileToDest(const QString &filepath,
1290@@ -229,9 +223,37 @@
1291 virtual QMap<QString, QVariant> printerGetJobAttributes(
1292 const QString &name, const int jobId) override
1293 {
1294- Q_UNUSED(name);
1295- Q_UNUSED(jobId);
1296- return QMap<QString, QVariant>();
1297+ QMap<QString, QVariant> attributes;
1298+
1299+ Q_FOREACH(auto job, m_jobs) {
1300+ if (job->printerName() == name
1301+ && job->jobId() == jobId) {
1302+ // Emulate reverse of PrinterJob::loadAttributes
1303+ // using local jobs defined in tests
1304+ attributes.insert("Collate", job->collate());
1305+ attributes.insert("copies", job->copies());
1306+ attributes.insert("ColorModel", job->getColorModel().name);
1307+ attributes.insert("CompletedTime", job->completedTime());
1308+ attributes.insert("CreationTime", job->creationTime());
1309+ attributes.insert("Duplex", Utils::duplexModeToPpdChoice(job->getDuplexMode()));
1310+ attributes.insert("landscape", job->landscape());
1311+ attributes.insert("messages", job->messages());
1312+ if (job->printRangeMode() == PrinterEnum::PrintRange::AllPages) {
1313+ attributes.insert("page-ranges", QStringList());
1314+ } else {
1315+ attributes.insert("page-ranges", job->printRange().split(QLocale::system().groupSeparator()));
1316+ }
1317+ attributes.insert("ProcessingTime", job->processingTime());
1318+ attributes.insert("Quality", job->getPrintQuality().name);
1319+ attributes.insert("OutputOrder", job->reverse() ? "Reverse" : "Normal");
1320+ attributes.insert("Size", job->size());
1321+ attributes.insert("User", job->user());
1322+
1323+ break;
1324+ }
1325+ }
1326+
1327+ return attributes;
1328 }
1329
1330 virtual QString printerName() const override
1331@@ -337,6 +359,13 @@
1332 m_requestedPrinters << printerName;
1333 }
1334
1335+ virtual void requestJobExtendedAttributes(QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job) override
1336+ {
1337+ QMap<QString, QVariant> attributes = printerGetJobAttributes(printer->name(), job->jobId());
1338+
1339+ Q_EMIT jobLoaded(printer->name(), job->jobId(), attributes);
1340+ }
1341+
1342 virtual PrinterEnum::PrinterType type() const override
1343 {
1344 return m_type;
1345@@ -393,6 +422,34 @@
1346 );
1347 }
1348
1349+ void mockJobCompleted(
1350+ const QString &text, const QString &printer_uri,
1351+ const QString &printer_name, uint printer_state,
1352+ const QString &printer_state_reasons, bool printer_is_accepting_jobs,
1353+ uint job_id, uint job_state, const QString &job_state_reasons,
1354+ const QString &job_name, uint job_impressions_completed)
1355+ {
1356+ Q_EMIT jobCompleted(
1357+ text, printer_uri, printer_name, printer_state,
1358+ printer_state_reasons, printer_is_accepting_jobs, job_id,
1359+ job_state, job_state_reasons, job_name, job_impressions_completed
1360+ );
1361+ }
1362+
1363+ void mockJobState(
1364+ const QString &text, const QString &printer_uri,
1365+ const QString &printer_name, uint printer_state,
1366+ const QString &printer_state_reasons, bool printer_is_accepting_jobs,
1367+ uint job_id, uint job_state, const QString &job_state_reasons,
1368+ const QString &job_name, uint job_impressions_completed)
1369+ {
1370+ Q_EMIT jobState(
1371+ text, printer_uri, printer_name, printer_state,
1372+ printer_state_reasons, printer_is_accepting_jobs, job_id,
1373+ job_state, job_state_reasons, job_name, job_impressions_completed
1374+ );
1375+ }
1376+
1377 void mockDriversLoaded(const QList<PrinterDriver> &drivers)
1378 {
1379 Q_EMIT printerDriversLoaded(drivers);
1380
1381=== modified file 'tests/unittests/Printers/tst_jobfilter.cpp'
1382--- tests/unittests/Printers/tst_jobfilter.cpp 2017-02-21 10:46:29 +0000
1383+++ tests/unittests/Printers/tst_jobfilter.cpp 2017-03-16 15:26:32 +0000
1384@@ -32,10 +32,12 @@
1385 QScopedPointer<MockPrinterBackend> backend(new MockPrinterBackend);
1386 JobModel model(backend.data());
1387
1388- auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend.data()));
1389+ auto job = QSharedPointer<PrinterJob>(
1390+ new PrinterJob("test-printer", backend.data(), 100)
1391+ );
1392 backend->m_jobs << job;
1393 // Trigger update.
1394- backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1395+ backend->mockJobCreated("", "", "test-printer", 1, "", true, 100, 3, "", "", 1);
1396
1397 JobFilter filter;
1398 filter.setSourceModel(&model);
1399
1400=== modified file 'tests/unittests/Printers/tst_jobmodel.cpp'
1401--- tests/unittests/Printers/tst_jobmodel.cpp 2017-03-06 11:44:11 +0000
1402+++ tests/unittests/Printers/tst_jobmodel.cpp 2017-03-16 15:26:32 +0000
1403@@ -18,12 +18,14 @@
1404
1405 #include "backend/backend.h"
1406 #include "models/jobmodel.h"
1407+#include "printers/printers.h"
1408
1409 #include <QDebug>
1410 #include <QObject>
1411 #include <QSignalSpy>
1412 #include <QTest>
1413
1414+
1415 class TestJobModel : public QObject
1416 {
1417 Q_OBJECT
1418@@ -31,14 +33,19 @@
1419 void init()
1420 {
1421 m_backend = new MockPrinterBackend;
1422- m_model = new JobModel(m_backend);
1423+ m_printers = new Printers(m_backend);
1424+
1425+ m_model = static_cast<JobModel *>(m_printers->printJobs());
1426+
1427+ PrinterBackend* backend = new MockPrinterBackend("test-printer");
1428+ auto printer = QSharedPointer<Printer>(new Printer(backend));
1429+ m_backend->mockPrinterLoaded(printer);
1430 }
1431 void cleanup()
1432 {
1433- QSignalSpy destroyedSpy(m_model, SIGNAL(destroyed(QObject*)));
1434- m_model->deleteLater();
1435+ QSignalSpy destroyedSpy(m_printers, SIGNAL(destroyed(QObject*)));
1436+ m_printers->deleteLater();
1437 QTRY_COMPARE(destroyedSpy.count(), 1);
1438- delete m_backend;
1439 }
1440
1441 // Tests for adding/removing/changing things in the model
1442@@ -71,7 +78,7 @@
1443 catchall handler in the model. */
1444 QSignalSpy removeSpy(m_model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));
1445 m_backend->m_jobs.clear();
1446- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1447+ m_backend->mockJobCompleted("", "", "", 1, "", true, 100, 1, "", "", 1);
1448 QCOMPARE(removeSpy.count(), 1);
1449
1450 // Check item was removed
1451@@ -79,38 +86,20 @@
1452 QCOMPARE(args.at(1).toInt(), 0);
1453 QCOMPARE(args.at(2).toInt(), 0);
1454 }
1455- void testMove()
1456- {
1457- // Add two jobs.
1458- auto job1 = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
1459- auto job2 = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
1460- m_backend->m_jobs << job1 << job2;
1461- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1462-
1463- m_backend->m_jobs.move(0, 1);
1464- // Triggers a move.
1465- QSignalSpy moveSpy(m_model, SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)));
1466- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1467- QCOMPARE(moveSpy.count(), 1);
1468- QList<QVariant> args = moveSpy.at(0);
1469- QCOMPARE(args.at(1).toInt(), 1);
1470- QCOMPARE(args.at(2).toInt(), 1);
1471- QCOMPARE(args.at(4).toInt(), 0);
1472- }
1473 void testModify()
1474 {
1475 auto jobBefore = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
1476+ int impressions_count = 1;
1477
1478 m_backend->m_jobs << jobBefore;
1479- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1480-
1481- auto jobAfter = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
1482- jobAfter->setCopies(100);
1483- m_backend->m_jobs.replace(0, jobAfter);
1484+ m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", impressions_count);
1485
1486 // Triggers a change.
1487 QSignalSpy changedSpy(m_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
1488- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1489+
1490+ impressions_count = 5;
1491+ m_backend->mockJobState("", "", "", 1, "", true, 100, 1, "", "", impressions_count);
1492+
1493 QCOMPARE(changedSpy.count(), 1);
1494 }
1495
1496@@ -135,14 +124,19 @@
1497 jobB->setCollate(true);
1498
1499 m_backend->m_jobs << jobA << jobB;
1500- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1501+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1502+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1503
1504 QTRY_COMPARE(m_model->count(), 2);
1505+
1506 QCOMPARE(m_model->data(m_model->index(0), JobModel::CollateRole).toBool(), false);
1507 QCOMPARE(m_model->data(m_model->index(1), JobModel::CollateRole).toBool(), true);
1508 }
1509 void testColorModelRole()
1510 {
1511+ // FIXME: read comment in JobModel::updateJob
1512+ QSKIP("We are ignoring colorModel for now as it requires a loaded Printer for the PrinterJob.");
1513+
1514 ColorModel a;
1515 a.name = "KGray";
1516 a.text = "Gray";
1517@@ -159,17 +153,21 @@
1518
1519 auto printer = QSharedPointer<Printer>(new Printer(backend));
1520 m_backend->mockPrinterLoaded(printer);
1521+// m_printers->m_printers << printer;
1522
1523 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 1));
1524 jobA->setPrinter(printer);
1525+ jobA->loadDefaults();
1526 jobA->setColorModel(models.indexOf(a));
1527
1528 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 2));
1529 jobB->setPrinter(printer);
1530+ jobB->loadDefaults();
1531 jobB->setColorModel(models.indexOf(b));
1532
1533 m_backend->m_jobs << jobA << jobB;
1534- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1535+ m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1);
1536+ m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 2, 1, "", "", 1);
1537
1538 QTRY_COMPARE(m_model->count(), 2);
1539 QCOMPARE(m_model->data(m_model->index(0), JobModel::ColorModelRole).toString(),
1540@@ -189,7 +187,8 @@
1541 jobB->setCompletedTime(dateTimeB);
1542
1543 m_backend->m_jobs << jobA << jobB;
1544- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1545+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1546+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1547
1548 QTRY_COMPARE(m_model->count(), 2);
1549 QCOMPARE(m_model->data(m_model->index(0), JobModel::CompletedTimeRole).toDateTime(),
1550@@ -206,7 +205,8 @@
1551 jobB->setCopies(5);
1552
1553 m_backend->m_jobs << jobA << jobB;
1554- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1555+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1556+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1557
1558 QTRY_COMPARE(m_model->count(), 2);
1559 QCOMPARE(m_model->data(m_model->index(0), JobModel::CopiesRole).toInt(), 2);
1560@@ -224,7 +224,8 @@
1561 jobB->setCreationTime(dateTimeB);
1562
1563 m_backend->m_jobs << jobA << jobB;
1564- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1565+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1566+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1567
1568 QTRY_COMPARE(m_model->count(), 2);
1569 QCOMPARE(m_model->data(m_model->index(0), JobModel::CreationTimeRole).toDateTime(),
1570@@ -234,6 +235,9 @@
1571 }
1572 void testDuplexRole()
1573 {
1574+ // FIXME: read comment in JobModel::updateJob
1575+ QSKIP("We are ignoring duplex for now as it requires a loaded Printer for the PrinterJob.");
1576+
1577 QList<PrinterEnum::DuplexMode> modes({
1578 PrinterEnum::DuplexMode::DuplexNone,
1579 PrinterEnum::DuplexMode::DuplexLongSide,
1580@@ -257,7 +261,8 @@
1581 jobB->setDuplexMode(modes.indexOf(PrinterEnum::DuplexMode::DuplexNone));
1582
1583 m_backend->m_jobs << jobA << jobB;
1584- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1585+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1586+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1587
1588 QTRY_COMPARE(m_model->count(), 2);
1589 QCOMPARE(m_model->data(m_model->index(0), JobModel::DuplexRole).toString(),
1590@@ -274,7 +279,8 @@
1591 jobB->setState(PrinterEnum::JobState::Held);
1592
1593 m_backend->m_jobs << jobA << jobB;
1594- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1595+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, static_cast<uint>(jobA->state()), "", "", 1);
1596+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, static_cast<uint>(jobB->state()), "", "", 1);
1597
1598 QTRY_COMPARE(m_model->count(), 2);
1599 QCOMPARE(m_model->data(m_model->index(0), JobModel::HeldRole).toBool(), false);
1600@@ -289,7 +295,8 @@
1601 jobB->setImpressionsCompleted(5);
1602
1603 m_backend->m_jobs << jobA << jobB;
1604- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1605+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", jobA->impressionsCompleted());
1606+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", jobB->impressionsCompleted());
1607
1608 QTRY_COMPARE(m_model->count(), 2);
1609 QCOMPARE(m_model->data(m_model->index(0), JobModel::ImpressionsCompletedRole).toInt(), 2);
1610@@ -304,7 +311,8 @@
1611 jobB->setLandscape(true);
1612
1613 m_backend->m_jobs << jobA << jobB;
1614- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1615+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1616+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1617
1618 QTRY_COMPARE(m_model->count(), 2);
1619 QCOMPARE(m_model->data(m_model->index(0), JobModel::LandscapeRole).toBool(), false);
1620@@ -312,14 +320,15 @@
1621 }
1622 void testMessagesRole()
1623 {
1624- auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", m_backend, 1));
1625+ auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
1626 jobA->setMessages(QStringList() << "a-message" << "b-message");
1627
1628- auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("b-printer", m_backend, 2));
1629+ auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
1630 jobB->setMessages(QStringList() << "c-message" << "d-message");
1631
1632 m_backend->m_jobs << jobA << jobB;
1633- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1634+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1635+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1636
1637 QTRY_COMPARE(m_model->count(), 2);
1638 QCOMPARE(m_model->data(m_model->index(0), JobModel::MessagesRole).toStringList(),
1639@@ -334,7 +343,8 @@
1640 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("b-printer", m_backend, 2));
1641
1642 m_backend->m_jobs << jobA << jobB;
1643- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1644+ m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1);
1645+ m_backend->mockJobCreated("", "", "b-printer", 1, "", true, 2, 1, "", "", 1);
1646
1647 QTRY_COMPARE(m_model->count(), 2);
1648 QCOMPARE(m_model->data(m_model->index(0), JobModel::PrinterNameRole).toString(), QString("a-printer"));
1649@@ -344,12 +354,15 @@
1650 {
1651 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
1652 jobA->setPrintRange("1-3,5");
1653+ jobA->setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
1654
1655 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
1656 jobB->setPrintRange("-3,6,10-");
1657+ jobB->setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
1658
1659 m_backend->m_jobs << jobA << jobB;
1660- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1661+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1662+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1663
1664 QTRY_COMPARE(m_model->count(), 2);
1665 QCOMPARE(m_model->data(m_model->index(0), JobModel::PrintRangeRole).toString(), QString("1-3,5"));
1666@@ -361,10 +374,12 @@
1667 jobA->setPrintRangeMode(PrinterEnum::PrintRange::AllPages);
1668
1669 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
1670+ jobB->setPrintRange("1-3");
1671 jobB->setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
1672
1673 m_backend->m_jobs << jobA << jobB;
1674- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1675+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1676+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1677
1678 QTRY_COMPARE(m_model->count(), 2);
1679 QCOMPARE(m_model->data(m_model->index(0), JobModel::PrintRangeModeRole).value<PrinterEnum::PrintRange>(), PrinterEnum::PrintRange::AllPages);
1680@@ -382,7 +397,8 @@
1681 jobB->setProcessingTime(dateTimeB);
1682
1683 m_backend->m_jobs << jobA << jobB;
1684- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1685+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1686+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1687
1688 QTRY_COMPARE(m_model->count(), 2);
1689 QCOMPARE(m_model->data(m_model->index(0), JobModel::ProcessingTimeRole).toDateTime(),
1690@@ -392,6 +408,9 @@
1691 }
1692 void testQualityRole()
1693 {
1694+ // FIXME: read comment in JobModel::updateJob
1695+ QSKIP("We are ignoring quality for now as it requires a loaded Printer for the PrinterJob.");
1696+
1697 PrintQuality a;
1698 a.name = "fast-draft";
1699 a.text = "Draft";
1700@@ -418,7 +437,8 @@
1701 jobB->setQuality(qualities.indexOf(b));
1702
1703 m_backend->m_jobs << jobA << jobB;
1704- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1705+ m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1);
1706+ m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 2, 1, "", "", 1);
1707
1708 QTRY_COMPARE(m_model->count(), 2);
1709 QCOMPARE(m_model->data(m_model->index(0), JobModel::QualityRole).toString(),
1710@@ -435,7 +455,8 @@
1711 jobB->setReverse(true);
1712
1713 m_backend->m_jobs << jobA << jobB;
1714- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1715+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1716+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1717
1718 QTRY_COMPARE(m_model->count(), 2);
1719 QCOMPARE(m_model->data(m_model->index(0), JobModel::ReverseRole).toBool(), false);
1720@@ -450,7 +471,8 @@
1721 jobB->setSize(64);
1722
1723 m_backend->m_jobs << jobA << jobB;
1724- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1725+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1726+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1727
1728 QTRY_COMPARE(m_model->count(), 2);
1729 QCOMPARE(m_model->data(m_model->index(0), JobModel::SizeRole).toInt(), 32);
1730@@ -465,7 +487,8 @@
1731 jobB->setState(PrinterEnum::JobState::Processing);
1732
1733 m_backend->m_jobs << jobA << jobB;
1734- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1735+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, static_cast<uint>(jobA->state()), "", "", 1);
1736+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, static_cast<uint>(jobB->state()), "", "", 1);
1737
1738 QTRY_COMPARE(m_model->count(), 2);
1739 QCOMPARE(m_model->data(m_model->index(0), JobModel::StateRole).value<PrinterEnum::JobState>(), PrinterEnum::JobState::Pending);
1740@@ -480,7 +503,8 @@
1741 jobB->setTitle("b-job");
1742
1743 m_backend->m_jobs << jobA << jobB;
1744- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1745+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", jobA->title(), 1);
1746+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", jobB->title(), 1);
1747
1748 QTRY_COMPARE(m_model->count(), 2);
1749 QCOMPARE(m_model->data(m_model->index(0), JobModel::TitleRole).toString(), QString("a-job"));
1750@@ -495,7 +519,8 @@
1751 jobB->setUser("b-user");
1752
1753 m_backend->m_jobs << jobA << jobB;
1754- m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1755+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1756+ m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
1757
1758 QTRY_COMPARE(m_model->count(), 2);
1759 QCOMPARE(m_model->data(m_model->index(0), JobModel::UserRole).toString(), QString("a-user"));
1760@@ -505,6 +530,7 @@
1761 private:
1762 MockPrinterBackend *m_backend;
1763 JobModel *m_model;
1764+ Printers *m_printers;
1765 };
1766
1767 QTEST_GUILESS_MAIN(TestJobModel)
1768
1769=== modified file 'tests/unittests/Printers/tst_printerjob.cpp'
1770--- tests/unittests/Printers/tst_printerjob.cpp 2017-03-14 12:01:48 +0000
1771+++ tests/unittests/Printers/tst_printerjob.cpp 2017-03-16 15:26:32 +0000
1772@@ -39,6 +39,7 @@
1773 m_mock_printer = QSharedPointer<Printer>(new Printer(m_backend));
1774 m_instance = new PrinterJob(m_printer_name, m_backend);
1775 m_instance->setPrinter(m_mock_printer);
1776+ m_instance->loadDefaults();
1777 }
1778 void cleanup()
1779 {
1780@@ -60,6 +61,7 @@
1781
1782 m_instance = new PrinterJob(m_printer_name, m_backend);
1783 m_instance->setPrinter(m_mock_printer);
1784+ m_instance->loadDefaults();
1785 }
1786 void refreshInstanceWithBackend(MockPrinterBackend *backend)
1787 {
1788
1789=== modified file 'tests/unittests/Printers/tst_printers.cpp'
1790--- tests/unittests/Printers/tst_printers.cpp 2017-03-02 14:19:56 +0000
1791+++ tests/unittests/Printers/tst_printers.cpp 2017-03-16 15:26:32 +0000
1792@@ -120,9 +120,9 @@
1793 Printers p(backend);
1794
1795 // Add one.
1796- QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend));
1797+ QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1));
1798 backend->m_jobs << job;
1799- backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1800+ backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1801
1802 // Check it was added
1803 QCOMPARE(model->count(), 1);
1804@@ -147,13 +147,13 @@
1805 Printers p(backend);
1806
1807 // Add one.
1808- QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend));
1809+ QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1));
1810 backend->m_jobs << job;
1811- backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1812+ backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, static_cast<uint>(PrinterEnum::JobState::Pending), "", "", 1);
1813
1814 // Check it was added
1815 QCOMPARE(model->count(), 1);
1816- QCOMPARE(job->state(), PrinterEnum::JobState::Pending);
1817+ QCOMPARE(model->getJob("test-printer", 1)->state(), PrinterEnum::JobState::Pending);
1818
1819 // Setup the spy
1820 QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
1821@@ -163,7 +163,7 @@
1822
1823 // Check item was removed
1824 QTRY_COMPARE(dataChangedSpy.count(), 1);
1825- QCOMPARE(job->state(), PrinterEnum::JobState::Held);
1826+ QCOMPARE(model->getJob("test-printer", 1)->state(), PrinterEnum::JobState::Held);
1827 }
1828 void testReleaseJob()
1829 {
1830@@ -172,15 +172,15 @@
1831 Printers p(backend);
1832
1833 // Add one.
1834- QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend));
1835+ QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1));
1836 backend->m_jobs << job;
1837- backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1838+ backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1839
1840 p.holdJob(job->printerName(), job->jobId());
1841
1842 // Check it was added and is in held state
1843 QCOMPARE(model->count(), 1);
1844- QCOMPARE(job->state(), PrinterEnum::JobState::Held);
1845+ QCOMPARE(model->getJob("test-printer", 1)->state(), PrinterEnum::JobState::Held);
1846
1847 // Setup the spy
1848 QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
1849@@ -190,7 +190,7 @@
1850
1851 // Check item was removed
1852 QTRY_COMPARE(dataChangedSpy.count(), 1);
1853- QCOMPARE(job->state(), PrinterEnum::JobState::Pending);
1854+ QCOMPARE(model->getJob("test-printer", 1)->state(), PrinterEnum::JobState::Pending);
1855 }
1856 void testPrinterRemove()
1857 {
1858@@ -252,23 +252,31 @@
1859 auto printer = QSharedPointer<Printer>(new Printer(printerBackend));
1860 backend->mockPrinterLoaded(printer);
1861
1862- auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend));
1863+ auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1));
1864 backend->m_jobs << job;
1865
1866+ // Setup the spy
1867+ QSignalSpy jobLoadedSpy(backend, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>)));
1868+
1869 // Trigger update.
1870- backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1871+ backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1872+
1873+ QTRY_COMPARE(jobLoadedSpy.count(), 1);
1874
1875 // Job now has a shared pointer to printer.
1876- QCOMPARE(job->printer()->name(), printer->name());
1877+ JobModel *model = static_cast<JobModel *>(p.printJobs());
1878+
1879+ QCOMPARE(model->getJob(printer->name(), job->jobId())->printer(), printer);
1880+ QCOMPARE(model->getJob(printer->name(), job->jobId())->printer()->name(), printer->name());
1881 }
1882 void testSetPrinterJobFilter()
1883 {
1884 MockPrinterBackend *backend = new MockPrinterBackend;
1885 Printers p(backend);
1886
1887- auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend));
1888+ auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1));
1889 backend->m_jobs << job;
1890- backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
1891+ backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
1892
1893 MockPrinterBackend *printerBackend = new MockPrinterBackend("test-printer");
1894 auto printer = QSharedPointer<Printer>(new Printer(printerBackend));

Subscribers

People subscribed via source and target branches