Merge lp:~jonas-drange/ubuntu-ui-extras/printerloader-thread-affinity into lp:ubuntu-ui-extras
- printerloader-thread-affinity
- Merge into trunk
Proposed by
Jonas G. Drange
Status: | Superseded |
---|---|
Proposed branch: | lp:~jonas-drange/ubuntu-ui-extras/printerloader-thread-affinity |
Merge into: | lp:ubuntu-ui-extras |
Diff against target: |
6179 lines (+3849/-439) 45 files modified
modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml (+24/-8) modules/Ubuntu/Components/Extras/Example/Printers.qml (+192/-44) modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt (+4/-1) modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp (+48/-0) modules/Ubuntu/Components/Extras/Printers/backend/backend.h (+13/-0) modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp (+225/-44) modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h (+25/-1) modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp (+10/-0) modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp (+70/-0) modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h (+57/-0) modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp (+163/-9) modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h (+13/-1) 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/cups/printerloader.cpp (+3/-0) modules/Ubuntu/Components/Extras/Printers/enums.h (+23/-0) modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp (+149/-0) modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h (+78/-0) modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp (+267/-126) modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h (+53/-11) modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp (+55/-19) modules/Ubuntu/Components/Extras/Printers/models/printermodel.h (+13/-4) modules/Ubuntu/Components/Extras/Printers/plugin.cpp (+2/-0) modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp (+149/-24) modules/Ubuntu/Components/Extras/Printers/printer/printer.h (+29/-3) modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp (+108/-60) modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h (+14/-11) modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.cpp (+28/-6) modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.h (+8/-6) modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp (+132/-7) modules/Ubuntu/Components/Extras/Printers/printers/printers.h (+18/-0) modules/Ubuntu/Components/Extras/Printers/structs.h (+84/-0) po/ubuntu-ui-extras.pot (+26/-2) tests/unittests/Printers/CMakeLists.txt (+13/-3) tests/unittests/Printers/mockbackend.h (+127/-4) tests/unittests/Printers/tst_jobfilter.cpp (+4/-2) tests/unittests/Printers/tst_jobmodel.cpp (+446/-29) tests/unittests/Printers/tst_printer.cpp (+96/-0) tests/unittests/Printers/tst_printerdevice.cpp (+131/-0) tests/unittests/Printers/tst_printerdevicemodel.cpp (+162/-0) tests/unittests/Printers/tst_printerfilter.cpp (+30/-0) tests/unittests/Printers/tst_printerjob.cpp (+53/-0) tests/unittests/Printers/tst_printermodel.cpp (+489/-1) tests/unittests/Printers/tst_printers.cpp (+92/-7) tests/unittests/Printers/tst_signalratelimiter.cpp (+26/-6) |
To merge this branch: | bzr merge lp:~jonas-drange/ubuntu-ui-extras/printerloader-thread-affinity |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email: mp+320354@code.launchpad.net |
Commit message
corrects thread affinity for printerloaded printers, as well as any qobject children it might have
Description of the change
corrects thread affinity for printerloaded printers, as well as any qobject children it might have
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml' |
2 | --- modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml 2017-02-21 11:31:44 +0000 |
3 | +++ modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml 2017-03-20 13:32:24 +0000 |
4 | @@ -46,20 +46,36 @@ |
5 | } |
6 | delegate: ListItem { |
7 | height: modelLayout.height + (divider.visible ? divider.height : 0) |
8 | + trailingActions: ListItemActions { |
9 | + actions: [ |
10 | + Action { |
11 | + iconName: model.held ? "media-playback-start" : "media-playback-pause" |
12 | + text: model.held ? "Release" : "Hold" |
13 | + |
14 | + onTriggered: { |
15 | + if (model.held) { |
16 | + Printers.releaseJob(printer.name, model.id); |
17 | + } else { |
18 | + Printers.holdJob(printer.name, model.id); |
19 | + } |
20 | + } |
21 | + }, |
22 | + Action { |
23 | + iconName: "cancel" |
24 | + text: "Cancel" |
25 | + |
26 | + onTriggered: Printers.cancelJob(printer.name, model.id); |
27 | + } |
28 | + ] |
29 | + } |
30 | + |
31 | ListItemLayout { |
32 | id: modelLayout |
33 | title.text: displayName |
34 | - subtitle.text: "Job: " + model.id + " State: " + model.state |
35 | - + " Color: " + model.colorModel + " CreationTime: " |
36 | - + model.creationTime + " PageRange: " |
37 | - + model.printRange + " Messages: " + model.messages; |
38 | + subtitle.text: model.title + " (" + model.id + ")\nPrinting " + model.impressionsCompleted + " pages" |
39 | subtitle.wrapMode: Text.WrapAtWordBoundaryOrAnywhere |
40 | subtitle.maximumLineCount: 3 |
41 | } |
42 | - onClicked: { |
43 | - console.debug("Cancel:", printer.name, model.id); |
44 | - Printers.cancelJob(printer.name, model.id); |
45 | - } |
46 | } |
47 | model: printer.jobs |
48 | |
49 | |
50 | === modified file 'modules/Ubuntu/Components/Extras/Example/Printers.qml' |
51 | --- modules/Ubuntu/Components/Extras/Example/Printers.qml 2017-02-21 11:31:44 +0000 |
52 | +++ modules/Ubuntu/Components/Extras/Example/Printers.qml 2017-03-20 13:32:24 +0000 |
53 | @@ -51,17 +51,17 @@ |
54 | } |
55 | } |
56 | |
57 | - Component.onCompleted: { |
58 | - printer.description; |
59 | - } |
60 | - |
61 | Flickable { |
62 | id: printerFlickable |
63 | anchors.fill: parent |
64 | - |
65 | + contentHeight: contentItem.childrenRect.height |
66 | Loader { |
67 | id: printerPageBitsLoader |
68 | - anchors.fill: parent |
69 | + anchors { |
70 | + left: parent.left |
71 | + right: parent.right |
72 | + } |
73 | + |
74 | sourceComponent: printer.isLoaded ? printerPageLoaded : printerPageNotYetLoaded |
75 | } |
76 | } |
77 | @@ -70,7 +70,7 @@ |
78 | id: printerPageLoaded |
79 | |
80 | Column { |
81 | - spacing: units.gu(2) |
82 | + height: childrenRect.height + anchors.topMargin |
83 | anchors { |
84 | top: parent.top |
85 | topMargin: units.gu(2) |
86 | @@ -91,6 +91,31 @@ |
87 | } |
88 | } |
89 | |
90 | + ListItems.SingleValue { |
91 | + anchors { |
92 | + left: parent.left |
93 | + right: parent.right |
94 | + } |
95 | + text: "Status" |
96 | + |
97 | + value: { |
98 | + var state; |
99 | + if (printer.state == PrinterEnum.IdleState) { |
100 | + state = i18n.tr("Idle"); |
101 | + } else if (printer.state == PrinterEnum.AbortedState) { |
102 | + state = i18n.tr("Aborted"); |
103 | + } else if (printer.state == PrinterEnum.ActiveState) { |
104 | + state = i18n.tr("Active"); |
105 | + } else if (printer.state == PrinterEnum.ErrorState) { |
106 | + state = i18n.tr("Stopped"); |
107 | + } |
108 | + return "%1 — %2" |
109 | + .arg(state) |
110 | + .arg(printer.lastMessage ? |
111 | + printer.lastMessage : i18n.tr("No messages")); |
112 | + } |
113 | + } |
114 | + |
115 | ListItems.Standard { |
116 | anchors { |
117 | left: parent.left |
118 | @@ -109,25 +134,30 @@ |
119 | left: parent.left |
120 | right: parent.right |
121 | } |
122 | + text: "Shared" |
123 | + |
124 | + control: Switch { |
125 | + checked: printer.shared |
126 | + onCheckedChanged: printer.shared = checked |
127 | + } |
128 | + } |
129 | + |
130 | + ListItems.Standard { |
131 | + anchors { |
132 | + left: parent.left |
133 | + right: parent.right |
134 | + } |
135 | text: "Jobs" |
136 | progression: true |
137 | onClicked: pageStack.push(jobPage, { printer: printer }) |
138 | } |
139 | |
140 | - Label { |
141 | + ListItems.Standard { |
142 | anchors { |
143 | left: parent.left |
144 | right: parent.right |
145 | - margins: units.gu(2) |
146 | } |
147 | text: "Description" |
148 | - } |
149 | - |
150 | - ListItems.SingleControl { |
151 | - anchors { |
152 | - left: parent.left |
153 | - right: parent.right |
154 | - } |
155 | |
156 | control: TextField { |
157 | anchors { |
158 | @@ -141,6 +171,27 @@ |
159 | } |
160 | } |
161 | |
162 | + ListItems.Standard { |
163 | + anchors { |
164 | + left: parent.left |
165 | + right: parent.right |
166 | + } |
167 | + text: "Copies" |
168 | + |
169 | + control: TextField { |
170 | + id: copiesField |
171 | + inputMethodHints: Qt.ImhDigitsOnly |
172 | + text: printer.copies |
173 | + validator: IntValidator { |
174 | + bottom: 1 |
175 | + top: 999 |
176 | + } |
177 | + width: units.gu(10) |
178 | + onTextChanged: printer.copies = text |
179 | + } |
180 | + |
181 | + } |
182 | + |
183 | |
184 | ListItems.ValueSelector { |
185 | anchors { |
186 | @@ -200,6 +251,26 @@ |
187 | selectedIndex = printer.printQuality |
188 | } |
189 | } |
190 | + |
191 | + ListItems.SingleControl { |
192 | + anchors { |
193 | + left: parent.left |
194 | + right: parent.right |
195 | + } |
196 | + control: Button { |
197 | + text: "Print test page" |
198 | + onClicked: Printers.printTestPage(printer.name) |
199 | + } |
200 | + } |
201 | + |
202 | + ListItems.SingleValue { |
203 | + anchors { |
204 | + left: parent.left |
205 | + right: parent.right |
206 | + } |
207 | + text: "Device URI" |
208 | + value: printer.deviceUri |
209 | + } |
210 | } |
211 | } |
212 | } |
213 | @@ -338,9 +409,18 @@ |
214 | |
215 | ProgressionSlot {} |
216 | } |
217 | - onClicked: pageStack.push(printerPage, { printer: model }) |
218 | + onClicked: { |
219 | + Printers.loadPrinter(model.name); |
220 | + pageStack.push(printerPage, { printer: model }); |
221 | + } |
222 | } |
223 | } |
224 | + |
225 | + Label { |
226 | + anchors.centerIn: parent |
227 | + visible: printerList.count === 0 |
228 | + text: "No printers found" |
229 | + } |
230 | } |
231 | } |
232 | |
233 | @@ -423,9 +503,7 @@ |
234 | } |
235 | } |
236 | |
237 | - Component.onCompleted: { |
238 | - Printers.prepareToAddPrinter(); |
239 | - } |
240 | + Component.onCompleted: Printers.prepareToAddPrinter() |
241 | |
242 | Timer { |
243 | id: okTimer |
244 | @@ -436,14 +514,12 @@ |
245 | Flickable { |
246 | id: addPrinterFlickable |
247 | anchors.fill: parent |
248 | + contentHeight: contentItem.childrenRect.height |
249 | |
250 | Column { |
251 | id: addPrinterCol |
252 | property bool enabled: true |
253 | - anchors { |
254 | - left: parent.left |
255 | - right: parent.right |
256 | - } |
257 | + anchors { left: parent.left; right: parent.right } |
258 | |
259 | Item { |
260 | id: errorMessageContainer |
261 | @@ -476,10 +552,7 @@ |
262 | |
263 | ListItems.ValueSelector { |
264 | id: driverSelector |
265 | - anchors { |
266 | - left: parent.left |
267 | - right: parent.right |
268 | - } |
269 | + anchors { left: parent.left; right: parent.right } |
270 | text: "Choose driver" |
271 | values: [ |
272 | "Select printer from database", |
273 | @@ -489,10 +562,7 @@ |
274 | } |
275 | |
276 | ListItems.Standard { |
277 | - anchors { |
278 | - left: parent.left |
279 | - right: parent.right |
280 | - } |
281 | + anchors { left: parent.left; right: parent.right } |
282 | text: "Filter drivers" |
283 | control: TextField { |
284 | id: driverFilter |
285 | @@ -559,10 +629,7 @@ |
286 | } |
287 | |
288 | ListItems.Standard { |
289 | - anchors { |
290 | - left: parent.left |
291 | - right: parent.right |
292 | - } |
293 | + anchors { left: parent.left; right: parent.right } |
294 | text: "Printer name" |
295 | control: TextField { |
296 | id: printerName |
297 | @@ -572,10 +639,7 @@ |
298 | } |
299 | |
300 | ListItems.Standard { |
301 | - anchors { |
302 | - left: parent.left |
303 | - right: parent.right |
304 | - } |
305 | + anchors { left: parent.left; right: parent.right } |
306 | text: "Description (optional)" |
307 | control: TextField { |
308 | id: printerDescription |
309 | @@ -585,10 +649,7 @@ |
310 | } |
311 | |
312 | ListItems.Standard { |
313 | - anchors { |
314 | - left: parent.left |
315 | - right: parent.right |
316 | - } |
317 | + anchors { left: parent.left; right: parent.right } |
318 | text: "Location (optional)" |
319 | control: TextField { |
320 | id: printerLocation |
321 | @@ -597,6 +658,93 @@ |
322 | enabled: parent.enabled |
323 | } |
324 | } |
325 | + |
326 | + Label { |
327 | + id: remotePrintersLabel |
328 | + anchors { |
329 | + left: parent.left |
330 | + right: parent.right |
331 | + margins: units.gu(2) |
332 | + top: addPrinterCol.bottom |
333 | + } |
334 | + text: "Other printers" |
335 | + |
336 | + ActivityIndicator { |
337 | + id: remotePrintersSearchIndicator |
338 | + anchors { |
339 | + right: parent.right |
340 | + verticalCenter: parent.verticalCenter |
341 | + } |
342 | + property var target |
343 | + Component.onCompleted: target = Printers.remotePrinters |
344 | + running: target.searching |
345 | + } |
346 | + } |
347 | + |
348 | + ListView { |
349 | + id: remotePrintersList |
350 | + anchors { |
351 | + left: parent.left |
352 | + right: parent.right |
353 | + top: remotePrintersLabel.bottom |
354 | + topMargin: units.gu(2) |
355 | + } |
356 | + height: contentItem.childrenRect.height |
357 | + model: Printers.remotePrinters |
358 | + delegate: ListItem { |
359 | + height: modelLayout.height + (divider.visible ? divider.height : 0) |
360 | + ListItemLayout { |
361 | + id: modelLayout |
362 | + title.text: displayName |
363 | + subtitle.text: { |
364 | + if (type == PrinterEnum.LPDType) return "LPD"; |
365 | + if (type == PrinterEnum.IppSType) return "IppS"; |
366 | + if (type == PrinterEnum.Ipp14Type) return "Ipp14"; |
367 | + if (type == PrinterEnum.HttpType) return "Http"; |
368 | + if (type == PrinterEnum.BehType) return "Beh"; |
369 | + if (type == PrinterEnum.SocketType) return "Socket"; |
370 | + if (type == PrinterEnum.HttpsType) return "Https"; |
371 | + if (type == PrinterEnum.IppType) return "Ipp"; |
372 | + if (type == PrinterEnum.HPType) return "HP"; |
373 | + if (type == PrinterEnum.USBType) return "USB"; |
374 | + if (type == PrinterEnum.HPFaxType) return "HPFax"; |
375 | + if (type == PrinterEnum.DNSSDType) return "DNSSD"; |
376 | + else return "Unknown protocol"; |
377 | + } |
378 | + |
379 | + Icon { |
380 | + id: icon |
381 | + width: height |
382 | + height: units.gu(2.5) |
383 | + name: "network-printer-symbolic" |
384 | + SlotsLayout.position: SlotsLayout.First |
385 | + } |
386 | + |
387 | + Button { |
388 | + text: "Select printer" |
389 | + onClicked: { |
390 | + var suggestedPrinterName = (" " + displayName).slice(1); |
391 | + suggestedPrinterName = suggestedPrinterName.replace(/\ /g, "\-"); |
392 | + printerUri.text = uri; |
393 | + printerName.text = suggestedPrinterName; |
394 | + printerDescription.text = info; |
395 | + printerLocation.text = location; |
396 | + } |
397 | + } |
398 | + } |
399 | + } |
400 | + } |
401 | + |
402 | + Label { |
403 | + anchors { |
404 | + left: parent.left |
405 | + right: parent.right |
406 | + top: remotePrintersLabel.bottom |
407 | + topMargin: units.gu(2) |
408 | + } |
409 | + text: "No other printers found" |
410 | + visible: !remotePrintersSearchIndicator.running && remotePrintersList.count == 0 |
411 | + } |
412 | } |
413 | } |
414 | } |
415 | |
416 | === modified file 'modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt' |
417 | --- modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt 2017-02-21 16:55:36 +0000 |
418 | +++ modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt 2017-03-20 13:32:24 +0000 |
419 | @@ -29,17 +29,20 @@ |
420 | backend/backend_cups.cpp |
421 | backend/backend_pdf.cpp |
422 | |
423 | + cups/devicesearcher.cpp |
424 | cups/ippclient.cpp |
425 | + cups/jobloader.cpp |
426 | cups/printerdriverloader.cpp |
427 | cups/printerloader.cpp |
428 | |
429 | + models/devicemodel.cpp |
430 | models/drivermodel.cpp |
431 | models/jobmodel.cpp |
432 | models/printermodel.cpp |
433 | |
434 | printer/printer.cpp |
435 | printer/printerjob.cpp |
436 | - printer/printersignalhandler.cpp |
437 | + printer/signalratelimiter.cpp |
438 | printers/printers.cpp |
439 | |
440 | enums.h |
441 | |
442 | === modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp' |
443 | --- modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp 2017-02-23 14:04:26 +0000 |
444 | +++ modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp 2017-03-20 13:32:24 +0000 |
445 | @@ -91,6 +91,22 @@ |
446 | return QString(); |
447 | } |
448 | |
449 | +QString PrinterBackend::printerSetCopies(const QString &name, |
450 | + const int &copies) |
451 | +{ |
452 | + Q_UNUSED(name); |
453 | + Q_UNUSED(copies); |
454 | + return QString(); |
455 | +} |
456 | + |
457 | +QString PrinterBackend::printerSetShared(const QString &name, |
458 | + const bool shared) |
459 | +{ |
460 | + Q_UNUSED(name); |
461 | + Q_UNUSED(shared); |
462 | + return QString(); |
463 | +} |
464 | + |
465 | QString PrinterBackend::printerSetInfo(const QString &name, |
466 | const QString &info) |
467 | { |
468 | @@ -139,6 +155,18 @@ |
469 | Q_UNUSED(name); |
470 | } |
471 | |
472 | +void PrinterBackend::holdJob(const QString &name, const int jobId) |
473 | +{ |
474 | + Q_UNUSED(jobId); |
475 | + Q_UNUSED(name); |
476 | +} |
477 | + |
478 | +void PrinterBackend::releaseJob(const QString &name, const int jobId) |
479 | +{ |
480 | + Q_UNUSED(jobId); |
481 | + Q_UNUSED(name); |
482 | +} |
483 | + |
484 | int PrinterBackend::printFileToDest(const QString &filepath, |
485 | const QString &title, |
486 | const cups_dest_t *dest) |
487 | @@ -154,6 +182,14 @@ |
488 | return QList<QSharedPointer<PrinterJob>>{}; |
489 | } |
490 | |
491 | +QSharedPointer<PrinterJob> PrinterBackend::printerGetJob( |
492 | + const QString &printerName, const int jobId) |
493 | +{ |
494 | + Q_UNUSED(printerName); |
495 | + Q_UNUSED(jobId); |
496 | + return QSharedPointer<PrinterJob>(Q_NULLPTR); |
497 | +} |
498 | + |
499 | QMap<QString, QVariant> PrinterBackend::printerGetJobAttributes( |
500 | const QString &name, const int jobId) |
501 | { |
502 | @@ -182,6 +218,11 @@ |
503 | return QString(); |
504 | } |
505 | |
506 | +bool PrinterBackend::isRemote() const |
507 | +{ |
508 | + return false; |
509 | +} |
510 | + |
511 | PrinterEnum::State PrinterBackend::state() const |
512 | { |
513 | return PrinterEnum::State::IdleState; |
514 | @@ -248,6 +289,13 @@ |
515 | return QString(); |
516 | } |
517 | |
518 | +void PrinterBackend::requestJobExtendedAttributes( |
519 | + QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job) |
520 | +{ |
521 | + Q_UNUSED(printer); |
522 | + Q_UNUSED(job); |
523 | +} |
524 | + |
525 | void PrinterBackend::requestPrinterDrivers() |
526 | { |
527 | } |
528 | |
529 | === modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend.h' |
530 | --- modules/Ubuntu/Components/Extras/Printers/backend/backend.h 2017-02-23 14:04:26 +0000 |
531 | +++ modules/Ubuntu/Components/Extras/Printers/backend/backend.h 2017-03-20 13:32:24 +0000 |
532 | @@ -63,6 +63,9 @@ |
533 | const QString &name, |
534 | const bool accept, |
535 | const QString &reason = QString::null); |
536 | + virtual QString printerSetCopies(const QString &name, const int &copies); |
537 | + virtual QString printerSetShared(const QString &name, |
538 | + const bool shared); |
539 | virtual QString printerSetInfo(const QString &name, |
540 | const QString &info); |
541 | virtual QString printerAddOption(const QString &name, |
542 | @@ -77,10 +80,14 @@ |
543 | const PrinterJob *options); |
544 | |
545 | virtual void cancelJob(const QString &name, const int jobId); |
546 | + virtual void holdJob(const QString &name, const int jobId); |
547 | + virtual void releaseJob(const QString &name, const int jobId); |
548 | virtual int printFileToDest(const QString &filepath, |
549 | const QString &title, |
550 | const cups_dest_t *dest); |
551 | virtual QList<QSharedPointer<PrinterJob>> printerGetJobs(); |
552 | + virtual QSharedPointer<PrinterJob> printerGetJob(const QString &printerName, |
553 | + const int jobId); |
554 | virtual QMap<QString, QVariant> printerGetJobAttributes( |
555 | const QString &name, const int jobId); |
556 | |
557 | @@ -88,6 +95,7 @@ |
558 | virtual QString description() const; |
559 | virtual QString location() const; |
560 | virtual QString makeAndModel() const; |
561 | + virtual bool isRemote() const; |
562 | |
563 | virtual PrinterEnum::State state() const; |
564 | virtual QList<QPageSize> supportedPageSizes() const; |
565 | @@ -105,6 +113,8 @@ |
566 | virtual QSharedPointer<Printer> getPrinter(const QString &printerName); |
567 | virtual QString defaultPrinterName(); |
568 | |
569 | + virtual void requestJobExtendedAttributes(QSharedPointer<Printer> printer, |
570 | + QSharedPointer<PrinterJob> job); |
571 | virtual void requestPrinterDrivers(); |
572 | virtual void requestPrinter(const QString &printerName); |
573 | |
574 | @@ -119,7 +129,10 @@ |
575 | void printerDriversLoaded(const QList<PrinterDriver> &drivers); |
576 | void printerDriversFailedToLoad(const QString &errorMessage); |
577 | |
578 | + void jobLoaded(QString, int, QMap<QString, QVariant>); |
579 | void printerLoaded(QSharedPointer<Printer> printers); |
580 | + void deviceFound(const Device &device); |
581 | + void deviceSearchFinished(); |
582 | |
583 | void jobCompleted( |
584 | const QString &text, |
585 | |
586 | === modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp' |
587 | --- modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp 2017-02-24 12:53:34 +0000 |
588 | +++ modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp 2017-03-20 13:32:24 +0000 |
589 | @@ -15,6 +15,8 @@ |
590 | */ |
591 | |
592 | #include "backend/backend_cups.h" |
593 | +#include "cups/devicesearcher.h" |
594 | +#include "cups/jobloader.h" |
595 | #include "cups/printerdriverloader.h" |
596 | #include "cups/printerloader.h" |
597 | #include "utils.h" |
598 | @@ -40,6 +42,10 @@ |
599 | , m_knownQualityOptions({ |
600 | "Quality", "PrintQuality", "HPPrintQuality", "StpQuality", |
601 | "OutputMode",}) |
602 | + , m_extendedAttributeNames({ |
603 | + QStringLiteral("StateMessage"), QStringLiteral("DeviceUri"), |
604 | + QStringLiteral("IsShared"), QStringLiteral("Copies"), |
605 | + }) |
606 | , m_client(client) |
607 | , m_info(info) |
608 | , m_notifier(notifier) |
609 | @@ -178,6 +184,24 @@ |
610 | return QString(); |
611 | } |
612 | |
613 | +QString PrinterCupsBackend::printerSetCopies(const QString &name, |
614 | + const int &copies) |
615 | +{ |
616 | + if (!m_client->printerSetCopies(name, copies)) { |
617 | + return m_client->getLastError(); |
618 | + } |
619 | + return QString(); |
620 | +} |
621 | + |
622 | +QString PrinterCupsBackend::printerSetShared(const QString &name, |
623 | + const bool shared) |
624 | +{ |
625 | + if (!m_client->printerSetShared(name, shared)) { |
626 | + return m_client->getLastError(); |
627 | + } |
628 | + return QString(); |
629 | +} |
630 | + |
631 | QString PrinterCupsBackend::printerSetInfo(const QString &name, |
632 | const QString &info) |
633 | { |
634 | @@ -213,12 +237,27 @@ |
635 | cups_dest_t *dest = getDest(name); |
636 | ppd_file_t* ppd = getPpd(name); |
637 | |
638 | - if (!dest || !ppd) { |
639 | - return ret; |
640 | + // Used to store extended attributes, which we should request maximum once. |
641 | + QMap<QString, QVariant> extendedAttributesResults; |
642 | + |
643 | + /* Goes through known extended attributes. If one is being asked for, |
644 | + ask for all of them right away. */ |
645 | + Q_FOREACH(const QString &extendedOption, m_extendedAttributeNames) { |
646 | + if (options.contains(extendedOption)) { |
647 | + extendedAttributesResults = m_client->printerGetAttributes( |
648 | + name, QStringList({ |
649 | + QStringLiteral("device-uri"), |
650 | + QStringLiteral("printer-uri-supported"), |
651 | + QStringLiteral("printer-state-message"), |
652 | + QStringLiteral("copies-default"), |
653 | + }) |
654 | + ); |
655 | + break; |
656 | + } |
657 | } |
658 | |
659 | Q_FOREACH(const QString &option, options) { |
660 | - if (option == QStringLiteral("DefaultColorModel")) { |
661 | + if (option == QStringLiteral("DefaultColorModel") && ppd) { |
662 | ColorModel model; |
663 | ppd_option_t *ppdColorModel = ppdFindOption(ppd, "ColorModel"); |
664 | if (ppdColorModel) { |
665 | @@ -231,7 +270,7 @@ |
666 | } |
667 | } |
668 | ret[option] = QVariant::fromValue(model); |
669 | - } else if (option == QStringLiteral("DefaultPrintQuality")) { |
670 | + } else if (option == QStringLiteral("DefaultPrintQuality") && ppd) { |
671 | PrintQuality quality; |
672 | Q_FOREACH(const QString opt, m_knownQualityOptions) { |
673 | ppd_option_t *ppdQuality = ppdFindOption(ppd, opt.toUtf8()); |
674 | @@ -245,7 +284,7 @@ |
675 | } |
676 | } |
677 | ret[option] = QVariant::fromValue(quality); |
678 | - } else if (option == QStringLiteral("SupportedPrintQualities")) { |
679 | + } else if (option == QStringLiteral("SupportedPrintQualities") && ppd) { |
680 | QList<PrintQuality> qualities; |
681 | Q_FOREACH(const QString &opt, m_knownQualityOptions) { |
682 | ppd_option_t *qualityOpt = ppdFindOption(ppd, opt.toUtf8()); |
683 | @@ -262,7 +301,7 @@ |
684 | } |
685 | } |
686 | ret[option] = QVariant::fromValue(qualities); |
687 | - } else if (option == QStringLiteral("SupportedColorModels")) { |
688 | + } else if (option == QStringLiteral("SupportedColorModels") && ppd) { |
689 | QList<ColorModel> models; |
690 | ppd_option_t *colorModels = ppdFindOption(ppd, "ColorModel"); |
691 | if (colorModels) { |
692 | @@ -277,19 +316,29 @@ |
693 | } |
694 | } |
695 | ret[option] = QVariant::fromValue(models); |
696 | - } else if (option == QStringLiteral("AcceptJobs")) { |
697 | + } else if (option == QStringLiteral("AcceptJobs") && dest) { |
698 | // "true" if the destination is accepting new jobs, "false" if not. |
699 | QString res = cupsGetOption("printer-is-accepting-jobs", |
700 | dest->num_options, dest->options); |
701 | ret[option] = res.contains("true"); |
702 | - } else { |
703 | - ppd_option_t *val = ppdFindOption(ppd, option.toUtf8()); |
704 | - |
705 | - if (val) { |
706 | - qWarning() << "asking for" << option << "returns" << val->text; |
707 | - } else { |
708 | - qWarning() << "option" << option << "yielded no option"; |
709 | - } |
710 | + } else if (option == QStringLiteral("StateReasons") && dest) { |
711 | + ret[option] = cupsGetOption("printer-state-reasons", |
712 | + dest->num_options, dest->options); |
713 | + } else if (option == QStringLiteral("StateMessage")) { |
714 | + ret[option] = extendedAttributesResults["printer-state-message"]; |
715 | + } else if (option == QStringLiteral("DeviceUri")) { |
716 | + auto res = extendedAttributesResults; |
717 | + if (!res["printer-uri-supported"].toString().isEmpty()) { |
718 | + ret[option] = res["printer-uri-supported"]; |
719 | + } |
720 | + if (!res["device-uri"].toString().isEmpty()) { |
721 | + ret[option] = res["device-uri"]; |
722 | + } |
723 | + } else if (option == QStringLiteral("Copies")) { |
724 | + ret[option] = extendedAttributesResults[QStringLiteral("copies-default")]; |
725 | + } else if (option == QStringLiteral("Shared") && dest) { |
726 | + ret[option] = cupsGetOption("printer-is-shared", |
727 | + dest->num_options, dest->options); |
728 | } |
729 | } |
730 | return ret; |
731 | @@ -306,10 +355,7 @@ |
732 | __CUPS_ADD_OPTION(dest, "Collate", "False"); |
733 | } |
734 | |
735 | - if (options->copies() > 1) { |
736 | - __CUPS_ADD_OPTION(dest, "copies", QString::number(options->copies()).toLocal8Bit()); |
737 | - } |
738 | - |
739 | + __CUPS_ADD_OPTION(dest, "copies", QString::number(options->copies()).toLocal8Bit()); |
740 | __CUPS_ADD_OPTION(dest, "ColorModel", options->getColorModel().name.toLocal8Bit()); |
741 | __CUPS_ADD_OPTION(dest, "Duplex", Utils::duplexModeToPpdChoice(options->getDuplexMode()).toLocal8Bit()); |
742 | |
743 | @@ -347,6 +393,20 @@ |
744 | } |
745 | } |
746 | |
747 | +void PrinterCupsBackend::holdJob(const QString &name, const int jobId) |
748 | +{ |
749 | + if (!m_client->printerHoldJob(name, jobId)) { |
750 | + qWarning() << "Failed to hold job:" << jobId << "for" << name; |
751 | + } |
752 | +} |
753 | + |
754 | +void PrinterCupsBackend::releaseJob(const QString &name, const int jobId) |
755 | +{ |
756 | + if (!m_client->printerReleaseJob(name, jobId)) { |
757 | + qWarning() << "Failed to release job:" << jobId << "for" << name; |
758 | + } |
759 | +} |
760 | + |
761 | int PrinterCupsBackend::printFileToDest(const QString &filepath, |
762 | const QString &title, |
763 | const cups_dest_t *dest) |
764 | @@ -385,7 +445,7 @@ |
765 | const QString &name, const int jobId) |
766 | { |
767 | Q_UNUSED(name); |
768 | - QMap<QString, QVariant> rawMap = m_client->printerGetJobAttributes(jobId); |
769 | + QMap<QString, QVariant> rawMap = m_client->printerGetJobAttributes(name, jobId); |
770 | QMap<QString, QVariant> map; |
771 | |
772 | // Filter attributes to know values |
773 | @@ -409,12 +469,34 @@ |
774 | map.insert("ColorModel", QVariant("")); |
775 | } |
776 | |
777 | + if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-completed", QDateTime)) { |
778 | + map.insert("CompletedTime", rawMap.value("date-time-at-completed")); |
779 | + } else { |
780 | + map.insert("CompletedTime", QVariant(QDateTime())); |
781 | + } |
782 | + |
783 | + if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-creation", QDateTime)) { |
784 | + map.insert("CreationTime", rawMap.value("date-time-at-creation")); |
785 | + } else { |
786 | + map.insert("CreationTime", QVariant(QDateTime())); |
787 | + } |
788 | + |
789 | if (__CUPS_ATTR_EXISTS(rawMap, "Duplex", QString)) { |
790 | map.insert("Duplex", rawMap.value("Duplex")); |
791 | } else { |
792 | map.insert("Duplex", QVariant("")); |
793 | } |
794 | |
795 | + // Try job-media-sheets-completed first as it should include duplex |
796 | + // if it doesn't exist fallback to job-impressions-completed |
797 | + if (__CUPS_ATTR_EXISTS(rawMap, "job-media-sheets-completed", int)) { |
798 | + map.insert("impressionsCompleted", rawMap.value("job-media-sheets-completed")); |
799 | + } else if (__CUPS_ATTR_EXISTS(rawMap, "job-impressions-completed", int)) { |
800 | + map.insert("impressionsCompleted", rawMap.value("job-impressions-completed")); |
801 | + } else { |
802 | + map.insert("impressionsCompleted", QVariant(0)); |
803 | + } |
804 | + |
805 | if (__CUPS_ATTR_EXISTS(rawMap, "landscape", bool)) { |
806 | map.insert("landscape", rawMap.value("landscape")); |
807 | } else { |
808 | @@ -434,6 +516,12 @@ |
809 | map.insert("page-ranges", QVariant(QStringList())); |
810 | } |
811 | |
812 | + if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-processing", QDateTime)) { |
813 | + map.insert("ProcessingTime", rawMap.value("date-time-at-processing")); |
814 | + } else { |
815 | + map.insert("ProcessingTime", QVariant(QDateTime())); |
816 | + } |
817 | + |
818 | Q_FOREACH(QString qualityOption, m_knownQualityOptions) { |
819 | if (rawMap.contains(qualityOption) |
820 | && rawMap.value(qualityOption).canConvert<QString>()) { |
821 | @@ -451,6 +539,24 @@ |
822 | map.insert("OutputOrder", "Normal"); |
823 | } |
824 | |
825 | + if (__CUPS_ATTR_EXISTS(rawMap, "job-k-octets", int)) { |
826 | + map.insert("Size", rawMap.value("job-k-octets")); |
827 | + } else { |
828 | + map.insert("Size", QVariant(0)); |
829 | + } |
830 | + |
831 | + // If there is a state then get it, as there could have been a signal |
832 | + // flood. Which then means a forceJobRefresh is able to update the state |
833 | + if (__CUPS_ATTR_EXISTS(rawMap, "job-state", int)) { |
834 | + map.insert("State", rawMap.value("job-state").toInt()); |
835 | + } |
836 | + |
837 | + if (__CUPS_ATTR_EXISTS(rawMap, "job-originating-user-name", QString)) { |
838 | + map.insert("User", rawMap.value("job-originating-user-name")); |
839 | + } else { |
840 | + map.insert("User", QVariant("")); |
841 | + } |
842 | + |
843 | // Generate a list of messages |
844 | // TODO: for now just using job-printer-state-message, are there others? |
845 | QStringList messages; |
846 | @@ -471,31 +577,13 @@ |
847 | QList<QSharedPointer<PrinterJob>> list; |
848 | |
849 | Q_FOREACH(auto job, jobs) { |
850 | + // Note: extended attributes are not loaded here |
851 | + // they are loaded in JobLoader |
852 | auto newJob = QSharedPointer<PrinterJob>( |
853 | new PrinterJob(QString::fromUtf8(job->dest), this, job->id) |
854 | ); |
855 | - |
856 | - // Extract the times |
857 | - QDateTime completedTime; |
858 | - completedTime.setTimeZone(QTimeZone::systemTimeZone()); |
859 | - completedTime.setTime_t(job->completed_time); |
860 | - |
861 | - QDateTime creationTime; |
862 | - creationTime.setTimeZone(QTimeZone::systemTimeZone()); |
863 | - creationTime.setTime_t(job->creation_time); |
864 | - |
865 | - QDateTime processingTime; |
866 | - processingTime.setTimeZone(QTimeZone::systemTimeZone()); |
867 | - processingTime.setTime_t(job->processing_time); |
868 | - |
869 | - // Load the information from the cups struct |
870 | - newJob->setCompletedTime(completedTime); |
871 | - newJob->setCreationTime(creationTime); |
872 | - newJob->setProcessingTime(processingTime); |
873 | - newJob->setSize(job->size); |
874 | newJob->setState(static_cast<PrinterEnum::JobState>(job->state)); |
875 | newJob->setTitle(QString::fromLocal8Bit(job->title)); |
876 | - newJob->setUser(QString::fromLocal8Bit(job->user)); |
877 | |
878 | list.append(newJob); |
879 | } |
880 | @@ -505,6 +593,35 @@ |
881 | return list; |
882 | } |
883 | |
884 | +QSharedPointer<PrinterJob> PrinterCupsBackend::printerGetJob( |
885 | + const QString &printerName, const int jobId) |
886 | +{ |
887 | + auto jobs = getCupsJobs(printerName); |
888 | + cups_job_t *cupsJob = Q_NULLPTR; |
889 | + QSharedPointer<PrinterJob> job(Q_NULLPTR); |
890 | + |
891 | + for (int i=0; i < jobs.size(); i++) { |
892 | + if (jobs.at(i)->id == jobId) { |
893 | + cupsJob = jobs.at(i); |
894 | + break; |
895 | + } |
896 | + } |
897 | + |
898 | + if (cupsJob) { |
899 | + job = QSharedPointer<PrinterJob>( |
900 | + new PrinterJob(QString::fromUtf8(cupsJob->dest), this, cupsJob->id) |
901 | + ); |
902 | + |
903 | + job->setState(static_cast<PrinterEnum::JobState>(cupsJob->state)); |
904 | + job->setTitle(QString::fromLocal8Bit(cupsJob->title)); |
905 | + } |
906 | + |
907 | + if (!jobs.size()) |
908 | + cupsFreeJobs(jobs.size(), jobs.first()); |
909 | + |
910 | + return job; |
911 | +} |
912 | + |
913 | QString PrinterCupsBackend::printerName() const |
914 | { |
915 | return m_printerName; |
916 | @@ -525,6 +642,11 @@ |
917 | return m_info.makeAndModel(); |
918 | } |
919 | |
920 | +bool PrinterCupsBackend::isRemote() const |
921 | +{ |
922 | + return m_info.isRemote(); |
923 | +} |
924 | + |
925 | PrinterEnum::State PrinterCupsBackend::state() const |
926 | { |
927 | switch (m_info.state()) { |
928 | @@ -611,9 +733,35 @@ |
929 | return QPrinterInfo::defaultPrinterName(); |
930 | } |
931 | |
932 | +void PrinterCupsBackend::requestJobExtendedAttributes( |
933 | + QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job) |
934 | +{ |
935 | + QPair<QString, int> pair(printer->name(), job->jobId()); |
936 | + |
937 | + if (m_activeJobRequests.contains(pair)) { |
938 | + return; |
939 | + } |
940 | + |
941 | + auto thread = new QThread; |
942 | + auto loader = new JobLoader(this, printer->name(), job->jobId()); |
943 | + loader->moveToThread(thread); |
944 | + connect(thread, SIGNAL(started()), loader, SLOT(load())); |
945 | + connect(loader, SIGNAL(finished()), thread, SLOT(quit())); |
946 | + connect(loader, SIGNAL(finished()), loader, SLOT(deleteLater())); |
947 | + connect(loader, SIGNAL(loaded(QString, int, QMap<QString, QVariant>)), |
948 | + this, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>))); |
949 | + connect(loader, SIGNAL(loaded(QString, int, QMap<QString, QVariant>)), |
950 | + this, SLOT(onJobLoaded(QString, int, QMap<QString, QVariant>))); |
951 | + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); |
952 | + |
953 | + m_activeJobRequests << pair; |
954 | + |
955 | + thread->start(); |
956 | +} |
957 | + |
958 | void PrinterCupsBackend::requestPrinter(const QString &printerName) |
959 | { |
960 | - if (m_activeRequests.contains(printerName)) { |
961 | + if (m_activePrinterRequests.contains(printerName)) { |
962 | return; |
963 | } |
964 | |
965 | @@ -628,9 +776,10 @@ |
966 | connect(loader, SIGNAL(loaded(QSharedPointer<Printer>)), |
967 | this, SLOT(onPrinterLoaded(QSharedPointer<Printer>))); |
968 | connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); |
969 | + |
970 | + m_activePrinterRequests << printerName; |
971 | + |
972 | thread->start(); |
973 | - |
974 | - m_activeRequests << printerName; |
975 | } |
976 | |
977 | void PrinterCupsBackend::requestPrinterDrivers() |
978 | @@ -647,6 +796,7 @@ |
979 | connect(loader, SIGNAL(loaded(const QList<PrinterDriver>&)), |
980 | this, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&))); |
981 | connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); |
982 | + |
983 | thread->start(); |
984 | } |
985 | |
986 | @@ -655,6 +805,22 @@ |
987 | Q_EMIT requestPrinterDriverCancel(); |
988 | } |
989 | |
990 | +void PrinterCupsBackend::searchForDevices() |
991 | +{ |
992 | + |
993 | + auto thread = new QThread; |
994 | + auto searcher = new DeviceSearcher(); |
995 | + searcher->moveToThread(thread); |
996 | + connect(thread, SIGNAL(started()), searcher, SLOT(load())); |
997 | + connect(searcher, SIGNAL(finished()), thread, SLOT(quit())); |
998 | + connect(searcher, SIGNAL(finished()), searcher, SLOT(deleteLater())); |
999 | + connect(searcher, SIGNAL(finished()), this, SIGNAL(deviceSearchFinished())); |
1000 | + connect(searcher, SIGNAL(loaded(const Device&)), |
1001 | + this, SIGNAL(deviceFound(const Device&))); |
1002 | + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); |
1003 | + thread->start(); |
1004 | +} |
1005 | + |
1006 | void PrinterCupsBackend::refresh() |
1007 | { |
1008 | if (m_printerName.isEmpty()) { |
1009 | @@ -716,7 +882,22 @@ |
1010 | } |
1011 | } |
1012 | |
1013 | +bool PrinterCupsBackend::isExtendedAttribute(const QString &attributeName) const |
1014 | +{ |
1015 | + return m_extendedAttributeNames.contains(attributeName); |
1016 | +} |
1017 | + |
1018 | +void PrinterCupsBackend::onJobLoaded(QString printerName, int jobId, |
1019 | + QMap<QString, QVariant> attributes) |
1020 | +{ |
1021 | + Q_UNUSED(attributes); |
1022 | + |
1023 | + QPair<QString, int> pair(printerName, jobId); |
1024 | + m_activeJobRequests.remove(pair); |
1025 | +} |
1026 | + |
1027 | void PrinterCupsBackend::onPrinterLoaded(QSharedPointer<Printer> printer) |
1028 | { |
1029 | - m_activeRequests.remove(printer->name()); |
1030 | + m_activePrinterRequests.remove(printer->name()); |
1031 | } |
1032 | + |
1033 | |
1034 | === modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h' |
1035 | --- modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h 2017-02-24 12:53:34 +0000 |
1036 | +++ modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h 2017-03-20 13:32:24 +0000 |
1037 | @@ -55,6 +55,10 @@ |
1038 | const QString &name, |
1039 | const bool accept, |
1040 | const QString &reason = QString::null) override; |
1041 | + virtual QString printerSetCopies( |
1042 | + const QString &name, const int &copies) override; |
1043 | + virtual QString printerSetShared(const QString &name, |
1044 | + const bool shared) override; |
1045 | virtual QString printerSetInfo(const QString &name, |
1046 | const QString &info) override; |
1047 | virtual QString printerAddOption(const QString &name, |
1048 | @@ -71,15 +75,20 @@ |
1049 | const PrinterJob *options) override; |
1050 | |
1051 | virtual void cancelJob(const QString &name, const int jobId) override; |
1052 | + virtual void holdJob(const QString &name, const int jobId) override; |
1053 | + virtual void releaseJob(const QString &name, const int jobId) override; |
1054 | virtual int printFileToDest(const QString &filepath, |
1055 | const QString &title, |
1056 | const cups_dest_t *dest) override; |
1057 | virtual QList<QSharedPointer<PrinterJob>> printerGetJobs() override; |
1058 | + virtual QSharedPointer<PrinterJob> printerGetJob( |
1059 | + const QString &printerName, const int jobId) override; |
1060 | |
1061 | virtual QString printerName() const override; |
1062 | virtual QString description() const override; |
1063 | virtual QString location() const override; |
1064 | virtual QString makeAndModel() const override; |
1065 | + virtual bool isRemote() const override; |
1066 | |
1067 | virtual PrinterEnum::State state() const override; |
1068 | virtual QList<QPageSize> supportedPageSizes() const override; |
1069 | @@ -96,6 +105,10 @@ |
1070 | virtual QStringList availablePrinterNames() override; |
1071 | virtual QSharedPointer<Printer> getPrinter(const QString &printerName) override; |
1072 | virtual QString defaultPrinterName() override; |
1073 | + |
1074 | + virtual void requestJobExtendedAttributes( |
1075 | + QSharedPointer<Printer> printer, |
1076 | + QSharedPointer<PrinterJob> job) override; |
1077 | virtual void requestPrinterDrivers() override; |
1078 | virtual void requestPrinter(const QString &printerName) override; |
1079 | virtual QMap<QString, QVariant> printerGetJobAttributes( |
1080 | @@ -105,6 +118,11 @@ |
1081 | virtual void refresh() override; |
1082 | void createSubscription(); |
1083 | |
1084 | + /* Starts a search for devices. Devices are synonymous with network devices |
1085 | + that may potentially be queues. This search will take at minimum 5 seconds, |
1086 | + normally longer. */ |
1087 | + void searchForDevices(); |
1088 | + |
1089 | Q_SIGNALS: |
1090 | void cancelWorkers(); |
1091 | void printerDriversLoaded(const QList<PrinterDriver> &drivers); |
1092 | @@ -120,16 +138,22 @@ |
1093 | QString getPrinterInstance(const QString &name) const; |
1094 | cups_dest_t* getDest(const QString &name) const; |
1095 | ppd_file_t* getPpd(const QString &name) const; |
1096 | + bool isExtendedAttribute(const QString &attributeName) const; |
1097 | + |
1098 | const QStringList m_knownQualityOptions; |
1099 | + const QStringList m_extendedAttributeNames; |
1100 | IppClient *m_client; |
1101 | QPrinterInfo m_info; |
1102 | OrgCupsCupsdNotifierInterface *m_notifier; |
1103 | int m_cupsSubscriptionId; |
1104 | mutable QMap<QString, cups_dest_t*> m_dests; // Printer name, dest. |
1105 | mutable QMap<QString, ppd_file_t*> m_ppds; // Printer name, ppd. |
1106 | - QSet<QString> m_activeRequests; |
1107 | + QSet<QString> m_activePrinterRequests; |
1108 | + QSet<QPair<QString, int>> m_activeJobRequests; |
1109 | |
1110 | private Q_SLOTS: |
1111 | + void onJobLoaded(QString printerName, int jobId, |
1112 | + QMap<QString, QVariant> attributes); |
1113 | void onPrinterLoaded(QSharedPointer<Printer> printer); |
1114 | }; |
1115 | |
1116 | |
1117 | === modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp' |
1118 | --- modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp 2017-02-21 10:46:29 +0000 |
1119 | +++ modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp 2017-03-20 13:32:24 +0000 |
1120 | @@ -59,6 +59,16 @@ |
1121 | ret[option] = QVariant::fromValue(models); |
1122 | } else if (option == QLatin1String("AcceptJobs")) { |
1123 | ret[option] = true; |
1124 | + } else if (option == QLatin1String("StateReasons")) { |
1125 | + ret[option] = QLatin1String(""); |
1126 | + } else if (option == QLatin1String("StateMessage")) { |
1127 | + ret[option] = QLatin1String(""); |
1128 | + } else if (option == QLatin1String("DeviceUri")) { |
1129 | + ret[option] = QLatin1String(""); |
1130 | + } else if (option == QLatin1String("Copies")) { |
1131 | + ret[option] = 0; |
1132 | + } else if (option == QLatin1String("Shared")) { |
1133 | + ret[option] = false; |
1134 | } else { |
1135 | throw std::invalid_argument("Invalid value for PDF printer: " + option.toStdString()); |
1136 | } |
1137 | |
1138 | === added file 'modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp' |
1139 | --- modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp 1970-01-01 00:00:00 +0000 |
1140 | +++ modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp 2017-03-20 13:32:24 +0000 |
1141 | @@ -0,0 +1,70 @@ |
1142 | +/* |
1143 | + * Copyright (C) 2017 Canonical, Ltd. |
1144 | + * |
1145 | + * This program is free software; you can redistribute it and/or modify |
1146 | + * it under the terms of the GNU Lesser General Public License as published by |
1147 | + * the Free Software Foundation; version 3. |
1148 | + * |
1149 | + * This program is distributed in the hope that it will be useful, |
1150 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1151 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1152 | + * GNU Lesser General Public License for more details. |
1153 | + * |
1154 | + * You should have received a copy of the GNU Lesser General Public License |
1155 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1156 | + */ |
1157 | + |
1158 | +#include "cups/ippclient.h" |
1159 | +#include "devicesearcher.h" |
1160 | + |
1161 | +#include <QUrl> |
1162 | + |
1163 | +DeviceSearcher::DeviceSearcher(IppClient *client, QObject *parent) |
1164 | + : QObject(parent) |
1165 | + , m_client(client) |
1166 | +{ |
1167 | +} |
1168 | + |
1169 | +DeviceSearcher::~DeviceSearcher() |
1170 | +{ |
1171 | + delete m_client; |
1172 | +} |
1173 | + |
1174 | +void DeviceSearcher::load() |
1175 | +{ |
1176 | + if (!m_client->getDevices(&DeviceSearcher::deviceCallBack, this)) { |
1177 | + Q_EMIT failed(cupsLastErrorString()); |
1178 | + } |
1179 | + Q_EMIT finished(); |
1180 | +} |
1181 | + |
1182 | +void DeviceSearcher::deviceCallBack( |
1183 | + const char *deviceClass, |
1184 | + const char *deviceId, |
1185 | + const char *deviceInfo, |
1186 | + const char *deviceMakeAndModel, |
1187 | + const char *deviceUri, |
1188 | + const char *deviceLocation, |
1189 | + void *context) |
1190 | +{ |
1191 | + auto searcher = qobject_cast<DeviceSearcher*>(static_cast<QObject*>(context)); |
1192 | + if (!searcher) { |
1193 | + qWarning() << Q_FUNC_INFO << "context was not a DeviceSearcher."; |
1194 | + return; |
1195 | + } |
1196 | + |
1197 | + Device d; |
1198 | + d.cls = deviceClass; |
1199 | + d.id = deviceId; |
1200 | + d.info = deviceInfo; |
1201 | + d.makeModel = deviceMakeAndModel; |
1202 | + d.uri = deviceUri; |
1203 | + d.location = deviceLocation; |
1204 | + |
1205 | + searcher->deviceFound(d); |
1206 | +} |
1207 | + |
1208 | +void DeviceSearcher::deviceFound(const Device &device) |
1209 | +{ |
1210 | + Q_EMIT loaded(device); |
1211 | +} |
1212 | |
1213 | === added file 'modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h' |
1214 | --- modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h 1970-01-01 00:00:00 +0000 |
1215 | +++ modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h 2017-03-20 13:32:24 +0000 |
1216 | @@ -0,0 +1,57 @@ |
1217 | +/* |
1218 | + * Copyright (C) 2017 Canonical, Ltd. |
1219 | + * |
1220 | + * This program is free software; you can redistribute it and/or modify |
1221 | + * it under the terms of the GNU Lesser General Public License as published by |
1222 | + * the Free Software Foundation; version 3. |
1223 | + * |
1224 | + * This program is distributed in the hope that it will be useful, |
1225 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1226 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1227 | + * GNU Lesser General Public License for more details. |
1228 | + * |
1229 | + * You should have received a copy of the GNU Lesser General Public License |
1230 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1231 | + */ |
1232 | + |
1233 | +#ifndef USC_PRINTERS_CUPS_DEVICESEARCHER_H |
1234 | +#define USC_PRINTERS_CUPS_DEVICESEARCHER_H |
1235 | + |
1236 | +#include "cups/ippclient.h" |
1237 | +#include "structs.h" |
1238 | + |
1239 | +#include <QObject> |
1240 | +#include <QString> |
1241 | + |
1242 | +/* Class representing a device search. It is a worker object due to the time |
1243 | +such a search takes (minimum 10 seconds). */ |
1244 | +class DeviceSearcher : public QObject |
1245 | +{ |
1246 | + Q_OBJECT |
1247 | + IppClient *m_client; |
1248 | +public: |
1249 | + explicit DeviceSearcher(IppClient *client = new IppClient, |
1250 | + QObject *parent = Q_NULLPTR); |
1251 | + ~DeviceSearcher(); |
1252 | + |
1253 | +public Q_SLOTS: |
1254 | + void load(); |
1255 | + |
1256 | +private: |
1257 | + static void deviceCallBack( |
1258 | + const char *cls, |
1259 | + const char *id, |
1260 | + const char *info, |
1261 | + const char *makeAndModel, |
1262 | + const char *uri, |
1263 | + const char *location, |
1264 | + void *context); |
1265 | + void deviceFound(const Device &device); |
1266 | + |
1267 | +Q_SIGNALS: |
1268 | + void loaded(const Device &device); |
1269 | + void failed(const QString &errorMessage); |
1270 | + void finished(); |
1271 | +}; |
1272 | + |
1273 | +#endif // USC_PRINTERS_CUPS_DEVICESEARCHER_H |
1274 | |
1275 | === modified file 'modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp' |
1276 | --- modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp 2017-02-21 10:46:29 +0000 |
1277 | +++ modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp 2017-03-20 13:32:24 +0000 |
1278 | @@ -25,6 +25,7 @@ |
1279 | |
1280 | #include <QDebug> |
1281 | #include <QDateTime> |
1282 | +#include <QtAlgorithms> |
1283 | #include <QTimeZone> |
1284 | #include <QUrl> |
1285 | |
1286 | @@ -173,6 +174,30 @@ |
1287 | return postRequest(request, ppdFileName.toUtf8(), CupsResourceAdmin); |
1288 | } |
1289 | |
1290 | +bool IppClient::printerHoldJob(const QString &printerName, const int jobId) |
1291 | +{ |
1292 | + ipp_t *request = ippNewRequest(IPP_HOLD_JOB); |
1293 | + addPrinterUri(request, printerName); |
1294 | + addRequestingUsername(request, NULL); |
1295 | + |
1296 | + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, |
1297 | + "job-id", jobId); |
1298 | + |
1299 | + return sendRequest(request, CupsResourceJobs); |
1300 | +} |
1301 | + |
1302 | +bool IppClient::printerReleaseJob(const QString &printerName, const int jobId) |
1303 | +{ |
1304 | + ipp_t *request = ippNewRequest(IPP_RELEASE_JOB); |
1305 | + addPrinterUri(request, printerName); |
1306 | + addRequestingUsername(request, NULL); |
1307 | + |
1308 | + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, |
1309 | + "job-id", jobId); |
1310 | + |
1311 | + return sendRequest(request, CupsResourceJobs); |
1312 | +} |
1313 | + |
1314 | bool IppClient::printerSetDefault(const QString &printerName) |
1315 | { |
1316 | return sendNewSimpleRequest(CUPS_SET_DEFAULT, printerName.toUtf8(), |
1317 | @@ -225,9 +250,46 @@ |
1318 | } |
1319 | } |
1320 | |
1321 | +bool IppClient::printerSetCopies(const QString &printerName, const int &copies) |
1322 | +{ |
1323 | + ipp_t *request; |
1324 | + |
1325 | + if (!isPrinterNameValid(printerName)) { |
1326 | + setInternalStatus(QString("%1 is not a valid printer name.").arg(printerName)); |
1327 | + return false; |
1328 | + } |
1329 | + request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); |
1330 | + addPrinterUri(request, printerName); |
1331 | + addRequestingUsername(request, NULL); |
1332 | + ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_INTEGER, |
1333 | + "copies-default", copies); |
1334 | + /* TODO: The request will fail if this was a printer class, and it should |
1335 | + be retried. */ |
1336 | + return sendRequest(request, CupsResourceAdmin); |
1337 | +} |
1338 | + |
1339 | +bool IppClient::printerSetShared(const QString &printerName, const bool shared) |
1340 | +{ |
1341 | + ipp_t *request; |
1342 | + |
1343 | + if (!isPrinterNameValid(printerName)) { |
1344 | + setInternalStatus(QString("%1 is not a valid printer name.").arg(printerName)); |
1345 | + return false; |
1346 | + } |
1347 | + |
1348 | + request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); |
1349 | + addPrinterUri(request, printerName); |
1350 | + addRequestingUsername(request, NULL); |
1351 | + ippAddBoolean(request, IPP_TAG_OPERATION, |
1352 | + "printer-is-shared", shared ? 1 : 0); |
1353 | + /* TODO: The request will fail if this was a printer class, and it should |
1354 | + be retried. */ |
1355 | + |
1356 | + return sendRequest(request, CupsResourceAdmin); |
1357 | +} |
1358 | |
1359 | bool IppClient::printerClassSetInfo(const QString &name, |
1360 | - const QString &info) |
1361 | + const QString &info) |
1362 | { |
1363 | if (!isPrinterNameValid(name)) { |
1364 | setInternalStatus(QString("%1 is not a valid printer name.").arg(name)); |
1365 | @@ -336,18 +398,99 @@ |
1366 | return retval; |
1367 | } |
1368 | |
1369 | -QMap<QString, QVariant> IppClient::printerGetJobAttributes(const int jobId) |
1370 | +QMap<QString, QVariant> IppClient::printerGetAttributes( |
1371 | + const QString &printerName, const QStringList &attributes) |
1372 | +{ |
1373 | + QMap<QString, QVariant> result; |
1374 | + QList<QByteArray*> attrByteArrays; |
1375 | + ipp_t *request; |
1376 | + ipp_attribute_t *attr; |
1377 | + |
1378 | + if (attributes.isEmpty()) { |
1379 | + return result; |
1380 | + } |
1381 | + |
1382 | + int i; |
1383 | + size_t n = attributes.size(); |
1384 | + char **attrs; |
1385 | + attrs = (char**) malloc ((n + 1) * sizeof (char *)); |
1386 | + |
1387 | + /* This is some trickery to compensate for a lack of C array/pointer |
1388 | + skills. The VLA attrs gets the underlying data structure of a QByterArray |
1389 | + on the heap. When cups is done with it, and in the end of this method, |
1390 | + the QByteArrays are deleted, and attrs is freed. */ |
1391 | + for (i = 0; i < ((int) n); i++) { |
1392 | + QByteArray *array = new QByteArray(attributes.value(i).toLocal8Bit()); |
1393 | + attrByteArrays << array; |
1394 | + attrs[i] = array->data(); |
1395 | + } |
1396 | + attrs[n] = NULL; |
1397 | + |
1398 | + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); |
1399 | + addPrinterUri(request, printerName); |
1400 | + addRequestingUsername(request, QString()); |
1401 | + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
1402 | + "requested-attributes", attributes.size(), NULL, attrs); |
1403 | + auto resource = getResource(CupsResource::CupsResourceRoot); |
1404 | + |
1405 | + ipp_t *reply; |
1406 | + reply = cupsDoRequest(m_connection, request, resource.toUtf8()); |
1407 | + |
1408 | + if (!isReplyOk(reply, false)) { |
1409 | + qWarning() << Q_FUNC_INFO << "failed to get attributes" |
1410 | + << attributes << "for printer" << printerName; |
1411 | + } else { |
1412 | + for (attr = ippFirstAttribute(reply); attr; attr = ippNextAttribute(reply)) { |
1413 | + while (attr && ippGetGroupTag(attr) != IPP_TAG_PRINTER) |
1414 | + attr = ippNextAttribute(reply); |
1415 | + |
1416 | + if (!attr) |
1417 | + break; |
1418 | + |
1419 | + for (; attr && ippGetGroupTag(attr) == IPP_TAG_PRINTER; |
1420 | + attr = ippNextAttribute(reply)) { |
1421 | + |
1422 | + /* TODO: Here we need to take into account that the returned |
1423 | + attributes could be lists and other things. */ |
1424 | + result[ippGetName(attr)] = getAttributeValue(attr); |
1425 | + |
1426 | + if (!attr) |
1427 | + break; |
1428 | + } |
1429 | + } |
1430 | + } |
1431 | + |
1432 | + if (reply) |
1433 | + ippDelete(reply); |
1434 | + |
1435 | + qDeleteAll(attrByteArrays); |
1436 | + free(attrs); |
1437 | + |
1438 | + return result; |
1439 | +} |
1440 | + |
1441 | +QMap<QString, QVariant> IppClient::printerGetJobAttributes(const QString &printerName, |
1442 | + const int jobId) |
1443 | { |
1444 | ipp_t *request; |
1445 | QMap<QString, QVariant> map; |
1446 | |
1447 | + // Try to get the lock, if we can't after 5 seconds then fail and return |
1448 | + if (!m_thread_lock.tryLock(5000)) { |
1449 | + qWarning() << "Unable to get lock for IppClient::printerGetJobAttributes." |
1450 | + << "Unable to load attributes for job:" << jobId << " for " |
1451 | + << printerName; |
1452 | + return map; |
1453 | + } |
1454 | + |
1455 | // Construct request |
1456 | request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES); |
1457 | - QString uri = QStringLiteral("ipp://localhost/jobs/") + QString::number(jobId); |
1458 | - qDebug() << "URI:" << uri; |
1459 | - |
1460 | - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri.toStdString().data()); |
1461 | - |
1462 | + |
1463 | + addPrinterUri(request, printerName); |
1464 | + addRequestingUsername(request, NULL); |
1465 | + |
1466 | + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, |
1467 | + "job-id", jobId); |
1468 | |
1469 | // Send request and construct reply |
1470 | ipp_t *reply; |
1471 | @@ -365,7 +508,8 @@ |
1472 | map.insert(ippGetName(attr), value); |
1473 | } |
1474 | } else { |
1475 | - qWarning() << "Not able to get attributes of job:" << jobId; |
1476 | + qWarning() << "Not able to get attributes of job:" << jobId << " for " |
1477 | + << printerName; |
1478 | } |
1479 | |
1480 | // Destruct the reply if valid |
1481 | @@ -373,6 +517,8 @@ |
1482 | ippDelete(reply); |
1483 | } |
1484 | |
1485 | + m_thread_lock.unlock(); |
1486 | + |
1487 | return map; |
1488 | } |
1489 | |
1490 | @@ -972,8 +1118,8 @@ |
1491 | case IPP_TAG_DATE: { |
1492 | time_t time = ippDateToTime(ippGetDate(attr, index)); |
1493 | QDateTime datetime; |
1494 | - datetime.setTimeZone(QTimeZone::systemTimeZone()); |
1495 | datetime.setTime_t(time); |
1496 | + datetime.setTimeZone(QTimeZone::utc()); |
1497 | |
1498 | var = QVariant::fromValue<QDateTime>(datetime); |
1499 | break; |
1500 | @@ -986,3 +1132,11 @@ |
1501 | |
1502 | return var; |
1503 | } |
1504 | + |
1505 | +bool IppClient::getDevices(cups_device_cb_t callback, void *context) const |
1506 | +{ |
1507 | + auto reply = cupsGetDevices(m_connection, CUPS_TIMEOUT_DEFAULT, |
1508 | + CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE, callback, |
1509 | + context); |
1510 | + return reply == IPP_OK; |
1511 | +} |
1512 | |
1513 | === modified file 'modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h' |
1514 | --- modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h 2017-02-21 10:46:29 +0000 |
1515 | +++ modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h 2017-03-20 13:32:24 +0000 |
1516 | @@ -19,11 +19,13 @@ |
1517 | |
1518 | #include "structs.h" |
1519 | |
1520 | +#include <cups/adminutil.h> |
1521 | #include <cups/cups.h> |
1522 | #include <cups/http.h> |
1523 | #include <cups/ipp.h> |
1524 | #include <cups/ppd.h> |
1525 | |
1526 | +#include <QMutex> |
1527 | #include <QString> |
1528 | #include <QStringList> |
1529 | |
1530 | @@ -51,17 +53,25 @@ |
1531 | const QString &ppdFileName, |
1532 | const QString &info, |
1533 | const QString &location); |
1534 | + bool printerHoldJob(const QString &printerName, const int jobId); |
1535 | + bool printerReleaseJob(const QString &printerName, const int jobId); |
1536 | bool printerSetDefault(const QString &printerName); |
1537 | bool printerSetEnabled(const QString &printerName, const bool enabled); |
1538 | bool printerSetAcceptJobs(const QString &printerName, const bool accept, |
1539 | const QString &reason); |
1540 | + bool printerSetCopies(const QString &printerName, const int &copies); |
1541 | + bool printerSetShared(const QString &printerName, const bool shared); |
1542 | bool printerClassSetInfo(const QString &name, const QString &info); |
1543 | bool printerClassSetOption(const QString &name, const QString &option, |
1544 | const QStringList &values); |
1545 | ppd_file_t* getPpdFile(const QString &name, const QString &instance) const; |
1546 | cups_dest_t* getDest(const QString &name, const QString &instance) const; |
1547 | |
1548 | - QMap<QString, QVariant> printerGetJobAttributes(const int jobId); |
1549 | + // Fetch more attributes, as normally just a small subset is fetched. |
1550 | + QMap<QString, QVariant> printerGetAttributes(const QString &printerName, |
1551 | + const QStringList &attributes); |
1552 | + QMap<QString, QVariant> printerGetJobAttributes(const QString &printerName, |
1553 | + const int jobId); |
1554 | |
1555 | QString getLastError() const; |
1556 | |
1557 | @@ -73,6 +83,7 @@ |
1558 | ); |
1559 | int createSubscription(); |
1560 | void cancelSubscription(const int &subscriptionId); |
1561 | + bool getDevices(cups_device_cb_t callback, void *context) const; |
1562 | |
1563 | private: |
1564 | enum CupsResource |
1565 | @@ -115,6 +126,7 @@ |
1566 | http_t *m_connection; |
1567 | ipp_status_t m_lastStatus = IPP_OK; |
1568 | mutable QString m_internalStatus = QString::null; |
1569 | + QMutex m_thread_lock; |
1570 | }; |
1571 | |
1572 | |
1573 | |
1574 | === added file 'modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp' |
1575 | --- modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp 1970-01-01 00:00:00 +0000 |
1576 | +++ modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp 2017-03-20 13:32:24 +0000 |
1577 | @@ -0,0 +1,50 @@ |
1578 | +/* |
1579 | + * Copyright (C) 2017 Canonical, Ltd. |
1580 | + * |
1581 | + * This program is free software; you can redistribute it and/or modify |
1582 | + * it under the terms of the GNU Lesser General Public License as published by |
1583 | + * the Free Software Foundation; version 3. |
1584 | + * |
1585 | + * This program is distributed in the hope that it will be useful, |
1586 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1587 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1588 | + * GNU Lesser General Public License for more details. |
1589 | + * |
1590 | + * You should have received a copy of the GNU Lesser General Public License |
1591 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1592 | + */ |
1593 | + |
1594 | +#include "jobloader.h" |
1595 | + |
1596 | +#include "backend/backend.h" |
1597 | + |
1598 | +#include "printers/printers.h" |
1599 | + |
1600 | +#include <QDBusConnection> |
1601 | +#include <QPrinterInfo> |
1602 | + |
1603 | +class PrinterCupsBackend; |
1604 | +JobLoader::JobLoader(PrinterBackend *backend, |
1605 | + QString printerName, |
1606 | + int jobId, |
1607 | + QObject *parent) |
1608 | + : QObject(parent) |
1609 | + , m_backend(backend) |
1610 | + , m_job_id(jobId) |
1611 | + , m_printer_name(printerName) |
1612 | +{ |
1613 | +} |
1614 | + |
1615 | +JobLoader::~JobLoader() |
1616 | +{ |
1617 | +} |
1618 | + |
1619 | +void JobLoader::load() |
1620 | +{ |
1621 | + QMap<QString, QVariant> map = m_backend->printerGetJobAttributes( |
1622 | + m_printer_name, m_job_id |
1623 | + ); |
1624 | + |
1625 | + Q_EMIT loaded(m_printer_name, m_job_id, map); |
1626 | + Q_EMIT finished(); |
1627 | +} |
1628 | |
1629 | === added file 'modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h' |
1630 | --- modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h 1970-01-01 00:00:00 +0000 |
1631 | +++ modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h 2017-03-20 13:32:24 +0000 |
1632 | @@ -0,0 +1,47 @@ |
1633 | +/* |
1634 | + * Copyright (C) 2017 Canonical, Ltd. |
1635 | + * |
1636 | + * This program is free software; you can redistribute it and/or modify |
1637 | + * it under the terms of the GNU Lesser General Public License as published by |
1638 | + * the Free Software Foundation; version 3. |
1639 | + * |
1640 | + * This program is distributed in the hope that it will be useful, |
1641 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1642 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1643 | + * GNU Lesser General Public License for more details. |
1644 | + * |
1645 | + * You should have received a copy of the GNU Lesser General Public License |
1646 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1647 | + */ |
1648 | + |
1649 | +#ifndef USC_PRINTERS_CUPS_JOBLOADER_H |
1650 | +#define USC_PRINTERS_CUPS_JOBLOADER_H |
1651 | + |
1652 | +#include "printer/printer.h" |
1653 | +#include "printer/printerjob.h" |
1654 | + |
1655 | +#include <QList> |
1656 | +#include <QObject> |
1657 | +#include <QSharedPointer> |
1658 | + |
1659 | +class JobLoader : public QObject |
1660 | +{ |
1661 | + Q_OBJECT |
1662 | + PrinterBackend *m_backend; |
1663 | + int m_job_id; |
1664 | + QString m_printer_name; |
1665 | +public: |
1666 | + explicit JobLoader(PrinterBackend *backend, |
1667 | + QString printerName, int jobId, |
1668 | + QObject *parent = Q_NULLPTR); |
1669 | + ~JobLoader(); |
1670 | + |
1671 | +public Q_SLOTS: |
1672 | + void load(); |
1673 | + |
1674 | +Q_SIGNALS: |
1675 | + void finished(); |
1676 | + void loaded(QString, int, QMap<QString, QVariant>); |
1677 | +}; |
1678 | + |
1679 | +#endif // USC_PRINTERS_CUPS_JOBLOADER_H |
1680 | |
1681 | === modified file 'modules/Ubuntu/Components/Extras/Printers/cups/printerloader.cpp' |
1682 | --- modules/Ubuntu/Components/Extras/Printers/cups/printerloader.cpp 2017-02-21 10:46:29 +0000 |
1683 | +++ modules/Ubuntu/Components/Extras/Printers/cups/printerloader.cpp 2017-03-20 13:32:24 +0000 |
1684 | @@ -18,6 +18,7 @@ |
1685 | #include "backend/backend_cups.h" |
1686 | #include "printerloader.h" |
1687 | |
1688 | +#include <QApplication> |
1689 | #include <QPrinterInfo> |
1690 | |
1691 | class PrinterCupsBackend; |
1692 | @@ -48,6 +49,8 @@ |
1693 | |
1694 | auto p = QSharedPointer<Printer>(new Printer(backend)); |
1695 | |
1696 | + p->moveToThread(QApplication::instance()->thread()); |
1697 | + |
1698 | Q_EMIT loaded(p); |
1699 | Q_EMIT finished(); |
1700 | } |
1701 | |
1702 | === modified file 'modules/Ubuntu/Components/Extras/Printers/enums.h' |
1703 | --- modules/Ubuntu/Components/Extras/Printers/enums.h 2017-02-23 14:04:26 +0000 |
1704 | +++ modules/Ubuntu/Components/Extras/Printers/enums.h 2017-03-20 13:32:24 +0000 |
1705 | @@ -101,6 +101,29 @@ |
1706 | PdfType, |
1707 | }; |
1708 | Q_ENUM(PrinterType) |
1709 | + |
1710 | + enum class DeviceType |
1711 | + { |
1712 | + UnknownType = 0, |
1713 | + LPDType, |
1714 | + IppSType, |
1715 | + Ipp14Type, |
1716 | + HttpType, |
1717 | + BehType, |
1718 | + SocketType, |
1719 | + HttpsType, |
1720 | + IppType, |
1721 | + HPType, |
1722 | + USBType, |
1723 | + HPFaxType, |
1724 | + DNSSDType, |
1725 | + }; |
1726 | + Q_ENUM(DeviceType) |
1727 | }; |
1728 | |
1729 | +inline uint qHash(const PrinterEnum::JobState &state, uint seed) |
1730 | +{ |
1731 | + return qHash((int) state, seed); |
1732 | +} |
1733 | + |
1734 | #endif // USC_PRINTERS_ENUMS_H |
1735 | |
1736 | === added file 'modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp' |
1737 | --- modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp 1970-01-01 00:00:00 +0000 |
1738 | +++ modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp 2017-03-20 13:32:24 +0000 |
1739 | @@ -0,0 +1,149 @@ |
1740 | +/* |
1741 | + * Copyright (C) 2017 Canonical, Ltd. |
1742 | + * |
1743 | + * This program is free software; you can redistribute it and/or modify |
1744 | + * it under the terms of the GNU Lesser General Public License as published by |
1745 | + * the Free Software Foundation; version 3. |
1746 | + * |
1747 | + * This program is distributed in the hope that it will be useful, |
1748 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1749 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1750 | + * GNU Lesser General Public License for more details. |
1751 | + * |
1752 | + * You should have received a copy of the GNU Lesser General Public License |
1753 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1754 | + */ |
1755 | + |
1756 | +#include "backend/backend_cups.h" |
1757 | +#include "models/devicemodel.h" |
1758 | + |
1759 | +#include <QDebug> |
1760 | + |
1761 | +DeviceModel::DeviceModel(PrinterBackend *backend, QObject *parent) |
1762 | + : QAbstractListModel(parent) |
1763 | + , m_backend(backend) |
1764 | + , m_isSearching(false) |
1765 | +{ |
1766 | + connect(m_backend, SIGNAL(deviceFound(const Device&)), |
1767 | + this, SLOT(deviceLoaded(const Device&))); |
1768 | + connect(m_backend, SIGNAL(deviceSearchFinished()), |
1769 | + this, SLOT(deviceSearchFinished())); |
1770 | +} |
1771 | + |
1772 | +DeviceModel::~DeviceModel() |
1773 | +{ |
1774 | +} |
1775 | + |
1776 | +int DeviceModel::rowCount(const QModelIndex &parent) const |
1777 | +{ |
1778 | + Q_UNUSED(parent); |
1779 | + return m_devices.size(); |
1780 | +} |
1781 | + |
1782 | +int DeviceModel::count() const |
1783 | +{ |
1784 | + return rowCount(); |
1785 | +} |
1786 | + |
1787 | +QVariant DeviceModel::data(const QModelIndex &index, int role) const |
1788 | +{ |
1789 | + QVariant ret; |
1790 | + |
1791 | + if ((0 <= index.row()) && (index.row() < m_devices.size())) { |
1792 | + |
1793 | + auto device = m_devices[index.row()]; |
1794 | + |
1795 | + switch (role) { |
1796 | + case Qt::DisplayRole: |
1797 | + ret = device.toString(); |
1798 | + break; |
1799 | + case IdRole: |
1800 | + ret = device.id; |
1801 | + break; |
1802 | + case InfoRole: |
1803 | + ret = device.info; |
1804 | + break; |
1805 | + case UriRole: |
1806 | + ret = device.uri; |
1807 | + break; |
1808 | + case LocationRole: |
1809 | + ret = device.location; |
1810 | + break; |
1811 | + case TypeRole: |
1812 | + ret = QVariant::fromValue(device.type()); |
1813 | + break; |
1814 | + case MakeModelRole: |
1815 | + ret = device.makeModel; |
1816 | + break; |
1817 | + } |
1818 | + } |
1819 | + |
1820 | + return ret; |
1821 | +} |
1822 | + |
1823 | +QHash<int, QByteArray> DeviceModel::roleNames() const |
1824 | +{ |
1825 | + static QHash<int,QByteArray> names; |
1826 | + |
1827 | + if (Q_UNLIKELY(names.empty())) { |
1828 | + names[Qt::DisplayRole] = "displayName"; |
1829 | + names[IdRole] = "id"; |
1830 | + names[InfoRole] = "info"; |
1831 | + names[UriRole] = "uri"; |
1832 | + names[LocationRole] = "location"; |
1833 | + names[TypeRole] = "type"; |
1834 | + names[MakeModelRole] = "makeModel"; |
1835 | + } |
1836 | + |
1837 | + return names; |
1838 | +} |
1839 | + |
1840 | +void DeviceModel::deviceLoaded(const Device &device) |
1841 | +{ |
1842 | + if (!deviceWanted(device)) { |
1843 | + return; |
1844 | + } |
1845 | + |
1846 | + if (!m_devices.contains(device)) { |
1847 | + int i = m_devices.size(); |
1848 | + beginInsertRows(QModelIndex(), i, i); |
1849 | + m_devices.append(device); |
1850 | + endInsertRows(); |
1851 | + |
1852 | + Q_EMIT countChanged(); |
1853 | + } |
1854 | +} |
1855 | + |
1856 | +bool DeviceModel::deviceWanted(const Device &device) |
1857 | +{ |
1858 | + auto parts = device.uri.split(":", QString::SkipEmptyParts); |
1859 | + return parts.size() > 1; |
1860 | +} |
1861 | + |
1862 | +void DeviceModel::clear() |
1863 | +{ |
1864 | + beginResetModel(); |
1865 | + m_devices.clear(); |
1866 | + endResetModel(); |
1867 | +} |
1868 | + |
1869 | +void DeviceModel::load() |
1870 | +{ |
1871 | + if (m_isSearching) { |
1872 | + qWarning() << Q_FUNC_INFO |
1873 | + << "Ignoring load request as search is ongoing."; |
1874 | + } else { |
1875 | + clear(); |
1876 | + if (m_backend->type() == PrinterEnum::PrinterType::CupsType) { |
1877 | + ((PrinterCupsBackend*) m_backend)->searchForDevices(); |
1878 | + m_isSearching = true; |
1879 | + Q_EMIT searchingChanged(); |
1880 | + } |
1881 | + } |
1882 | +} |
1883 | + |
1884 | +void DeviceModel::deviceSearchFinished() |
1885 | +{ |
1886 | + m_isSearching = false; |
1887 | + Q_EMIT searchingChanged(); |
1888 | +} |
1889 | |
1890 | === added file 'modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h' |
1891 | --- modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h 1970-01-01 00:00:00 +0000 |
1892 | +++ modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h 2017-03-20 13:32:24 +0000 |
1893 | @@ -0,0 +1,78 @@ |
1894 | +/* |
1895 | + * Copyright (C) 2017 Canonical, Ltd. |
1896 | + * |
1897 | + * This program is free software; you can redistribute it and/or modify |
1898 | + * it under the terms of the GNU Lesser General Public License as published by |
1899 | + * the Free Software Foundation; version 3. |
1900 | + * |
1901 | + * This program is distributed in the hope that it will be useful, |
1902 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1903 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1904 | + * GNU Lesser General Public License for more details. |
1905 | + * |
1906 | + * You should have received a copy of the GNU Lesser General Public License |
1907 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1908 | + */ |
1909 | + |
1910 | +#ifndef USC_PRINTER_DEVICEMODEL_H |
1911 | +#define USC_PRINTER_DEVICEMODEL_H |
1912 | + |
1913 | +#include "printers_global.h" |
1914 | + |
1915 | +#include "structs.h" |
1916 | + |
1917 | +#include <QAbstractListModel> |
1918 | +#include <QList> |
1919 | +#include <QModelIndex> |
1920 | +#include <QObject> |
1921 | +#include <QVariant> |
1922 | + |
1923 | +class PRINTERS_DECL_EXPORT DeviceModel : public QAbstractListModel |
1924 | +{ |
1925 | + Q_OBJECT |
1926 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
1927 | + Q_PROPERTY(bool searching MEMBER m_isSearching NOTIFY searchingChanged) |
1928 | +public: |
1929 | + explicit DeviceModel(PrinterBackend *backend, QObject *parent = Q_NULLPTR); |
1930 | + ~DeviceModel(); |
1931 | + |
1932 | + enum Roles |
1933 | + { |
1934 | + // Qt::DisplayRole holds device name |
1935 | + ClassRole = Qt::UserRole, |
1936 | + IdRole, |
1937 | + InfoRole, |
1938 | + UriRole, |
1939 | + LocationRole, |
1940 | + TypeRole, |
1941 | + MakeModelRole, |
1942 | + LastRole = MakeModelRole, |
1943 | + }; |
1944 | + |
1945 | + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
1946 | + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
1947 | + virtual QHash<int, QByteArray> roleNames() const override; |
1948 | + |
1949 | + int count() const; |
1950 | + void load(); |
1951 | + void clear(); |
1952 | + |
1953 | +private Q_SLOTS: |
1954 | + void deviceLoaded(const Device &device); |
1955 | + void deviceSearchFinished(); |
1956 | + |
1957 | +Q_SIGNALS: |
1958 | + void countChanged(); |
1959 | + void searchingChanged(); |
1960 | + |
1961 | +private: |
1962 | + /* Checks if we want it in the list or not. Wanted is intentionally |
1963 | + ambiguous. */ |
1964 | + bool deviceWanted(const Device &device); |
1965 | + |
1966 | + PrinterBackend *m_backend; |
1967 | + QList<Device> m_devices; |
1968 | + bool m_isSearching; |
1969 | +}; |
1970 | + |
1971 | +#endif // USC_PRINTER_DEVICEMODEL_H |
1972 | |
1973 | === modified file 'modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp' |
1974 | --- modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp 2017-02-23 14:04:26 +0000 |
1975 | +++ modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp 2017-03-20 13:32:24 +0000 |
1976 | @@ -31,113 +31,190 @@ |
1977 | : QAbstractListModel(parent) |
1978 | , m_backend(backend) |
1979 | { |
1980 | - update(); |
1981 | - |
1982 | QObject::connect(m_backend, &PrinterBackend::jobCreated, |
1983 | - this, &JobModel::jobSignalCatchAll); |
1984 | + this, &JobModel::jobCreated); |
1985 | QObject::connect(m_backend, &PrinterBackend::jobState, |
1986 | - this, &JobModel::jobSignalCatchAll); |
1987 | + this, &JobModel::jobState); |
1988 | QObject::connect(m_backend, &PrinterBackend::jobCompleted, |
1989 | - this, &JobModel::jobSignalCatchAll); |
1990 | + this, &JobModel::jobCompleted); |
1991 | + |
1992 | + connect(m_backend, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>)), |
1993 | + this, SLOT(updateJob(QString, int, QMap<QString, QVariant>))); |
1994 | + |
1995 | + // Impressions completed happens via printer state changed |
1996 | + QObject::connect(m_backend, &PrinterBackend::printerStateChanged, |
1997 | + &m_signalHandler, &SignalRateLimiter::onPrinterStateChanged); |
1998 | + |
1999 | + QObject::connect(&m_signalHandler, SIGNAL(printerModified(const QString&)), |
2000 | + this, SLOT(jobSignalPrinterModified(const QString&))); |
2001 | + |
2002 | + // Add already existing jobs |
2003 | + // TODO: even this should probably be in a background thread? |
2004 | + // so that it doesn't block startup? |
2005 | + Q_FOREACH(auto job, m_backend->printerGetJobs()) { |
2006 | + addJob(job); |
2007 | + } |
2008 | } |
2009 | |
2010 | JobModel::~JobModel() |
2011 | { |
2012 | } |
2013 | |
2014 | -void JobModel::jobSignalCatchAll( |
2015 | - const QString &text, const QString &printer_uri, |
2016 | - const QString &printer_name, uint printer_state, |
2017 | - const QString &printer_state_reasons, bool printer_is_accepting_jobs, |
2018 | - uint job_id, uint job_state, const QString &job_state_reasons, |
2019 | - const QString &job_name, uint job_impressions_completed) |
2020 | -{ |
2021 | - Q_UNUSED(text); |
2022 | - Q_UNUSED(printer_uri); |
2023 | - Q_UNUSED(printer_name); |
2024 | - Q_UNUSED(printer_state); |
2025 | - Q_UNUSED(printer_state_reasons); |
2026 | - Q_UNUSED(printer_is_accepting_jobs); |
2027 | - Q_UNUSED(job_id); |
2028 | +void JobModel::jobCreated( |
2029 | + const QString &text, const QString &printer_uri, |
2030 | + const QString &printer_name, uint printer_state, |
2031 | + const QString &printer_state_reasons, bool printer_is_accepting_jobs, |
2032 | + uint job_id, uint job_state, const QString &job_state_reasons, |
2033 | + const QString &job_name, uint job_impressions_completed) |
2034 | +{ |
2035 | + Q_UNUSED(text); // "Job Created" |
2036 | + Q_UNUSED(printer_uri); |
2037 | + Q_UNUSED(printer_state); |
2038 | + Q_UNUSED(printer_state_reasons); |
2039 | + Q_UNUSED(printer_is_accepting_jobs); |
2040 | + Q_UNUSED(job_state_reasons); |
2041 | + |
2042 | + QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>( |
2043 | + new PrinterJob(printer_name, m_backend, job_id) |
2044 | + ); |
2045 | + job->setImpressionsCompleted(job_impressions_completed); |
2046 | + job->setState(static_cast<PrinterEnum::JobState>(job_state)); |
2047 | + job->setTitle(job_name); |
2048 | + |
2049 | + // Printers listens to rowInserted and spawns a JobLoader to set the |
2050 | + // printer of the job, which triggers the extended attributes to be loaded |
2051 | + // once complete this triggers JobModel::updateJob |
2052 | + addJob(job); |
2053 | +} |
2054 | + |
2055 | +void JobModel::jobState( |
2056 | + const QString &text, const QString &printer_uri, |
2057 | + const QString &printer_name, uint printer_state, |
2058 | + const QString &printer_state_reasons, bool printer_is_accepting_jobs, |
2059 | + uint job_id, uint job_state, const QString &job_state_reasons, |
2060 | + const QString &job_name, uint job_impressions_completed) |
2061 | +{ |
2062 | + Q_UNUSED(text); |
2063 | + Q_UNUSED(printer_uri); |
2064 | + Q_UNUSED(printer_state); |
2065 | + Q_UNUSED(printer_state_reasons); |
2066 | + Q_UNUSED(printer_is_accepting_jobs); |
2067 | + Q_UNUSED(job_state_reasons); |
2068 | + Q_UNUSED(job_name); |
2069 | + |
2070 | + QSharedPointer<PrinterJob> job = getJob(printer_name, job_id); |
2071 | + |
2072 | + if (job) { |
2073 | + job->setImpressionsCompleted(job_impressions_completed); |
2074 | + job->setState(static_cast<PrinterEnum::JobState>(job_state)); |
2075 | + |
2076 | + updateJob(job); |
2077 | + } else { |
2078 | + qWarning() << "JobModel::jobState for unknown job: " << job_name << " (" |
2079 | + << job_id << ") for " << printer_name; |
2080 | + } |
2081 | +} |
2082 | + |
2083 | +void JobModel::jobCompleted( |
2084 | + const QString &text, const QString &printer_uri, |
2085 | + const QString &printer_name, uint printer_state, |
2086 | + const QString &printer_state_reasons, bool printer_is_accepting_jobs, |
2087 | + uint job_id, uint job_state, const QString &job_state_reasons, |
2088 | + const QString &job_name, uint job_impressions_completed) |
2089 | +{ |
2090 | + Q_UNUSED(text); |
2091 | + Q_UNUSED(printer_uri); |
2092 | + Q_UNUSED(printer_state); |
2093 | + Q_UNUSED(printer_state_reasons); |
2094 | + Q_UNUSED(printer_is_accepting_jobs); |
2095 | Q_UNUSED(job_state); |
2096 | Q_UNUSED(job_state_reasons); |
2097 | Q_UNUSED(job_name); |
2098 | - |
2099 | - auto job = getJobById(job_id); |
2100 | - if (job) |
2101 | - job->setImpressionsCompleted(job_impressions_completed); |
2102 | - |
2103 | - update(); |
2104 | -} |
2105 | - |
2106 | -void JobModel::update() |
2107 | -{ |
2108 | - // Store the old count and get the new printers |
2109 | - int oldCount = m_jobs.size(); |
2110 | - QList<QSharedPointer<PrinterJob>> newJobs = m_backend->printerGetJobs(); |
2111 | - |
2112 | - // Go through the old model |
2113 | - for (int i=0; i < m_jobs.count(); i++) { |
2114 | - // Determine if the old printer exists in the new model |
2115 | - bool exists = false; |
2116 | - |
2117 | - Q_FOREACH(QSharedPointer<PrinterJob> p, newJobs) { |
2118 | - if (p->jobId() == m_jobs.at(i)->jobId()) { |
2119 | - exists = true; |
2120 | - |
2121 | - // Ensure the other properties of the job are up to date |
2122 | - if (!m_jobs.at(i)->deepCompare(p)) { |
2123 | - m_jobs.at(i)->updateFrom(p); |
2124 | - |
2125 | - Q_EMIT dataChanged(index(i), index(i)); |
2126 | - } |
2127 | - |
2128 | - break; |
2129 | - } |
2130 | - } |
2131 | - |
2132 | - // If it doesn't exist then remove it from the old model |
2133 | - if (!exists) { |
2134 | - beginRemoveRows(QModelIndex(), i, i); |
2135 | - QSharedPointer<PrinterJob> p = m_jobs.takeAt(i); |
2136 | - endRemoveRows(); |
2137 | - |
2138 | - i--; // as we have removed an item decrement |
2139 | - } |
2140 | - } |
2141 | - |
2142 | - // Go through the new model |
2143 | - for (int i=0; i < newJobs.count(); i++) { |
2144 | - // Determine if the new printer exists in the old model |
2145 | - bool exists = false; |
2146 | - int j; |
2147 | - |
2148 | - for (j=0; j < m_jobs.count(); j++) { |
2149 | - if (m_jobs.at(j)->jobId() == newJobs.at(i)->jobId()) { |
2150 | - exists = true; |
2151 | - break; |
2152 | - } |
2153 | - } |
2154 | - |
2155 | - if (exists) { |
2156 | - if (j == i) { // New printer exists and in correct position |
2157 | - continue; |
2158 | - } else { |
2159 | - // New printer does exist but needs to be moved in old model |
2160 | - beginMoveRows(QModelIndex(), j, 1, QModelIndex(), i); |
2161 | - m_jobs.move(j, i); |
2162 | - endMoveRows(); |
2163 | - } |
2164 | - } else { |
2165 | - // New printer does not exist insert into model |
2166 | - beginInsertRows(QModelIndex(), i, i); |
2167 | - m_jobs.insert(i, newJobs.at(i)); |
2168 | - endInsertRows(); |
2169 | - } |
2170 | - } |
2171 | - |
2172 | - if (oldCount != m_jobs.size()) { |
2173 | - Q_EMIT countChanged(); |
2174 | + Q_UNUSED(job_impressions_completed); |
2175 | + |
2176 | + auto job = getJob(printer_name, job_id); |
2177 | + if (job) { |
2178 | + removeJob(job); |
2179 | + } else { |
2180 | + qWarning() << "JobModel::jobCompleted for unknown job: " << job_name << " (" |
2181 | + << job_id << ") for " << printer_name; |
2182 | + } |
2183 | +} |
2184 | + |
2185 | +void JobModel::jobSignalPrinterModified(const QString &printerName) |
2186 | +{ |
2187 | + // Find the active or pending job and force a refresh |
2188 | + // We force refresh pending jobs incase there is a flood of signals |
2189 | + // meaning that the jobStateChanged signal might not have happened yet |
2190 | + Q_FOREACH(auto job, m_jobs) { |
2191 | + if (job->printerName() == printerName |
2192 | + && (job->state() == PrinterEnum::JobState::Processing |
2193 | + || job->state() == PrinterEnum::JobState::Pending)) { |
2194 | + Q_EMIT forceJobRefresh(printerName, job->jobId()); |
2195 | + } |
2196 | + } |
2197 | +} |
2198 | + |
2199 | +void JobModel::addJob(QSharedPointer<PrinterJob> job) |
2200 | +{ |
2201 | + int i = m_jobs.size(); |
2202 | + |
2203 | + beginInsertRows(QModelIndex(), i, i); |
2204 | + m_jobs.append(job); |
2205 | + endInsertRows(); |
2206 | + |
2207 | + Q_EMIT countChanged(); |
2208 | +} |
2209 | + |
2210 | +void JobModel::removeJob(QSharedPointer<PrinterJob> job) |
2211 | +{ |
2212 | + int i = m_jobs.indexOf(job); |
2213 | + |
2214 | + beginRemoveRows(QModelIndex(), i, i); |
2215 | + m_jobs.removeAt(i); |
2216 | + endRemoveRows(); |
2217 | + |
2218 | + Q_EMIT countChanged(); |
2219 | +} |
2220 | + |
2221 | +// This is used by JobModel::jobState as it has modified an existing job |
2222 | +void JobModel::updateJob(QSharedPointer<PrinterJob> job) |
2223 | +{ |
2224 | + int i = m_jobs.indexOf(job); |
2225 | + QModelIndex idx = index(i); |
2226 | + Q_EMIT dataChanged(idx, idx); |
2227 | +} |
2228 | + |
2229 | +// This is used by JobLoader as it gives us the oldJob and a newJob which has |
2230 | +// the extended attributes loaded. We then load the data from this newJob. |
2231 | +void JobModel::updateJob(QString printerName, int jobId, |
2232 | + QMap<QString, QVariant> attributes) |
2233 | +{ |
2234 | + QSharedPointer<PrinterJob> job = getJob(printerName, jobId); |
2235 | + |
2236 | + int i = m_jobs.indexOf(job); |
2237 | + QModelIndex idx = index(i); |
2238 | + |
2239 | + if (i > -1) { |
2240 | + job->loadAttributes(attributes); |
2241 | + |
2242 | + Q_EMIT dataChanged(idx, idx); |
2243 | + } else { |
2244 | + qWarning() << "Tried to updateJob which doesn't exist:" << printerName << jobId; |
2245 | + } |
2246 | +} |
2247 | + |
2248 | +void JobModel::updateJobPrinter(QSharedPointer<PrinterJob> job, QSharedPointer<Printer> printer) |
2249 | +{ |
2250 | + int i = m_jobs.indexOf(job); |
2251 | + QModelIndex idx = index(i); |
2252 | + |
2253 | + if (i > -1) { |
2254 | + job->setPrinter(printer); |
2255 | + |
2256 | + Q_EMIT dataChanged(idx, idx); |
2257 | + } else { |
2258 | + qWarning() << "Tried to updateJobPrinter which doesn't exist:" << printer->name() << job->jobId(); |
2259 | } |
2260 | } |
2261 | |
2262 | @@ -166,7 +243,8 @@ |
2263 | break; |
2264 | case ColorModelRole: { |
2265 | if (job->printer()) { |
2266 | - ret = job->printer()->supportedColorModels().at(job->colorModel()).text; |
2267 | + ColorModel m = job->printer()->supportedColorModels().at(job->colorModel()); |
2268 | + ret = m.text.isEmpty() ? m.name : m.text; |
2269 | } else { |
2270 | qWarning() << "Printer is undefined, no colorModel"; |
2271 | ret = ""; |
2272 | @@ -174,13 +252,13 @@ |
2273 | break; |
2274 | } |
2275 | case CompletedTimeRole: |
2276 | - ret = job->completedTime().toString(QLocale::system().dateTimeFormat()); |
2277 | + ret = job->completedTime().toLocalTime(); |
2278 | break; |
2279 | case CopiesRole: |
2280 | ret = job->copies(); |
2281 | break; |
2282 | case CreationTimeRole: |
2283 | - ret = job->creationTime().toString(QLocale::system().dateTimeFormat()); |
2284 | + ret = job->creationTime().toLocalTime(); |
2285 | break; |
2286 | case DuplexRole: { |
2287 | if (job->printer()) { |
2288 | @@ -194,6 +272,9 @@ |
2289 | case IdRole: |
2290 | ret = job->jobId(); |
2291 | break; |
2292 | + case HeldRole: |
2293 | + ret = job->state() == PrinterEnum::JobState::Held; |
2294 | + break; |
2295 | case ImpressionsCompletedRole: |
2296 | ret = job->impressionsCompleted(); |
2297 | break; |
2298 | @@ -213,11 +294,12 @@ |
2299 | ret = QVariant::fromValue<PrinterEnum::PrintRange>(job->printRangeMode()); |
2300 | break; |
2301 | case ProcessingTimeRole: |
2302 | - ret = job->processingTime().toString(QLocale::system().dateTimeFormat()); |
2303 | + ret = job->processingTime().toLocalTime(); |
2304 | break; |
2305 | case QualityRole: { |
2306 | if (job->printer()) { |
2307 | - ret = job->printer()->supportedPrintQualities().at(job->quality()).text; |
2308 | + PrintQuality q = job->printer()->supportedPrintQualities().at(job->quality()); |
2309 | + ret = q.text.isEmpty() ? q.name : q.text; |
2310 | } else { |
2311 | qWarning() << "Printer is undefined, no quality"; |
2312 | ret = ""; |
2313 | @@ -231,30 +313,7 @@ |
2314 | ret = job->size(); |
2315 | break; |
2316 | case StateRole: |
2317 | - // TODO: improve, for now have a switch |
2318 | - switch (job->state()) { |
2319 | - case PrinterEnum::JobState::Aborted: |
2320 | - ret = "Aborted"; |
2321 | - break; |
2322 | - case PrinterEnum::JobState::Canceled: |
2323 | - ret = "Canceled"; |
2324 | - break; |
2325 | - case PrinterEnum::JobState::Complete: |
2326 | - ret = "Compelete"; |
2327 | - break; |
2328 | - case PrinterEnum::JobState::Held: |
2329 | - ret = "Held"; |
2330 | - break; |
2331 | - case PrinterEnum::JobState::Pending: |
2332 | - ret = "Pending"; |
2333 | - break; |
2334 | - case PrinterEnum::JobState::Processing: |
2335 | - ret = "Processing"; |
2336 | - break; |
2337 | - case PrinterEnum::JobState::Stopped: |
2338 | - ret = "Stopped"; |
2339 | - break; |
2340 | - } |
2341 | + ret = QVariant::fromValue<PrinterEnum::JobState>(job->state()); |
2342 | break; |
2343 | case Qt::DisplayRole: |
2344 | case TitleRole: |
2345 | @@ -263,6 +322,15 @@ |
2346 | case UserRole: |
2347 | ret = job->user(); |
2348 | break; |
2349 | + case LastStateMessageRole: { |
2350 | + if (job->printer()) { |
2351 | + ret = job->printer()->lastMessage(); |
2352 | + } else { |
2353 | + ret = ""; |
2354 | + } |
2355 | + break; |
2356 | + } |
2357 | + |
2358 | } |
2359 | } |
2360 | |
2361 | @@ -283,6 +351,7 @@ |
2362 | names[CreationTimeRole] = "creationTime"; |
2363 | names[DuplexRole] = "duplexMode"; |
2364 | names[ImpressionsCompletedRole] = "impressionsCompleted"; |
2365 | + names[HeldRole] = "held"; |
2366 | names[LandscapeRole] = "landscape"; |
2367 | names[MessagesRole] = "messages"; |
2368 | names[PrinterNameRole] = "printerName"; |
2369 | @@ -315,10 +384,10 @@ |
2370 | return result; |
2371 | } |
2372 | |
2373 | -QSharedPointer<PrinterJob> JobModel::getJobById(const int &id) |
2374 | +QSharedPointer<PrinterJob> JobModel::getJob(const QString &printerName, const int &id) |
2375 | { |
2376 | Q_FOREACH(auto job, m_jobs) { |
2377 | - if (job->jobId() == id) { |
2378 | + if (job->printerName() == printerName && job->jobId() == id) { |
2379 | return job; |
2380 | } |
2381 | } |
2382 | @@ -367,6 +436,33 @@ |
2383 | return rowCount(); |
2384 | } |
2385 | |
2386 | +void JobFilter::filterOnActive() |
2387 | +{ |
2388 | + m_activeStates = QSet<PrinterEnum::JobState>{ |
2389 | + PrinterEnum::JobState::Processing, |
2390 | + }; |
2391 | + m_activeFilterEnabled = true; |
2392 | + invalidate(); |
2393 | +} |
2394 | + |
2395 | +void JobFilter::filterOnPaused() |
2396 | +{ |
2397 | + m_pausedStates = QSet<PrinterEnum::JobState>{ |
2398 | + PrinterEnum::JobState::Held, |
2399 | + }; |
2400 | + m_pausedFilterEnabled = true; |
2401 | + invalidate(); |
2402 | +} |
2403 | + |
2404 | +void JobFilter::filterOnQueued() |
2405 | +{ |
2406 | + m_queuedStates = QSet<PrinterEnum::JobState>{ |
2407 | + PrinterEnum::JobState::Pending, |
2408 | + }; |
2409 | + m_queuedFilterEnabled = true; |
2410 | + invalidate(); |
2411 | +} |
2412 | + |
2413 | void JobFilter::filterOnPrinterName(const QString &name) |
2414 | { |
2415 | m_printerName = name; |
2416 | @@ -386,5 +482,50 @@ |
2417 | accepts = m_printerName == printerName; |
2418 | } |
2419 | |
2420 | + if (accepts && m_activeFilterEnabled) { |
2421 | + PrinterEnum::JobState state = childIndex.model()->data( |
2422 | + childIndex, JobModel::StateRole |
2423 | + ).value<PrinterEnum::JobState>(); |
2424 | + |
2425 | + accepts = m_activeStates.contains(state); |
2426 | + } |
2427 | + |
2428 | + if (accepts && m_pausedFilterEnabled) { |
2429 | + PrinterEnum::JobState state = childIndex.model()->data( |
2430 | + childIndex, JobModel::StateRole |
2431 | + ).value<PrinterEnum::JobState>(); |
2432 | + |
2433 | + accepts = m_pausedStates.contains(state); |
2434 | + } |
2435 | + |
2436 | + if (accepts && m_queuedFilterEnabled) { |
2437 | + PrinterEnum::JobState state = childIndex.model()->data( |
2438 | + childIndex, JobModel::StateRole |
2439 | + ).value<PrinterEnum::JobState>(); |
2440 | + |
2441 | + accepts = m_queuedStates.contains(state); |
2442 | + } |
2443 | + |
2444 | return accepts; |
2445 | } |
2446 | + |
2447 | +bool JobFilter::lessThan(const QModelIndex &source_left, |
2448 | + const QModelIndex &source_right) const |
2449 | +{ |
2450 | + QVariant leftData = sourceModel()->data(source_left, sortRole()); |
2451 | + QVariant rightData = sourceModel()->data(source_right, sortRole()); |
2452 | + |
2453 | + if (sortRole() == (int) JobModel::CreationTimeRole) { |
2454 | + // If creationDateTime is the same, fallback to Id |
2455 | + if (leftData.toDateTime() == rightData.toDateTime()) { |
2456 | + int leftId = sourceModel()->data(source_left, JobModel::IdRole).toInt(); |
2457 | + int rightId = sourceModel()->data(source_right, JobModel::IdRole).toInt(); |
2458 | + |
2459 | + return leftId < rightId; |
2460 | + } else { |
2461 | + return leftData.toDateTime() < rightData.toDateTime(); |
2462 | + } |
2463 | + } else { |
2464 | + return leftData < rightData; |
2465 | + } |
2466 | +} |
2467 | |
2468 | === modified file 'modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h' |
2469 | --- modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h 2017-02-21 10:46:29 +0000 |
2470 | +++ modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h 2017-03-20 13:32:24 +0000 |
2471 | @@ -20,6 +20,7 @@ |
2472 | #include "printers_global.h" |
2473 | #include "backend/backend.h" |
2474 | #include "printer/printerjob.h" |
2475 | +#include "printer/signalratelimiter.h" |
2476 | |
2477 | #include <QAbstractListModel> |
2478 | #include <QByteArray> |
2479 | @@ -30,6 +31,8 @@ |
2480 | #include <QTimer> |
2481 | #include <QVariant> |
2482 | |
2483 | +class PrinterBackend; |
2484 | +class PrinterJob; |
2485 | class PRINTERS_DECL_EXPORT JobModel : public QAbstractListModel |
2486 | { |
2487 | Q_OBJECT |
2488 | @@ -51,6 +54,7 @@ |
2489 | CopiesRole, |
2490 | CreationTimeRole, |
2491 | DuplexRole, |
2492 | + HeldRole, |
2493 | ImpressionsCompletedRole, |
2494 | LandscapeRole, |
2495 | MessagesRole, |
2496 | @@ -75,23 +79,46 @@ |
2497 | int count() const; |
2498 | |
2499 | Q_INVOKABLE QVariantMap get(const int row) const; |
2500 | - QSharedPointer<PrinterJob> getJobById(const int &id); |
2501 | + QSharedPointer<PrinterJob> getJob(const QString &printerName, const int &id); |
2502 | + |
2503 | + void updateJobPrinter(QSharedPointer<PrinterJob> job, QSharedPointer<Printer> printer); |
2504 | private: |
2505 | + void addJob(QSharedPointer<PrinterJob> job); |
2506 | + void removeJob(QSharedPointer<PrinterJob> job); |
2507 | + void updateJob(QSharedPointer<PrinterJob> Job); |
2508 | + |
2509 | PrinterBackend *m_backend; |
2510 | |
2511 | QList<QSharedPointer<PrinterJob>> m_jobs; |
2512 | + SignalRateLimiter m_signalHandler; |
2513 | private Q_SLOTS: |
2514 | - void update(); |
2515 | - void jobSignalCatchAll(const QString &text, const QString &printer_uri, |
2516 | - const QString &printer_name, uint printer_state, |
2517 | - const QString &printer_state_reasons, |
2518 | - bool printer_is_accepting_jobs, uint job_id, |
2519 | - uint job_state, const QString &job_state_reasons, |
2520 | - const QString &job_name, |
2521 | - uint job_impressions_completed); |
2522 | + void jobCreated(const QString &text, const QString &printer_uri, |
2523 | + const QString &printer_name, uint printer_state, |
2524 | + const QString &printer_state_reasons, |
2525 | + bool printer_is_accepting_jobs, uint job_id, |
2526 | + uint job_state, const QString &job_state_reasons, |
2527 | + const QString &job_name, |
2528 | + uint job_impressions_completed); |
2529 | + void jobState(const QString &text, const QString &printer_uri, |
2530 | + const QString &printer_name, uint printer_state, |
2531 | + const QString &printer_state_reasons, |
2532 | + bool printer_is_accepting_jobs, uint job_id, |
2533 | + uint job_state, const QString &job_state_reasons, |
2534 | + const QString &job_name, |
2535 | + uint job_impressions_completed); |
2536 | + void jobCompleted(const QString &text, const QString &printer_uri, |
2537 | + const QString &printer_name, uint printer_state, |
2538 | + const QString &printer_state_reasons, |
2539 | + bool printer_is_accepting_jobs, uint job_id, |
2540 | + uint job_state, const QString &job_state_reasons, |
2541 | + const QString &job_name, |
2542 | + uint job_impressions_completed); |
2543 | + void jobSignalPrinterModified(const QString &printerName); |
2544 | + void updateJob(QString printerName, int jobId, QMap<QString, QVariant> attributes); |
2545 | |
2546 | Q_SIGNALS: |
2547 | void countChanged(); |
2548 | + void forceJobRefresh(const QString &printerName, const int jobId); |
2549 | }; |
2550 | |
2551 | class PRINTERS_DECL_EXPORT JobFilter : public QSortFilterProxyModel |
2552 | @@ -102,13 +129,19 @@ |
2553 | explicit JobFilter(QObject *parent = Q_NULLPTR); |
2554 | ~JobFilter(); |
2555 | |
2556 | - Q_INVOKABLE QVariantMap get(const int row) const; |
2557 | - |
2558 | void filterOnPrinterName(const QString &name); |
2559 | int count() const; |
2560 | +public Q_SLOTS: |
2561 | + QVariantMap get(const int row) const; |
2562 | + |
2563 | + void filterOnActive(); |
2564 | + void filterOnQueued(); |
2565 | + void filterOnPaused(); |
2566 | protected: |
2567 | virtual bool filterAcceptsRow( |
2568 | int sourceRow, const QModelIndex &sourceParent) const override; |
2569 | + virtual bool lessThan(const QModelIndex &source_left, |
2570 | + const QModelIndex &source_right) const; |
2571 | |
2572 | Q_SIGNALS: |
2573 | void countChanged(); |
2574 | @@ -120,6 +153,15 @@ |
2575 | private: |
2576 | QString m_printerName = QString::null; |
2577 | bool m_printerNameFilterEnabled = false; |
2578 | + |
2579 | + bool m_activeFilterEnabled = false; |
2580 | + QSet<PrinterEnum::JobState> m_activeStates; |
2581 | + |
2582 | + bool m_queuedFilterEnabled = false; |
2583 | + QSet<PrinterEnum::JobState> m_queuedStates; |
2584 | + |
2585 | + bool m_pausedFilterEnabled = false; |
2586 | + QSet<PrinterEnum::JobState> m_pausedStates; |
2587 | }; |
2588 | |
2589 | #endif // USC_JOB_MODEL_H |
2590 | |
2591 | === modified file 'modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp' |
2592 | --- modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp 2017-02-23 14:04:26 +0000 |
2593 | +++ modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp 2017-03-20 13:32:24 +0000 |
2594 | @@ -22,6 +22,7 @@ |
2595 | #include "utils.h" |
2596 | |
2597 | #include <QDebug> |
2598 | +#include <QUrl> |
2599 | |
2600 | PrinterModel::PrinterModel(PrinterBackend *backend, QObject *parent) |
2601 | : QAbstractListModel(parent) |
2602 | @@ -31,9 +32,9 @@ |
2603 | QObject::connect(m_backend, &PrinterBackend::printerAdded, |
2604 | this, &PrinterModel::printerAdded); |
2605 | QObject::connect(m_backend, &PrinterBackend::printerModified, |
2606 | - &m_signalHandler, &PrinterSignalHandler::onPrinterModified); |
2607 | + &m_signalHandler, &SignalRateLimiter::onPrinterModified); |
2608 | QObject::connect(m_backend, &PrinterBackend::printerStateChanged, |
2609 | - &m_signalHandler, &PrinterSignalHandler::onPrinterModified); |
2610 | + &m_signalHandler, &SignalRateLimiter::onPrinterModified); |
2611 | QObject::connect(m_backend, &PrinterBackend::printerDeleted, |
2612 | this, &PrinterModel::printerDeleted); |
2613 | |
2614 | @@ -126,22 +127,6 @@ |
2615 | return QSharedPointer<Printer>(Q_NULLPTR); |
2616 | } |
2617 | |
2618 | -void PrinterModel::movePrinter(const int &from, const int &to) |
2619 | -{ |
2620 | - int size = m_printers.size(); |
2621 | - if (from < 0 || to < 0 || from >= size || to >= size) { |
2622 | - qWarning() << Q_FUNC_INFO << "Illegal move operation from" |
2623 | - << from << "to" << to << ". Size was" << size; |
2624 | - return; |
2625 | - } |
2626 | - if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), to)) { |
2627 | - qWarning() << Q_FUNC_INFO << "failed to move rows."; |
2628 | - return; |
2629 | - } |
2630 | - m_printers.move(from, to); |
2631 | - endMoveRows(); |
2632 | -} |
2633 | - |
2634 | void PrinterModel::removePrinter(QSharedPointer<Printer> printer, const CountChangeSignal ¬ify) |
2635 | { |
2636 | int idx = m_printers.indexOf(printer); |
2637 | @@ -214,6 +199,15 @@ |
2638 | case Qt::DisplayRole: |
2639 | ret = printer->name(); |
2640 | break; |
2641 | + case DeviceUriRole: |
2642 | + ret = printer->deviceUri(); |
2643 | + break; |
2644 | + case HostNameRole: |
2645 | + ret = QUrl(printer->deviceUri()).host(); |
2646 | + break; |
2647 | + case MakeRole: |
2648 | + ret = printer->make(); |
2649 | + break; |
2650 | case ColorModelRole: |
2651 | ret = printer->supportedColorModels().indexOf(printer->defaultColorModel()); |
2652 | break; |
2653 | @@ -248,6 +242,9 @@ |
2654 | case DescriptionRole: |
2655 | ret = printer->description(); |
2656 | break; |
2657 | + case LocationRole: |
2658 | + ret = printer->location(); |
2659 | + break; |
2660 | case PageSizeRole: |
2661 | ret = printer->defaultPageSize().name(); |
2662 | break; |
2663 | @@ -274,15 +271,27 @@ |
2664 | case IsRawRole: |
2665 | ret = !printer->holdsDefinition(); |
2666 | break; |
2667 | + case IsRemoteRole: |
2668 | + ret = printer->isRemote(); |
2669 | + break; |
2670 | + case LastMessageRole: |
2671 | + ret = printer->lastMessage(); |
2672 | + break; |
2673 | case JobRole: |
2674 | ret = QVariant::fromValue(printer->jobs()); |
2675 | break; |
2676 | + case CopiesRole: |
2677 | + ret = printer->copies(); |
2678 | + break; |
2679 | case EnabledRole: |
2680 | ret = printer->enabled(); |
2681 | break; |
2682 | case AcceptJobsRole: |
2683 | ret = printer->acceptJobs(); |
2684 | break; |
2685 | + case SharedRole: |
2686 | + ret = printer->shared(); |
2687 | + break; |
2688 | } |
2689 | } |
2690 | |
2691 | @@ -338,6 +347,11 @@ |
2692 | case AcceptJobsRole: |
2693 | printer->setAcceptJobs(value.toBool()); |
2694 | break; |
2695 | + case CopiesRole: |
2696 | + printer->setCopies(value.toInt()); |
2697 | + case SharedRole: |
2698 | + printer->setShared(value.toBool()); |
2699 | + break; |
2700 | } |
2701 | } |
2702 | |
2703 | @@ -356,12 +370,16 @@ |
2704 | names[DuplexRole] = "duplexMode"; |
2705 | names[SupportedDuplexModesRole] = "supportedDuplexModes"; |
2706 | names[NameRole] = "name"; |
2707 | + names[DeviceUriRole] = "deviceUri"; |
2708 | + names[HostNameRole] = "hostname"; |
2709 | + names[MakeRole] = "make"; |
2710 | names[EnabledRole] = "printerEnabled"; |
2711 | names[AcceptJobsRole] = "acceptJobs"; |
2712 | - names[PdfModeRole] = "pdfMode"; |
2713 | + names[SharedRole] = "shared"; |
2714 | names[PrintQualityRole] = "printQuality"; |
2715 | names[SupportedPrintQualitiesRole] = "supportedPrintQualities"; |
2716 | names[DescriptionRole] = "description"; |
2717 | + names[LocationRole] = "location"; |
2718 | names[PageSizeRole] = "pageSize"; |
2719 | names[SupportedPageSizesRole] = "supportedPageSizes"; |
2720 | names[StateRole] = "state"; |
2721 | @@ -369,6 +387,9 @@ |
2722 | names[IsPdfRole] = "isPdf"; |
2723 | names[IsLoadedRole] = "isLoaded"; |
2724 | names[IsRawRole] = "isRaw"; |
2725 | + names[IsRemoteRole] = "isRemote"; |
2726 | + names[LastMessageRole] = "lastMessage"; |
2727 | + names[CopiesRole] = "copies"; |
2728 | names[JobRole] = "jobs"; |
2729 | } |
2730 | |
2731 | @@ -447,6 +468,13 @@ |
2732 | m_pdf = pdf; |
2733 | } |
2734 | |
2735 | +void PrinterFilter::filterOnRemote(const bool remote) |
2736 | +{ |
2737 | + m_remoteEnabled = true; |
2738 | + m_remote = remote; |
2739 | + invalidate(); |
2740 | +} |
2741 | + |
2742 | bool PrinterFilter::filterAcceptsRow(int sourceRow, |
2743 | const QModelIndex &sourceParent) const |
2744 | { |
2745 | @@ -472,6 +500,14 @@ |
2746 | accepts = m_state == state; |
2747 | } |
2748 | |
2749 | + // If m_remote is true, we only show remote printers. |
2750 | + if (accepts && m_remoteEnabled) { |
2751 | + const bool isRemote = childIndex.model()->data( |
2752 | + childIndex, PrinterModel::IsRemoteRole |
2753 | + ).toBool(); |
2754 | + accepts = m_remote == isRemote; |
2755 | + } |
2756 | + |
2757 | return accepts; |
2758 | } |
2759 | bool PrinterFilter::lessThan(const QModelIndex &left, |
2760 | |
2761 | === modified file 'modules/Ubuntu/Components/Extras/Printers/models/printermodel.h' |
2762 | --- modules/Ubuntu/Components/Extras/Printers/models/printermodel.h 2017-02-23 14:04:26 +0000 |
2763 | +++ modules/Ubuntu/Components/Extras/Printers/models/printermodel.h 2017-03-20 13:32:24 +0000 |
2764 | @@ -21,7 +21,7 @@ |
2765 | |
2766 | #include "models/jobmodel.h" |
2767 | #include "printer/printer.h" |
2768 | -#include "printer/printersignalhandler.h" |
2769 | +#include "printer/signalratelimiter.h" |
2770 | |
2771 | #include <QAbstractListModel> |
2772 | #include <QByteArray> |
2773 | @@ -47,9 +47,13 @@ |
2774 | DuplexRole, |
2775 | SupportedDuplexModesRole, |
2776 | NameRole, |
2777 | + DeviceUriRole, |
2778 | + HostNameRole, |
2779 | + MakeRole, |
2780 | + LocationRole, |
2781 | EnabledRole, |
2782 | AcceptJobsRole, |
2783 | - PdfModeRole, |
2784 | + SharedRole, |
2785 | PrintQualityRole, |
2786 | SupportedPrintQualitiesRole, |
2787 | DescriptionRole, |
2788 | @@ -68,6 +72,9 @@ |
2789 | |
2790 | /* Indicates that this printers has no associated PPD. */ |
2791 | IsRawRole, |
2792 | + IsRemoteRole, |
2793 | + LastMessageRole, |
2794 | + CopiesRole, |
2795 | JobRole, |
2796 | LastRole = JobRole, |
2797 | }; |
2798 | @@ -92,13 +99,12 @@ |
2799 | const CountChangeSignal ¬ify = CountChangeSignal::Defer); |
2800 | void removePrinter(QSharedPointer<Printer> printer, |
2801 | const CountChangeSignal ¬ify = CountChangeSignal::Defer); |
2802 | - void movePrinter(const int &from, const int &to); |
2803 | void updatePrinter(QSharedPointer<Printer> old, |
2804 | QSharedPointer<Printer> newPrinter); |
2805 | PrinterBackend *m_backend; |
2806 | |
2807 | QList<QSharedPointer<Printer>> m_printers; |
2808 | - PrinterSignalHandler m_signalHandler; |
2809 | + SignalRateLimiter m_signalHandler; |
2810 | |
2811 | private Q_SLOTS: |
2812 | void printerLoaded(QSharedPointer<Printer> printer); |
2813 | @@ -127,6 +133,7 @@ |
2814 | void filterOnState(const PrinterEnum::State &state); |
2815 | void filterOnRecent(const bool recent); |
2816 | void filterOnPdf(const bool pdf); |
2817 | + void filterOnRemote(const bool remote); |
2818 | |
2819 | int count() const; |
2820 | protected: |
2821 | @@ -149,6 +156,8 @@ |
2822 | bool m_recentEnabled = false; |
2823 | bool m_pdfEnabled = false; |
2824 | bool m_pdf = false; |
2825 | + bool m_remoteEnabled = false; |
2826 | + bool m_remote = false; |
2827 | }; |
2828 | |
2829 | #endif // USC_PRINTER_MODEL_H |
2830 | |
2831 | === modified file 'modules/Ubuntu/Components/Extras/Printers/plugin.cpp' |
2832 | --- modules/Ubuntu/Components/Extras/Printers/plugin.cpp 2017-02-21 11:31:44 +0000 |
2833 | +++ modules/Ubuntu/Components/Extras/Printers/plugin.cpp 2017-03-20 13:32:24 +0000 |
2834 | @@ -54,5 +54,7 @@ |
2835 | |
2836 | qmlRegisterUncreatableType<PrinterEnum>(uri, 0, 1, "PrinterEnum", "Is an enum"); |
2837 | qRegisterMetaType<QList<PrinterDriver>>("QList<PrinterDriver>"); |
2838 | + qRegisterMetaType<QSharedPointer<PrinterJob>>("QSharedPointer<PrinterJob>"); |
2839 | qRegisterMetaType<QList<QSharedPointer<Printer>>>("QList<QSharedPointer<Printer>>"); |
2840 | + qRegisterMetaType<Device>("Device"); |
2841 | } |
2842 | |
2843 | === modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp' |
2844 | --- modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp 2017-02-24 17:47:22 +0000 |
2845 | +++ modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp 2017-03-20 13:32:24 +0000 |
2846 | @@ -14,22 +14,26 @@ |
2847 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2848 | */ |
2849 | |
2850 | +#include "i18n.h" |
2851 | #include "utils.h" |
2852 | |
2853 | #include "printer.h" |
2854 | |
2855 | #include <QDebug> |
2856 | +#include <QLocale> |
2857 | #include <QQmlEngine> |
2858 | |
2859 | Printer::Printer(PrinterBackend *backend, QObject *parent) |
2860 | : QObject(parent) |
2861 | , m_backend(backend) |
2862 | { |
2863 | - loadColorModel(); |
2864 | - loadPrintQualities(); |
2865 | - loadAcceptJobs(); |
2866 | + loadAttributes(); |
2867 | |
2868 | + m_jobs.setParent(this); |
2869 | m_jobs.filterOnPrinterName(name()); |
2870 | + |
2871 | + QObject::connect(m_backend, &PrinterBackend::printerStateChanged, |
2872 | + this, &Printer::onPrinterStateChanged); |
2873 | } |
2874 | |
2875 | Printer::~Printer() |
2876 | @@ -41,48 +45,87 @@ |
2877 | { |
2878 | if (!m_jobs.sourceModel()) { |
2879 | m_jobs.setSourceModel(jobModel); |
2880 | - m_jobs.sort(JobModel::Roles::IdRole); |
2881 | } |
2882 | } |
2883 | |
2884 | -void Printer::loadAcceptJobs() |
2885 | +void Printer::updateAcceptJobs(const QMap<QString, QVariant> &serverAttrs) |
2886 | { |
2887 | - auto opt = QStringLiteral("AcceptJobs"); |
2888 | - m_acceptJobs = m_backend->printerGetOption(name(), opt).toBool(); |
2889 | + m_acceptJobs = serverAttrs.value(QStringLiteral("AcceptJobs")).toBool(); |
2890 | } |
2891 | |
2892 | -void Printer::loadColorModel() |
2893 | +void Printer::updateColorModel(const QMap<QString, QVariant> &serverAttrs) |
2894 | { |
2895 | auto defModel = QStringLiteral("DefaultColorModel"); |
2896 | auto models = QStringLiteral("SupportedColorModels"); |
2897 | - auto result = m_backend->printerGetOptions( |
2898 | - name(), QStringList({defModel, models}) |
2899 | - ); |
2900 | |
2901 | - m_defaultColorModel = result.value(defModel).value<ColorModel>(); |
2902 | - m_supportedColorModels = result.value(models).value<QList<ColorModel>>(); |
2903 | + m_defaultColorModel = serverAttrs.value(defModel).value<ColorModel>(); |
2904 | + m_supportedColorModels = serverAttrs.value(models).value<QList<ColorModel>>(); |
2905 | |
2906 | if (m_supportedColorModels.size() == 0) { |
2907 | m_supportedColorModels.append(m_defaultColorModel); |
2908 | } |
2909 | } |
2910 | |
2911 | -void Printer::loadPrintQualities() |
2912 | +void Printer::updatePrintQualities(const QMap<QString, QVariant> &serverAttrs) |
2913 | { |
2914 | auto defQuality = QStringLiteral("DefaultPrintQuality"); |
2915 | auto qualities = QStringLiteral("SupportedPrintQualities"); |
2916 | - auto result = m_backend->printerGetOptions( |
2917 | - name(), QStringList({defQuality, qualities}) |
2918 | - ); |
2919 | |
2920 | - m_supportedPrintQualities = result.value(qualities).value<QList<PrintQuality>>(); |
2921 | - m_defaultPrintQuality = result.value(defQuality).value<PrintQuality>(); |
2922 | + m_supportedPrintQualities = serverAttrs.value(qualities).value<QList<PrintQuality>>(); |
2923 | + m_defaultPrintQuality = serverAttrs.value(defQuality).value<PrintQuality>(); |
2924 | |
2925 | if (m_supportedPrintQualities.size() == 0) { |
2926 | m_supportedPrintQualities.append(m_defaultPrintQuality); |
2927 | } |
2928 | } |
2929 | |
2930 | +void Printer::updateLastMessage(const QMap<QString, QVariant> &serverAttrs) |
2931 | +{ |
2932 | + m_stateMessage = serverAttrs.value(QStringLiteral("StateMessage")).toString(); |
2933 | +} |
2934 | + |
2935 | + |
2936 | +void Printer::updateDeviceUri(const QMap<QString, QVariant> &serverAttrs) |
2937 | +{ |
2938 | + m_deviceUri = serverAttrs.value(QStringLiteral("DeviceUri")).toString(); |
2939 | +} |
2940 | + |
2941 | +void Printer::updateCopies(const QMap<QString, QVariant> &serverAttrs) |
2942 | +{ |
2943 | + m_copies = serverAttrs.value(QStringLiteral("Copies")).toInt(); |
2944 | + if (m_copies <= 0) |
2945 | + m_copies = 1; |
2946 | +} |
2947 | + |
2948 | +void Printer::updateShared(const QMap<QString, QVariant> &serverAttrs) |
2949 | +{ |
2950 | + m_shared = serverAttrs.value(QStringLiteral("Shared")).toBool(); |
2951 | +} |
2952 | + |
2953 | +void Printer::loadAttributes() |
2954 | +{ |
2955 | + auto opts = QStringList({ |
2956 | + QStringLiteral("AcceptJobs"), |
2957 | + QStringLiteral("DefaultColorModel"), |
2958 | + QStringLiteral("SupportedColorModels"), |
2959 | + QStringLiteral("DefaultPrintQuality"), |
2960 | + QStringLiteral("SupportedPrintQualities"), |
2961 | + QStringLiteral("StateMessage"), |
2962 | + QStringLiteral("DeviceUri"), |
2963 | + QStringLiteral("Copies"), |
2964 | + QStringLiteral("Shared"), |
2965 | + }); |
2966 | + auto result = m_backend->printerGetOptions(name(), opts); |
2967 | + |
2968 | + updateAcceptJobs(result); |
2969 | + updateColorModel(result); |
2970 | + updatePrintQualities(result); |
2971 | + updateLastMessage(result); |
2972 | + updateDeviceUri(result); |
2973 | + updateCopies(result); |
2974 | + updateShared(result); |
2975 | +} |
2976 | + |
2977 | ColorModel Printer::defaultColorModel() const |
2978 | { |
2979 | return m_defaultColorModel; |
2980 | @@ -135,11 +178,26 @@ |
2981 | return m_backend->printerName(); |
2982 | } |
2983 | |
2984 | +QString Printer::deviceUri() const |
2985 | +{ |
2986 | + return m_deviceUri; |
2987 | +} |
2988 | + |
2989 | +QString Printer::make() const |
2990 | +{ |
2991 | + return m_backend->makeAndModel(); |
2992 | +} |
2993 | + |
2994 | QString Printer::description() const |
2995 | { |
2996 | return m_backend->description(); |
2997 | } |
2998 | |
2999 | +QString Printer::location() const |
3000 | +{ |
3001 | + return m_backend->location(); |
3002 | +} |
3003 | + |
3004 | QPageSize Printer::defaultPageSize() const |
3005 | { |
3006 | return m_backend->defaultPageSize(); |
3007 | @@ -170,6 +228,11 @@ |
3008 | return m_backend->state(); |
3009 | } |
3010 | |
3011 | +bool Printer::shared() const |
3012 | +{ |
3013 | + return m_shared; |
3014 | +} |
3015 | + |
3016 | bool Printer::acceptJobs() const |
3017 | { |
3018 | return m_acceptJobs; |
3019 | @@ -180,11 +243,21 @@ |
3020 | return m_backend->holdsDefinition(); |
3021 | } |
3022 | |
3023 | +bool Printer::isRemote() const |
3024 | +{ |
3025 | + return m_backend->isRemote(); |
3026 | +} |
3027 | + |
3028 | PrinterEnum::PrinterType Printer::type() const |
3029 | { |
3030 | return m_backend->type(); |
3031 | } |
3032 | |
3033 | +int Printer::copies() const |
3034 | +{ |
3035 | + return m_copies; |
3036 | +} |
3037 | + |
3038 | void Printer::setDefaultColorModel(const ColorModel &colorModel) |
3039 | { |
3040 | if (defaultColorModel() == colorModel) { |
3041 | @@ -242,6 +315,16 @@ |
3042 | } |
3043 | } |
3044 | |
3045 | +void Printer::setShared(const bool shared) |
3046 | +{ |
3047 | + if (this->shared() != shared) { |
3048 | + QString reply = m_backend->printerSetShared(name(), shared); |
3049 | + if (!reply.isEmpty()) { |
3050 | + qWarning() << Q_FUNC_INFO << "failed to set shared:" << reply; |
3051 | + } |
3052 | + } |
3053 | +} |
3054 | + |
3055 | void Printer::setDefaultPrintQuality(const PrintQuality &quality) |
3056 | { |
3057 | if (defaultPrintQuality() == quality) { |
3058 | @@ -278,6 +361,20 @@ |
3059 | m_backend->refresh(); |
3060 | } |
3061 | |
3062 | +void Printer::setCopies(const int &copies) |
3063 | +{ |
3064 | + if (this->copies() == copies) { |
3065 | + return; |
3066 | + } |
3067 | + |
3068 | + m_backend->printerSetCopies(name(), copies); |
3069 | +} |
3070 | + |
3071 | +QString Printer::lastMessage() const |
3072 | +{ |
3073 | + return m_stateMessage; |
3074 | +} |
3075 | + |
3076 | QAbstractItemModel* Printer::jobs() |
3077 | { |
3078 | auto ret = &m_jobs; |
3079 | @@ -296,16 +393,44 @@ |
3080 | && type() == other->type() |
3081 | && acceptJobs() == other->acceptJobs() |
3082 | && enabled() == other->enabled() |
3083 | - && state() == other->state(); |
3084 | + && state() == other->state() |
3085 | + && lastMessage() == other->lastMessage() |
3086 | + && deviceUri() == other->deviceUri() |
3087 | + && shared() == other->shared() |
3088 | + && copies() == other->copies() |
3089 | + && isRemote() == other->isRemote(); |
3090 | } |
3091 | |
3092 | void Printer::updateFrom(QSharedPointer<Printer> other) |
3093 | { |
3094 | PrinterBackend *tmp = m_backend; |
3095 | + |
3096 | + // Copy values from other printer which has been loaded in another thread |
3097 | + // Note: do not use loadAttributes otherwise can cause UI block |
3098 | + m_acceptJobs = other->m_acceptJobs; |
3099 | m_backend = other->m_backend; |
3100 | + m_defaultColorModel = other->m_defaultColorModel; |
3101 | + m_defaultPrintQuality = other->m_defaultPrintQuality; |
3102 | + m_deviceUri = other->m_deviceUri; |
3103 | + m_shared = other->m_shared; |
3104 | + m_stateMessage = other->m_stateMessage; |
3105 | + m_supportedColorModels = other->m_supportedColorModels; |
3106 | + m_supportedPrintQualities = other->m_supportedPrintQualities; |
3107 | + |
3108 | other->m_backend = tmp; |
3109 | - |
3110 | - loadColorModel(); |
3111 | - loadPrintQualities(); |
3112 | - loadAcceptJobs(); |
3113 | +} |
3114 | + |
3115 | +void Printer::onPrinterStateChanged( |
3116 | + const QString &text, const QString &printerUri, |
3117 | + const QString &printerName, uint printerState, |
3118 | + const QString &printerStateReason, bool acceptingJobs) |
3119 | +{ |
3120 | + Q_UNUSED(printerUri); |
3121 | + Q_UNUSED(printerState); |
3122 | + Q_UNUSED(printerStateReason); |
3123 | + Q_UNUSED(acceptingJobs); |
3124 | + |
3125 | + if (name() == printerName) { |
3126 | + m_stateMessage = text; |
3127 | + } |
3128 | } |
3129 | |
3130 | === modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printer.h' |
3131 | --- modules/Ubuntu/Components/Extras/Printers/printer/printer.h 2017-02-23 14:04:26 +0000 |
3132 | +++ modules/Ubuntu/Components/Extras/Printers/printer/printer.h 2017-03-20 13:32:24 +0000 |
3133 | @@ -49,17 +49,24 @@ |
3134 | QStringList supportedDuplexStrings() const; |
3135 | PrinterEnum::DuplexMode defaultDuplexMode() const; |
3136 | QString name() const; |
3137 | + QString deviceUri() const; |
3138 | + QString make() const; |
3139 | PrintQuality defaultPrintQuality() const; |
3140 | QList<PrintQuality> supportedPrintQualities() const; |
3141 | QString description() const; |
3142 | + QString location() const; |
3143 | QPageSize defaultPageSize() const; |
3144 | QList<QPageSize> supportedPageSizes() const; |
3145 | PrinterEnum::AccessControl accessControl() const; |
3146 | PrinterEnum::ErrorPolicy errorPolicy() const; |
3147 | PrinterEnum::State state() const; |
3148 | + bool shared() const; |
3149 | bool acceptJobs() const; |
3150 | bool holdsDefinition() const; |
3151 | + bool isRemote() const; |
3152 | + QString lastMessage() const; |
3153 | QAbstractItemModel* jobs(); |
3154 | + int copies() const; |
3155 | |
3156 | PrinterEnum::PrinterType type() const; |
3157 | |
3158 | @@ -68,9 +75,11 @@ |
3159 | void setDefaultDuplexMode(const PrinterEnum::DuplexMode &duplexMode); |
3160 | void setEnabled(const bool enabled); |
3161 | void setAcceptJobs(const bool accepting); |
3162 | + void setShared(const bool shared); |
3163 | void setDefaultPrintQuality(const PrintQuality &quality); |
3164 | void setDefaultPageSize(const QPageSize &pageSize); |
3165 | void setJobModel(JobModel* jobModel); |
3166 | + void setCopies(const int &copies); |
3167 | |
3168 | bool deepCompare(QSharedPointer<Printer> other) const; |
3169 | void updateFrom(QSharedPointer<Printer> other); |
3170 | @@ -79,10 +88,22 @@ |
3171 | public Q_SLOTS: |
3172 | int printFile(const QString &filepath, const PrinterJob *options); |
3173 | |
3174 | +private Q_SLOTS: |
3175 | + void onPrinterStateChanged( |
3176 | + const QString &text, const QString &printerUri, |
3177 | + const QString &printerName, uint printerState, |
3178 | + const QString &printerStateReason, bool acceptingJobs |
3179 | + ); |
3180 | + |
3181 | private: |
3182 | - void loadAcceptJobs(); |
3183 | - void loadColorModel(); |
3184 | - void loadPrintQualities(); |
3185 | + void updateAcceptJobs(const QMap<QString, QVariant> &serverAttrs); |
3186 | + void updateColorModel(const QMap<QString, QVariant> &serverAttrs); |
3187 | + void updatePrintQualities(const QMap<QString, QVariant> &serverAttrs); |
3188 | + void updateLastMessage(const QMap<QString, QVariant> &serverAttrs); |
3189 | + void updateDeviceUri(const QMap<QString, QVariant> &serverAttrs); |
3190 | + void updateCopies(const QMap<QString, QVariant> &serverAttrs); |
3191 | + void updateShared(const QMap<QString, QVariant> &serverAttrs); |
3192 | + void loadAttributes(); |
3193 | |
3194 | JobFilter m_jobs; |
3195 | PrinterBackend *m_backend; |
3196 | @@ -91,6 +112,11 @@ |
3197 | PrintQuality m_defaultPrintQuality; |
3198 | QList<PrintQuality> m_supportedPrintQualities; |
3199 | bool m_acceptJobs; |
3200 | + bool m_shared; |
3201 | + QString m_deviceUri; |
3202 | + int m_copies; |
3203 | + |
3204 | + QString m_stateMessage; |
3205 | }; |
3206 | |
3207 | #endif // USC_PRINTERS_PRINTER_H |
3208 | |
3209 | === modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp' |
3210 | --- modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp 2017-02-24 17:47:22 +0000 |
3211 | +++ modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp 2017-03-20 13:32:24 +0000 |
3212 | @@ -55,6 +55,8 @@ |
3213 | , m_title(QStringLiteral("")) |
3214 | , m_user("") |
3215 | { |
3216 | + connect(this, SIGNAL(printerAboutToChange(QSharedPointer<Printer>, QSharedPointer<Printer>)), |
3217 | + this, SLOT(onPrinterAboutToChange(QSharedPointer<Printer>, QSharedPointer<Printer>))); |
3218 | } |
3219 | |
3220 | PrinterJob::~PrinterJob() |
3221 | @@ -143,6 +145,69 @@ |
3222 | return m_landscape; |
3223 | } |
3224 | |
3225 | +void PrinterJob::loadAttributes(const QMap<QString, QVariant> &attributes) |
3226 | +{ |
3227 | + // Load the extra attributes for the job |
3228 | + // NOTE: we don't need to type check them as they have been filtered for us |
3229 | + |
3230 | + setCollate(attributes.value("Collate").toBool()); |
3231 | + setCopies(attributes.value("copies").toInt()); |
3232 | + |
3233 | + // No colorModel will result in PrinterJob using defaultColorModel |
3234 | + QString colorModel = attributes.value("ColorModel").toString(); |
3235 | + for (int i=0; i < m_printer->supportedColorModels().length(); i++) { |
3236 | + if (m_printer->supportedColorModels().at(i).name == colorModel) { |
3237 | + setColorModel(i); |
3238 | + } |
3239 | + } |
3240 | + |
3241 | + setCompletedTime(attributes.value("CompletedTime").toDateTime()); |
3242 | + setCreationTime(attributes.value("CreationTime").toDateTime()); |
3243 | + |
3244 | + // No duplexMode will result in PrinterJob using defaultDuplexMode |
3245 | + QString duplex = attributes.value("Duplex").toString(); |
3246 | + PrinterEnum::DuplexMode duplexMode = Utils::ppdChoiceToDuplexMode(duplex); |
3247 | + for (int i=0; i < m_printer->supportedDuplexModes().length(); i++) { |
3248 | + if (m_printer->supportedDuplexModes().at(i) == duplexMode) { |
3249 | + setDuplexMode(i); |
3250 | + } |
3251 | + } |
3252 | + |
3253 | + setImpressionsCompleted(attributes.value("impressionsCompleted").toInt()); |
3254 | + setLandscape(attributes.value("landscape").toBool()); |
3255 | + setMessages(attributes.value("messages").toStringList()); |
3256 | + |
3257 | + QStringList pageRanges = attributes.value("page-ranges").toStringList(); |
3258 | + if (pageRanges.isEmpty()) { |
3259 | + setPrintRangeMode(PrinterEnum::PrintRange::AllPages); |
3260 | + setPrintRange(QStringLiteral("")); |
3261 | + } else { |
3262 | + setPrintRangeMode(PrinterEnum::PrintRange::PageRange); |
3263 | + // Use groupSeparator as createSeparatedList adds "and" into the string |
3264 | + setPrintRange(pageRanges.join(QLocale::system().groupSeparator())); |
3265 | + } |
3266 | + |
3267 | + setProcessingTime(attributes.value("ProcessingTime").toDateTime()); |
3268 | + |
3269 | + // No quality will result in PrinterJob using defaultPrintQuality |
3270 | + QString quality = attributes.value("quality").toString(); |
3271 | + for (int i=0; i < m_printer->supportedPrintQualities().length(); i++) { |
3272 | + if (m_printer->supportedPrintQualities().at(i).name == quality) { |
3273 | + setQuality(i); |
3274 | + } |
3275 | + } |
3276 | + |
3277 | + setReverse(attributes.value("OutputOrder").toString() == "Reverse"); |
3278 | + |
3279 | + // If there was a state then set it |
3280 | + if (attributes.contains("State")) { |
3281 | + setState(static_cast<PrinterEnum::JobState>(attributes.value("State").toInt())); |
3282 | + } |
3283 | + |
3284 | + setSize(attributes.value("Size").toInt()); |
3285 | + setUser(attributes.value("User").toString()); |
3286 | +} |
3287 | + |
3288 | void PrinterJob::loadDefaults() |
3289 | { |
3290 | if (!m_printer) { |
3291 | @@ -150,62 +215,17 @@ |
3292 | return; |
3293 | } |
3294 | |
3295 | - qWarning() << Q_FUNC_INFO << jobId(); |
3296 | - |
3297 | if (jobId() > 0) { |
3298 | - // Load the extra attributes for the job |
3299 | - // NOTE: we don't need to type check them as they have been filtered for us |
3300 | - |
3301 | - QMap<QString, QVariant> attributes = m_backend->printerGetJobAttributes( |
3302 | - m_printer->name(), jobId()); |
3303 | - |
3304 | - setCollate(attributes.value("Collate").toBool()); |
3305 | - setCopies(attributes.value("copies").toInt()); |
3306 | - |
3307 | - // No colorModel will result in PrinterJob using defaultColorModel |
3308 | - QString colorModel = attributes.value("ColorModel").toString(); |
3309 | - for (int i=0; i < m_printer->supportedColorModels().length(); i++) { |
3310 | - if (m_printer->supportedColorModels().at(i).originalOption == colorModel) { |
3311 | - setColorModel(i); |
3312 | - } |
3313 | - } |
3314 | - |
3315 | - // No duplexMode will result in PrinterJob using defaultDuplexMode |
3316 | - QString duplex = attributes.value("Duplex").toString(); |
3317 | - PrinterEnum::DuplexMode duplexMode = Utils::ppdChoiceToDuplexMode(duplex); |
3318 | - for (int i=0; i < m_printer->supportedDuplexModes().length(); i++) { |
3319 | - if (m_printer->supportedDuplexModes().at(i) == duplexMode) { |
3320 | - setDuplexMode(i); |
3321 | - } |
3322 | - } |
3323 | - |
3324 | - setLandscape(attributes.value("landscape").toBool()); |
3325 | - setMessages(attributes.value("messages").toStringList()); |
3326 | - |
3327 | - QStringList pageRanges = attributes.value("page-ranges").toStringList(); |
3328 | - if (pageRanges.isEmpty()) { |
3329 | - setPrintRangeMode(PrinterEnum::PrintRange::AllPages); |
3330 | - setPrintRange(QStringLiteral("")); |
3331 | - } else { |
3332 | - setPrintRangeMode(PrinterEnum::PrintRange::PageRange); |
3333 | - // Use groupSeparator as createSeparatedList adds "and" into the string |
3334 | - setPrintRange(pageRanges.join(QLocale::system().groupSeparator())); |
3335 | - } |
3336 | - |
3337 | - // No quality will result in PrinterJob using defaultPrintQuality |
3338 | - QString quality = attributes.value("quality").toString(); |
3339 | - for (int i=0; i < m_printer->supportedPrintQualities().length(); i++) { |
3340 | - if (m_printer->supportedPrintQualities().at(i).name == quality) { |
3341 | - setQuality(i); |
3342 | - } |
3343 | - } |
3344 | - |
3345 | - setReverse(attributes.value("OutputOrder").toString() == "Reverse"); |
3346 | + loadAttributes( |
3347 | + m_backend->printerGetJobAttributes( |
3348 | + printerName(), jobId() |
3349 | + ) |
3350 | + ); |
3351 | + } else { |
3352 | + setColorModel(m_printer->supportedColorModels().indexOf(m_printer->defaultColorModel())); |
3353 | + setDuplexMode(m_printer->supportedDuplexModes().indexOf(m_printer->defaultDuplexMode())); |
3354 | + setQuality(m_printer->supportedPrintQualities().indexOf(m_printer->defaultPrintQuality())); |
3355 | } |
3356 | - |
3357 | - setColorModel(m_printer->supportedColorModels().indexOf(m_printer->defaultColorModel())); |
3358 | - setDuplexMode(m_printer->supportedDuplexModes().indexOf(m_printer->defaultDuplexMode())); |
3359 | - setQuality(m_printer->supportedPrintQualities().indexOf(m_printer->defaultPrintQuality())); |
3360 | } |
3361 | |
3362 | QStringList PrinterJob::messages() const |
3363 | @@ -373,16 +393,16 @@ |
3364 | void PrinterJob::setPrinter(QSharedPointer<Printer> printer) |
3365 | { |
3366 | if (m_printer != printer) { |
3367 | - m_printer = printer; |
3368 | + Q_EMIT printerAboutToChange(m_printer, printer); |
3369 | + m_printer = printer; |
3370 | |
3371 | - if (printer->name() != m_printerName) { |
3372 | + if (printer->name() != m_printerName) { |
3373 | m_printerName = printer->name(); |
3374 | Q_EMIT printerNameChanged(); |
3375 | - } |
3376 | + } |
3377 | |
3378 | - Q_EMIT printerChanged(); |
3379 | + Q_EMIT printerChanged(); |
3380 | } |
3381 | - loadDefaults(); |
3382 | } |
3383 | |
3384 | void PrinterJob::setPrintRange(const QString &printRange) |
3385 | @@ -478,33 +498,61 @@ |
3386 | // Return true if they are the same |
3387 | return collate() == other->collate() |
3388 | && colorModel() == other->colorModel() |
3389 | + && completedTime() == other->completedTime() |
3390 | && copies() == other->copies() |
3391 | + && creationTime() == other->creationTime() |
3392 | && duplexMode() == other->duplexMode() |
3393 | + && impressionsCompleted() == other->impressionsCompleted() |
3394 | && landscape() == other->landscape() |
3395 | + && messages() == other->messages() |
3396 | && printRange() == other->printRange() |
3397 | && printRangeMode() == other->printRangeMode() |
3398 | + && processingTime() == other->processingTime() |
3399 | && quality() == other->quality() |
3400 | && reverse() == other->reverse() |
3401 | + && size() == other->size() |
3402 | && state() == other->state() |
3403 | - && title() == other->title(); |
3404 | + && title() == other->title() |
3405 | + && user() == other->user(); |
3406 | } |
3407 | |
3408 | void PrinterJob::updateFrom(QSharedPointer<PrinterJob> other) |
3409 | { |
3410 | setCollate(other->collate()); |
3411 | setColorModel(other->colorModel()); |
3412 | + setCompletedTime(other->completedTime()); |
3413 | setCopies(other->copies()); |
3414 | + setCreationTime(other->creationTime()); |
3415 | setDuplexMode(other->duplexMode()); |
3416 | + setImpressionsCompleted(other->impressionsCompleted()); |
3417 | setLandscape(other->landscape()); |
3418 | + setMessages(other->messages()); |
3419 | setPrintRange(other->printRange()); |
3420 | setPrintRangeMode(other->printRangeMode()); |
3421 | + setProcessingTime(other->processingTime()); |
3422 | setQuality(other->quality()); |
3423 | setReverse(other->reverse()); |
3424 | + setSize(other->size()); |
3425 | setState(other->state()); |
3426 | setTitle(other->title()); |
3427 | + setUser(other->user()); |
3428 | } |
3429 | |
3430 | QString PrinterJob::user() const |
3431 | { |
3432 | return m_user; |
3433 | } |
3434 | + |
3435 | +void PrinterJob::onPrinterAboutToChange(QSharedPointer<Printer> old, |
3436 | + QSharedPointer<Printer> replacement) |
3437 | +{ |
3438 | + /* If we have an old printer, and the current copies value matches that |
3439 | + of the old printer's, we'll use the new printer's copy value. |
3440 | + |
3441 | + The second case is if there was no old printer. */ |
3442 | + bool haveOld = old && replacement && (copies() == old->copies()); |
3443 | + bool noOld = !old && replacement; |
3444 | + if (haveOld || noOld) { |
3445 | + setCopies(replacement->copies()); |
3446 | + } |
3447 | +} |
3448 | |
3449 | === modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h' |
3450 | --- modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h 2017-02-23 14:04:26 +0000 |
3451 | +++ modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h 2017-03-20 13:32:24 +0000 |
3452 | @@ -58,8 +58,6 @@ |
3453 | Q_PROPERTY(PrinterEnum::JobState state READ state NOTIFY stateChanged) |
3454 | Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) |
3455 | Q_PROPERTY(QString user READ user NOTIFY userChanged) |
3456 | - |
3457 | - friend class PrinterCupsBackend; |
3458 | public: |
3459 | explicit PrinterJob(QString dest, |
3460 | PrinterBackend *backend, |
3461 | @@ -97,31 +95,34 @@ |
3462 | PrinterEnum::DuplexMode getDuplexMode() const; |
3463 | ColorModel getColorModel() const; |
3464 | PrintQuality getPrintQuality() const; |
3465 | + void loadAttributes(const QMap<QString, QVariant>& attributes); |
3466 | + void loadDefaults(); |
3467 | Q_INVOKABLE void printFile(const QUrl &url); |
3468 | void setCollate(const bool collate); |
3469 | void setColorModel(const int colorModel); |
3470 | + void setCompletedTime(const QDateTime &completedTime); |
3471 | void setCopies(const int copies); |
3472 | + void setCreationTime(const QDateTime &creationTime); |
3473 | void setDuplexMode(const int duplexMode); |
3474 | void setImpressionsCompleted(const int &impressionsCompleted); |
3475 | + void setIsTwoSided(const bool isTwoSided); |
3476 | void setLandscape(const bool landscape); |
3477 | + void setMessages(const QStringList &messages); |
3478 | void setPrinter(QSharedPointer<Printer> printer); |
3479 | void setPrintRange(const QString &printRange); |
3480 | void setPrintRangeMode(const PrinterEnum::PrintRange printRangeMode); |
3481 | + void setProcessingTime(const QDateTime &processingTime); |
3482 | void setQuality(const int quality); |
3483 | void setReverse(const bool reverse); |
3484 | + void setSize(const int size); |
3485 | + void setState(const PrinterEnum::JobState &state); |
3486 | void setTitle(const QString &title); |
3487 | + void setUser(const QString &user); |
3488 | |
3489 | void updateFrom(QSharedPointer<PrinterJob> other); |
3490 | private Q_SLOTS: |
3491 | - void loadDefaults(); |
3492 | - void setCompletedTime(const QDateTime &completedTime); |
3493 | - void setCreationTime(const QDateTime &creationTime); |
3494 | - void setIsTwoSided(const bool isTwoSided); |
3495 | - void setMessages(const QStringList &messages); |
3496 | - void setProcessingTime(const QDateTime &processingTime); |
3497 | - void setSize(const int size); |
3498 | - void setState(const PrinterEnum::JobState &state); |
3499 | - void setUser(const QString &user); |
3500 | + void onPrinterAboutToChange(QSharedPointer<Printer> old, |
3501 | + QSharedPointer<Printer> replacement); |
3502 | Q_SIGNALS: |
3503 | void collateChanged(); |
3504 | void colorModelChanged(); |
3505 | @@ -134,6 +135,8 @@ |
3506 | void isTwoSidedChanged(); |
3507 | void landscapeChanged(); |
3508 | void messagesChanged(); |
3509 | + void printerAboutToChange(QSharedPointer<Printer> old, |
3510 | + QSharedPointer<Printer> replacement); |
3511 | void printerChanged(); |
3512 | void printerNameChanged(); |
3513 | void printRangeChanged(); |
3514 | |
3515 | === renamed file 'modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.cpp' => 'modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.cpp' |
3516 | --- modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.cpp 2017-02-21 10:46:29 +0000 |
3517 | +++ modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.cpp 2017-03-20 13:32:24 +0000 |
3518 | @@ -14,9 +14,9 @@ |
3519 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3520 | */ |
3521 | |
3522 | -#include "printersignalhandler.h" |
3523 | +#include "signalratelimiter.h" |
3524 | |
3525 | -PrinterSignalHandler::PrinterSignalHandler(int triggerEventDelay, |
3526 | +SignalRateLimiter::SignalRateLimiter(int triggerEventDelay, |
3527 | QObject *parent) |
3528 | : QObject(parent) |
3529 | { |
3530 | @@ -24,11 +24,11 @@ |
3531 | connect(&m_timer, SIGNAL(timeout()), this, SLOT(process())); |
3532 | } |
3533 | |
3534 | -PrinterSignalHandler::~PrinterSignalHandler() |
3535 | +SignalRateLimiter::~SignalRateLimiter() |
3536 | { |
3537 | } |
3538 | |
3539 | -void PrinterSignalHandler::process() |
3540 | +void SignalRateLimiter::process() |
3541 | { |
3542 | Q_FOREACH(auto printer, m_unprocessed) { |
3543 | Q_EMIT printerModified(printer); |
3544 | @@ -37,7 +37,7 @@ |
3545 | m_timer.stop(); |
3546 | } |
3547 | |
3548 | -void PrinterSignalHandler::onPrinterModified( |
3549 | +void SignalRateLimiter::onPrinterModified( |
3550 | const QString &text, const QString &printerUri, |
3551 | const QString &printerName, uint printerState, |
3552 | const QString &printerStateReason, bool acceptingJobs) |
3553 | @@ -49,11 +49,22 @@ |
3554 | Q_UNUSED(printerStateReason); |
3555 | Q_UNUSED(acceptingJobs); |
3556 | |
3557 | + // Track when the first item was added to the unprocessed queue |
3558 | + if (m_unprocessed.count() == 0) { |
3559 | + m_unprocessed_time = QDateTime::currentDateTime(); |
3560 | + } |
3561 | + |
3562 | m_unprocessed << printerName; |
3563 | m_timer.start(); |
3564 | + |
3565 | + // Ensure that process is fired if we have reached four times |
3566 | + // longer than the timer, this is due to many signals coming in rapidly |
3567 | + if (m_unprocessed_time.msecsTo(QDateTime::currentDateTime()) > m_timer.interval() * 4) { |
3568 | + process(); |
3569 | + } |
3570 | } |
3571 | |
3572 | -void PrinterSignalHandler::onPrinterStateChanged( |
3573 | +void SignalRateLimiter::onPrinterStateChanged( |
3574 | const QString &text, const QString &printerUri, |
3575 | const QString &printerName, uint printerState, |
3576 | const QString &printerStateReason, bool acceptingJobs) |
3577 | @@ -64,6 +75,17 @@ |
3578 | Q_UNUSED(printerStateReason); |
3579 | Q_UNUSED(acceptingJobs); |
3580 | |
3581 | + // Track when the first item was added to the unprocessed queue |
3582 | + if (m_unprocessed.count() == 0) { |
3583 | + m_unprocessed_time = QDateTime::currentDateTime(); |
3584 | + } |
3585 | + |
3586 | m_unprocessed << printerName; |
3587 | m_timer.start(); |
3588 | + |
3589 | + // Ensure that process is fired if we have reached four times |
3590 | + // longer than the timer, this is due to many signals coming in rapidly |
3591 | + if (m_unprocessed_time.msecsTo(QDateTime::currentDateTime()) > m_timer.interval() * 4) { |
3592 | + process(); |
3593 | + } |
3594 | } |
3595 | |
3596 | === renamed file 'modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.h' => 'modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.h' |
3597 | --- modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.h 2017-02-21 10:46:29 +0000 |
3598 | +++ modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.h 2017-03-20 13:32:24 +0000 |
3599 | @@ -14,24 +14,26 @@ |
3600 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3601 | */ |
3602 | |
3603 | -#ifndef USC_PRINTER_SIGNAL_HANDLER_H |
3604 | -#define USC_PRINTER_SIGNAL_HANDLER_H |
3605 | +#ifndef USC_SIGNAL_RATE_LIMITER_H |
3606 | +#define USC_SIGNAL_RATE_LIMITER_H |
3607 | |
3608 | #include "printers_global.h" |
3609 | |
3610 | +#include <QDateTime> |
3611 | #include <QObject> |
3612 | #include <QSet> |
3613 | #include <QTimer> |
3614 | |
3615 | -class PRINTERS_DECL_EXPORT PrinterSignalHandler : public QObject |
3616 | +class PRINTERS_DECL_EXPORT SignalRateLimiter : public QObject |
3617 | { |
3618 | Q_OBJECT |
3619 | QTimer m_timer; |
3620 | QSet<QString> m_unprocessed; |
3621 | + QDateTime m_unprocessed_time; |
3622 | public: |
3623 | - explicit PrinterSignalHandler(int triggerEventDelay = 500, |
3624 | + explicit SignalRateLimiter(int triggerEventDelay = 500, |
3625 | QObject *parent = Q_NULLPTR); |
3626 | - ~PrinterSignalHandler(); |
3627 | + ~SignalRateLimiter(); |
3628 | |
3629 | public Q_SLOTS: |
3630 | void onPrinterModified( |
3631 | @@ -52,4 +54,4 @@ |
3632 | void printerModified(const QString &printerName); |
3633 | }; |
3634 | |
3635 | -#endif // USC_PRINTER_SIGNAL_HANDLER_H |
3636 | +#endif // USC_SIGNAL_RATE_LIMITERR_H |
3637 | |
3638 | === modified file 'modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp' |
3639 | --- modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp 2017-02-24 13:14:13 +0000 |
3640 | +++ modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp 2017-03-20 13:32:24 +0000 |
3641 | @@ -15,6 +15,7 @@ |
3642 | */ |
3643 | |
3644 | #include "backend/backend_cups.h" |
3645 | +#include "i18n.h" |
3646 | #include "printers/printers.h" |
3647 | #include "cupsdnotifier.h" // Note: this file was generated. |
3648 | |
3649 | @@ -33,6 +34,7 @@ |
3650 | Printers::Printers(PrinterBackend *backend, QObject *parent) |
3651 | : QObject(parent) |
3652 | , m_backend(backend) |
3653 | + , m_devices(backend) |
3654 | , m_drivers(backend) |
3655 | , m_model(backend) |
3656 | , m_jobs(backend) |
3657 | @@ -56,8 +58,20 @@ |
3658 | const QModelIndex &parent, int first, int) { |
3659 | int jobId = m_jobs.data(m_jobs.index(first, 0, parent), |
3660 | JobModel::Roles::IdRole).toInt(); |
3661 | - jobAdded(m_jobs.getJobById(jobId)); |
3662 | - }); |
3663 | + QString printerName = m_jobs.data( |
3664 | + m_jobs.index(first, 0, parent), |
3665 | + JobModel::Roles::PrinterNameRole |
3666 | + ).toString(); |
3667 | + |
3668 | + jobAdded(m_jobs.getJob(printerName, jobId)); |
3669 | + }); |
3670 | + |
3671 | + // If the jobModel forces a refresh, load extended attributes for the job |
3672 | + connect(&m_jobs, &JobModel::forceJobRefresh, [this]( |
3673 | + const QString &printerName, const int jobId) { |
3674 | + jobAdded(m_jobs.getJob(printerName, jobId)); |
3675 | + }); |
3676 | + |
3677 | connect(&m_model, &QAbstractItemModel::rowsInserted, [this]( |
3678 | const QModelIndex &parent, int first, int) { |
3679 | auto printer = m_model.data( |
3680 | @@ -76,6 +90,17 @@ |
3681 | ); |
3682 | } |
3683 | |
3684 | + // Ensure existing jobs have been added, incase some were added before |
3685 | + // the connect to rowsInserted was done |
3686 | + for (int i = 0; i < m_jobs.rowCount(); i++) { |
3687 | + jobAdded( |
3688 | + m_jobs.getJob( |
3689 | + m_jobs.data(m_jobs.index(i), JobModel::Roles::PrinterNameRole).toString(), |
3690 | + m_jobs.data(m_jobs.index(i), JobModel::IdRole).toInt() |
3691 | + ) |
3692 | + ); |
3693 | + } |
3694 | + |
3695 | if (m_backend->type() == PrinterEnum::PrinterType::CupsType) { |
3696 | ((PrinterCupsBackend*) m_backend)->createSubscription(); |
3697 | } |
3698 | @@ -103,6 +128,29 @@ |
3699 | return ret; |
3700 | } |
3701 | |
3702 | +QAbstractItemModel* Printers::remotePrinters() |
3703 | +{ |
3704 | + m_devices.load(); |
3705 | + auto ret = &m_devices; |
3706 | + QQmlEngine::setObjectOwnership(ret, QQmlEngine::CppOwnership); |
3707 | + return ret; |
3708 | +} |
3709 | +QAbstractItemModel* Printers::localPrinters() |
3710 | +{ |
3711 | + /* Lazily initialize this model. Local printers are discerned from remotes |
3712 | + by checking if they are remote. */ |
3713 | + if (!m_localPrinters.sourceModel()) { |
3714 | + m_localPrinters.setSourceModel(&m_model); |
3715 | + m_localPrinters.filterOnRemote(false); |
3716 | + m_localPrinters.setSortRole(PrinterModel::Roles::DefaultPrinterRole); |
3717 | + m_localPrinters.sort(0, Qt::DescendingOrder); |
3718 | + } |
3719 | + |
3720 | + auto ret = &m_localPrinters; |
3721 | + QQmlEngine::setObjectOwnership(ret, QQmlEngine::CppOwnership); |
3722 | + return ret; |
3723 | +} |
3724 | + |
3725 | QAbstractItemModel* Printers::printJobs() |
3726 | { |
3727 | auto ret = &m_jobs; |
3728 | @@ -143,11 +191,33 @@ |
3729 | return new PrinterJob(printerName, m_backend); |
3730 | } |
3731 | |
3732 | +QAbstractItemModel* Printers::createJobFilter() |
3733 | +{ |
3734 | + // Note: If called by QML, it gains ownership of the job filter. |
3735 | + JobFilter *filter = new JobFilter(); |
3736 | + filter->setSourceModel(&m_jobs); |
3737 | + |
3738 | + filter->setSortRole(JobModel::Roles::CreationTimeRole); |
3739 | + filter->sort(0, Qt::AscendingOrder); |
3740 | + |
3741 | + return filter; |
3742 | +} |
3743 | + |
3744 | void Printers::cancelJob(const QString &printerName, const int jobId) |
3745 | { |
3746 | m_backend->cancelJob(printerName, jobId); |
3747 | } |
3748 | |
3749 | +void Printers::holdJob(const QString &printerName, const int jobId) |
3750 | +{ |
3751 | + m_backend->holdJob(printerName, jobId); |
3752 | +} |
3753 | + |
3754 | +void Printers::releaseJob(const QString &printerName, const int jobId) |
3755 | +{ |
3756 | + m_backend->releaseJob(printerName, jobId); |
3757 | +} |
3758 | + |
3759 | void Printers::setDefaultPrinterName(const QString &name) |
3760 | { |
3761 | QString reply = m_backend->printerSetDefault(name); |
3762 | @@ -164,6 +234,11 @@ |
3763 | } |
3764 | } |
3765 | |
3766 | +void Printers::searchForDevices() |
3767 | +{ |
3768 | + m_devices.load(); |
3769 | +} |
3770 | + |
3771 | bool Printers::addPrinter(const QString &name, const QString &ppd, |
3772 | const QString &device, const QString &description, |
3773 | const QString &location) |
3774 | @@ -174,6 +249,9 @@ |
3775 | m_lastMessage = reply; |
3776 | return false; |
3777 | } |
3778 | + |
3779 | + provisionPrinter(name); |
3780 | + |
3781 | return true; |
3782 | } |
3783 | |
3784 | @@ -189,9 +267,19 @@ |
3785 | m_lastMessage = reply; |
3786 | return false; |
3787 | } |
3788 | + |
3789 | + provisionPrinter(name); |
3790 | + |
3791 | return true; |
3792 | } |
3793 | |
3794 | +void Printers::provisionPrinter(const QString &name) |
3795 | +{ |
3796 | + // We mimic what System Config Printer does here. |
3797 | + m_backend->printerSetEnabled(name, true); |
3798 | + m_backend->printerSetAcceptJobs(name, true); |
3799 | +} |
3800 | + |
3801 | bool Printers::removePrinter(const QString &name) |
3802 | { |
3803 | QString reply = m_backend->printerDelete(name); |
3804 | @@ -206,8 +294,21 @@ |
3805 | void Printers::jobAdded(QSharedPointer<PrinterJob> job) |
3806 | { |
3807 | auto printer = m_model.getPrinterByName(job->printerName()); |
3808 | - if (printer && job) |
3809 | - job->setPrinter(printer); |
3810 | + |
3811 | + // Check if we have a valid printer, does not need to be loaded as JobLoader |
3812 | + // creates it's own Backend. |
3813 | + if (printer && job) { |
3814 | + // TODO: this printer may not be fully loaded |
3815 | + // Which has the side affect of colorModel, duplex, quality not working |
3816 | + // in PrinterJob as Printer::supportedColorModels etc fail |
3817 | + // Potentially trigger loadPrinter and listen for the new printer? |
3818 | + |
3819 | + // Set the printer to the job |
3820 | + m_jobs.updateJobPrinter(job, printer); |
3821 | + |
3822 | + // Trigger JobLoader to load extended attributes in the background |
3823 | + m_backend->requestJobExtendedAttributes(printer, job); |
3824 | + } |
3825 | } |
3826 | |
3827 | void Printers::printerAdded(QSharedPointer<Printer> printer) |
3828 | @@ -223,10 +324,9 @@ |
3829 | ).toString(); |
3830 | |
3831 | int jobId = m_jobs.data(idx, JobModel::Roles::IdRole).toInt(); |
3832 | - auto job = m_jobs.getJobById(jobId); |
3833 | + auto job = m_jobs.getJob(printerName, jobId); |
3834 | if (printerName == printer->name() && !job->printer()) { |
3835 | - job->setPrinter(printer); |
3836 | - return; |
3837 | + jobAdded(job); |
3838 | } |
3839 | } |
3840 | } |
3841 | @@ -243,3 +343,28 @@ |
3842 | m_backend->requestPrinter(name); |
3843 | } |
3844 | } |
3845 | + |
3846 | +void Printers::printTestPage(const QString &name) |
3847 | +{ |
3848 | + |
3849 | + auto printer = m_model.getPrinterByName(name); |
3850 | + if (!printer) { |
3851 | + qWarning() << Q_FUNC_INFO << "no known printer named" << name; |
3852 | + return; |
3853 | + } |
3854 | + |
3855 | + auto page = QStandardPaths::locate(QStandardPaths::GenericDataLocation, |
3856 | + "cups/data/default-testpage.pdf", |
3857 | + QStandardPaths::LocateFile); |
3858 | + |
3859 | + if (page.isEmpty()) { |
3860 | + qCritical() << Q_FUNC_INFO << "Could not find test page."; |
3861 | + return; |
3862 | + } |
3863 | + |
3864 | + auto job = new PrinterJob(name, m_backend); |
3865 | + job->setPrinter(printer); |
3866 | + job->setTitle(__("Test page")); |
3867 | + job->printFile(QUrl::fromLocalFile(page)); |
3868 | + job->deleteLater(); |
3869 | +} |
3870 | |
3871 | === modified file 'modules/Ubuntu/Components/Extras/Printers/printers/printers.h' |
3872 | --- modules/Ubuntu/Components/Extras/Printers/printers/printers.h 2017-02-24 12:20:07 +0000 |
3873 | +++ modules/Ubuntu/Components/Extras/Printers/printers/printers.h 2017-03-20 13:32:24 +0000 |
3874 | @@ -19,6 +19,7 @@ |
3875 | |
3876 | #include "printers_global.h" |
3877 | |
3878 | +#include "models/devicemodel.h" |
3879 | #include "models/drivermodel.h" |
3880 | #include "models/printermodel.h" |
3881 | #include "printer/printer.h" |
3882 | @@ -36,6 +37,8 @@ |
3883 | Q_OBJECT |
3884 | Q_PROPERTY(QAbstractItemModel* allPrinters READ allPrinters CONSTANT) |
3885 | Q_PROPERTY(QAbstractItemModel* allPrintersWithPdf READ allPrintersWithPdf CONSTANT) |
3886 | + Q_PROPERTY(QAbstractItemModel* remotePrinters READ remotePrinters CONSTANT) |
3887 | + Q_PROPERTY(QAbstractItemModel* localPrinters READ localPrinters CONSTANT) |
3888 | Q_PROPERTY(QAbstractItemModel* printJobs READ printJobs CONSTANT) |
3889 | Q_PROPERTY(QAbstractItemModel* drivers READ drivers CONSTANT) |
3890 | Q_PROPERTY(QString driverFilter READ driverFilter WRITE setDriverFilter NOTIFY driverFilterChanged) |
3891 | @@ -51,6 +54,8 @@ |
3892 | |
3893 | QAbstractItemModel* allPrinters(); |
3894 | QAbstractItemModel* allPrintersWithPdf(); |
3895 | + QAbstractItemModel* remotePrinters(); |
3896 | + QAbstractItemModel* localPrinters(); |
3897 | QAbstractItemModel* printJobs(); |
3898 | QAbstractItemModel* drivers(); |
3899 | QString driverFilter() const; |
3900 | @@ -62,7 +67,11 @@ |
3901 | |
3902 | public Q_SLOTS: |
3903 | PrinterJob* createJob(const QString &printerName); |
3904 | + QAbstractItemModel* createJobFilter(); |
3905 | + |
3906 | void cancelJob(const QString &printerName, const int jobId); |
3907 | + void holdJob(const QString &printerName, const int jobId); |
3908 | + void releaseJob(const QString &printerName, const int jobId); |
3909 | |
3910 | /* Instructs us to start loading drivers and what have you. In most cases, |
3911 | the user is likely to merely configure existing printers/jobs. Loading |
3912 | @@ -70,6 +79,9 @@ |
3913 | add printers, this method should be called first. */ |
3914 | void prepareToAddPrinter(); |
3915 | |
3916 | + // Starts a search for devices on local and remote resources. |
3917 | + void searchForDevices(); |
3918 | + |
3919 | bool addPrinter(const QString &name, const QString &ppd, |
3920 | const QString &device, const QString &description, |
3921 | const QString &location); |
3922 | @@ -83,6 +95,8 @@ |
3923 | // Instruct us to start (eagerly) loading a printer. |
3924 | void loadPrinter(const QString &name); |
3925 | |
3926 | + void printTestPage(const QString &name); |
3927 | + |
3928 | private Q_SLOTS: |
3929 | void jobAdded(QSharedPointer<PrinterJob> job); |
3930 | void printerAdded(QSharedPointer<Printer> printer); |
3931 | @@ -92,12 +106,16 @@ |
3932 | void driverFilterChanged(); |
3933 | |
3934 | private: |
3935 | + void provisionPrinter(const QString &name); |
3936 | PrinterBackend *m_backend; |
3937 | + DeviceModel m_devices; |
3938 | DriverModel m_drivers; |
3939 | PrinterModel m_model; |
3940 | JobModel m_jobs; |
3941 | PrinterFilter m_allPrinters; |
3942 | PrinterFilter m_allPrintersWithPdf; |
3943 | + PrinterFilter m_remotePrinters; |
3944 | + PrinterFilter m_localPrinters; |
3945 | PrinterFilter m_recentPrinters; |
3946 | QString m_lastMessage; |
3947 | }; |
3948 | |
3949 | === modified file 'modules/Ubuntu/Components/Extras/Printers/structs.h' |
3950 | --- modules/Ubuntu/Components/Extras/Printers/structs.h 2017-02-23 14:04:26 +0000 |
3951 | +++ modules/Ubuntu/Components/Extras/Printers/structs.h 2017-03-20 13:32:24 +0000 |
3952 | @@ -84,6 +84,87 @@ |
3953 | } |
3954 | }; |
3955 | |
3956 | +struct Device |
3957 | +{ |
3958 | +public: |
3959 | + QString cls; |
3960 | + QString id; |
3961 | + QString info; |
3962 | + QString makeModel; |
3963 | + QString uri; |
3964 | + QString location; |
3965 | + PrinterEnum::DeviceType type() |
3966 | + { |
3967 | + auto parts = uri.split(":", QString::SkipEmptyParts); |
3968 | + QString scheme = parts.size() > 0 ? parts[0] : QStringLiteral(""); |
3969 | + if (scheme == QStringLiteral("dnssd")) |
3970 | + return PrinterEnum::DeviceType::DNSSDType; |
3971 | + else if (scheme == QStringLiteral("lpd")) |
3972 | + return PrinterEnum::DeviceType::LPDType; |
3973 | + else if (scheme == QStringLiteral("ipps")) |
3974 | + return PrinterEnum::DeviceType::IppSType; |
3975 | + else if (scheme == QStringLiteral("ipp14")) |
3976 | + return PrinterEnum::DeviceType::Ipp14Type; |
3977 | + else if (scheme == QStringLiteral("http")) |
3978 | + return PrinterEnum::DeviceType::HttpType; |
3979 | + else if (scheme == QStringLiteral("beh")) |
3980 | + return PrinterEnum::DeviceType::BehType; |
3981 | + else if (scheme == QStringLiteral("socket")) |
3982 | + return PrinterEnum::DeviceType::SocketType; |
3983 | + else if (scheme == QStringLiteral("https")) |
3984 | + return PrinterEnum::DeviceType::HttpsType; |
3985 | + else if (scheme == QStringLiteral("ipp")) |
3986 | + return PrinterEnum::DeviceType::IppType; |
3987 | + else if (scheme == QStringLiteral("hp")) |
3988 | + return PrinterEnum::DeviceType::HPType; |
3989 | + else if (scheme == QStringLiteral("usb")) |
3990 | + return PrinterEnum::DeviceType::USBType; |
3991 | + else if (scheme == QStringLiteral("hpfax")) |
3992 | + return PrinterEnum::DeviceType::HPFaxType; |
3993 | + else |
3994 | + return PrinterEnum::DeviceType::UnknownType; |
3995 | + } |
3996 | + |
3997 | + QString toString() const { |
3998 | + /* 1. Split the id, which is of format "KEY:VAL; … KEYN:VALN;" into |
3999 | + ["KEY:VAL", …, "KEYN:VALN"] |
4000 | + 2. Split each pair into |
4001 | + ["KEY", "VAL"] … ["KEYN", "VALN"]*/ |
4002 | + QMap<QString, QString> idMap; |
4003 | + auto pairs = id.split(";"); |
4004 | + Q_FOREACH(const QString &pair, pairs) { |
4005 | + auto keyValue = pair.split(":"); |
4006 | + |
4007 | + /* Sometimes key,val pairs are not terminated by ";". We just |
4008 | + use the first value in that case. E.g.: |
4009 | + "MFG:HP MDL:Laserfjert;" |
4010 | + Will give "HP" as MFG, and "" as MDL. */ |
4011 | + if (keyValue.size() >= 2) { |
4012 | + idMap[keyValue[0]] = keyValue[1]; |
4013 | + } |
4014 | + } |
4015 | + auto mfg = idMap.value("MFG", ""); |
4016 | + auto mdl = idMap.value("MDL", ""); |
4017 | + |
4018 | + /* If the MDL field contains CMD, somebody forgot to terminate, and we |
4019 | + remove it. */ |
4020 | + if (mdl.contains("CMD")) { |
4021 | + mdl = mdl.split("CMD")[0]; |
4022 | + } |
4023 | + |
4024 | + return QString("%1 %2").arg(mfg).arg(mdl); |
4025 | + } |
4026 | + |
4027 | + bool operator==(const Device &other) |
4028 | + { |
4029 | + return ((cls == other.cls) && (id == other.id) && (info == other.info) && |
4030 | + (makeModel == other.makeModel) && (uri == other.uri) && |
4031 | + (location == other.location)); |
4032 | + } |
4033 | +}; |
4034 | + |
4035 | + |
4036 | + |
4037 | Q_DECLARE_TYPEINFO(ColorModel, Q_PRIMITIVE_TYPE); |
4038 | Q_DECLARE_METATYPE(ColorModel) |
4039 | |
4040 | @@ -94,4 +175,7 @@ |
4041 | Q_DECLARE_METATYPE(PrinterDriver) |
4042 | Q_DECLARE_METATYPE(QList<PrinterDriver>) |
4043 | |
4044 | +Q_DECLARE_TYPEINFO(Device, Q_MOVABLE_TYPE); |
4045 | +Q_DECLARE_METATYPE(Device) |
4046 | + |
4047 | #endif // USC_PRINTERS_STRUCTS_H |
4048 | |
4049 | === modified file 'po/ubuntu-ui-extras.pot' |
4050 | --- po/ubuntu-ui-extras.pot 2017-02-21 10:46:29 +0000 |
4051 | +++ po/ubuntu-ui-extras.pot 2017-03-20 13:32:24 +0000 |
4052 | @@ -8,7 +8,7 @@ |
4053 | msgstr "" |
4054 | "Project-Id-Version: ubuntu-ui-extras\n" |
4055 | "Report-Msgid-Bugs-To: \n" |
4056 | -"POT-Creation-Date: 2017-02-21 10:42+0000\n" |
4057 | +"POT-Creation-Date: 2017-03-15 17:39+0000\n" |
4058 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
4059 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
4060 | "Language-Team: LANGUAGE <LL@li.org>\n" |
4061 | @@ -17,6 +17,14 @@ |
4062 | "Content-Type: text/plain; charset=CHARSET\n" |
4063 | "Content-Transfer-Encoding: 8bit\n" |
4064 | |
4065 | +#: modules/Ubuntu/Components/Extras/Example/Printers.qml:106 |
4066 | +msgid "Aborted" |
4067 | +msgstr "" |
4068 | + |
4069 | +#: modules/Ubuntu/Components/Extras/Example/Printers.qml:108 |
4070 | +msgid "Active" |
4071 | +msgstr "" |
4072 | + |
4073 | #: modules/Ubuntu/Components/Extras/PhotoEditor.qml:206 |
4074 | #: modules/Ubuntu/Components/Extras/PhotoEditor/ExposureAdjuster.qml:81 |
4075 | msgid "Cancel" |
4076 | @@ -26,7 +34,7 @@ |
4077 | msgid "Color" |
4078 | msgstr "" |
4079 | |
4080 | -#: modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp:53 |
4081 | +#: modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp:54 |
4082 | msgid "Create PDF" |
4083 | msgstr "" |
4084 | |
4085 | @@ -43,10 +51,18 @@ |
4086 | msgid "Enhancing photo..." |
4087 | msgstr "" |
4088 | |
4089 | +#: modules/Ubuntu/Components/Extras/Example/Printers.qml:104 |
4090 | +msgid "Idle" |
4091 | +msgstr "" |
4092 | + |
4093 | #: modules/Ubuntu/Components/Extras/Printers/utils.h:61 |
4094 | msgid "Long Edge (Standard)" |
4095 | msgstr "" |
4096 | |
4097 | +#: modules/Ubuntu/Components/Extras/Example/Printers.qml:115 |
4098 | +msgid "No messages" |
4099 | +msgstr "" |
4100 | + |
4101 | #: modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp:47 |
4102 | msgid "Normal" |
4103 | msgstr "" |
4104 | @@ -79,6 +95,14 @@ |
4105 | msgid "Short Edge (Flip)" |
4106 | msgstr "" |
4107 | |
4108 | +#: modules/Ubuntu/Components/Extras/Example/Printers.qml:110 |
4109 | +msgid "Stopped" |
4110 | +msgstr "" |
4111 | + |
4112 | +#: modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp:367 |
4113 | +msgid "Test page" |
4114 | +msgstr "" |
4115 | + |
4116 | #: modules/Ubuntu/Components/Extras/PhotoEditor.qml:197 |
4117 | msgid "This will undo all edits, including those from previous sessions." |
4118 | msgstr "" |
4119 | |
4120 | === modified file 'tests/unittests/Printers/CMakeLists.txt' |
4121 | --- tests/unittests/Printers/CMakeLists.txt 2017-02-21 16:55:36 +0000 |
4122 | +++ tests/unittests/Printers/CMakeLists.txt 2017-03-20 13:32:24 +0000 |
4123 | @@ -22,6 +22,8 @@ |
4124 | add_executable(testPrintersPrinters tst_printers.cpp ${MOCK_SOURCES}) |
4125 | target_link_libraries(testPrintersPrinters UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4126 | add_test(tst_printers testPrintersPrinters) |
4127 | +set_tests_properties(tst_printers PROPERTIES |
4128 | + ENVIRONMENT "XDG_DATA_DIRS=${CMAKE_CURRENT_SOURCE_DIR}/testdata") |
4129 | |
4130 | add_executable(testPrintersPrinterModel tst_printermodel.cpp ${MOCK_SOURCES}) |
4131 | target_link_libraries(testPrintersPrinterModel UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4132 | @@ -43,6 +45,14 @@ |
4133 | target_link_libraries(testPrintersJobFilter UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4134 | add_test(tst_jobfilter testPrintersJobFilter) |
4135 | |
4136 | -add_executable(testPrintersSignalHandler tst_signalhandler.cpp ${MOCK_SOURCES}) |
4137 | -target_link_libraries(testPrintersSignalHandler UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4138 | -add_test(tst_signalhandler testPrintersSignalHandler) |
4139 | +add_executable(testPrintersSignalRateLimiter tst_signalratelimiter.cpp ${MOCK_SOURCES}) |
4140 | +target_link_libraries(testPrintersSignalRateLimiter UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4141 | +add_test(tst_signalratelimiter testPrintersSignalRateLimiter) |
4142 | + |
4143 | +add_executable(testPrintersDevice tst_printerdevice.cpp ${MOCK_SOURCES}) |
4144 | +target_link_libraries(testPrintersDevice UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4145 | +add_test(tst_printerdevice testPrintersDevice) |
4146 | + |
4147 | +add_executable(testPrintersDeviceModel tst_printerdevicemodel.cpp ${MOCK_SOURCES}) |
4148 | +target_link_libraries(testPrintersDeviceModel UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui) |
4149 | +add_test(tst_printerdevicemodel testPrintersDeviceModel) |
4150 | |
4151 | === modified file 'tests/unittests/Printers/mockbackend.h' |
4152 | --- tests/unittests/Printers/mockbackend.h 2017-02-24 12:20:07 +0000 |
4153 | +++ tests/unittests/Printers/mockbackend.h 2017-03-20 13:32:24 +0000 |
4154 | @@ -40,7 +40,7 @@ |
4155 | |
4156 | virtual bool holdsDefinition() const override |
4157 | { |
4158 | - return true; |
4159 | + return m_holdsDefinition; |
4160 | } |
4161 | |
4162 | virtual QString printerAdd(const QString &name, |
4163 | @@ -105,6 +105,19 @@ |
4164 | return returnValue; |
4165 | } |
4166 | |
4167 | + virtual QString printerSetCopies(const QString &name, const int &copies) |
4168 | + { |
4169 | + printerOptions[name].insert("Copies", copies); |
4170 | + return returnValue; |
4171 | + } |
4172 | + |
4173 | + virtual QString printerSetShared(const QString &name, |
4174 | + const bool shared) override |
4175 | + { |
4176 | + printerOptions[name].insert("Shared", shared); |
4177 | + return returnValue; |
4178 | + } |
4179 | + |
4180 | virtual QString printerSetInfo(const QString &name, |
4181 | const QString &info) override |
4182 | { |
4183 | @@ -163,6 +176,32 @@ |
4184 | } |
4185 | } |
4186 | |
4187 | + virtual void holdJob(const QString &printerName, const int jobId) override |
4188 | + { |
4189 | + // Change the faked job state |
4190 | + Q_FOREACH(auto job, m_jobs) { |
4191 | + if (job->printerName() == printerName |
4192 | + && job->jobId() == jobId) { |
4193 | + job->setState(PrinterEnum::JobState::Held); |
4194 | + } |
4195 | + } |
4196 | + |
4197 | + Q_EMIT jobState("", "", printerName, 1, "", true, jobId, static_cast<uint>(PrinterEnum::JobState::Held), "", "", 1); |
4198 | + } |
4199 | + |
4200 | + virtual void releaseJob(const QString &printerName, const int jobId) override |
4201 | + { |
4202 | + // Change the faked job state |
4203 | + Q_FOREACH(auto job, m_jobs) { |
4204 | + if (job->printerName() == printerName |
4205 | + && job->jobId() == jobId) { |
4206 | + job->setState(PrinterEnum::JobState::Pending); |
4207 | + } |
4208 | + } |
4209 | + |
4210 | + Q_EMIT jobState("", "", printerName, 1, "", true, jobId, static_cast<uint>(PrinterEnum::JobState::Pending), "", "", 1); |
4211 | + } |
4212 | + |
4213 | virtual int printFileToDest(const QString &filepath, |
4214 | const QString &title, |
4215 | const cups_dest_t *dest) override |
4216 | @@ -184,9 +223,39 @@ |
4217 | virtual QMap<QString, QVariant> printerGetJobAttributes( |
4218 | const QString &name, const int jobId) override |
4219 | { |
4220 | - Q_UNUSED(name); |
4221 | - Q_UNUSED(jobId); |
4222 | - return QMap<QString, QVariant>(); |
4223 | + QMap<QString, QVariant> attributes; |
4224 | + |
4225 | + Q_FOREACH(auto job, m_jobs) { |
4226 | + if (job->printerName() == name |
4227 | + && job->jobId() == jobId) { |
4228 | + // Emulate reverse of PrinterJob::loadAttributes |
4229 | + // using local jobs defined in tests |
4230 | + attributes.insert("Collate", job->collate()); |
4231 | + attributes.insert("copies", job->copies()); |
4232 | + attributes.insert("ColorModel", job->getColorModel().name); |
4233 | + attributes.insert("CompletedTime", job->completedTime()); |
4234 | + attributes.insert("CreationTime", job->creationTime()); |
4235 | + attributes.insert("Duplex", Utils::duplexModeToPpdChoice(job->getDuplexMode())); |
4236 | + attributes.insert("impressionsCompleted", job->impressionsCompleted()); |
4237 | + attributes.insert("landscape", job->landscape()); |
4238 | + attributes.insert("messages", job->messages()); |
4239 | + if (job->printRangeMode() == PrinterEnum::PrintRange::AllPages) { |
4240 | + attributes.insert("page-ranges", QStringList()); |
4241 | + } else { |
4242 | + attributes.insert("page-ranges", job->printRange().split(QLocale::system().groupSeparator())); |
4243 | + } |
4244 | + attributes.insert("ProcessingTime", job->processingTime()); |
4245 | + attributes.insert("Quality", job->getPrintQuality().name); |
4246 | + attributes.insert("OutputOrder", job->reverse() ? "Reverse" : "Normal"); |
4247 | + attributes.insert("State", static_cast<int>(job->state())); |
4248 | + attributes.insert("Size", job->size()); |
4249 | + attributes.insert("User", job->user()); |
4250 | + |
4251 | + break; |
4252 | + } |
4253 | + } |
4254 | + |
4255 | + return attributes; |
4256 | } |
4257 | |
4258 | virtual QString printerName() const override |
4259 | @@ -209,6 +278,11 @@ |
4260 | return m_makeAndModel; |
4261 | } |
4262 | |
4263 | + virtual bool isRemote() const override |
4264 | + { |
4265 | + return m_remote; |
4266 | + } |
4267 | + |
4268 | virtual PrinterEnum::State state() const override |
4269 | { |
4270 | return m_state; |
4271 | @@ -287,6 +361,17 @@ |
4272 | m_requestedPrinters << printerName; |
4273 | } |
4274 | |
4275 | + virtual void requestJobExtendedAttributes(QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job) override |
4276 | + { |
4277 | + QMap<QString, QVariant> attributes = printerGetJobAttributes(printer->name(), job->jobId()); |
4278 | + |
4279 | + Q_EMIT jobLoaded(printer->name(), job->jobId(), attributes); |
4280 | + } |
4281 | + |
4282 | + virtual PrinterEnum::PrinterType type() const override |
4283 | + { |
4284 | + return m_type; |
4285 | + } |
4286 | |
4287 | void mockPrinterAdded( |
4288 | const QString &text, |
4289 | @@ -339,6 +424,34 @@ |
4290 | ); |
4291 | } |
4292 | |
4293 | + void mockJobCompleted( |
4294 | + const QString &text, const QString &printer_uri, |
4295 | + const QString &printer_name, uint printer_state, |
4296 | + const QString &printer_state_reasons, bool printer_is_accepting_jobs, |
4297 | + uint job_id, uint job_state, const QString &job_state_reasons, |
4298 | + const QString &job_name, uint job_impressions_completed) |
4299 | + { |
4300 | + Q_EMIT jobCompleted( |
4301 | + text, printer_uri, printer_name, printer_state, |
4302 | + printer_state_reasons, printer_is_accepting_jobs, job_id, |
4303 | + job_state, job_state_reasons, job_name, job_impressions_completed |
4304 | + ); |
4305 | + } |
4306 | + |
4307 | + void mockJobState( |
4308 | + const QString &text, const QString &printer_uri, |
4309 | + const QString &printer_name, uint printer_state, |
4310 | + const QString &printer_state_reasons, bool printer_is_accepting_jobs, |
4311 | + uint job_id, uint job_state, const QString &job_state_reasons, |
4312 | + const QString &job_name, uint job_impressions_completed) |
4313 | + { |
4314 | + Q_EMIT jobState( |
4315 | + text, printer_uri, printer_name, printer_state, |
4316 | + printer_state_reasons, printer_is_accepting_jobs, job_id, |
4317 | + job_state, job_state_reasons, job_name, job_impressions_completed |
4318 | + ); |
4319 | + } |
4320 | + |
4321 | void mockDriversLoaded(const QList<PrinterDriver> &drivers) |
4322 | { |
4323 | Q_EMIT printerDriversLoaded(drivers); |
4324 | @@ -354,6 +467,11 @@ |
4325 | Q_EMIT printerLoaded(printer); |
4326 | } |
4327 | |
4328 | + void mockDeviceFound(const Device &device) |
4329 | + { |
4330 | + Q_EMIT deviceFound(device); |
4331 | + } |
4332 | + |
4333 | QString returnValue = QString::null; |
4334 | |
4335 | // Map from printer to key/val. |
4336 | @@ -366,6 +484,9 @@ |
4337 | QMap<QString, PrinterEnum::ErrorPolicy> errorPolicies; |
4338 | QMap<QString, PrinterEnum::OperationPolicy> operationPolicies; |
4339 | |
4340 | + bool m_holdsDefinition = true; |
4341 | + bool m_remote = false; |
4342 | + |
4343 | QString m_description = QString::null; |
4344 | QString m_location = QString::null; |
4345 | QString m_makeAndModel = QString::null; |
4346 | @@ -383,6 +504,8 @@ |
4347 | QList<QSharedPointer<PrinterJob>> m_jobs; |
4348 | QStringList m_requestedPrinters; |
4349 | |
4350 | + PrinterEnum::PrinterType m_type = PrinterEnum::PrinterType::ProxyType; |
4351 | + |
4352 | Q_SIGNALS: |
4353 | void printToFile(const QString &filepath, const QString &title); |
4354 | }; |
4355 | |
4356 | === added directory 'tests/unittests/Printers/testdata' |
4357 | === added directory 'tests/unittests/Printers/testdata/cups' |
4358 | === added directory 'tests/unittests/Printers/testdata/cups/data' |
4359 | === added file 'tests/unittests/Printers/testdata/cups/data/default-testpage.pdf' |
4360 | === modified file 'tests/unittests/Printers/tst_jobfilter.cpp' |
4361 | --- tests/unittests/Printers/tst_jobfilter.cpp 2017-02-21 10:46:29 +0000 |
4362 | +++ tests/unittests/Printers/tst_jobfilter.cpp 2017-03-20 13:32:24 +0000 |
4363 | @@ -32,10 +32,12 @@ |
4364 | QScopedPointer<MockPrinterBackend> backend(new MockPrinterBackend); |
4365 | JobModel model(backend.data()); |
4366 | |
4367 | - auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend.data())); |
4368 | + auto job = QSharedPointer<PrinterJob>( |
4369 | + new PrinterJob("test-printer", backend.data(), 100) |
4370 | + ); |
4371 | backend->m_jobs << job; |
4372 | // Trigger update. |
4373 | - backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4374 | + backend->mockJobCreated("", "", "test-printer", 1, "", true, 100, 3, "", "", 1); |
4375 | |
4376 | JobFilter filter; |
4377 | filter.setSourceModel(&model); |
4378 | |
4379 | === modified file 'tests/unittests/Printers/tst_jobmodel.cpp' |
4380 | --- tests/unittests/Printers/tst_jobmodel.cpp 2017-02-21 10:46:29 +0000 |
4381 | +++ tests/unittests/Printers/tst_jobmodel.cpp 2017-03-20 13:32:24 +0000 |
4382 | @@ -18,12 +18,14 @@ |
4383 | |
4384 | #include "backend/backend.h" |
4385 | #include "models/jobmodel.h" |
4386 | +#include "printers/printers.h" |
4387 | |
4388 | #include <QDebug> |
4389 | #include <QObject> |
4390 | #include <QSignalSpy> |
4391 | #include <QTest> |
4392 | |
4393 | + |
4394 | class TestJobModel : public QObject |
4395 | { |
4396 | Q_OBJECT |
4397 | @@ -31,15 +33,23 @@ |
4398 | void init() |
4399 | { |
4400 | m_backend = new MockPrinterBackend; |
4401 | - m_model = new JobModel(m_backend); |
4402 | + m_printers = new Printers(m_backend); |
4403 | + |
4404 | + m_model = static_cast<JobModel *>(m_printers->printJobs()); |
4405 | + |
4406 | + PrinterBackend* backend = new MockPrinterBackend("test-printer"); |
4407 | + auto printer = QSharedPointer<Printer>(new Printer(backend)); |
4408 | + m_backend->mockPrinterLoaded(printer); |
4409 | } |
4410 | void cleanup() |
4411 | { |
4412 | - QSignalSpy destroyedSpy(m_model, SIGNAL(destroyed(QObject*))); |
4413 | - m_model->deleteLater(); |
4414 | + QSignalSpy destroyedSpy(m_printers, SIGNAL(destroyed(QObject*))); |
4415 | + m_printers->deleteLater(); |
4416 | QTRY_COMPARE(destroyedSpy.count(), 1); |
4417 | - delete m_backend; |
4418 | } |
4419 | + |
4420 | + // Tests for adding/removing/changing things in the model |
4421 | + |
4422 | void testInsert() |
4423 | { |
4424 | QSignalSpy countSpy(m_model, SIGNAL(countChanged())); |
4425 | @@ -68,7 +78,7 @@ |
4426 | catchall handler in the model. */ |
4427 | QSignalSpy removeSpy(m_model, SIGNAL(rowsRemoved(const QModelIndex&, int, int))); |
4428 | m_backend->m_jobs.clear(); |
4429 | - m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4430 | + m_backend->mockJobCompleted("", "", "", 1, "", true, 100, 1, "", "", 1); |
4431 | QCOMPARE(removeSpy.count(), 1); |
4432 | |
4433 | // Check item was removed |
4434 | @@ -76,44 +86,451 @@ |
4435 | QCOMPARE(args.at(1).toInt(), 0); |
4436 | QCOMPARE(args.at(2).toInt(), 0); |
4437 | } |
4438 | - void testMove() |
4439 | - { |
4440 | - // Add two jobs. |
4441 | - auto job1 = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4442 | - auto job2 = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4443 | - m_backend->m_jobs << job1 << job2; |
4444 | - m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4445 | - |
4446 | - m_backend->m_jobs.move(0, 1); |
4447 | - // Triggers a move. |
4448 | - QSignalSpy moveSpy(m_model, SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); |
4449 | - m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4450 | - QCOMPARE(moveSpy.count(), 1); |
4451 | - QList<QVariant> args = moveSpy.at(0); |
4452 | - QCOMPARE(args.at(1).toInt(), 1); |
4453 | - QCOMPARE(args.at(2).toInt(), 1); |
4454 | - QCOMPARE(args.at(4).toInt(), 0); |
4455 | - } |
4456 | void testModify() |
4457 | { |
4458 | auto jobBefore = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4459 | + int impressions_count = 1; |
4460 | |
4461 | m_backend->m_jobs << jobBefore; |
4462 | - m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4463 | - |
4464 | - auto jobAfter = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4465 | - jobAfter->setCopies(100); |
4466 | - m_backend->m_jobs.replace(0, jobAfter); |
4467 | + m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", impressions_count); |
4468 | |
4469 | // Triggers a change. |
4470 | QSignalSpy changedSpy(m_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
4471 | - m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4472 | + |
4473 | + impressions_count = 5; |
4474 | + m_backend->mockJobState("", "", "", 1, "", true, 100, 1, "", "", impressions_count); |
4475 | + |
4476 | QCOMPARE(changedSpy.count(), 1); |
4477 | } |
4478 | |
4479 | + // Tests for the roles in the model exposed to QML |
4480 | + |
4481 | + void testIdRole() |
4482 | + { |
4483 | + auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 100)); |
4484 | + m_backend->m_jobs << job; |
4485 | + m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1); |
4486 | + |
4487 | + QTRY_COMPARE(m_model->count(), 1); |
4488 | + QCOMPARE(job->jobId(), 100); |
4489 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::IdRole).toInt(), 100); |
4490 | + } |
4491 | + void testCollateRole() |
4492 | + { |
4493 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4494 | + jobA->setCollate(false); |
4495 | + |
4496 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4497 | + jobB->setCollate(true); |
4498 | + |
4499 | + m_backend->m_jobs << jobA << jobB; |
4500 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4501 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4502 | + |
4503 | + QTRY_COMPARE(m_model->count(), 2); |
4504 | + |
4505 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::CollateRole).toBool(), false); |
4506 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::CollateRole).toBool(), true); |
4507 | + } |
4508 | + void testColorModelRole() |
4509 | + { |
4510 | + // FIXME: read comment in JobModel::updateJob |
4511 | + QSKIP("We are ignoring colorModel for now as it requires a loaded Printer for the PrinterJob."); |
4512 | + |
4513 | + ColorModel a; |
4514 | + a.name = "KGray"; |
4515 | + a.text = "Gray"; |
4516 | + |
4517 | + ColorModel b; |
4518 | + b.name = "RGB"; |
4519 | + b.text = ""; |
4520 | + QList<ColorModel> models({a, b}); |
4521 | + |
4522 | + PrinterBackend* backend = new MockPrinterBackend("a-printer"); |
4523 | + ((MockPrinterBackend*) backend)->printerOptions["a-printer"].insert( |
4524 | + "SupportedColorModels", QVariant::fromValue(models) |
4525 | + ); |
4526 | + |
4527 | + auto printer = QSharedPointer<Printer>(new Printer(backend)); |
4528 | + m_backend->mockPrinterLoaded(printer); |
4529 | +// m_printers->m_printers << printer; |
4530 | + |
4531 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 1)); |
4532 | + jobA->setPrinter(printer); |
4533 | + jobA->loadDefaults(); |
4534 | + jobA->setColorModel(models.indexOf(a)); |
4535 | + |
4536 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 2)); |
4537 | + jobB->setPrinter(printer); |
4538 | + jobB->loadDefaults(); |
4539 | + jobB->setColorModel(models.indexOf(b)); |
4540 | + |
4541 | + m_backend->m_jobs << jobA << jobB; |
4542 | + m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1); |
4543 | + m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 2, 1, "", "", 1); |
4544 | + |
4545 | + QTRY_COMPARE(m_model->count(), 2); |
4546 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::ColorModelRole).toString(), |
4547 | + a.text); |
4548 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::ColorModelRole).toString(), |
4549 | + b.name); |
4550 | + } |
4551 | + void testCompletedTimeRole() |
4552 | + { |
4553 | + QDateTime dateTimeA = QDateTime::currentDateTime(); |
4554 | + QDateTime dateTimeB = QDateTime::currentDateTime().addSecs(100); |
4555 | + |
4556 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4557 | + jobA->setCompletedTime(dateTimeA); |
4558 | + |
4559 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4560 | + jobB->setCompletedTime(dateTimeB); |
4561 | + |
4562 | + m_backend->m_jobs << jobA << jobB; |
4563 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4564 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4565 | + |
4566 | + QTRY_COMPARE(m_model->count(), 2); |
4567 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::CompletedTimeRole).toDateTime(), |
4568 | + dateTimeA); |
4569 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::CompletedTimeRole).toDateTime(), |
4570 | + dateTimeB); |
4571 | + } |
4572 | + void testCopiesRole() |
4573 | + { |
4574 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4575 | + jobA->setCopies(2); |
4576 | + |
4577 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4578 | + jobB->setCopies(5); |
4579 | + |
4580 | + m_backend->m_jobs << jobA << jobB; |
4581 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4582 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4583 | + |
4584 | + QTRY_COMPARE(m_model->count(), 2); |
4585 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::CopiesRole).toInt(), 2); |
4586 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::CopiesRole).toInt(), 5); |
4587 | + } |
4588 | + void testCreationTimeRole() |
4589 | + { |
4590 | + QDateTime dateTimeA = QDateTime::currentDateTime(); |
4591 | + QDateTime dateTimeB = QDateTime::currentDateTime().addSecs(100); |
4592 | + |
4593 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4594 | + jobA->setCreationTime(dateTimeA); |
4595 | + |
4596 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4597 | + jobB->setCreationTime(dateTimeB); |
4598 | + |
4599 | + m_backend->m_jobs << jobA << jobB; |
4600 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4601 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4602 | + |
4603 | + QTRY_COMPARE(m_model->count(), 2); |
4604 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::CreationTimeRole).toDateTime(), |
4605 | + dateTimeA); |
4606 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::CreationTimeRole).toDateTime(), |
4607 | + dateTimeB); |
4608 | + } |
4609 | + void testDuplexRole() |
4610 | + { |
4611 | + // FIXME: read comment in JobModel::updateJob |
4612 | + QSKIP("We are ignoring duplex for now as it requires a loaded Printer for the PrinterJob."); |
4613 | + |
4614 | + QList<PrinterEnum::DuplexMode> modes({ |
4615 | + PrinterEnum::DuplexMode::DuplexNone, |
4616 | + PrinterEnum::DuplexMode::DuplexLongSide, |
4617 | + PrinterEnum::DuplexMode::DuplexShortSide, |
4618 | + }); |
4619 | + |
4620 | + ((MockPrinterBackend*) m_backend)->m_supportedDuplexModes = modes; |
4621 | + |
4622 | + PrinterBackend* backend = new MockPrinterBackend("test-printer"); |
4623 | + ((MockPrinterBackend*) backend)->m_supportedDuplexModes = modes; |
4624 | + |
4625 | + auto printer = QSharedPointer<Printer>(new Printer(backend)); |
4626 | + m_backend->mockPrinterLoaded(printer); |
4627 | + |
4628 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1)); |
4629 | + jobA->setPrinter(printer); |
4630 | + jobA->setDuplexMode(modes.indexOf(PrinterEnum::DuplexMode::DuplexLongSide)); |
4631 | + |
4632 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 2)); |
4633 | + jobB->setPrinter(printer); |
4634 | + jobB->setDuplexMode(modes.indexOf(PrinterEnum::DuplexMode::DuplexNone)); |
4635 | + |
4636 | + m_backend->m_jobs << jobA << jobB; |
4637 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4638 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4639 | + |
4640 | + QTRY_COMPARE(m_model->count(), 2); |
4641 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::DuplexRole).toString(), |
4642 | + Utils::duplexModeToUIString(PrinterEnum::DuplexMode::DuplexLongSide)); |
4643 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::DuplexRole).toString(), |
4644 | + Utils::duplexModeToUIString(PrinterEnum::DuplexMode::DuplexNone)); |
4645 | + } |
4646 | + void testHeldRole() |
4647 | + { |
4648 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4649 | + jobA->setState(PrinterEnum::JobState::Pending); |
4650 | + |
4651 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4652 | + jobB->setState(PrinterEnum::JobState::Held); |
4653 | + |
4654 | + m_backend->m_jobs << jobA << jobB; |
4655 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, static_cast<uint>(jobA->state()), "", "", 1); |
4656 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, static_cast<uint>(jobB->state()), "", "", 1); |
4657 | + |
4658 | + QTRY_COMPARE(m_model->count(), 2); |
4659 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::HeldRole).toBool(), false); |
4660 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::HeldRole).toBool(), true); |
4661 | + } |
4662 | + void testImpressionsCompletedRole() |
4663 | + { |
4664 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4665 | + jobA->setImpressionsCompleted(2); |
4666 | + |
4667 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4668 | + jobB->setImpressionsCompleted(5); |
4669 | + |
4670 | + m_backend->m_jobs << jobA << jobB; |
4671 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", jobA->impressionsCompleted()); |
4672 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", jobB->impressionsCompleted()); |
4673 | + |
4674 | + QTRY_COMPARE(m_model->count(), 2); |
4675 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::ImpressionsCompletedRole).toInt(), 2); |
4676 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::ImpressionsCompletedRole).toInt(), 5); |
4677 | + } |
4678 | + void testLandscapeRole() |
4679 | + { |
4680 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4681 | + jobA->setLandscape(false); |
4682 | + |
4683 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4684 | + jobB->setLandscape(true); |
4685 | + |
4686 | + m_backend->m_jobs << jobA << jobB; |
4687 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4688 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4689 | + |
4690 | + QTRY_COMPARE(m_model->count(), 2); |
4691 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::LandscapeRole).toBool(), false); |
4692 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::LandscapeRole).toBool(), true); |
4693 | + } |
4694 | + void testMessagesRole() |
4695 | + { |
4696 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4697 | + jobA->setMessages(QStringList() << "a-message" << "b-message"); |
4698 | + |
4699 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4700 | + jobB->setMessages(QStringList() << "c-message" << "d-message"); |
4701 | + |
4702 | + m_backend->m_jobs << jobA << jobB; |
4703 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4704 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4705 | + |
4706 | + QTRY_COMPARE(m_model->count(), 2); |
4707 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::MessagesRole).toStringList(), |
4708 | + QStringList() << "a-message" << "b-message"); |
4709 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::MessagesRole).toStringList(), |
4710 | + QStringList() << "c-message" << "d-message"); |
4711 | + } |
4712 | + void testPrinterNameRole() |
4713 | + { |
4714 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", m_backend, 1)); |
4715 | + |
4716 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("b-printer", m_backend, 2)); |
4717 | + |
4718 | + m_backend->m_jobs << jobA << jobB; |
4719 | + m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1); |
4720 | + m_backend->mockJobCreated("", "", "b-printer", 1, "", true, 2, 1, "", "", 1); |
4721 | + |
4722 | + QTRY_COMPARE(m_model->count(), 2); |
4723 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::PrinterNameRole).toString(), QString("a-printer")); |
4724 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::PrinterNameRole).toString(), QString("b-printer")); |
4725 | + } |
4726 | + void testPrintRangeRole() |
4727 | + { |
4728 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4729 | + jobA->setPrintRange("1-3,5"); |
4730 | + jobA->setPrintRangeMode(PrinterEnum::PrintRange::PageRange); |
4731 | + |
4732 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4733 | + jobB->setPrintRange("-3,6,10-"); |
4734 | + jobB->setPrintRangeMode(PrinterEnum::PrintRange::PageRange); |
4735 | + |
4736 | + m_backend->m_jobs << jobA << jobB; |
4737 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4738 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4739 | + |
4740 | + QTRY_COMPARE(m_model->count(), 2); |
4741 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::PrintRangeRole).toString(), QString("1-3,5")); |
4742 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::PrintRangeRole).toString(), QString("-3,6,10-")); |
4743 | + } |
4744 | + void testPrintRangeModeRole() |
4745 | + { |
4746 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4747 | + jobA->setPrintRangeMode(PrinterEnum::PrintRange::AllPages); |
4748 | + |
4749 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4750 | + jobB->setPrintRange("1-3"); |
4751 | + jobB->setPrintRangeMode(PrinterEnum::PrintRange::PageRange); |
4752 | + |
4753 | + m_backend->m_jobs << jobA << jobB; |
4754 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4755 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4756 | + |
4757 | + QTRY_COMPARE(m_model->count(), 2); |
4758 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::PrintRangeModeRole).value<PrinterEnum::PrintRange>(), PrinterEnum::PrintRange::AllPages); |
4759 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::PrintRangeModeRole).value<PrinterEnum::PrintRange>(), PrinterEnum::PrintRange::PageRange); |
4760 | + } |
4761 | + void testProcessingTimeRole() |
4762 | + { |
4763 | + QDateTime dateTimeA = QDateTime::currentDateTime(); |
4764 | + QDateTime dateTimeB = QDateTime::currentDateTime().addSecs(100); |
4765 | + |
4766 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4767 | + jobA->setProcessingTime(dateTimeA); |
4768 | + |
4769 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4770 | + jobB->setProcessingTime(dateTimeB); |
4771 | + |
4772 | + m_backend->m_jobs << jobA << jobB; |
4773 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4774 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4775 | + |
4776 | + QTRY_COMPARE(m_model->count(), 2); |
4777 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::ProcessingTimeRole).toDateTime(), |
4778 | + dateTimeA); |
4779 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::ProcessingTimeRole).toDateTime(), |
4780 | + dateTimeB); |
4781 | + } |
4782 | + void testQualityRole() |
4783 | + { |
4784 | + // FIXME: read comment in JobModel::updateJob |
4785 | + QSKIP("We are ignoring quality for now as it requires a loaded Printer for the PrinterJob."); |
4786 | + |
4787 | + PrintQuality a; |
4788 | + a.name = "fast-draft"; |
4789 | + a.text = "Draft"; |
4790 | + |
4791 | + PrintQuality b; |
4792 | + b.name = "normal"; |
4793 | + b.text = ""; |
4794 | + QList<PrintQuality> qualities({a, b}); |
4795 | + |
4796 | + PrinterBackend *backend = new MockPrinterBackend("a-printer"); |
4797 | + ((MockPrinterBackend*) backend)->printerOptions["a-printer"].insert( |
4798 | + "SupportedPrintQualities", QVariant::fromValue(qualities) |
4799 | + ); |
4800 | + |
4801 | + auto printer = QSharedPointer<Printer>(new Printer(backend)); |
4802 | + m_backend->mockPrinterLoaded(printer); |
4803 | + |
4804 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 1)); |
4805 | + jobA->setPrinter(printer); |
4806 | + jobA->setQuality(qualities.indexOf(a)); |
4807 | + |
4808 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 2)); |
4809 | + jobB->setPrinter(printer); |
4810 | + jobB->setQuality(qualities.indexOf(b)); |
4811 | + |
4812 | + m_backend->m_jobs << jobA << jobB; |
4813 | + m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1); |
4814 | + m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 2, 1, "", "", 1); |
4815 | + |
4816 | + QTRY_COMPARE(m_model->count(), 2); |
4817 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::QualityRole).toString(), |
4818 | + a.text); |
4819 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::QualityRole).toString(), |
4820 | + b.name); |
4821 | + } |
4822 | + void testReverseRole() |
4823 | + { |
4824 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4825 | + jobA->setReverse(false); |
4826 | + |
4827 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4828 | + jobB->setReverse(true); |
4829 | + |
4830 | + m_backend->m_jobs << jobA << jobB; |
4831 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4832 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4833 | + |
4834 | + QTRY_COMPARE(m_model->count(), 2); |
4835 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::ReverseRole).toBool(), false); |
4836 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::ReverseRole).toBool(), true); |
4837 | + } |
4838 | + void testSizeRole() |
4839 | + { |
4840 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4841 | + jobA->setSize(32); |
4842 | + |
4843 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4844 | + jobB->setSize(64); |
4845 | + |
4846 | + m_backend->m_jobs << jobA << jobB; |
4847 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4848 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4849 | + |
4850 | + QTRY_COMPARE(m_model->count(), 2); |
4851 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::SizeRole).toInt(), 32); |
4852 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::SizeRole).toInt(), 64); |
4853 | + } |
4854 | + void testStateRole() |
4855 | + { |
4856 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4857 | + jobA->setState(PrinterEnum::JobState::Pending); |
4858 | + |
4859 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4860 | + jobB->setState(PrinterEnum::JobState::Processing); |
4861 | + |
4862 | + m_backend->m_jobs << jobA << jobB; |
4863 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, static_cast<uint>(jobA->state()), "", "", 1); |
4864 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, static_cast<uint>(jobB->state()), "", "", 1); |
4865 | + |
4866 | + QTRY_COMPARE(m_model->count(), 2); |
4867 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::StateRole).value<PrinterEnum::JobState>(), PrinterEnum::JobState::Pending); |
4868 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::StateRole).value<PrinterEnum::JobState>(), PrinterEnum::JobState::Processing); |
4869 | + } |
4870 | + void testTitleRole() |
4871 | + { |
4872 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4873 | + jobA->setTitle("a-job"); |
4874 | + |
4875 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4876 | + jobB->setTitle("b-job"); |
4877 | + |
4878 | + m_backend->m_jobs << jobA << jobB; |
4879 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", jobA->title(), 1); |
4880 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", jobB->title(), 1); |
4881 | + |
4882 | + QTRY_COMPARE(m_model->count(), 2); |
4883 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::TitleRole).toString(), QString("a-job")); |
4884 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::TitleRole).toString(), QString("b-job")); |
4885 | + } |
4886 | + void testUserRole() |
4887 | + { |
4888 | + auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1)); |
4889 | + jobA->setUser("a-user"); |
4890 | + |
4891 | + auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2)); |
4892 | + jobB->setUser("b-user"); |
4893 | + |
4894 | + m_backend->m_jobs << jobA << jobB; |
4895 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1); |
4896 | + m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1); |
4897 | + |
4898 | + QTRY_COMPARE(m_model->count(), 2); |
4899 | + QCOMPARE(m_model->data(m_model->index(0), JobModel::UserRole).toString(), QString("a-user")); |
4900 | + QCOMPARE(m_model->data(m_model->index(1), JobModel::UserRole).toString(), QString("b-user")); |
4901 | + } |
4902 | + |
4903 | private: |
4904 | MockPrinterBackend *m_backend; |
4905 | JobModel *m_model; |
4906 | + Printers *m_printers; |
4907 | }; |
4908 | |
4909 | QTEST_GUILESS_MAIN(TestJobModel) |
4910 | |
4911 | === modified file 'tests/unittests/Printers/tst_printer.cpp' |
4912 | --- tests/unittests/Printers/tst_printer.cpp 2017-02-21 10:46:29 +0000 |
4913 | +++ tests/unittests/Printers/tst_printer.cpp 2017-03-20 13:32:24 +0000 |
4914 | @@ -60,6 +60,54 @@ |
4915 | m_instance->setDescription(desc); |
4916 | QCOMPARE(m_backend->infos.value(m_printerName), desc); |
4917 | } |
4918 | + void testDeviceUri() |
4919 | + { |
4920 | + MockPrinterBackend *backend = new MockPrinterBackend(m_printerName); |
4921 | + backend->printerOptions[m_printerName].insert( |
4922 | + "DeviceUri", "/dev/null"); |
4923 | + Printer p(backend); |
4924 | + QCOMPARE(p.deviceUri(), (QString) "/dev/null"); |
4925 | + } |
4926 | + void testLastMessage() |
4927 | + { |
4928 | + MockPrinterBackend *backend = new MockPrinterBackend(m_printerName); |
4929 | + backend->printerOptions[m_printerName].insert( |
4930 | + "StateMessage", "died"); |
4931 | + Printer p(backend); |
4932 | + QCOMPARE(p.lastMessage(), (QString) "died"); |
4933 | + } |
4934 | + void testMakeModel() |
4935 | + { |
4936 | + m_backend->m_makeAndModel = "make and model"; |
4937 | + QCOMPARE(m_instance->make(), m_backend->makeAndModel()); |
4938 | + } |
4939 | + void testLocation() |
4940 | + { |
4941 | + m_backend->m_location = "location"; |
4942 | + QCOMPARE(m_instance->location(), m_backend->location()); |
4943 | + } |
4944 | + void testCopies() |
4945 | + { |
4946 | + MockPrinterBackend *backend = new MockPrinterBackend(m_printerName); |
4947 | + backend->printerOptions[m_printerName].insert("Copies", "2"); |
4948 | + Printer p(backend); |
4949 | + QCOMPARE(p.copies(), 2); |
4950 | + } |
4951 | + void testSetCopies() |
4952 | + { |
4953 | + MockPrinterBackend *backend = new MockPrinterBackend(m_printerName); |
4954 | + backend->printerOptions[m_printerName].insert("Copies", "2"); |
4955 | + Printer p(backend); |
4956 | + p.setCopies(5); |
4957 | + QCOMPARE(backend->printerOptions[m_printerName].value("Copies").toInt(), 5); |
4958 | + } |
4959 | + void testRemote() |
4960 | + { |
4961 | + m_backend->m_remote = false; |
4962 | + QCOMPARE(m_instance->isRemote(), m_backend->isRemote()); |
4963 | + m_backend->m_remote = true; |
4964 | + QCOMPARE(m_instance->isRemote(), m_backend->isRemote()); |
4965 | + } |
4966 | void testSupportedDuplexModes_data() |
4967 | { |
4968 | QTest::addColumn<QList<PrinterEnum::DuplexMode>>("modes"); |
4969 | @@ -263,6 +311,32 @@ |
4970 | p2.setAcceptJobs(false); |
4971 | QVERIFY(!backend->printerOptions[m_printerName]["AcceptJobs"].toBool()); |
4972 | } |
4973 | + void testShared() |
4974 | + { |
4975 | + MockPrinterBackend *backend = new MockPrinterBackend(m_printerName); |
4976 | + |
4977 | + backend->printerOptions[m_printerName].insert("Shared", false); |
4978 | + Printer p(backend); |
4979 | + QVERIFY(!p.shared()); |
4980 | + |
4981 | + backend->printerOptions[m_printerName].insert("Shared", true); |
4982 | + Printer p2(backend); |
4983 | + QVERIFY(p2.shared()); |
4984 | + } |
4985 | + void testSetShared() |
4986 | + { |
4987 | + MockPrinterBackend *backend = new MockPrinterBackend(m_printerName); |
4988 | + |
4989 | + backend->printerOptions[m_printerName].insert("Shared", false); |
4990 | + Printer p(backend); |
4991 | + p.setShared(true); |
4992 | + QVERIFY(backend->printerOptions[m_printerName]["Shared"].toBool()); |
4993 | + |
4994 | + backend->printerOptions[m_printerName].insert("Shared", true); |
4995 | + Printer p2(backend); |
4996 | + p2.setShared(false); |
4997 | + QVERIFY(!backend->printerOptions[m_printerName]["Shared"].toBool()); |
4998 | + } |
4999 | void testJobs() |
5000 | { |
The diff has been truncated for viewing.