Merge lp:ubuntu-ui-extras/staging into lp:ubuntu-ui-extras

Proposed by Jonas G. Drange
Status: Merged
Approved by: Andrew Hayzen
Approved revision: no longer in the source branch.
Merged at revision: 131
Proposed branch: lp:ubuntu-ui-extras/staging
Merge into: lp:ubuntu-ui-extras
Diff against target: 6506 lines (+3970/-590)
46 files modified
debian/changelog (+67/-0)
modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml (+0/-117)
modules/Ubuntu/Components/Extras/Example/Printers.qml (+232/-75)
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 (+70/-30)
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 (+150/-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 (+152/-7)
modules/Ubuntu/Components/Extras/Printers/printers/printers.h (+20/-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:ubuntu-ui-extras/staging
Reviewer Review Type Date Requested Status
Andrew Hayzen (community) Approve
Jonas G. Drange (community) Approve
Review via email: mp+320797@code.launchpad.net

Description of the change

Please see the changelog entry for details.

Testing:
1. Build it
2. qmlscene -I <path/to/build/folder/modules/ <path/to/workding-dir>/modules/Ubuntu/Components/Extras/Example/Printers.qml
3. Add a printer
4. Explore configured printers
5. Change configured printers

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

I approve all the changes made by Andrew, which is this whole branch minus my own changes.

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

I approve all the changes made by Jonas, which is this whole branch minus my own changes.

review: Approve
lp:ubuntu-ui-extras/staging updated
131. By CI Train Bot Account

* Adds devices as an model on Printers, and re-instates remote printer model on Printers.
* makes sure the backend is refreshed on enable/disable
* If printerAdded is called ensure there is always a proxy printer
      corrects thread affinity for printerloaded printers, as well as any qobject children it might have
* Remove PrinterQueue.qml example and add missing job methods to Printers.qml example, so we have only one example
* improves the deviceName by dropping the CMD (note that the full string remains accessible from device.id)
* Connect job-impressions-completed from cups to PrinterJob::impressionsCompleted()
* In the job model listen to printerStateChanged as changes t job-impressions-completed causes that signal
* Improve the PrinterSignalHandler to limit the maximum wait time of unprocessed signals to four times the timeout
* Add unit test for SignalRateLimiter to check it does perform a flush
* Rename PrinterSignalHandler to SignalRateLimiter
* Add a JobLoader for loading a specific jobId for a printer and loading the extended attributes
* Move the loading of creationTime, completedTime, processingTime, size and user to extended attributes as signals don't give us those
* Add method for PrinterBackend for getting a specific job
* Split up JobModel::update so there is jobCreated, jobState and jobCompleted which then call addJob, removeJob and updateJob
* Improve Printer::updateFrom to not call loadAttributes as this results in a possible UI block
* Add missing comparisions for PrinterJob deepCompare and updateFrom
* Change PrinterJob::setPrinter to not call loadDefaults and instead explicitly call it
* Change Printers to trigger requestJobExtendedAttributes which triggers a background thread rather than doing in foreground
* exposes copies attribute on the printer
* includes cups/adminutils.h into which the cups device callback was moved in >= libcups2-dev 2.2.2
* allows browsing on local and remote printers
* Add filters for active, paused and queued
* Add sorting by creationTime and then falling back to id
* Change time related roles in JobModel to return QDateTime, not QString, so sorting doesn't break
* Update tests
* Change printerGetJobAttributes to use printer-uri and job-id (the same as holdJob and releaseJob
* Give printerGetJobAttributes printerName so we can ensure we get the correct job
* adds read/write of the shared property
* adds extended attribute fetching (IppClient::printerGetAttributes)
* refactors attribute retrieval from cups
* implements deviceUri and lastMessage on Printer
* adds Printers.printTestPage
* Add tests for JobModel roles
* Add tests for make and location in Printer
* Fix JobModel color and quality roles to use fallback if no text
* Add tests for all roles in PrinterModel
* Remove PdfRole it is not used (IsPdfRole instead)
* Add holdJob and releaseJob methods to Printers
* Add HeldRole to JobModel
* Add tests for hold and releasing a job
* Update example to show how hold and release work
* Update StateRole to return just the state, not text
* Remove PrinterJob friends and make setters public as they aren't exposed to QML anyway
* adds make and location to printermodel and printer
* Pull of trunk
* Remove use of bitewise or as it fails in CI
* guards against excessive loading of printers and drivers
* adds loadPrinter method on Printers
* drops a lot of code that was not used, and some TODOS/FIXMES that aren't necessary
* Fix/add commented or empty tests
* Implement tests that had QSKIP
* removes empty brackets
* adds cmake extras, required by printer stuff
* Remove remaining fixme's
* Rename UbuntuSettingsComponentsPrintersPlugin to UbuntuComponentsExtrasPrintersPlugin
* Remove import Ubuntu.Settings.Components 0.1 from example qml imports
* Rename definition UBUNTUSETTINGSPRINTERS_LIBRARY to UBUNTUCOMPONENTSEXTRASPRINTERS_LIBRARY
* Rename UbuntuSettingsPrintersQml to UbuntuComponentsExtrasPrintersQml
* Rename translation domain to ubuntu-ui-extras
* Fix for printsupport being build-depends rather than depends

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2017-03-01 22:24:08 +0000
+++ debian/changelog 2017-03-23 12:51:36 +0000
@@ -1,3 +1,70 @@
1ubuntu-ui-extras (0.3+17.04.20170301.2-0ubuntu2) UNRELEASED; urgency=medium
2
3 [ Andrew Hayzen, Jonas G. Drange ]
4 * Adds devices as an model on Printers, and re-instates remote printer model on Printers.
5 * makes sure the backend is refreshed on enable/disable
6 * If printerAdded is called ensure there is always a proxy printer
7 corrects thread affinity for printerloaded printers, as well as any qobject children it might have
8 * Remove PrinterQueue.qml example and add missing job methods to Printers.qml example, so we have only one example
9 * improves the deviceName by dropping the CMD (note that the full string remains accessible from device.id)
10 * Connect job-impressions-completed from cups to PrinterJob::impressionsCompleted()
11 * In the job model listen to printerStateChanged as changes t job-impressions-completed causes that signal
12 * Improve the PrinterSignalHandler to limit the maximum wait time of unprocessed signals to four times the timeout
13 * Add unit test for SignalRateLimiter to check it does perform a flush
14 * Rename PrinterSignalHandler to SignalRateLimiter
15 * Add a JobLoader for loading a specific jobId for a printer and loading the extended attributes
16 * Move the loading of creationTime, completedTime, processingTime, size and user to extended attributes as signals don't give us those
17 * Add method for PrinterBackend for getting a specific job
18 * Split up JobModel::update so there is jobCreated, jobState and jobCompleted which then call addJob, removeJob and updateJob
19 * Improve Printer::updateFrom to not call loadAttributes as this results in a possible UI block
20 * Add missing comparisions for PrinterJob deepCompare and updateFrom
21 * Change PrinterJob::setPrinter to not call loadDefaults and instead explicitly call it
22 * Change Printers to trigger requestJobExtendedAttributes which triggers a background thread rather than doing in foreground
23 * exposes copies attribute on the printer
24 * includes cups/adminutils.h into which the cups device callback was moved in >= libcups2-dev 2.2.2
25 * allows browsing on local and remote printers
26 * Add filters for active, paused and queued
27 * Add sorting by creationTime and then falling back to id
28 * Change time related roles in JobModel to return QDateTime, not QString, so sorting doesn't break
29 * Update tests
30 * Change printerGetJobAttributes to use printer-uri and job-id (the same as holdJob and releaseJob
31 * Give printerGetJobAttributes printerName so we can ensure we get the correct job
32 * adds read/write of the shared property
33 * adds extended attribute fetching (IppClient::printerGetAttributes)
34 * refactors attribute retrieval from cups
35 * implements deviceUri and lastMessage on Printer
36 * adds Printers.printTestPage
37 * Add tests for JobModel roles
38 * Add tests for make and location in Printer
39 * Fix JobModel color and quality roles to use fallback if no text
40 * Add tests for all roles in PrinterModel
41 * Remove PdfRole it is not used (IsPdfRole instead)
42 * Add holdJob and releaseJob methods to Printers
43 * Add HeldRole to JobModel
44 * Add tests for hold and releasing a job
45 * Update example to show how hold and release work
46 * Update StateRole to return just the state, not text
47 * Remove PrinterJob friends and make setters public as they aren't exposed to QML anyway
48 * adds make and location to printermodel and printer
49 * Pull of trunk
50 * Remove use of bitewise or as it fails in CI
51 * guards against excessive loading of printers and drivers
52 * adds loadPrinter method on Printers
53 * drops a lot of code that was not used, and some TODOS/FIXMES that aren't necessary
54 * Fix/add commented or empty tests
55 * Implement tests that had QSKIP
56 * removes empty brackets
57 * adds cmake extras, required by printer stuff
58 * Remove remaining fixme's
59 * Rename UbuntuSettingsComponentsPrintersPlugin to UbuntuComponentsExtrasPrintersPlugin
60 * Remove import Ubuntu.Settings.Components 0.1 from example qml imports
61 * Rename definition UBUNTUSETTINGSPRINTERS_LIBRARY to UBUNTUCOMPONENTSEXTRASPRINTERS_LIBRARY
62 * Rename UbuntuSettingsPrintersQml to UbuntuComponentsExtrasPrintersQml
63 * Rename translation domain to ubuntu-ui-extras
64 * Fix for printsupport being build-depends rather than depends
65
66 -- Jonas G. Drange <jonas.drange@canonical.com> Mon, 20 Mar 2017 21:04:05 +0100
67
1ubuntu-ui-extras (0.2+17.04.20170301.2-0ubuntu1) zesty; urgency=medium68ubuntu-ui-extras (0.2+17.04.20170301.2-0ubuntu1) zesty; urgency=medium
269
3 [ Andrew Hayzen, Jonas G. Drange ]70 [ Andrew Hayzen, Jonas G. Drange ]
471
=== removed file 'modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml'
--- modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml 2017-02-21 11:31:44 +0000
+++ modules/Ubuntu/Components/Extras/Example/PrinterQueue.qml 1970-01-01 00:00:00 +0000
@@ -1,117 +0,0 @@
1/*
2 * Copyright 2017 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by Jonas G. Drange <jonas.drange@canonical.com>
17 * Andrew Hayzen <andrew.hayzen@canonical.com>
18 */
19
20import QtQuick 2.4
21import QtQuick.Layouts 1.1
22import Ubuntu.Components 1.3
23import Ubuntu.Components.ListItems 1.3 as ListItems
24import Ubuntu.Components.Extras.Printers 0.1
25
26MainView {
27 width: units.gu(50)
28 height: units.gu(90)
29
30 Component {
31 id: queuePage
32
33 Page {
34 header: PageHeader {
35 title: "Queue: " + printer.name
36 flickable: queueView
37 }
38 visible: false
39
40 property var printer
41
42 ListView {
43 id: queueView
44 anchors {
45 fill: parent
46 }
47 delegate: ListItem {
48 height: modelLayout.height + (divider.visible ? divider.height : 0)
49 ListItemLayout {
50 id: modelLayout
51 title.text: displayName
52 subtitle.text: "Job: " + model.id + " State: " + model.state
53 + " Color: " + model.colorModel + " CreationTime: "
54 + model.creationTime + " PageRange: "
55 + model.printRange + " Messages: " + model.messages;
56 subtitle.wrapMode: Text.WrapAtWordBoundaryOrAnywhere
57 subtitle.maximumLineCount: 3
58 }
59 onClicked: {
60 console.debug("Cancel:", printer.name, model.id);
61 Printers.cancelJob(printer.name, model.id);
62 }
63 }
64 model: printer.jobs
65
66 Label {
67 anchors {
68 centerIn: parent
69 }
70 text: "Empty queue"
71 visible: queueView.count === 0
72 }
73 }
74 }
75 }
76
77 PageStack {
78 id: pageStack
79
80 Page {
81 id: printersPage
82 header: PageHeader {
83 title: "Printers"
84 flickable: printerList
85 }
86 visible: false
87
88 ListView {
89 id: printerList
90 anchors { fill: parent }
91 model: Printers.allPrintersWithPdf
92 delegate: ListItem {
93 height: modelLayout.height + (divider.visible ? divider.height : 0)
94 ListItemLayout {
95 id: modelLayout
96 title.text: displayName
97 title.font.bold: model.default
98 subtitle.text: description
99
100 Icon {
101 id: icon
102 width: height
103 height: units.gu(2.5)
104 name: "printer-symbolic"
105 SlotsLayout.position: SlotsLayout.First
106 }
107
108 ProgressionSlot {}
109 }
110 onClicked: pageStack.push(queuePage, { printer: model })
111 }
112 }
113 }
114
115 Component.onCompleted: push(printersPage)
116 }
117}
1180
=== modified file 'modules/Ubuntu/Components/Extras/Example/Printers.qml'
--- modules/Ubuntu/Components/Extras/Example/Printers.qml 2017-02-21 11:31:44 +0000
+++ modules/Ubuntu/Components/Extras/Example/Printers.qml 2017-03-23 12:51:36 +0000
@@ -51,17 +51,17 @@
51 }51 }
52 }52 }
5353
54 Component.onCompleted: {
55 printer.description;
56 }
57
58 Flickable {54 Flickable {
59 id: printerFlickable55 id: printerFlickable
60 anchors.fill: parent56 anchors.fill: parent
6157 contentHeight: contentItem.childrenRect.height
62 Loader {58 Loader {
63 id: printerPageBitsLoader59 id: printerPageBitsLoader
64 anchors.fill: parent60 anchors {
61 left: parent.left
62 right: parent.right
63 }
64
65 sourceComponent: printer.isLoaded ? printerPageLoaded : printerPageNotYetLoaded65 sourceComponent: printer.isLoaded ? printerPageLoaded : printerPageNotYetLoaded
66 }66 }
67 }67 }
@@ -70,7 +70,7 @@
70 id: printerPageLoaded70 id: printerPageLoaded
7171
72 Column {72 Column {
73 spacing: units.gu(2)73 height: childrenRect.height + anchors.topMargin
74 anchors {74 anchors {
75 top: parent.top75 top: parent.top
76 topMargin: units.gu(2)76 topMargin: units.gu(2)
@@ -91,6 +91,31 @@
91 }91 }
92 }92 }
9393
94 ListItems.SingleValue {
95 anchors {
96 left: parent.left
97 right: parent.right
98 }
99 text: "Status"
100
101 value: {
102 var state;
103 if (printer.state == PrinterEnum.IdleState) {
104 state = i18n.tr("Idle");
105 } else if (printer.state == PrinterEnum.AbortedState) {
106 state = i18n.tr("Aborted");
107 } else if (printer.state == PrinterEnum.ActiveState) {
108 state = i18n.tr("Active");
109 } else if (printer.state == PrinterEnum.ErrorState) {
110 state = i18n.tr("Stopped");
111 }
112 return "%1 — %2"
113 .arg(state)
114 .arg(printer.lastMessage ?
115 printer.lastMessage : i18n.tr("No messages"));
116 }
117 }
118
94 ListItems.Standard {119 ListItems.Standard {
95 anchors {120 anchors {
96 left: parent.left121 left: parent.left
@@ -109,25 +134,30 @@
109 left: parent.left134 left: parent.left
110 right: parent.right135 right: parent.right
111 }136 }
137 text: "Shared"
138
139 control: Switch {
140 checked: printer.shared
141 onCheckedChanged: printer.shared = checked
142 }
143 }
144
145 ListItems.Standard {
146 anchors {
147 left: parent.left
148 right: parent.right
149 }
112 text: "Jobs"150 text: "Jobs"
113 progression: true151 progression: true
114 onClicked: pageStack.push(jobPage, { printer: printer })152 onClicked: pageStack.push(jobPage, { printer: printer })
115 }153 }
116154
117 Label {155 ListItems.Standard {
118 anchors {156 anchors {
119 left: parent.left157 left: parent.left
120 right: parent.right158 right: parent.right
121 margins: units.gu(2)
122 }159 }
123 text: "Description"160 text: "Description"
124 }
125
126 ListItems.SingleControl {
127 anchors {
128 left: parent.left
129 right: parent.right
130 }
131161
132 control: TextField {162 control: TextField {
133 anchors {163 anchors {
@@ -141,6 +171,27 @@
141 }171 }
142 }172 }
143173
174 ListItems.Standard {
175 anchors {
176 left: parent.left
177 right: parent.right
178 }
179 text: "Copies"
180
181 control: TextField {
182 id: copiesField
183 inputMethodHints: Qt.ImhDigitsOnly
184 text: printer.copies
185 validator: IntValidator {
186 bottom: 1
187 top: 999
188 }
189 width: units.gu(10)
190 onTextChanged: printer.copies = text
191 }
192
193 }
194
144195
145 ListItems.ValueSelector {196 ListItems.ValueSelector {
146 anchors {197 anchors {
@@ -200,12 +251,70 @@
200 selectedIndex = printer.printQuality251 selectedIndex = printer.printQuality
201 }252 }
202 }253 }
254
255 ListItems.SingleControl {
256 anchors {
257 left: parent.left
258 right: parent.right
259 }
260 control: Button {
261 text: "Print test page"
262 onClicked: Printers.printTestPage(printer.name)
263 }
264 }
265
266 ListItems.SingleValue {
267 anchors {
268 left: parent.left
269 right: parent.right
270 }
271 text: "Device URI"
272 value: printer.deviceUri
273 }
203 }274 }
204 }275 }
205 }276 }
206 }277 }
207278
208 Component {279 Component {
280 id: jobDelegate
281
282 ListItem {
283 height: modelLayout.height + (divider.visible ? divider.height : 0)
284 trailingActions: ListItemActions {
285 actions: [
286 Action {
287 iconName: model.held ? "media-playback-start" : "media-playback-pause"
288 text: model.held ? "Release" : "Hold"
289
290 onTriggered: {
291 if (model.held) {
292 Printers.releaseJob(model.printerName, model.id);
293 } else {
294 Printers.holdJob(model.printerName, model.id);
295 }
296 }
297 },
298 Action {
299 iconName: "cancel"
300 text: "Cancel"
301
302 onTriggered: Printers.cancelJob(model.printerName, model.id);
303 }
304 ]
305 }
306
307 ListItemLayout {
308 id: modelLayout
309 title.text: displayName
310 subtitle.text: "Printing " + model.impressionsCompleted + " pages" + "\n" + model.printerName
311 subtitle.wrapMode: Text.WrapAtWordBoundaryOrAnywhere
312 subtitle.maximumLineCount: 3
313 }
314 }
315 }
316
317 Component {
209 id: jobPage318 id: jobPage
210 Page {319 Page {
211 property var printer320 property var printer
@@ -219,26 +328,11 @@
219 id: jobList328 id: jobList
220 anchors.fill: parent329 anchors.fill: parent
221 model: printer.jobs330 model: printer.jobs
222 delegate: ListItem {331 delegate: jobDelegate
223 height: jobLayout.height + (divider.visible ? divider.height : 0)
224 ListItemLayout {
225 id: jobLayout
226 title.text: displayName
227
228 Icon {
229 id: icon
230 width: height
231 height: units.gu(2.5)
232 name: "stock_document"
233 SlotsLayout.position: SlotsLayout.First
234 }
235 }
236 }
237 }332 }
238 }333 }
239 }334 }
240335
241
242 Component {336 Component {
243 id: allJobsPage337 id: allJobsPage
244 Page {338 Page {
@@ -252,21 +346,7 @@
252 id: jobsList346 id: jobsList
253 anchors.fill: parent347 anchors.fill: parent
254 model: Printers.printJobs348 model: Printers.printJobs
255 delegate: ListItem {349 delegate: jobDelegate
256 height: jobsLayout.height + (divider.visible ? divider.height : 0)
257 ListItemLayout {
258 id: jobsLayout
259 title.text: displayName
260
261 Icon {
262 id: icon
263 width: height
264 height: units.gu(2.5)
265 name: "stock_document"
266 SlotsLayout.position: SlotsLayout.First
267 }
268 }
269 }
270 }350 }
271 }351 }
272 }352 }
@@ -338,9 +418,18 @@
338418
339 ProgressionSlot {}419 ProgressionSlot {}
340 }420 }
341 onClicked: pageStack.push(printerPage, { printer: model })421 onClicked: {
422 Printers.loadPrinter(model.name);
423 pageStack.push(printerPage, { printer: model });
424 }
342 }425 }
343 }426 }
427
428 Label {
429 anchors.centerIn: parent
430 visible: printerList.count === 0
431 text: "No printers found"
432 }
344 }433 }
345 }434 }
346435
@@ -423,9 +512,7 @@
423 }512 }
424 }513 }
425514
426 Component.onCompleted: {515 Component.onCompleted: Printers.prepareToAddPrinter()
427 Printers.prepareToAddPrinter();
428 }
429516
430 Timer {517 Timer {
431 id: okTimer518 id: okTimer
@@ -436,14 +523,12 @@
436 Flickable {523 Flickable {
437 id: addPrinterFlickable524 id: addPrinterFlickable
438 anchors.fill: parent525 anchors.fill: parent
526 contentHeight: contentItem.childrenRect.height
439527
440 Column {528 Column {
441 id: addPrinterCol529 id: addPrinterCol
442 property bool enabled: true530 property bool enabled: true
443 anchors {531 anchors { left: parent.left; right: parent.right }
444 left: parent.left
445 right: parent.right
446 }
447532
448 Item {533 Item {
449 id: errorMessageContainer534 id: errorMessageContainer
@@ -476,10 +561,7 @@
476561
477 ListItems.ValueSelector {562 ListItems.ValueSelector {
478 id: driverSelector563 id: driverSelector
479 anchors {564 anchors { left: parent.left; right: parent.right }
480 left: parent.left
481 right: parent.right
482 }
483 text: "Choose driver"565 text: "Choose driver"
484 values: [566 values: [
485 "Select printer from database",567 "Select printer from database",
@@ -489,10 +571,7 @@
489 }571 }
490572
491 ListItems.Standard {573 ListItems.Standard {
492 anchors {574 anchors { left: parent.left; right: parent.right }
493 left: parent.left
494 right: parent.right
495 }
496 text: "Filter drivers"575 text: "Filter drivers"
497 control: TextField {576 control: TextField {
498 id: driverFilter577 id: driverFilter
@@ -559,10 +638,7 @@
559 }638 }
560639
561 ListItems.Standard {640 ListItems.Standard {
562 anchors {641 anchors { left: parent.left; right: parent.right }
563 left: parent.left
564 right: parent.right
565 }
566 text: "Printer name"642 text: "Printer name"
567 control: TextField {643 control: TextField {
568 id: printerName644 id: printerName
@@ -572,10 +648,7 @@
572 }648 }
573649
574 ListItems.Standard {650 ListItems.Standard {
575 anchors {651 anchors { left: parent.left; right: parent.right }
576 left: parent.left
577 right: parent.right
578 }
579 text: "Description (optional)"652 text: "Description (optional)"
580 control: TextField {653 control: TextField {
581 id: printerDescription654 id: printerDescription
@@ -585,10 +658,7 @@
585 }658 }
586659
587 ListItems.Standard {660 ListItems.Standard {
588 anchors {661 anchors { left: parent.left; right: parent.right }
589 left: parent.left
590 right: parent.right
591 }
592 text: "Location (optional)"662 text: "Location (optional)"
593 control: TextField {663 control: TextField {
594 id: printerLocation664 id: printerLocation
@@ -597,6 +667,93 @@
597 enabled: parent.enabled667 enabled: parent.enabled
598 }668 }
599 }669 }
670
671 Label {
672 id: remotePrintersLabel
673 anchors {
674 left: parent.left
675 right: parent.right
676 margins: units.gu(2)
677 top: addPrinterCol.bottom
678 }
679 text: "Other printers"
680
681 ActivityIndicator {
682 id: remotePrintersSearchIndicator
683 anchors {
684 right: parent.right
685 verticalCenter: parent.verticalCenter
686 }
687 property var target
688 Component.onCompleted: target = Printers.devices
689 running: target.searching
690 }
691 }
692
693 ListView {
694 id: remotePrintersList
695 anchors {
696 left: parent.left
697 right: parent.right
698 top: remotePrintersLabel.bottom
699 topMargin: units.gu(2)
700 }
701 height: contentItem.childrenRect.height
702 model: Printers.devices
703 delegate: ListItem {
704 height: modelLayout.height + (divider.visible ? divider.height : 0)
705 ListItemLayout {
706 id: modelLayout
707 title.text: displayName
708 subtitle.text: {
709 if (type == PrinterEnum.LPDType) return "LPD";
710 if (type == PrinterEnum.IppSType) return "IppS";
711 if (type == PrinterEnum.Ipp14Type) return "Ipp14";
712 if (type == PrinterEnum.HttpType) return "Http";
713 if (type == PrinterEnum.BehType) return "Beh";
714 if (type == PrinterEnum.SocketType) return "Socket";
715 if (type == PrinterEnum.HttpsType) return "Https";
716 if (type == PrinterEnum.IppType) return "Ipp";
717 if (type == PrinterEnum.HPType) return "HP";
718 if (type == PrinterEnum.USBType) return "USB";
719 if (type == PrinterEnum.HPFaxType) return "HPFax";
720 if (type == PrinterEnum.DNSSDType) return "DNSSD";
721 else return "Unknown protocol";
722 }
723
724 Icon {
725 id: icon
726 width: height
727 height: units.gu(2.5)
728 name: "network-printer-symbolic"
729 SlotsLayout.position: SlotsLayout.First
730 }
731
732 Button {
733 text: "Select printer"
734 onClicked: {
735 var suggestedPrinterName = (" " + displayName).slice(1);
736 suggestedPrinterName = suggestedPrinterName.replace(/\ /g, "\-");
737 printerUri.text = uri;
738 printerName.text = suggestedPrinterName;
739 printerDescription.text = info;
740 printerLocation.text = location;
741 }
742 }
743 }
744 }
745 }
746
747 Label {
748 anchors {
749 left: parent.left
750 right: parent.right
751 top: remotePrintersLabel.bottom
752 topMargin: units.gu(2)
753 }
754 text: "No other printers found"
755 visible: !remotePrintersSearchIndicator.running && remotePrintersList.count == 0
756 }
600 }757 }
601 }758 }
602 }759 }
603760
=== modified file 'modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt'
--- modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt 2017-02-21 16:55:36 +0000
+++ modules/Ubuntu/Components/Extras/Printers/CMakeLists.txt 2017-03-23 12:51:36 +0000
@@ -29,17 +29,20 @@
29 backend/backend_cups.cpp29 backend/backend_cups.cpp
30 backend/backend_pdf.cpp30 backend/backend_pdf.cpp
3131
32 cups/devicesearcher.cpp
32 cups/ippclient.cpp33 cups/ippclient.cpp
34 cups/jobloader.cpp
33 cups/printerdriverloader.cpp35 cups/printerdriverloader.cpp
34 cups/printerloader.cpp36 cups/printerloader.cpp
3537
38 models/devicemodel.cpp
36 models/drivermodel.cpp39 models/drivermodel.cpp
37 models/jobmodel.cpp40 models/jobmodel.cpp
38 models/printermodel.cpp41 models/printermodel.cpp
3942
40 printer/printer.cpp43 printer/printer.cpp
41 printer/printerjob.cpp44 printer/printerjob.cpp
42 printer/printersignalhandler.cpp45 printer/signalratelimiter.cpp
43 printers/printers.cpp46 printers/printers.cpp
4447
45 enums.h48 enums.h
4649
=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp'
--- modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/backend/backend.cpp 2017-03-23 12:51:36 +0000
@@ -91,6 +91,22 @@
91 return QString();91 return QString();
92}92}
9393
94QString PrinterBackend::printerSetCopies(const QString &name,
95 const int &copies)
96{
97 Q_UNUSED(name);
98 Q_UNUSED(copies);
99 return QString();
100}
101
102QString PrinterBackend::printerSetShared(const QString &name,
103 const bool shared)
104{
105 Q_UNUSED(name);
106 Q_UNUSED(shared);
107 return QString();
108}
109
94QString PrinterBackend::printerSetInfo(const QString &name,110QString PrinterBackend::printerSetInfo(const QString &name,
95 const QString &info)111 const QString &info)
96{112{
@@ -139,6 +155,18 @@
139 Q_UNUSED(name);155 Q_UNUSED(name);
140}156}
141157
158void PrinterBackend::holdJob(const QString &name, const int jobId)
159{
160 Q_UNUSED(jobId);
161 Q_UNUSED(name);
162}
163
164void PrinterBackend::releaseJob(const QString &name, const int jobId)
165{
166 Q_UNUSED(jobId);
167 Q_UNUSED(name);
168}
169
142int PrinterBackend::printFileToDest(const QString &filepath,170int PrinterBackend::printFileToDest(const QString &filepath,
143 const QString &title,171 const QString &title,
144 const cups_dest_t *dest)172 const cups_dest_t *dest)
@@ -154,6 +182,14 @@
154 return QList<QSharedPointer<PrinterJob>>{};182 return QList<QSharedPointer<PrinterJob>>{};
155}183}
156184
185QSharedPointer<PrinterJob> PrinterBackend::printerGetJob(
186 const QString &printerName, const int jobId)
187{
188 Q_UNUSED(printerName);
189 Q_UNUSED(jobId);
190 return QSharedPointer<PrinterJob>(Q_NULLPTR);
191}
192
157QMap<QString, QVariant> PrinterBackend::printerGetJobAttributes(193QMap<QString, QVariant> PrinterBackend::printerGetJobAttributes(
158 const QString &name, const int jobId)194 const QString &name, const int jobId)
159{195{
@@ -182,6 +218,11 @@
182 return QString();218 return QString();
183}219}
184220
221bool PrinterBackend::isRemote() const
222{
223 return false;
224}
225
185PrinterEnum::State PrinterBackend::state() const226PrinterEnum::State PrinterBackend::state() const
186{227{
187 return PrinterEnum::State::IdleState;228 return PrinterEnum::State::IdleState;
@@ -248,6 +289,13 @@
248 return QString();289 return QString();
249}290}
250291
292void PrinterBackend::requestJobExtendedAttributes(
293 QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job)
294{
295 Q_UNUSED(printer);
296 Q_UNUSED(job);
297}
298
251void PrinterBackend::requestPrinterDrivers()299void PrinterBackend::requestPrinterDrivers()
252{300{
253}301}
254302
=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend.h'
--- modules/Ubuntu/Components/Extras/Printers/backend/backend.h 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/backend/backend.h 2017-03-23 12:51:36 +0000
@@ -63,6 +63,9 @@
63 const QString &name,63 const QString &name,
64 const bool accept,64 const bool accept,
65 const QString &reason = QString::null);65 const QString &reason = QString::null);
66 virtual QString printerSetCopies(const QString &name, const int &copies);
67 virtual QString printerSetShared(const QString &name,
68 const bool shared);
66 virtual QString printerSetInfo(const QString &name,69 virtual QString printerSetInfo(const QString &name,
67 const QString &info);70 const QString &info);
68 virtual QString printerAddOption(const QString &name,71 virtual QString printerAddOption(const QString &name,
@@ -77,10 +80,14 @@
77 const PrinterJob *options);80 const PrinterJob *options);
7881
79 virtual void cancelJob(const QString &name, const int jobId);82 virtual void cancelJob(const QString &name, const int jobId);
83 virtual void holdJob(const QString &name, const int jobId);
84 virtual void releaseJob(const QString &name, const int jobId);
80 virtual int printFileToDest(const QString &filepath,85 virtual int printFileToDest(const QString &filepath,
81 const QString &title,86 const QString &title,
82 const cups_dest_t *dest);87 const cups_dest_t *dest);
83 virtual QList<QSharedPointer<PrinterJob>> printerGetJobs();88 virtual QList<QSharedPointer<PrinterJob>> printerGetJobs();
89 virtual QSharedPointer<PrinterJob> printerGetJob(const QString &printerName,
90 const int jobId);
84 virtual QMap<QString, QVariant> printerGetJobAttributes(91 virtual QMap<QString, QVariant> printerGetJobAttributes(
85 const QString &name, const int jobId);92 const QString &name, const int jobId);
8693
@@ -88,6 +95,7 @@
88 virtual QString description() const;95 virtual QString description() const;
89 virtual QString location() const;96 virtual QString location() const;
90 virtual QString makeAndModel() const;97 virtual QString makeAndModel() const;
98 virtual bool isRemote() const;
9199
92 virtual PrinterEnum::State state() const;100 virtual PrinterEnum::State state() const;
93 virtual QList<QPageSize> supportedPageSizes() const;101 virtual QList<QPageSize> supportedPageSizes() const;
@@ -105,6 +113,8 @@
105 virtual QSharedPointer<Printer> getPrinter(const QString &printerName);113 virtual QSharedPointer<Printer> getPrinter(const QString &printerName);
106 virtual QString defaultPrinterName();114 virtual QString defaultPrinterName();
107115
116 virtual void requestJobExtendedAttributes(QSharedPointer<Printer> printer,
117 QSharedPointer<PrinterJob> job);
108 virtual void requestPrinterDrivers();118 virtual void requestPrinterDrivers();
109 virtual void requestPrinter(const QString &printerName);119 virtual void requestPrinter(const QString &printerName);
110120
@@ -119,7 +129,10 @@
119 void printerDriversLoaded(const QList<PrinterDriver> &drivers);129 void printerDriversLoaded(const QList<PrinterDriver> &drivers);
120 void printerDriversFailedToLoad(const QString &errorMessage);130 void printerDriversFailedToLoad(const QString &errorMessage);
121131
132 void jobLoaded(QString, int, QMap<QString, QVariant>);
122 void printerLoaded(QSharedPointer<Printer> printers);133 void printerLoaded(QSharedPointer<Printer> printers);
134 void deviceFound(const Device &device);
135 void deviceSearchFinished();
123136
124 void jobCompleted(137 void jobCompleted(
125 const QString &text,138 const QString &text,
126139
=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp'
--- modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp 2017-02-24 12:53:34 +0000
+++ modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.cpp 2017-03-23 12:51:36 +0000
@@ -15,6 +15,8 @@
15 */15 */
1616
17#include "backend/backend_cups.h"17#include "backend/backend_cups.h"
18#include "cups/devicesearcher.h"
19#include "cups/jobloader.h"
18#include "cups/printerdriverloader.h"20#include "cups/printerdriverloader.h"
19#include "cups/printerloader.h"21#include "cups/printerloader.h"
20#include "utils.h"22#include "utils.h"
@@ -40,6 +42,10 @@
40 , m_knownQualityOptions({42 , m_knownQualityOptions({
41 "Quality", "PrintQuality", "HPPrintQuality", "StpQuality",43 "Quality", "PrintQuality", "HPPrintQuality", "StpQuality",
42 "OutputMode",})44 "OutputMode",})
45 , m_extendedAttributeNames({
46 QStringLiteral("StateMessage"), QStringLiteral("DeviceUri"),
47 QStringLiteral("IsShared"), QStringLiteral("Copies"),
48 })
43 , m_client(client)49 , m_client(client)
44 , m_info(info)50 , m_info(info)
45 , m_notifier(notifier)51 , m_notifier(notifier)
@@ -178,6 +184,24 @@
178 return QString();184 return QString();
179}185}
180186
187QString PrinterCupsBackend::printerSetCopies(const QString &name,
188 const int &copies)
189{
190 if (!m_client->printerSetCopies(name, copies)) {
191 return m_client->getLastError();
192 }
193 return QString();
194}
195
196QString PrinterCupsBackend::printerSetShared(const QString &name,
197 const bool shared)
198{
199 if (!m_client->printerSetShared(name, shared)) {
200 return m_client->getLastError();
201 }
202 return QString();
203}
204
181QString PrinterCupsBackend::printerSetInfo(const QString &name,205QString PrinterCupsBackend::printerSetInfo(const QString &name,
182 const QString &info)206 const QString &info)
183{207{
@@ -213,12 +237,27 @@
213 cups_dest_t *dest = getDest(name);237 cups_dest_t *dest = getDest(name);
214 ppd_file_t* ppd = getPpd(name);238 ppd_file_t* ppd = getPpd(name);
215239
216 if (!dest || !ppd) {240 // Used to store extended attributes, which we should request maximum once.
217 return ret;241 QMap<QString, QVariant> extendedAttributesResults;
242
243 /* Goes through known extended attributes. If one is being asked for,
244 ask for all of them right away. */
245 Q_FOREACH(const QString &extendedOption, m_extendedAttributeNames) {
246 if (options.contains(extendedOption)) {
247 extendedAttributesResults = m_client->printerGetAttributes(
248 name, QStringList({
249 QStringLiteral("device-uri"),
250 QStringLiteral("printer-uri-supported"),
251 QStringLiteral("printer-state-message"),
252 QStringLiteral("copies-default"),
253 })
254 );
255 break;
256 }
218 }257 }
219258
220 Q_FOREACH(const QString &option, options) {259 Q_FOREACH(const QString &option, options) {
221 if (option == QStringLiteral("DefaultColorModel")) {260 if (option == QStringLiteral("DefaultColorModel") && ppd) {
222 ColorModel model;261 ColorModel model;
223 ppd_option_t *ppdColorModel = ppdFindOption(ppd, "ColorModel");262 ppd_option_t *ppdColorModel = ppdFindOption(ppd, "ColorModel");
224 if (ppdColorModel) {263 if (ppdColorModel) {
@@ -231,7 +270,7 @@
231 }270 }
232 }271 }
233 ret[option] = QVariant::fromValue(model);272 ret[option] = QVariant::fromValue(model);
234 } else if (option == QStringLiteral("DefaultPrintQuality")) {273 } else if (option == QStringLiteral("DefaultPrintQuality") && ppd) {
235 PrintQuality quality;274 PrintQuality quality;
236 Q_FOREACH(const QString opt, m_knownQualityOptions) {275 Q_FOREACH(const QString opt, m_knownQualityOptions) {
237 ppd_option_t *ppdQuality = ppdFindOption(ppd, opt.toUtf8());276 ppd_option_t *ppdQuality = ppdFindOption(ppd, opt.toUtf8());
@@ -245,7 +284,7 @@
245 }284 }
246 }285 }
247 ret[option] = QVariant::fromValue(quality);286 ret[option] = QVariant::fromValue(quality);
248 } else if (option == QStringLiteral("SupportedPrintQualities")) {287 } else if (option == QStringLiteral("SupportedPrintQualities") && ppd) {
249 QList<PrintQuality> qualities;288 QList<PrintQuality> qualities;
250 Q_FOREACH(const QString &opt, m_knownQualityOptions) {289 Q_FOREACH(const QString &opt, m_knownQualityOptions) {
251 ppd_option_t *qualityOpt = ppdFindOption(ppd, opt.toUtf8());290 ppd_option_t *qualityOpt = ppdFindOption(ppd, opt.toUtf8());
@@ -262,7 +301,7 @@
262 }301 }
263 }302 }
264 ret[option] = QVariant::fromValue(qualities);303 ret[option] = QVariant::fromValue(qualities);
265 } else if (option == QStringLiteral("SupportedColorModels")) {304 } else if (option == QStringLiteral("SupportedColorModels") && ppd) {
266 QList<ColorModel> models;305 QList<ColorModel> models;
267 ppd_option_t *colorModels = ppdFindOption(ppd, "ColorModel");306 ppd_option_t *colorModels = ppdFindOption(ppd, "ColorModel");
268 if (colorModels) {307 if (colorModels) {
@@ -277,19 +316,29 @@
277 }316 }
278 }317 }
279 ret[option] = QVariant::fromValue(models);318 ret[option] = QVariant::fromValue(models);
280 } else if (option == QStringLiteral("AcceptJobs")) {319 } else if (option == QStringLiteral("AcceptJobs") && dest) {
281 // "true" if the destination is accepting new jobs, "false" if not.320 // "true" if the destination is accepting new jobs, "false" if not.
282 QString res = cupsGetOption("printer-is-accepting-jobs",321 QString res = cupsGetOption("printer-is-accepting-jobs",
283 dest->num_options, dest->options);322 dest->num_options, dest->options);
284 ret[option] = res.contains("true");323 ret[option] = res.contains("true");
285 } else {324 } else if (option == QStringLiteral("StateReasons") && dest) {
286 ppd_option_t *val = ppdFindOption(ppd, option.toUtf8());325 ret[option] = cupsGetOption("printer-state-reasons",
287326 dest->num_options, dest->options);
288 if (val) {327 } else if (option == QStringLiteral("StateMessage")) {
289 qWarning() << "asking for" << option << "returns" << val->text;328 ret[option] = extendedAttributesResults["printer-state-message"];
290 } else {329 } else if (option == QStringLiteral("DeviceUri")) {
291 qWarning() << "option" << option << "yielded no option";330 auto res = extendedAttributesResults;
292 }331 if (!res["printer-uri-supported"].toString().isEmpty()) {
332 ret[option] = res["printer-uri-supported"];
333 }
334 if (!res["device-uri"].toString().isEmpty()) {
335 ret[option] = res["device-uri"];
336 }
337 } else if (option == QStringLiteral("Copies")) {
338 ret[option] = extendedAttributesResults[QStringLiteral("copies-default")];
339 } else if (option == QStringLiteral("Shared") && dest) {
340 ret[option] = cupsGetOption("printer-is-shared",
341 dest->num_options, dest->options);
293 }342 }
294 }343 }
295 return ret;344 return ret;
@@ -306,10 +355,7 @@
306 __CUPS_ADD_OPTION(dest, "Collate", "False");355 __CUPS_ADD_OPTION(dest, "Collate", "False");
307 }356 }
308357
309 if (options->copies() > 1) {358 __CUPS_ADD_OPTION(dest, "copies", QString::number(options->copies()).toLocal8Bit());
310 __CUPS_ADD_OPTION(dest, "copies", QString::number(options->copies()).toLocal8Bit());
311 }
312
313 __CUPS_ADD_OPTION(dest, "ColorModel", options->getColorModel().name.toLocal8Bit());359 __CUPS_ADD_OPTION(dest, "ColorModel", options->getColorModel().name.toLocal8Bit());
314 __CUPS_ADD_OPTION(dest, "Duplex", Utils::duplexModeToPpdChoice(options->getDuplexMode()).toLocal8Bit());360 __CUPS_ADD_OPTION(dest, "Duplex", Utils::duplexModeToPpdChoice(options->getDuplexMode()).toLocal8Bit());
315361
@@ -347,6 +393,20 @@
347 }393 }
348}394}
349395
396void PrinterCupsBackend::holdJob(const QString &name, const int jobId)
397{
398 if (!m_client->printerHoldJob(name, jobId)) {
399 qWarning() << "Failed to hold job:" << jobId << "for" << name;
400 }
401}
402
403void PrinterCupsBackend::releaseJob(const QString &name, const int jobId)
404{
405 if (!m_client->printerReleaseJob(name, jobId)) {
406 qWarning() << "Failed to release job:" << jobId << "for" << name;
407 }
408}
409
350int PrinterCupsBackend::printFileToDest(const QString &filepath,410int PrinterCupsBackend::printFileToDest(const QString &filepath,
351 const QString &title,411 const QString &title,
352 const cups_dest_t *dest)412 const cups_dest_t *dest)
@@ -385,7 +445,7 @@
385 const QString &name, const int jobId)445 const QString &name, const int jobId)
386{446{
387 Q_UNUSED(name);447 Q_UNUSED(name);
388 QMap<QString, QVariant> rawMap = m_client->printerGetJobAttributes(jobId);448 QMap<QString, QVariant> rawMap = m_client->printerGetJobAttributes(name, jobId);
389 QMap<QString, QVariant> map;449 QMap<QString, QVariant> map;
390450
391 // Filter attributes to know values451 // Filter attributes to know values
@@ -409,12 +469,34 @@
409 map.insert("ColorModel", QVariant(""));469 map.insert("ColorModel", QVariant(""));
410 }470 }
411471
472 if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-completed", QDateTime)) {
473 map.insert("CompletedTime", rawMap.value("date-time-at-completed"));
474 } else {
475 map.insert("CompletedTime", QVariant(QDateTime()));
476 }
477
478 if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-creation", QDateTime)) {
479 map.insert("CreationTime", rawMap.value("date-time-at-creation"));
480 } else {
481 map.insert("CreationTime", QVariant(QDateTime()));
482 }
483
412 if (__CUPS_ATTR_EXISTS(rawMap, "Duplex", QString)) {484 if (__CUPS_ATTR_EXISTS(rawMap, "Duplex", QString)) {
413 map.insert("Duplex", rawMap.value("Duplex"));485 map.insert("Duplex", rawMap.value("Duplex"));
414 } else {486 } else {
415 map.insert("Duplex", QVariant(""));487 map.insert("Duplex", QVariant(""));
416 }488 }
417489
490 // Try job-media-sheets-completed first as it should include duplex
491 // if it doesn't exist fallback to job-impressions-completed
492 if (__CUPS_ATTR_EXISTS(rawMap, "job-media-sheets-completed", int)) {
493 map.insert("impressionsCompleted", rawMap.value("job-media-sheets-completed"));
494 } else if (__CUPS_ATTR_EXISTS(rawMap, "job-impressions-completed", int)) {
495 map.insert("impressionsCompleted", rawMap.value("job-impressions-completed"));
496 } else {
497 map.insert("impressionsCompleted", QVariant(0));
498 }
499
418 if (__CUPS_ATTR_EXISTS(rawMap, "landscape", bool)) {500 if (__CUPS_ATTR_EXISTS(rawMap, "landscape", bool)) {
419 map.insert("landscape", rawMap.value("landscape"));501 map.insert("landscape", rawMap.value("landscape"));
420 } else {502 } else {
@@ -434,6 +516,12 @@
434 map.insert("page-ranges", QVariant(QStringList()));516 map.insert("page-ranges", QVariant(QStringList()));
435 }517 }
436518
519 if (__CUPS_ATTR_EXISTS(rawMap, "date-time-at-processing", QDateTime)) {
520 map.insert("ProcessingTime", rawMap.value("date-time-at-processing"));
521 } else {
522 map.insert("ProcessingTime", QVariant(QDateTime()));
523 }
524
437 Q_FOREACH(QString qualityOption, m_knownQualityOptions) {525 Q_FOREACH(QString qualityOption, m_knownQualityOptions) {
438 if (rawMap.contains(qualityOption)526 if (rawMap.contains(qualityOption)
439 && rawMap.value(qualityOption).canConvert<QString>()) {527 && rawMap.value(qualityOption).canConvert<QString>()) {
@@ -451,6 +539,24 @@
451 map.insert("OutputOrder", "Normal");539 map.insert("OutputOrder", "Normal");
452 }540 }
453541
542 if (__CUPS_ATTR_EXISTS(rawMap, "job-k-octets", int)) {
543 map.insert("Size", rawMap.value("job-k-octets"));
544 } else {
545 map.insert("Size", QVariant(0));
546 }
547
548 // If there is a state then get it, as there could have been a signal
549 // flood. Which then means a forceJobRefresh is able to update the state
550 if (__CUPS_ATTR_EXISTS(rawMap, "job-state", int)) {
551 map.insert("State", rawMap.value("job-state").toInt());
552 }
553
554 if (__CUPS_ATTR_EXISTS(rawMap, "job-originating-user-name", QString)) {
555 map.insert("User", rawMap.value("job-originating-user-name"));
556 } else {
557 map.insert("User", QVariant(""));
558 }
559
454 // Generate a list of messages560 // Generate a list of messages
455 // TODO: for now just using job-printer-state-message, are there others?561 // TODO: for now just using job-printer-state-message, are there others?
456 QStringList messages;562 QStringList messages;
@@ -471,31 +577,13 @@
471 QList<QSharedPointer<PrinterJob>> list;577 QList<QSharedPointer<PrinterJob>> list;
472578
473 Q_FOREACH(auto job, jobs) {579 Q_FOREACH(auto job, jobs) {
580 // Note: extended attributes are not loaded here
581 // they are loaded in JobLoader
474 auto newJob = QSharedPointer<PrinterJob>(582 auto newJob = QSharedPointer<PrinterJob>(
475 new PrinterJob(QString::fromUtf8(job->dest), this, job->id)583 new PrinterJob(QString::fromUtf8(job->dest), this, job->id)
476 );584 );
477
478 // Extract the times
479 QDateTime completedTime;
480 completedTime.setTimeZone(QTimeZone::systemTimeZone());
481 completedTime.setTime_t(job->completed_time);
482
483 QDateTime creationTime;
484 creationTime.setTimeZone(QTimeZone::systemTimeZone());
485 creationTime.setTime_t(job->creation_time);
486
487 QDateTime processingTime;
488 processingTime.setTimeZone(QTimeZone::systemTimeZone());
489 processingTime.setTime_t(job->processing_time);
490
491 // Load the information from the cups struct
492 newJob->setCompletedTime(completedTime);
493 newJob->setCreationTime(creationTime);
494 newJob->setProcessingTime(processingTime);
495 newJob->setSize(job->size);
496 newJob->setState(static_cast<PrinterEnum::JobState>(job->state));585 newJob->setState(static_cast<PrinterEnum::JobState>(job->state));
497 newJob->setTitle(QString::fromLocal8Bit(job->title));586 newJob->setTitle(QString::fromLocal8Bit(job->title));
498 newJob->setUser(QString::fromLocal8Bit(job->user));
499587
500 list.append(newJob);588 list.append(newJob);
501 }589 }
@@ -505,6 +593,35 @@
505 return list;593 return list;
506}594}
507595
596QSharedPointer<PrinterJob> PrinterCupsBackend::printerGetJob(
597 const QString &printerName, const int jobId)
598{
599 auto jobs = getCupsJobs(printerName);
600 cups_job_t *cupsJob = Q_NULLPTR;
601 QSharedPointer<PrinterJob> job(Q_NULLPTR);
602
603 for (int i=0; i < jobs.size(); i++) {
604 if (jobs.at(i)->id == jobId) {
605 cupsJob = jobs.at(i);
606 break;
607 }
608 }
609
610 if (cupsJob) {
611 job = QSharedPointer<PrinterJob>(
612 new PrinterJob(QString::fromUtf8(cupsJob->dest), this, cupsJob->id)
613 );
614
615 job->setState(static_cast<PrinterEnum::JobState>(cupsJob->state));
616 job->setTitle(QString::fromLocal8Bit(cupsJob->title));
617 }
618
619 if (!jobs.size())
620 cupsFreeJobs(jobs.size(), jobs.first());
621
622 return job;
623}
624
508QString PrinterCupsBackend::printerName() const625QString PrinterCupsBackend::printerName() const
509{626{
510 return m_printerName;627 return m_printerName;
@@ -525,6 +642,11 @@
525 return m_info.makeAndModel();642 return m_info.makeAndModel();
526}643}
527644
645bool PrinterCupsBackend::isRemote() const
646{
647 return m_info.isRemote();
648}
649
528PrinterEnum::State PrinterCupsBackend::state() const650PrinterEnum::State PrinterCupsBackend::state() const
529{651{
530 switch (m_info.state()) {652 switch (m_info.state()) {
@@ -611,9 +733,35 @@
611 return QPrinterInfo::defaultPrinterName();733 return QPrinterInfo::defaultPrinterName();
612}734}
613735
736void PrinterCupsBackend::requestJobExtendedAttributes(
737 QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job)
738{
739 QPair<QString, int> pair(printer->name(), job->jobId());
740
741 if (m_activeJobRequests.contains(pair)) {
742 return;
743 }
744
745 auto thread = new QThread;
746 auto loader = new JobLoader(this, printer->name(), job->jobId());
747 loader->moveToThread(thread);
748 connect(thread, SIGNAL(started()), loader, SLOT(load()));
749 connect(loader, SIGNAL(finished()), thread, SLOT(quit()));
750 connect(loader, SIGNAL(finished()), loader, SLOT(deleteLater()));
751 connect(loader, SIGNAL(loaded(QString, int, QMap<QString, QVariant>)),
752 this, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>)));
753 connect(loader, SIGNAL(loaded(QString, int, QMap<QString, QVariant>)),
754 this, SLOT(onJobLoaded(QString, int, QMap<QString, QVariant>)));
755 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
756
757 m_activeJobRequests << pair;
758
759 thread->start();
760}
761
614void PrinterCupsBackend::requestPrinter(const QString &printerName)762void PrinterCupsBackend::requestPrinter(const QString &printerName)
615{763{
616 if (m_activeRequests.contains(printerName)) {764 if (m_activePrinterRequests.contains(printerName)) {
617 return;765 return;
618 }766 }
619767
@@ -628,9 +776,10 @@
628 connect(loader, SIGNAL(loaded(QSharedPointer<Printer>)),776 connect(loader, SIGNAL(loaded(QSharedPointer<Printer>)),
629 this, SLOT(onPrinterLoaded(QSharedPointer<Printer>)));777 this, SLOT(onPrinterLoaded(QSharedPointer<Printer>)));
630 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));778 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
779
780 m_activePrinterRequests << printerName;
781
631 thread->start();782 thread->start();
632
633 m_activeRequests << printerName;
634}783}
635784
636void PrinterCupsBackend::requestPrinterDrivers()785void PrinterCupsBackend::requestPrinterDrivers()
@@ -647,6 +796,7 @@
647 connect(loader, SIGNAL(loaded(const QList<PrinterDriver>&)),796 connect(loader, SIGNAL(loaded(const QList<PrinterDriver>&)),
648 this, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&)));797 this, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&)));
649 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));798 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
799
650 thread->start();800 thread->start();
651}801}
652802
@@ -655,6 +805,22 @@
655 Q_EMIT requestPrinterDriverCancel();805 Q_EMIT requestPrinterDriverCancel();
656}806}
657807
808void PrinterCupsBackend::searchForDevices()
809{
810
811 auto thread = new QThread;
812 auto searcher = new DeviceSearcher();
813 searcher->moveToThread(thread);
814 connect(thread, SIGNAL(started()), searcher, SLOT(load()));
815 connect(searcher, SIGNAL(finished()), thread, SLOT(quit()));
816 connect(searcher, SIGNAL(finished()), searcher, SLOT(deleteLater()));
817 connect(searcher, SIGNAL(finished()), this, SIGNAL(deviceSearchFinished()));
818 connect(searcher, SIGNAL(loaded(const Device&)),
819 this, SIGNAL(deviceFound(const Device&)));
820 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
821 thread->start();
822}
823
658void PrinterCupsBackend::refresh()824void PrinterCupsBackend::refresh()
659{825{
660 if (m_printerName.isEmpty()) {826 if (m_printerName.isEmpty()) {
@@ -716,7 +882,22 @@
716 }882 }
717}883}
718884
885bool PrinterCupsBackend::isExtendedAttribute(const QString &attributeName) const
886{
887 return m_extendedAttributeNames.contains(attributeName);
888}
889
890void PrinterCupsBackend::onJobLoaded(QString printerName, int jobId,
891 QMap<QString, QVariant> attributes)
892{
893 Q_UNUSED(attributes);
894
895 QPair<QString, int> pair(printerName, jobId);
896 m_activeJobRequests.remove(pair);
897}
898
719void PrinterCupsBackend::onPrinterLoaded(QSharedPointer<Printer> printer)899void PrinterCupsBackend::onPrinterLoaded(QSharedPointer<Printer> printer)
720{900{
721 m_activeRequests.remove(printer->name());901 m_activePrinterRequests.remove(printer->name());
722}902}
903
723904
=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h'
--- modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h 2017-02-24 12:53:34 +0000
+++ modules/Ubuntu/Components/Extras/Printers/backend/backend_cups.h 2017-03-23 12:51:36 +0000
@@ -55,6 +55,10 @@
55 const QString &name,55 const QString &name,
56 const bool accept,56 const bool accept,
57 const QString &reason = QString::null) override;57 const QString &reason = QString::null) override;
58 virtual QString printerSetCopies(
59 const QString &name, const int &copies) override;
60 virtual QString printerSetShared(const QString &name,
61 const bool shared) override;
58 virtual QString printerSetInfo(const QString &name,62 virtual QString printerSetInfo(const QString &name,
59 const QString &info) override;63 const QString &info) override;
60 virtual QString printerAddOption(const QString &name,64 virtual QString printerAddOption(const QString &name,
@@ -71,15 +75,20 @@
71 const PrinterJob *options) override;75 const PrinterJob *options) override;
7276
73 virtual void cancelJob(const QString &name, const int jobId) override;77 virtual void cancelJob(const QString &name, const int jobId) override;
78 virtual void holdJob(const QString &name, const int jobId) override;
79 virtual void releaseJob(const QString &name, const int jobId) override;
74 virtual int printFileToDest(const QString &filepath,80 virtual int printFileToDest(const QString &filepath,
75 const QString &title,81 const QString &title,
76 const cups_dest_t *dest) override;82 const cups_dest_t *dest) override;
77 virtual QList<QSharedPointer<PrinterJob>> printerGetJobs() override;83 virtual QList<QSharedPointer<PrinterJob>> printerGetJobs() override;
84 virtual QSharedPointer<PrinterJob> printerGetJob(
85 const QString &printerName, const int jobId) override;
7886
79 virtual QString printerName() const override;87 virtual QString printerName() const override;
80 virtual QString description() const override;88 virtual QString description() const override;
81 virtual QString location() const override;89 virtual QString location() const override;
82 virtual QString makeAndModel() const override;90 virtual QString makeAndModel() const override;
91 virtual bool isRemote() const override;
8392
84 virtual PrinterEnum::State state() const override;93 virtual PrinterEnum::State state() const override;
85 virtual QList<QPageSize> supportedPageSizes() const override;94 virtual QList<QPageSize> supportedPageSizes() const override;
@@ -96,6 +105,10 @@
96 virtual QStringList availablePrinterNames() override;105 virtual QStringList availablePrinterNames() override;
97 virtual QSharedPointer<Printer> getPrinter(const QString &printerName) override;106 virtual QSharedPointer<Printer> getPrinter(const QString &printerName) override;
98 virtual QString defaultPrinterName() override;107 virtual QString defaultPrinterName() override;
108
109 virtual void requestJobExtendedAttributes(
110 QSharedPointer<Printer> printer,
111 QSharedPointer<PrinterJob> job) override;
99 virtual void requestPrinterDrivers() override;112 virtual void requestPrinterDrivers() override;
100 virtual void requestPrinter(const QString &printerName) override;113 virtual void requestPrinter(const QString &printerName) override;
101 virtual QMap<QString, QVariant> printerGetJobAttributes(114 virtual QMap<QString, QVariant> printerGetJobAttributes(
@@ -105,6 +118,11 @@
105 virtual void refresh() override;118 virtual void refresh() override;
106 void createSubscription();119 void createSubscription();
107120
121 /* Starts a search for devices. Devices are synonymous with network devices
122 that may potentially be queues. This search will take at minimum 5 seconds,
123 normally longer. */
124 void searchForDevices();
125
108Q_SIGNALS:126Q_SIGNALS:
109 void cancelWorkers();127 void cancelWorkers();
110 void printerDriversLoaded(const QList<PrinterDriver> &drivers);128 void printerDriversLoaded(const QList<PrinterDriver> &drivers);
@@ -120,16 +138,22 @@
120 QString getPrinterInstance(const QString &name) const;138 QString getPrinterInstance(const QString &name) const;
121 cups_dest_t* getDest(const QString &name) const;139 cups_dest_t* getDest(const QString &name) const;
122 ppd_file_t* getPpd(const QString &name) const;140 ppd_file_t* getPpd(const QString &name) const;
141 bool isExtendedAttribute(const QString &attributeName) const;
142
123 const QStringList m_knownQualityOptions;143 const QStringList m_knownQualityOptions;
144 const QStringList m_extendedAttributeNames;
124 IppClient *m_client;145 IppClient *m_client;
125 QPrinterInfo m_info;146 QPrinterInfo m_info;
126 OrgCupsCupsdNotifierInterface *m_notifier;147 OrgCupsCupsdNotifierInterface *m_notifier;
127 int m_cupsSubscriptionId;148 int m_cupsSubscriptionId;
128 mutable QMap<QString, cups_dest_t*> m_dests; // Printer name, dest.149 mutable QMap<QString, cups_dest_t*> m_dests; // Printer name, dest.
129 mutable QMap<QString, ppd_file_t*> m_ppds; // Printer name, ppd.150 mutable QMap<QString, ppd_file_t*> m_ppds; // Printer name, ppd.
130 QSet<QString> m_activeRequests;151 QSet<QString> m_activePrinterRequests;
152 QSet<QPair<QString, int>> m_activeJobRequests;
131153
132private Q_SLOTS:154private Q_SLOTS:
155 void onJobLoaded(QString printerName, int jobId,
156 QMap<QString, QVariant> attributes);
133 void onPrinterLoaded(QSharedPointer<Printer> printer);157 void onPrinterLoaded(QSharedPointer<Printer> printer);
134};158};
135159
136160
=== modified file 'modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp'
--- modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp 2017-03-23 12:51:36 +0000
@@ -59,6 +59,16 @@
59 ret[option] = QVariant::fromValue(models);59 ret[option] = QVariant::fromValue(models);
60 } else if (option == QLatin1String("AcceptJobs")) {60 } else if (option == QLatin1String("AcceptJobs")) {
61 ret[option] = true;61 ret[option] = true;
62 } else if (option == QLatin1String("StateReasons")) {
63 ret[option] = QLatin1String("");
64 } else if (option == QLatin1String("StateMessage")) {
65 ret[option] = QLatin1String("");
66 } else if (option == QLatin1String("DeviceUri")) {
67 ret[option] = QLatin1String("");
68 } else if (option == QLatin1String("Copies")) {
69 ret[option] = 0;
70 } else if (option == QLatin1String("Shared")) {
71 ret[option] = false;
62 } else {72 } else {
63 throw std::invalid_argument("Invalid value for PDF printer: " + option.toStdString());73 throw std::invalid_argument("Invalid value for PDF printer: " + option.toStdString());
64 }74 }
6575
=== added file 'modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp'
--- modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.cpp 2017-03-23 12:51:36 +0000
@@ -0,0 +1,70 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "cups/ippclient.h"
18#include "devicesearcher.h"
19
20#include <QUrl>
21
22DeviceSearcher::DeviceSearcher(IppClient *client, QObject *parent)
23 : QObject(parent)
24 , m_client(client)
25{
26}
27
28DeviceSearcher::~DeviceSearcher()
29{
30 delete m_client;
31}
32
33void DeviceSearcher::load()
34{
35 if (!m_client->getDevices(&DeviceSearcher::deviceCallBack, this)) {
36 Q_EMIT failed(cupsLastErrorString());
37 }
38 Q_EMIT finished();
39}
40
41void DeviceSearcher::deviceCallBack(
42 const char *deviceClass,
43 const char *deviceId,
44 const char *deviceInfo,
45 const char *deviceMakeAndModel,
46 const char *deviceUri,
47 const char *deviceLocation,
48 void *context)
49{
50 auto searcher = qobject_cast<DeviceSearcher*>(static_cast<QObject*>(context));
51 if (!searcher) {
52 qWarning() << Q_FUNC_INFO << "context was not a DeviceSearcher.";
53 return;
54 }
55
56 Device d;
57 d.cls = deviceClass;
58 d.id = deviceId;
59 d.info = deviceInfo;
60 d.makeModel = deviceMakeAndModel;
61 d.uri = deviceUri;
62 d.location = deviceLocation;
63
64 searcher->deviceFound(d);
65}
66
67void DeviceSearcher::deviceFound(const Device &device)
68{
69 Q_EMIT loaded(device);
70}
071
=== added file 'modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h'
--- modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/devicesearcher.h 2017-03-23 12:51:36 +0000
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef USC_PRINTERS_CUPS_DEVICESEARCHER_H
18#define USC_PRINTERS_CUPS_DEVICESEARCHER_H
19
20#include "cups/ippclient.h"
21#include "structs.h"
22
23#include <QObject>
24#include <QString>
25
26/* Class representing a device search. It is a worker object due to the time
27such a search takes (minimum 10 seconds). */
28class DeviceSearcher : public QObject
29{
30 Q_OBJECT
31 IppClient *m_client;
32public:
33 explicit DeviceSearcher(IppClient *client = new IppClient,
34 QObject *parent = Q_NULLPTR);
35 ~DeviceSearcher();
36
37public Q_SLOTS:
38 void load();
39
40private:
41 static void deviceCallBack(
42 const char *cls,
43 const char *id,
44 const char *info,
45 const char *makeAndModel,
46 const char *uri,
47 const char *location,
48 void *context);
49 void deviceFound(const Device &device);
50
51Q_SIGNALS:
52 void loaded(const Device &device);
53 void failed(const QString &errorMessage);
54 void finished();
55};
56
57#endif // USC_PRINTERS_CUPS_DEVICESEARCHER_H
058
=== modified file 'modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp'
--- modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/ippclient.cpp 2017-03-23 12:51:36 +0000
@@ -25,6 +25,7 @@
2525
26#include <QDebug>26#include <QDebug>
27#include <QDateTime>27#include <QDateTime>
28#include <QtAlgorithms>
28#include <QTimeZone>29#include <QTimeZone>
29#include <QUrl>30#include <QUrl>
3031
@@ -173,6 +174,30 @@
173 return postRequest(request, ppdFileName.toUtf8(), CupsResourceAdmin);174 return postRequest(request, ppdFileName.toUtf8(), CupsResourceAdmin);
174}175}
175176
177bool IppClient::printerHoldJob(const QString &printerName, const int jobId)
178{
179 ipp_t *request = ippNewRequest(IPP_HOLD_JOB);
180 addPrinterUri(request, printerName);
181 addRequestingUsername(request, NULL);
182
183 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
184 "job-id", jobId);
185
186 return sendRequest(request, CupsResourceJobs);
187}
188
189bool IppClient::printerReleaseJob(const QString &printerName, const int jobId)
190{
191 ipp_t *request = ippNewRequest(IPP_RELEASE_JOB);
192 addPrinterUri(request, printerName);
193 addRequestingUsername(request, NULL);
194
195 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
196 "job-id", jobId);
197
198 return sendRequest(request, CupsResourceJobs);
199}
200
176bool IppClient::printerSetDefault(const QString &printerName)201bool IppClient::printerSetDefault(const QString &printerName)
177{202{
178 return sendNewSimpleRequest(CUPS_SET_DEFAULT, printerName.toUtf8(),203 return sendNewSimpleRequest(CUPS_SET_DEFAULT, printerName.toUtf8(),
@@ -225,9 +250,46 @@
225 }250 }
226}251}
227252
253bool IppClient::printerSetCopies(const QString &printerName, const int &copies)
254{
255 ipp_t *request;
256
257 if (!isPrinterNameValid(printerName)) {
258 setInternalStatus(QString("%1 is not a valid printer name.").arg(printerName));
259 return false;
260 }
261 request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
262 addPrinterUri(request, printerName);
263 addRequestingUsername(request, NULL);
264 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
265 "copies-default", copies);
266 /* TODO: The request will fail if this was a printer class, and it should
267 be retried. */
268 return sendRequest(request, CupsResourceAdmin);
269}
270
271bool IppClient::printerSetShared(const QString &printerName, const bool shared)
272{
273 ipp_t *request;
274
275 if (!isPrinterNameValid(printerName)) {
276 setInternalStatus(QString("%1 is not a valid printer name.").arg(printerName));
277 return false;
278 }
279
280 request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
281 addPrinterUri(request, printerName);
282 addRequestingUsername(request, NULL);
283 ippAddBoolean(request, IPP_TAG_OPERATION,
284 "printer-is-shared", shared ? 1 : 0);
285 /* TODO: The request will fail if this was a printer class, and it should
286 be retried. */
287
288 return sendRequest(request, CupsResourceAdmin);
289}
228290
229bool IppClient::printerClassSetInfo(const QString &name,291bool IppClient::printerClassSetInfo(const QString &name,
230 const QString &info)292 const QString &info)
231{293{
232 if (!isPrinterNameValid(name)) {294 if (!isPrinterNameValid(name)) {
233 setInternalStatus(QString("%1 is not a valid printer name.").arg(name));295 setInternalStatus(QString("%1 is not a valid printer name.").arg(name));
@@ -336,18 +398,99 @@
336 return retval;398 return retval;
337}399}
338400
339QMap<QString, QVariant> IppClient::printerGetJobAttributes(const int jobId)401QMap<QString, QVariant> IppClient::printerGetAttributes(
402 const QString &printerName, const QStringList &attributes)
403{
404 QMap<QString, QVariant> result;
405 QList<QByteArray*> attrByteArrays;
406 ipp_t *request;
407 ipp_attribute_t *attr;
408
409 if (attributes.isEmpty()) {
410 return result;
411 }
412
413 int i;
414 size_t n = attributes.size();
415 char **attrs;
416 attrs = (char**) malloc ((n + 1) * sizeof (char *));
417
418 /* This is some trickery to compensate for a lack of C array/pointer
419 skills. The VLA attrs gets the underlying data structure of a QByterArray
420 on the heap. When cups is done with it, and in the end of this method,
421 the QByteArrays are deleted, and attrs is freed. */
422 for (i = 0; i < ((int) n); i++) {
423 QByteArray *array = new QByteArray(attributes.value(i).toLocal8Bit());
424 attrByteArrays << array;
425 attrs[i] = array->data();
426 }
427 attrs[n] = NULL;
428
429 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
430 addPrinterUri(request, printerName);
431 addRequestingUsername(request, QString());
432 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
433 "requested-attributes", attributes.size(), NULL, attrs);
434 auto resource = getResource(CupsResource::CupsResourceRoot);
435
436 ipp_t *reply;
437 reply = cupsDoRequest(m_connection, request, resource.toUtf8());
438
439 if (!isReplyOk(reply, false)) {
440 qWarning() << Q_FUNC_INFO << "failed to get attributes"
441 << attributes << "for printer" << printerName;
442 } else {
443 for (attr = ippFirstAttribute(reply); attr; attr = ippNextAttribute(reply)) {
444 while (attr && ippGetGroupTag(attr) != IPP_TAG_PRINTER)
445 attr = ippNextAttribute(reply);
446
447 if (!attr)
448 break;
449
450 for (; attr && ippGetGroupTag(attr) == IPP_TAG_PRINTER;
451 attr = ippNextAttribute(reply)) {
452
453 /* TODO: Here we need to take into account that the returned
454 attributes could be lists and other things. */
455 result[ippGetName(attr)] = getAttributeValue(attr);
456
457 if (!attr)
458 break;
459 }
460 }
461 }
462
463 if (reply)
464 ippDelete(reply);
465
466 qDeleteAll(attrByteArrays);
467 free(attrs);
468
469 return result;
470}
471
472QMap<QString, QVariant> IppClient::printerGetJobAttributes(const QString &printerName,
473 const int jobId)
340{474{
341 ipp_t *request;475 ipp_t *request;
342 QMap<QString, QVariant> map;476 QMap<QString, QVariant> map;
343477
478 // Try to get the lock, if we can't after 5 seconds then fail and return
479 if (!m_thread_lock.tryLock(5000)) {
480 qWarning() << "Unable to get lock for IppClient::printerGetJobAttributes."
481 << "Unable to load attributes for job:" << jobId << " for "
482 << printerName;
483 return map;
484 }
485
344 // Construct request486 // Construct request
345 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);487 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
346 QString uri = QStringLiteral("ipp://localhost/jobs/") + QString::number(jobId);488
347 qDebug() << "URI:" << uri;489 addPrinterUri(request, printerName);
348490 addRequestingUsername(request, NULL);
349 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri.toStdString().data());491
350492 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
493 "job-id", jobId);
351494
352 // Send request and construct reply495 // Send request and construct reply
353 ipp_t *reply;496 ipp_t *reply;
@@ -365,7 +508,8 @@
365 map.insert(ippGetName(attr), value);508 map.insert(ippGetName(attr), value);
366 }509 }
367 } else {510 } else {
368 qWarning() << "Not able to get attributes of job:" << jobId;511 qWarning() << "Not able to get attributes of job:" << jobId << " for "
512 << printerName;
369 }513 }
370514
371 // Destruct the reply if valid515 // Destruct the reply if valid
@@ -373,6 +517,8 @@
373 ippDelete(reply);517 ippDelete(reply);
374 }518 }
375519
520 m_thread_lock.unlock();
521
376 return map;522 return map;
377}523}
378524
@@ -972,8 +1118,8 @@
972 case IPP_TAG_DATE: {1118 case IPP_TAG_DATE: {
973 time_t time = ippDateToTime(ippGetDate(attr, index));1119 time_t time = ippDateToTime(ippGetDate(attr, index));
974 QDateTime datetime;1120 QDateTime datetime;
975 datetime.setTimeZone(QTimeZone::systemTimeZone());
976 datetime.setTime_t(time);1121 datetime.setTime_t(time);
1122 datetime.setTimeZone(QTimeZone::utc());
9771123
978 var = QVariant::fromValue<QDateTime>(datetime);1124 var = QVariant::fromValue<QDateTime>(datetime);
979 break;1125 break;
@@ -986,3 +1132,11 @@
9861132
987 return var;1133 return var;
988}1134}
1135
1136bool IppClient::getDevices(cups_device_cb_t callback, void *context) const
1137{
1138 auto reply = cupsGetDevices(m_connection, CUPS_TIMEOUT_DEFAULT,
1139 CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE, callback,
1140 context);
1141 return reply == IPP_OK;
1142}
9891143
=== modified file 'modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h'
--- modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/ippclient.h 2017-03-23 12:51:36 +0000
@@ -19,11 +19,13 @@
1919
20#include "structs.h"20#include "structs.h"
2121
22#include <cups/adminutil.h>
22#include <cups/cups.h>23#include <cups/cups.h>
23#include <cups/http.h>24#include <cups/http.h>
24#include <cups/ipp.h>25#include <cups/ipp.h>
25#include <cups/ppd.h>26#include <cups/ppd.h>
2627
28#include <QMutex>
27#include <QString>29#include <QString>
28#include <QStringList>30#include <QStringList>
2931
@@ -51,17 +53,25 @@
51 const QString &ppdFileName,53 const QString &ppdFileName,
52 const QString &info,54 const QString &info,
53 const QString &location);55 const QString &location);
56 bool printerHoldJob(const QString &printerName, const int jobId);
57 bool printerReleaseJob(const QString &printerName, const int jobId);
54 bool printerSetDefault(const QString &printerName);58 bool printerSetDefault(const QString &printerName);
55 bool printerSetEnabled(const QString &printerName, const bool enabled);59 bool printerSetEnabled(const QString &printerName, const bool enabled);
56 bool printerSetAcceptJobs(const QString &printerName, const bool accept,60 bool printerSetAcceptJobs(const QString &printerName, const bool accept,
57 const QString &reason);61 const QString &reason);
62 bool printerSetCopies(const QString &printerName, const int &copies);
63 bool printerSetShared(const QString &printerName, const bool shared);
58 bool printerClassSetInfo(const QString &name, const QString &info);64 bool printerClassSetInfo(const QString &name, const QString &info);
59 bool printerClassSetOption(const QString &name, const QString &option,65 bool printerClassSetOption(const QString &name, const QString &option,
60 const QStringList &values);66 const QStringList &values);
61 ppd_file_t* getPpdFile(const QString &name, const QString &instance) const;67 ppd_file_t* getPpdFile(const QString &name, const QString &instance) const;
62 cups_dest_t* getDest(const QString &name, const QString &instance) const;68 cups_dest_t* getDest(const QString &name, const QString &instance) const;
6369
64 QMap<QString, QVariant> printerGetJobAttributes(const int jobId);70 // Fetch more attributes, as normally just a small subset is fetched.
71 QMap<QString, QVariant> printerGetAttributes(const QString &printerName,
72 const QStringList &attributes);
73 QMap<QString, QVariant> printerGetJobAttributes(const QString &printerName,
74 const int jobId);
6575
66 QString getLastError() const;76 QString getLastError() const;
6777
@@ -73,6 +83,7 @@
73 );83 );
74 int createSubscription();84 int createSubscription();
75 void cancelSubscription(const int &subscriptionId);85 void cancelSubscription(const int &subscriptionId);
86 bool getDevices(cups_device_cb_t callback, void *context) const;
7687
77private:88private:
78 enum CupsResource89 enum CupsResource
@@ -115,6 +126,7 @@
115 http_t *m_connection;126 http_t *m_connection;
116 ipp_status_t m_lastStatus = IPP_OK;127 ipp_status_t m_lastStatus = IPP_OK;
117 mutable QString m_internalStatus = QString::null;128 mutable QString m_internalStatus = QString::null;
129 QMutex m_thread_lock;
118};130};
119131
120132
121133
=== added file 'modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp'
--- modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/jobloader.cpp 2017-03-23 12:51:36 +0000
@@ -0,0 +1,50 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "jobloader.h"
18
19#include "backend/backend.h"
20
21#include "printers/printers.h"
22
23#include <QDBusConnection>
24#include <QPrinterInfo>
25
26class PrinterCupsBackend;
27JobLoader::JobLoader(PrinterBackend *backend,
28 QString printerName,
29 int jobId,
30 QObject *parent)
31 : QObject(parent)
32 , m_backend(backend)
33 , m_job_id(jobId)
34 , m_printer_name(printerName)
35{
36}
37
38JobLoader::~JobLoader()
39{
40}
41
42void JobLoader::load()
43{
44 QMap<QString, QVariant> map = m_backend->printerGetJobAttributes(
45 m_printer_name, m_job_id
46 );
47
48 Q_EMIT loaded(m_printer_name, m_job_id, map);
49 Q_EMIT finished();
50}
051
=== added file 'modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h'
--- modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/jobloader.h 2017-03-23 12:51:36 +0000
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef USC_PRINTERS_CUPS_JOBLOADER_H
18#define USC_PRINTERS_CUPS_JOBLOADER_H
19
20#include "printer/printer.h"
21#include "printer/printerjob.h"
22
23#include <QList>
24#include <QObject>
25#include <QSharedPointer>
26
27class JobLoader : public QObject
28{
29 Q_OBJECT
30 PrinterBackend *m_backend;
31 int m_job_id;
32 QString m_printer_name;
33public:
34 explicit JobLoader(PrinterBackend *backend,
35 QString printerName, int jobId,
36 QObject *parent = Q_NULLPTR);
37 ~JobLoader();
38
39public Q_SLOTS:
40 void load();
41
42Q_SIGNALS:
43 void finished();
44 void loaded(QString, int, QMap<QString, QVariant>);
45};
46
47#endif // USC_PRINTERS_CUPS_JOBLOADER_H
048
=== modified file 'modules/Ubuntu/Components/Extras/Printers/cups/printerloader.cpp'
--- modules/Ubuntu/Components/Extras/Printers/cups/printerloader.cpp 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/cups/printerloader.cpp 2017-03-23 12:51:36 +0000
@@ -18,6 +18,7 @@
18#include "backend/backend_cups.h"18#include "backend/backend_cups.h"
19#include "printerloader.h"19#include "printerloader.h"
2020
21#include <QApplication>
21#include <QPrinterInfo>22#include <QPrinterInfo>
2223
23class PrinterCupsBackend;24class PrinterCupsBackend;
@@ -48,6 +49,8 @@
4849
49 auto p = QSharedPointer<Printer>(new Printer(backend));50 auto p = QSharedPointer<Printer>(new Printer(backend));
5051
52 p->moveToThread(QApplication::instance()->thread());
53
51 Q_EMIT loaded(p);54 Q_EMIT loaded(p);
52 Q_EMIT finished();55 Q_EMIT finished();
53}56}
5457
=== modified file 'modules/Ubuntu/Components/Extras/Printers/enums.h'
--- modules/Ubuntu/Components/Extras/Printers/enums.h 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/enums.h 2017-03-23 12:51:36 +0000
@@ -101,6 +101,29 @@
101 PdfType,101 PdfType,
102 };102 };
103 Q_ENUM(PrinterType)103 Q_ENUM(PrinterType)
104
105 enum class DeviceType
106 {
107 UnknownType = 0,
108 LPDType,
109 IppSType,
110 Ipp14Type,
111 HttpType,
112 BehType,
113 SocketType,
114 HttpsType,
115 IppType,
116 HPType,
117 USBType,
118 HPFaxType,
119 DNSSDType,
120 };
121 Q_ENUM(DeviceType)
104};122};
105123
124inline uint qHash(const PrinterEnum::JobState &state, uint seed)
125{
126 return qHash((int) state, seed);
127}
128
106#endif // USC_PRINTERS_ENUMS_H129#endif // USC_PRINTERS_ENUMS_H
107130
=== added file 'modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp'
--- modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Extras/Printers/models/devicemodel.cpp 2017-03-23 12:51:36 +0000
@@ -0,0 +1,149 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "backend/backend_cups.h"
18#include "models/devicemodel.h"
19
20#include <QDebug>
21
22DeviceModel::DeviceModel(PrinterBackend *backend, QObject *parent)
23 : QAbstractListModel(parent)
24 , m_backend(backend)
25 , m_isSearching(false)
26{
27 connect(m_backend, SIGNAL(deviceFound(const Device&)),
28 this, SLOT(deviceLoaded(const Device&)));
29 connect(m_backend, SIGNAL(deviceSearchFinished()),
30 this, SLOT(deviceSearchFinished()));
31}
32
33DeviceModel::~DeviceModel()
34{
35}
36
37int DeviceModel::rowCount(const QModelIndex &parent) const
38{
39 Q_UNUSED(parent);
40 return m_devices.size();
41}
42
43int DeviceModel::count() const
44{
45 return rowCount();
46}
47
48QVariant DeviceModel::data(const QModelIndex &index, int role) const
49{
50 QVariant ret;
51
52 if ((0 <= index.row()) && (index.row() < m_devices.size())) {
53
54 auto device = m_devices[index.row()];
55
56 switch (role) {
57 case Qt::DisplayRole:
58 ret = device.toString();
59 break;
60 case IdRole:
61 ret = device.id;
62 break;
63 case InfoRole:
64 ret = device.info;
65 break;
66 case UriRole:
67 ret = device.uri;
68 break;
69 case LocationRole:
70 ret = device.location;
71 break;
72 case TypeRole:
73 ret = QVariant::fromValue(device.type());
74 break;
75 case MakeModelRole:
76 ret = device.makeModel;
77 break;
78 }
79 }
80
81 return ret;
82}
83
84QHash<int, QByteArray> DeviceModel::roleNames() const
85{
86 static QHash<int,QByteArray> names;
87
88 if (Q_UNLIKELY(names.empty())) {
89 names[Qt::DisplayRole] = "displayName";
90 names[IdRole] = "id";
91 names[InfoRole] = "info";
92 names[UriRole] = "uri";
93 names[LocationRole] = "location";
94 names[TypeRole] = "type";
95 names[MakeModelRole] = "makeModel";
96 }
97
98 return names;
99}
100
101void DeviceModel::deviceLoaded(const Device &device)
102{
103 if (!deviceWanted(device)) {
104 return;
105 }
106
107 if (!m_devices.contains(device)) {
108 int i = m_devices.size();
109 beginInsertRows(QModelIndex(), i, i);
110 m_devices.append(device);
111 endInsertRows();
112
113 Q_EMIT countChanged();
114 }
115}
116
117bool DeviceModel::deviceWanted(const Device &device)
118{
119 auto parts = device.uri.split(":", QString::SkipEmptyParts);
120 return parts.size() > 1;
121}
122
123void DeviceModel::clear()
124{
125 beginResetModel();
126 m_devices.clear();
127 endResetModel();
128}
129
130void DeviceModel::load()
131{
132 if (m_isSearching) {
133 qWarning() << Q_FUNC_INFO
134 << "Ignoring load request as search is ongoing.";
135 } else {
136 clear();
137 if (m_backend->type() == PrinterEnum::PrinterType::CupsType) {
138 ((PrinterCupsBackend*) m_backend)->searchForDevices();
139 m_isSearching = true;
140 Q_EMIT searchingChanged();
141 }
142 }
143}
144
145void DeviceModel::deviceSearchFinished()
146{
147 m_isSearching = false;
148 Q_EMIT searchingChanged();
149}
0150
=== added file 'modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h'
--- modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Extras/Printers/models/devicemodel.h 2017-03-23 12:51:36 +0000
@@ -0,0 +1,78 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef USC_PRINTER_DEVICEMODEL_H
18#define USC_PRINTER_DEVICEMODEL_H
19
20#include "printers_global.h"
21
22#include "structs.h"
23
24#include <QAbstractListModel>
25#include <QList>
26#include <QModelIndex>
27#include <QObject>
28#include <QVariant>
29
30class PRINTERS_DECL_EXPORT DeviceModel : public QAbstractListModel
31{
32 Q_OBJECT
33 Q_PROPERTY(int count READ count NOTIFY countChanged)
34 Q_PROPERTY(bool searching MEMBER m_isSearching NOTIFY searchingChanged)
35public:
36 explicit DeviceModel(PrinterBackend *backend, QObject *parent = Q_NULLPTR);
37 ~DeviceModel();
38
39 enum Roles
40 {
41 // Qt::DisplayRole holds device name
42 ClassRole = Qt::UserRole,
43 IdRole,
44 InfoRole,
45 UriRole,
46 LocationRole,
47 TypeRole,
48 MakeModelRole,
49 LastRole = MakeModelRole,
50 };
51
52 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
53 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
54 virtual QHash<int, QByteArray> roleNames() const override;
55
56 int count() const;
57 void load();
58 void clear();
59
60private Q_SLOTS:
61 void deviceLoaded(const Device &device);
62 void deviceSearchFinished();
63
64Q_SIGNALS:
65 void countChanged();
66 void searchingChanged();
67
68private:
69 /* Checks if we want it in the list or not. Wanted is intentionally
70 ambiguous. */
71 bool deviceWanted(const Device &device);
72
73 PrinterBackend *m_backend;
74 QList<Device> m_devices;
75 bool m_isSearching;
76};
77
78#endif // USC_PRINTER_DEVICEMODEL_H
079
=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp'
--- modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/models/jobmodel.cpp 2017-03-23 12:51:36 +0000
@@ -31,113 +31,190 @@
31 : QAbstractListModel(parent)31 : QAbstractListModel(parent)
32 , m_backend(backend)32 , m_backend(backend)
33{33{
34 update();
35
36 QObject::connect(m_backend, &PrinterBackend::jobCreated,34 QObject::connect(m_backend, &PrinterBackend::jobCreated,
37 this, &JobModel::jobSignalCatchAll);35 this, &JobModel::jobCreated);
38 QObject::connect(m_backend, &PrinterBackend::jobState,36 QObject::connect(m_backend, &PrinterBackend::jobState,
39 this, &JobModel::jobSignalCatchAll);37 this, &JobModel::jobState);
40 QObject::connect(m_backend, &PrinterBackend::jobCompleted,38 QObject::connect(m_backend, &PrinterBackend::jobCompleted,
41 this, &JobModel::jobSignalCatchAll);39 this, &JobModel::jobCompleted);
40
41 connect(m_backend, SIGNAL(jobLoaded(QString, int, QMap<QString, QVariant>)),
42 this, SLOT(updateJob(QString, int, QMap<QString, QVariant>)));
43
44 // Impressions completed happens via printer state changed
45 QObject::connect(m_backend, &PrinterBackend::printerStateChanged,
46 &m_signalHandler, &SignalRateLimiter::onPrinterStateChanged);
47
48 QObject::connect(&m_signalHandler, SIGNAL(printerModified(const QString&)),
49 this, SLOT(jobSignalPrinterModified(const QString&)));
50
51 // Add already existing jobs
52 // TODO: even this should probably be in a background thread?
53 // so that it doesn't block startup?
54 Q_FOREACH(auto job, m_backend->printerGetJobs()) {
55 addJob(job);
56 }
42}57}
4358
44JobModel::~JobModel()59JobModel::~JobModel()
45{60{
46}61}
4762
48void JobModel::jobSignalCatchAll(63void JobModel::jobCreated(
49 const QString &text, const QString &printer_uri,64 const QString &text, const QString &printer_uri,
50 const QString &printer_name, uint printer_state,65 const QString &printer_name, uint printer_state,
51 const QString &printer_state_reasons, bool printer_is_accepting_jobs,66 const QString &printer_state_reasons, bool printer_is_accepting_jobs,
52 uint job_id, uint job_state, const QString &job_state_reasons,67 uint job_id, uint job_state, const QString &job_state_reasons,
53 const QString &job_name, uint job_impressions_completed)68 const QString &job_name, uint job_impressions_completed)
54{69{
55 Q_UNUSED(text);70 Q_UNUSED(text); // "Job Created"
56 Q_UNUSED(printer_uri);71 Q_UNUSED(printer_uri);
57 Q_UNUSED(printer_name);72 Q_UNUSED(printer_state);
58 Q_UNUSED(printer_state);73 Q_UNUSED(printer_state_reasons);
59 Q_UNUSED(printer_state_reasons);74 Q_UNUSED(printer_is_accepting_jobs);
60 Q_UNUSED(printer_is_accepting_jobs);75 Q_UNUSED(job_state_reasons);
61 Q_UNUSED(job_id);76
77 QSharedPointer<PrinterJob> job = QSharedPointer<PrinterJob>(
78 new PrinterJob(printer_name, m_backend, job_id)
79 );
80 job->setImpressionsCompleted(job_impressions_completed);
81 job->setState(static_cast<PrinterEnum::JobState>(job_state));
82 job->setTitle(job_name);
83
84 // Printers listens to rowInserted and spawns a JobLoader to set the
85 // printer of the job, which triggers the extended attributes to be loaded
86 // once complete this triggers JobModel::updateJob
87 addJob(job);
88}
89
90void JobModel::jobState(
91 const QString &text, const QString &printer_uri,
92 const QString &printer_name, uint printer_state,
93 const QString &printer_state_reasons, bool printer_is_accepting_jobs,
94 uint job_id, uint job_state, const QString &job_state_reasons,
95 const QString &job_name, uint job_impressions_completed)
96{
97 Q_UNUSED(text);
98 Q_UNUSED(printer_uri);
99 Q_UNUSED(printer_state);
100 Q_UNUSED(printer_state_reasons);
101 Q_UNUSED(printer_is_accepting_jobs);
102 Q_UNUSED(job_state_reasons);
103 Q_UNUSED(job_name);
104
105 QSharedPointer<PrinterJob> job = getJob(printer_name, job_id);
106
107 if (job) {
108 job->setImpressionsCompleted(job_impressions_completed);
109 job->setState(static_cast<PrinterEnum::JobState>(job_state));
110
111 updateJob(job);
112 } else {
113 qWarning() << "JobModel::jobState for unknown job: " << job_name << " ("
114 << job_id << ") for " << printer_name;
115 }
116}
117
118void JobModel::jobCompleted(
119 const QString &text, const QString &printer_uri,
120 const QString &printer_name, uint printer_state,
121 const QString &printer_state_reasons, bool printer_is_accepting_jobs,
122 uint job_id, uint job_state, const QString &job_state_reasons,
123 const QString &job_name, uint job_impressions_completed)
124{
125 Q_UNUSED(text);
126 Q_UNUSED(printer_uri);
127 Q_UNUSED(printer_state);
128 Q_UNUSED(printer_state_reasons);
129 Q_UNUSED(printer_is_accepting_jobs);
62 Q_UNUSED(job_state);130 Q_UNUSED(job_state);
63 Q_UNUSED(job_state_reasons);131 Q_UNUSED(job_state_reasons);
64 Q_UNUSED(job_name);132 Q_UNUSED(job_name);
65133 Q_UNUSED(job_impressions_completed);
66 auto job = getJobById(job_id);134
67 if (job)135 auto job = getJob(printer_name, job_id);
68 job->setImpressionsCompleted(job_impressions_completed);136 if (job) {
69137 removeJob(job);
70 update();138 } else {
71}139 qWarning() << "JobModel::jobCompleted for unknown job: " << job_name << " ("
72140 << job_id << ") for " << printer_name;
73void JobModel::update()141 }
74{142}
75 // Store the old count and get the new printers143
76 int oldCount = m_jobs.size();144void JobModel::jobSignalPrinterModified(const QString &printerName)
77 QList<QSharedPointer<PrinterJob>> newJobs = m_backend->printerGetJobs();145{
78146 // Find the active or pending job and force a refresh
79 // Go through the old model147 // We force refresh pending jobs incase there is a flood of signals
80 for (int i=0; i < m_jobs.count(); i++) {148 // meaning that the jobStateChanged signal might not have happened yet
81 // Determine if the old printer exists in the new model149 Q_FOREACH(auto job, m_jobs) {
82 bool exists = false;150 if (job->printerName() == printerName
83151 && (job->state() == PrinterEnum::JobState::Processing
84 Q_FOREACH(QSharedPointer<PrinterJob> p, newJobs) {152 || job->state() == PrinterEnum::JobState::Pending)) {
85 if (p->jobId() == m_jobs.at(i)->jobId()) {153 Q_EMIT forceJobRefresh(printerName, job->jobId());
86 exists = true;154 }
87155 }
88 // Ensure the other properties of the job are up to date156}
89 if (!m_jobs.at(i)->deepCompare(p)) {157
90 m_jobs.at(i)->updateFrom(p);158void JobModel::addJob(QSharedPointer<PrinterJob> job)
91159{
92 Q_EMIT dataChanged(index(i), index(i));160 int i = m_jobs.size();
93 }161
94162 beginInsertRows(QModelIndex(), i, i);
95 break;163 m_jobs.append(job);
96 }164 endInsertRows();
97 }165
98166 Q_EMIT countChanged();
99 // If it doesn't exist then remove it from the old model167}
100 if (!exists) {168
101 beginRemoveRows(QModelIndex(), i, i);169void JobModel::removeJob(QSharedPointer<PrinterJob> job)
102 QSharedPointer<PrinterJob> p = m_jobs.takeAt(i);170{
103 endRemoveRows();171 int i = m_jobs.indexOf(job);
104172
105 i--; // as we have removed an item decrement173 beginRemoveRows(QModelIndex(), i, i);
106 }174 m_jobs.removeAt(i);
107 }175 endRemoveRows();
108176
109 // Go through the new model177 Q_EMIT countChanged();
110 for (int i=0; i < newJobs.count(); i++) {178}
111 // Determine if the new printer exists in the old model179
112 bool exists = false;180// This is used by JobModel::jobState as it has modified an existing job
113 int j;181void JobModel::updateJob(QSharedPointer<PrinterJob> job)
114182{
115 for (j=0; j < m_jobs.count(); j++) {183 int i = m_jobs.indexOf(job);
116 if (m_jobs.at(j)->jobId() == newJobs.at(i)->jobId()) {184 QModelIndex idx = index(i);
117 exists = true;185 Q_EMIT dataChanged(idx, idx);
118 break;186}
119 }187
120 }188// This is used by JobLoader as it gives us the oldJob and a newJob which has
121189// the extended attributes loaded. We then load the data from this newJob.
122 if (exists) {190void JobModel::updateJob(QString printerName, int jobId,
123 if (j == i) { // New printer exists and in correct position191 QMap<QString, QVariant> attributes)
124 continue;192{
125 } else {193 QSharedPointer<PrinterJob> job = getJob(printerName, jobId);
126 // New printer does exist but needs to be moved in old model194
127 beginMoveRows(QModelIndex(), j, 1, QModelIndex(), i);195 int i = m_jobs.indexOf(job);
128 m_jobs.move(j, i);196 QModelIndex idx = index(i);
129 endMoveRows();197
130 }198 if (i > -1) {
131 } else {199 job->loadAttributes(attributes);
132 // New printer does not exist insert into model200
133 beginInsertRows(QModelIndex(), i, i);201 Q_EMIT dataChanged(idx, idx);
134 m_jobs.insert(i, newJobs.at(i));202 } else {
135 endInsertRows();203 qWarning() << "Tried to updateJob which doesn't exist:" << printerName << jobId;
136 }204 }
137 }205}
138206
139 if (oldCount != m_jobs.size()) {207void JobModel::updateJobPrinter(QSharedPointer<PrinterJob> job, QSharedPointer<Printer> printer)
140 Q_EMIT countChanged();208{
209 int i = m_jobs.indexOf(job);
210 QModelIndex idx = index(i);
211
212 if (i > -1) {
213 job->setPrinter(printer);
214
215 Q_EMIT dataChanged(idx, idx);
216 } else {
217 qWarning() << "Tried to updateJobPrinter which doesn't exist:" << printer->name() << job->jobId();
141 }218 }
142}219}
143220
@@ -166,7 +243,8 @@
166 break;243 break;
167 case ColorModelRole: {244 case ColorModelRole: {
168 if (job->printer()) {245 if (job->printer()) {
169 ret = job->printer()->supportedColorModels().at(job->colorModel()).text;246 ColorModel m = job->printer()->supportedColorModels().at(job->colorModel());
247 ret = m.text.isEmpty() ? m.name : m.text;
170 } else {248 } else {
171 qWarning() << "Printer is undefined, no colorModel";249 qWarning() << "Printer is undefined, no colorModel";
172 ret = "";250 ret = "";
@@ -174,13 +252,13 @@
174 break;252 break;
175 }253 }
176 case CompletedTimeRole:254 case CompletedTimeRole:
177 ret = job->completedTime().toString(QLocale::system().dateTimeFormat());255 ret = job->completedTime().toLocalTime();
178 break;256 break;
179 case CopiesRole:257 case CopiesRole:
180 ret = job->copies();258 ret = job->copies();
181 break;259 break;
182 case CreationTimeRole:260 case CreationTimeRole:
183 ret = job->creationTime().toString(QLocale::system().dateTimeFormat());261 ret = job->creationTime().toLocalTime();
184 break;262 break;
185 case DuplexRole: {263 case DuplexRole: {
186 if (job->printer()) {264 if (job->printer()) {
@@ -194,6 +272,9 @@
194 case IdRole:272 case IdRole:
195 ret = job->jobId();273 ret = job->jobId();
196 break;274 break;
275 case HeldRole:
276 ret = job->state() == PrinterEnum::JobState::Held;
277 break;
197 case ImpressionsCompletedRole:278 case ImpressionsCompletedRole:
198 ret = job->impressionsCompleted();279 ret = job->impressionsCompleted();
199 break;280 break;
@@ -213,11 +294,12 @@
213 ret = QVariant::fromValue<PrinterEnum::PrintRange>(job->printRangeMode());294 ret = QVariant::fromValue<PrinterEnum::PrintRange>(job->printRangeMode());
214 break;295 break;
215 case ProcessingTimeRole:296 case ProcessingTimeRole:
216 ret = job->processingTime().toString(QLocale::system().dateTimeFormat());297 ret = job->processingTime().toLocalTime();
217 break;298 break;
218 case QualityRole: {299 case QualityRole: {
219 if (job->printer()) {300 if (job->printer()) {
220 ret = job->printer()->supportedPrintQualities().at(job->quality()).text;301 PrintQuality q = job->printer()->supportedPrintQualities().at(job->quality());
302 ret = q.text.isEmpty() ? q.name : q.text;
221 } else {303 } else {
222 qWarning() << "Printer is undefined, no quality";304 qWarning() << "Printer is undefined, no quality";
223 ret = "";305 ret = "";
@@ -231,30 +313,7 @@
231 ret = job->size();313 ret = job->size();
232 break;314 break;
233 case StateRole:315 case StateRole:
234 // TODO: improve, for now have a switch316 ret = QVariant::fromValue<PrinterEnum::JobState>(job->state());
235 switch (job->state()) {
236 case PrinterEnum::JobState::Aborted:
237 ret = "Aborted";
238 break;
239 case PrinterEnum::JobState::Canceled:
240 ret = "Canceled";
241 break;
242 case PrinterEnum::JobState::Complete:
243 ret = "Compelete";
244 break;
245 case PrinterEnum::JobState::Held:
246 ret = "Held";
247 break;
248 case PrinterEnum::JobState::Pending:
249 ret = "Pending";
250 break;
251 case PrinterEnum::JobState::Processing:
252 ret = "Processing";
253 break;
254 case PrinterEnum::JobState::Stopped:
255 ret = "Stopped";
256 break;
257 }
258 break;317 break;
259 case Qt::DisplayRole:318 case Qt::DisplayRole:
260 case TitleRole:319 case TitleRole:
@@ -263,6 +322,15 @@
263 case UserRole:322 case UserRole:
264 ret = job->user();323 ret = job->user();
265 break;324 break;
325 case LastStateMessageRole: {
326 if (job->printer()) {
327 ret = job->printer()->lastMessage();
328 } else {
329 ret = "";
330 }
331 break;
332 }
333
266 }334 }
267 }335 }
268336
@@ -283,6 +351,7 @@
283 names[CreationTimeRole] = "creationTime";351 names[CreationTimeRole] = "creationTime";
284 names[DuplexRole] = "duplexMode";352 names[DuplexRole] = "duplexMode";
285 names[ImpressionsCompletedRole] = "impressionsCompleted";353 names[ImpressionsCompletedRole] = "impressionsCompleted";
354 names[HeldRole] = "held";
286 names[LandscapeRole] = "landscape";355 names[LandscapeRole] = "landscape";
287 names[MessagesRole] = "messages";356 names[MessagesRole] = "messages";
288 names[PrinterNameRole] = "printerName";357 names[PrinterNameRole] = "printerName";
@@ -315,10 +384,10 @@
315 return result;384 return result;
316}385}
317386
318QSharedPointer<PrinterJob> JobModel::getJobById(const int &id)387QSharedPointer<PrinterJob> JobModel::getJob(const QString &printerName, const int &id)
319{388{
320 Q_FOREACH(auto job, m_jobs) {389 Q_FOREACH(auto job, m_jobs) {
321 if (job->jobId() == id) {390 if (job->printerName() == printerName && job->jobId() == id) {
322 return job;391 return job;
323 }392 }
324 }393 }
@@ -367,6 +436,33 @@
367 return rowCount();436 return rowCount();
368}437}
369438
439void JobFilter::filterOnActive()
440{
441 m_activeStates = QSet<PrinterEnum::JobState>{
442 PrinterEnum::JobState::Processing,
443 };
444 m_activeFilterEnabled = true;
445 invalidate();
446}
447
448void JobFilter::filterOnPaused()
449{
450 m_pausedStates = QSet<PrinterEnum::JobState>{
451 PrinterEnum::JobState::Held,
452 };
453 m_pausedFilterEnabled = true;
454 invalidate();
455}
456
457void JobFilter::filterOnQueued()
458{
459 m_queuedStates = QSet<PrinterEnum::JobState>{
460 PrinterEnum::JobState::Pending,
461 };
462 m_queuedFilterEnabled = true;
463 invalidate();
464}
465
370void JobFilter::filterOnPrinterName(const QString &name)466void JobFilter::filterOnPrinterName(const QString &name)
371{467{
372 m_printerName = name;468 m_printerName = name;
@@ -386,5 +482,50 @@
386 accepts = m_printerName == printerName;482 accepts = m_printerName == printerName;
387 }483 }
388484
485 if (accepts && m_activeFilterEnabled) {
486 PrinterEnum::JobState state = childIndex.model()->data(
487 childIndex, JobModel::StateRole
488 ).value<PrinterEnum::JobState>();
489
490 accepts = m_activeStates.contains(state);
491 }
492
493 if (accepts && m_pausedFilterEnabled) {
494 PrinterEnum::JobState state = childIndex.model()->data(
495 childIndex, JobModel::StateRole
496 ).value<PrinterEnum::JobState>();
497
498 accepts = m_pausedStates.contains(state);
499 }
500
501 if (accepts && m_queuedFilterEnabled) {
502 PrinterEnum::JobState state = childIndex.model()->data(
503 childIndex, JobModel::StateRole
504 ).value<PrinterEnum::JobState>();
505
506 accepts = m_queuedStates.contains(state);
507 }
508
389 return accepts;509 return accepts;
390}510}
511
512bool JobFilter::lessThan(const QModelIndex &source_left,
513 const QModelIndex &source_right) const
514{
515 QVariant leftData = sourceModel()->data(source_left, sortRole());
516 QVariant rightData = sourceModel()->data(source_right, sortRole());
517
518 if (sortRole() == (int) JobModel::CreationTimeRole) {
519 // If creationDateTime is the same, fallback to Id
520 if (leftData.toDateTime() == rightData.toDateTime()) {
521 int leftId = sourceModel()->data(source_left, JobModel::IdRole).toInt();
522 int rightId = sourceModel()->data(source_right, JobModel::IdRole).toInt();
523
524 return leftId < rightId;
525 } else {
526 return leftData.toDateTime() < rightData.toDateTime();
527 }
528 } else {
529 return leftData < rightData;
530 }
531}
391532
=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h'
--- modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/models/jobmodel.h 2017-03-23 12:51:36 +0000
@@ -20,6 +20,7 @@
20#include "printers_global.h"20#include "printers_global.h"
21#include "backend/backend.h"21#include "backend/backend.h"
22#include "printer/printerjob.h"22#include "printer/printerjob.h"
23#include "printer/signalratelimiter.h"
2324
24#include <QAbstractListModel>25#include <QAbstractListModel>
25#include <QByteArray>26#include <QByteArray>
@@ -30,6 +31,8 @@
30#include <QTimer>31#include <QTimer>
31#include <QVariant>32#include <QVariant>
3233
34class PrinterBackend;
35class PrinterJob;
33class PRINTERS_DECL_EXPORT JobModel : public QAbstractListModel36class PRINTERS_DECL_EXPORT JobModel : public QAbstractListModel
34{37{
35 Q_OBJECT38 Q_OBJECT
@@ -51,6 +54,7 @@
51 CopiesRole,54 CopiesRole,
52 CreationTimeRole,55 CreationTimeRole,
53 DuplexRole,56 DuplexRole,
57 HeldRole,
54 ImpressionsCompletedRole,58 ImpressionsCompletedRole,
55 LandscapeRole,59 LandscapeRole,
56 MessagesRole,60 MessagesRole,
@@ -75,23 +79,46 @@
75 int count() const;79 int count() const;
7680
77 Q_INVOKABLE QVariantMap get(const int row) const;81 Q_INVOKABLE QVariantMap get(const int row) const;
78 QSharedPointer<PrinterJob> getJobById(const int &id);82 QSharedPointer<PrinterJob> getJob(const QString &printerName, const int &id);
83
84 void updateJobPrinter(QSharedPointer<PrinterJob> job, QSharedPointer<Printer> printer);
79private:85private:
86 void addJob(QSharedPointer<PrinterJob> job);
87 void removeJob(QSharedPointer<PrinterJob> job);
88 void updateJob(QSharedPointer<PrinterJob> Job);
89
80 PrinterBackend *m_backend;90 PrinterBackend *m_backend;
8191
82 QList<QSharedPointer<PrinterJob>> m_jobs;92 QList<QSharedPointer<PrinterJob>> m_jobs;
93 SignalRateLimiter m_signalHandler;
83private Q_SLOTS:94private Q_SLOTS:
84 void update();95 void jobCreated(const QString &text, const QString &printer_uri,
85 void jobSignalCatchAll(const QString &text, const QString &printer_uri,96 const QString &printer_name, uint printer_state,
86 const QString &printer_name, uint printer_state,97 const QString &printer_state_reasons,
87 const QString &printer_state_reasons,98 bool printer_is_accepting_jobs, uint job_id,
88 bool printer_is_accepting_jobs, uint job_id,99 uint job_state, const QString &job_state_reasons,
89 uint job_state, const QString &job_state_reasons,100 const QString &job_name,
90 const QString &job_name,101 uint job_impressions_completed);
91 uint job_impressions_completed);102 void jobState(const QString &text, const QString &printer_uri,
103 const QString &printer_name, uint printer_state,
104 const QString &printer_state_reasons,
105 bool printer_is_accepting_jobs, uint job_id,
106 uint job_state, const QString &job_state_reasons,
107 const QString &job_name,
108 uint job_impressions_completed);
109 void jobCompleted(const QString &text, const QString &printer_uri,
110 const QString &printer_name, uint printer_state,
111 const QString &printer_state_reasons,
112 bool printer_is_accepting_jobs, uint job_id,
113 uint job_state, const QString &job_state_reasons,
114 const QString &job_name,
115 uint job_impressions_completed);
116 void jobSignalPrinterModified(const QString &printerName);
117 void updateJob(QString printerName, int jobId, QMap<QString, QVariant> attributes);
92118
93Q_SIGNALS:119Q_SIGNALS:
94 void countChanged();120 void countChanged();
121 void forceJobRefresh(const QString &printerName, const int jobId);
95};122};
96123
97class PRINTERS_DECL_EXPORT JobFilter : public QSortFilterProxyModel124class PRINTERS_DECL_EXPORT JobFilter : public QSortFilterProxyModel
@@ -102,13 +129,19 @@
102 explicit JobFilter(QObject *parent = Q_NULLPTR);129 explicit JobFilter(QObject *parent = Q_NULLPTR);
103 ~JobFilter();130 ~JobFilter();
104131
105 Q_INVOKABLE QVariantMap get(const int row) const;
106
107 void filterOnPrinterName(const QString &name);132 void filterOnPrinterName(const QString &name);
108 int count() const;133 int count() const;
134public Q_SLOTS:
135 QVariantMap get(const int row) const;
136
137 void filterOnActive();
138 void filterOnQueued();
139 void filterOnPaused();
109protected:140protected:
110 virtual bool filterAcceptsRow(141 virtual bool filterAcceptsRow(
111 int sourceRow, const QModelIndex &sourceParent) const override;142 int sourceRow, const QModelIndex &sourceParent) const override;
143 virtual bool lessThan(const QModelIndex &source_left,
144 const QModelIndex &source_right) const;
112145
113Q_SIGNALS:146Q_SIGNALS:
114 void countChanged();147 void countChanged();
@@ -120,6 +153,15 @@
120private:153private:
121 QString m_printerName = QString::null;154 QString m_printerName = QString::null;
122 bool m_printerNameFilterEnabled = false;155 bool m_printerNameFilterEnabled = false;
156
157 bool m_activeFilterEnabled = false;
158 QSet<PrinterEnum::JobState> m_activeStates;
159
160 bool m_queuedFilterEnabled = false;
161 QSet<PrinterEnum::JobState> m_queuedStates;
162
163 bool m_pausedFilterEnabled = false;
164 QSet<PrinterEnum::JobState> m_pausedStates;
123};165};
124166
125#endif // USC_JOB_MODEL_H167#endif // USC_JOB_MODEL_H
126168
=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp'
--- modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp 2017-03-23 12:51:36 +0000
@@ -22,6 +22,7 @@
22#include "utils.h"22#include "utils.h"
2323
24#include <QDebug>24#include <QDebug>
25#include <QUrl>
2526
26PrinterModel::PrinterModel(PrinterBackend *backend, QObject *parent)27PrinterModel::PrinterModel(PrinterBackend *backend, QObject *parent)
27 : QAbstractListModel(parent)28 : QAbstractListModel(parent)
@@ -31,9 +32,9 @@
31 QObject::connect(m_backend, &PrinterBackend::printerAdded,32 QObject::connect(m_backend, &PrinterBackend::printerAdded,
32 this, &PrinterModel::printerAdded);33 this, &PrinterModel::printerAdded);
33 QObject::connect(m_backend, &PrinterBackend::printerModified,34 QObject::connect(m_backend, &PrinterBackend::printerModified,
34 &m_signalHandler, &PrinterSignalHandler::onPrinterModified);35 &m_signalHandler, &SignalRateLimiter::onPrinterModified);
35 QObject::connect(m_backend, &PrinterBackend::printerStateChanged,36 QObject::connect(m_backend, &PrinterBackend::printerStateChanged,
36 &m_signalHandler, &PrinterSignalHandler::onPrinterModified);37 &m_signalHandler, &SignalRateLimiter::onPrinterModified);
37 QObject::connect(m_backend, &PrinterBackend::printerDeleted,38 QObject::connect(m_backend, &PrinterBackend::printerDeleted,
38 this, &PrinterModel::printerDeleted);39 this, &PrinterModel::printerDeleted);
3940
@@ -63,20 +64,18 @@
6364
64void PrinterModel::printerLoaded(QSharedPointer<Printer> printer)65void PrinterModel::printerLoaded(QSharedPointer<Printer> printer)
65{66{
66 // Find and possibly replace an old printer.67 // If there is an existing printer then get it
67 for (int i=0; i < m_printers.count(); i++) {68 QSharedPointer<Printer> oldPrinter = getPrinterByName(printer->name());
68 auto oldPrinter = m_printers.at(i);
69 if (printer->name() == oldPrinter->name()) {
70 if (!oldPrinter->deepCompare(printer)) {
71 updatePrinter(oldPrinter, printer);
72 }
7369
74 // We're done.70 if (oldPrinter) {
75 return;71 // Check if the existing printer needs updating
72 if (!oldPrinter->deepCompare(printer)) {
73 updatePrinter(oldPrinter, printer);
76 }74 }
75 } else {
76 // There isn't an existing printer so add it
77 addPrinter(printer, CountChangeSignal::Emit);
77 }78 }
78
79 addPrinter(printer, CountChangeSignal::Emit);
80}79}
8180
82void PrinterModel::printerModified(const QString &printerName)81void PrinterModel::printerModified(const QString &printerName)
@@ -97,6 +96,12 @@
97 Q_UNUSED(printerStateReason);96 Q_UNUSED(printerStateReason);
98 Q_UNUSED(acceptingJobs);97 Q_UNUSED(acceptingJobs);
9998
99 // If there isn't an existing printer then add a proxy printer
100 if (!getPrinterByName(printerName)) {
101 auto p = QSharedPointer<Printer>(new Printer(new PrinterBackend(printerName)));
102 addPrinter(p);
103 }
104
100 m_backend->requestPrinter(printerName);105 m_backend->requestPrinter(printerName);
101}106}
102107
@@ -126,22 +131,6 @@
126 return QSharedPointer<Printer>(Q_NULLPTR);131 return QSharedPointer<Printer>(Q_NULLPTR);
127}132}
128133
129void PrinterModel::movePrinter(const int &from, const int &to)
130{
131 int size = m_printers.size();
132 if (from < 0 || to < 0 || from >= size || to >= size) {
133 qWarning() << Q_FUNC_INFO << "Illegal move operation from"
134 << from << "to" << to << ". Size was" << size;
135 return;
136 }
137 if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), to)) {
138 qWarning() << Q_FUNC_INFO << "failed to move rows.";
139 return;
140 }
141 m_printers.move(from, to);
142 endMoveRows();
143}
144
145void PrinterModel::removePrinter(QSharedPointer<Printer> printer, const CountChangeSignal &notify)134void PrinterModel::removePrinter(QSharedPointer<Printer> printer, const CountChangeSignal &notify)
146{135{
147 int idx = m_printers.indexOf(printer);136 int idx = m_printers.indexOf(printer);
@@ -214,6 +203,15 @@
214 case Qt::DisplayRole:203 case Qt::DisplayRole:
215 ret = printer->name();204 ret = printer->name();
216 break;205 break;
206 case DeviceUriRole:
207 ret = printer->deviceUri();
208 break;
209 case HostNameRole:
210 ret = QUrl(printer->deviceUri()).host();
211 break;
212 case MakeRole:
213 ret = printer->make();
214 break;
217 case ColorModelRole:215 case ColorModelRole:
218 ret = printer->supportedColorModels().indexOf(printer->defaultColorModel());216 ret = printer->supportedColorModels().indexOf(printer->defaultColorModel());
219 break;217 break;
@@ -248,6 +246,9 @@
248 case DescriptionRole:246 case DescriptionRole:
249 ret = printer->description();247 ret = printer->description();
250 break;248 break;
249 case LocationRole:
250 ret = printer->location();
251 break;
251 case PageSizeRole:252 case PageSizeRole:
252 ret = printer->defaultPageSize().name();253 ret = printer->defaultPageSize().name();
253 break;254 break;
@@ -274,15 +275,27 @@
274 case IsRawRole:275 case IsRawRole:
275 ret = !printer->holdsDefinition();276 ret = !printer->holdsDefinition();
276 break;277 break;
278 case IsRemoteRole:
279 ret = printer->isRemote();
280 break;
281 case LastMessageRole:
282 ret = printer->lastMessage();
283 break;
277 case JobRole:284 case JobRole:
278 ret = QVariant::fromValue(printer->jobs());285 ret = QVariant::fromValue(printer->jobs());
279 break;286 break;
287 case CopiesRole:
288 ret = printer->copies();
289 break;
280 case EnabledRole:290 case EnabledRole:
281 ret = printer->enabled();291 ret = printer->enabled();
282 break;292 break;
283 case AcceptJobsRole:293 case AcceptJobsRole:
284 ret = printer->acceptJobs();294 ret = printer->acceptJobs();
285 break;295 break;
296 case SharedRole:
297 ret = printer->shared();
298 break;
286 }299 }
287 }300 }
288301
@@ -338,6 +351,11 @@
338 case AcceptJobsRole:351 case AcceptJobsRole:
339 printer->setAcceptJobs(value.toBool());352 printer->setAcceptJobs(value.toBool());
340 break;353 break;
354 case CopiesRole:
355 printer->setCopies(value.toInt());
356 case SharedRole:
357 printer->setShared(value.toBool());
358 break;
341 }359 }
342 }360 }
343361
@@ -356,12 +374,16 @@
356 names[DuplexRole] = "duplexMode";374 names[DuplexRole] = "duplexMode";
357 names[SupportedDuplexModesRole] = "supportedDuplexModes";375 names[SupportedDuplexModesRole] = "supportedDuplexModes";
358 names[NameRole] = "name";376 names[NameRole] = "name";
377 names[DeviceUriRole] = "deviceUri";
378 names[HostNameRole] = "hostname";
379 names[MakeRole] = "make";
359 names[EnabledRole] = "printerEnabled";380 names[EnabledRole] = "printerEnabled";
360 names[AcceptJobsRole] = "acceptJobs";381 names[AcceptJobsRole] = "acceptJobs";
361 names[PdfModeRole] = "pdfMode";382 names[SharedRole] = "shared";
362 names[PrintQualityRole] = "printQuality";383 names[PrintQualityRole] = "printQuality";
363 names[SupportedPrintQualitiesRole] = "supportedPrintQualities";384 names[SupportedPrintQualitiesRole] = "supportedPrintQualities";
364 names[DescriptionRole] = "description";385 names[DescriptionRole] = "description";
386 names[LocationRole] = "location";
365 names[PageSizeRole] = "pageSize";387 names[PageSizeRole] = "pageSize";
366 names[SupportedPageSizesRole] = "supportedPageSizes";388 names[SupportedPageSizesRole] = "supportedPageSizes";
367 names[StateRole] = "state";389 names[StateRole] = "state";
@@ -369,6 +391,9 @@
369 names[IsPdfRole] = "isPdf";391 names[IsPdfRole] = "isPdf";
370 names[IsLoadedRole] = "isLoaded";392 names[IsLoadedRole] = "isLoaded";
371 names[IsRawRole] = "isRaw";393 names[IsRawRole] = "isRaw";
394 names[IsRemoteRole] = "isRemote";
395 names[LastMessageRole] = "lastMessage";
396 names[CopiesRole] = "copies";
372 names[JobRole] = "jobs";397 names[JobRole] = "jobs";
373 }398 }
374399
@@ -447,6 +472,13 @@
447 m_pdf = pdf;472 m_pdf = pdf;
448}473}
449474
475void PrinterFilter::filterOnRemote(const bool remote)
476{
477 m_remoteEnabled = true;
478 m_remote = remote;
479 invalidate();
480}
481
450bool PrinterFilter::filterAcceptsRow(int sourceRow,482bool PrinterFilter::filterAcceptsRow(int sourceRow,
451 const QModelIndex &sourceParent) const483 const QModelIndex &sourceParent) const
452{484{
@@ -472,6 +504,14 @@
472 accepts = m_state == state;504 accepts = m_state == state;
473 }505 }
474506
507 // If m_remote is true, we only show remote printers.
508 if (accepts && m_remoteEnabled) {
509 const bool isRemote = childIndex.model()->data(
510 childIndex, PrinterModel::IsRemoteRole
511 ).toBool();
512 accepts = m_remote == isRemote;
513 }
514
475 return accepts;515 return accepts;
476}516}
477bool PrinterFilter::lessThan(const QModelIndex &left,517bool PrinterFilter::lessThan(const QModelIndex &left,
478518
=== modified file 'modules/Ubuntu/Components/Extras/Printers/models/printermodel.h'
--- modules/Ubuntu/Components/Extras/Printers/models/printermodel.h 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/models/printermodel.h 2017-03-23 12:51:36 +0000
@@ -21,7 +21,7 @@
2121
22#include "models/jobmodel.h"22#include "models/jobmodel.h"
23#include "printer/printer.h"23#include "printer/printer.h"
24#include "printer/printersignalhandler.h"24#include "printer/signalratelimiter.h"
2525
26#include <QAbstractListModel>26#include <QAbstractListModel>
27#include <QByteArray>27#include <QByteArray>
@@ -47,9 +47,13 @@
47 DuplexRole,47 DuplexRole,
48 SupportedDuplexModesRole,48 SupportedDuplexModesRole,
49 NameRole,49 NameRole,
50 DeviceUriRole,
51 HostNameRole,
52 MakeRole,
53 LocationRole,
50 EnabledRole,54 EnabledRole,
51 AcceptJobsRole,55 AcceptJobsRole,
52 PdfModeRole,56 SharedRole,
53 PrintQualityRole,57 PrintQualityRole,
54 SupportedPrintQualitiesRole,58 SupportedPrintQualitiesRole,
55 DescriptionRole,59 DescriptionRole,
@@ -68,6 +72,9 @@
6872
69 /* Indicates that this printers has no associated PPD. */73 /* Indicates that this printers has no associated PPD. */
70 IsRawRole,74 IsRawRole,
75 IsRemoteRole,
76 LastMessageRole,
77 CopiesRole,
71 JobRole,78 JobRole,
72 LastRole = JobRole,79 LastRole = JobRole,
73 };80 };
@@ -92,13 +99,12 @@
92 const CountChangeSignal &notify = CountChangeSignal::Defer);99 const CountChangeSignal &notify = CountChangeSignal::Defer);
93 void removePrinter(QSharedPointer<Printer> printer,100 void removePrinter(QSharedPointer<Printer> printer,
94 const CountChangeSignal &notify = CountChangeSignal::Defer);101 const CountChangeSignal &notify = CountChangeSignal::Defer);
95 void movePrinter(const int &from, const int &to);
96 void updatePrinter(QSharedPointer<Printer> old,102 void updatePrinter(QSharedPointer<Printer> old,
97 QSharedPointer<Printer> newPrinter);103 QSharedPointer<Printer> newPrinter);
98 PrinterBackend *m_backend;104 PrinterBackend *m_backend;
99105
100 QList<QSharedPointer<Printer>> m_printers;106 QList<QSharedPointer<Printer>> m_printers;
101 PrinterSignalHandler m_signalHandler;107 SignalRateLimiter m_signalHandler;
102108
103private Q_SLOTS:109private Q_SLOTS:
104 void printerLoaded(QSharedPointer<Printer> printer);110 void printerLoaded(QSharedPointer<Printer> printer);
@@ -127,6 +133,7 @@
127 void filterOnState(const PrinterEnum::State &state);133 void filterOnState(const PrinterEnum::State &state);
128 void filterOnRecent(const bool recent);134 void filterOnRecent(const bool recent);
129 void filterOnPdf(const bool pdf);135 void filterOnPdf(const bool pdf);
136 void filterOnRemote(const bool remote);
130137
131 int count() const;138 int count() const;
132protected:139protected:
@@ -149,6 +156,8 @@
149 bool m_recentEnabled = false;156 bool m_recentEnabled = false;
150 bool m_pdfEnabled = false;157 bool m_pdfEnabled = false;
151 bool m_pdf = false;158 bool m_pdf = false;
159 bool m_remoteEnabled = false;
160 bool m_remote = false;
152};161};
153162
154#endif // USC_PRINTER_MODEL_H163#endif // USC_PRINTER_MODEL_H
155164
=== modified file 'modules/Ubuntu/Components/Extras/Printers/plugin.cpp'
--- modules/Ubuntu/Components/Extras/Printers/plugin.cpp 2017-02-21 11:31:44 +0000
+++ modules/Ubuntu/Components/Extras/Printers/plugin.cpp 2017-03-23 12:51:36 +0000
@@ -54,5 +54,7 @@
5454
55 qmlRegisterUncreatableType<PrinterEnum>(uri, 0, 1, "PrinterEnum", "Is an enum");55 qmlRegisterUncreatableType<PrinterEnum>(uri, 0, 1, "PrinterEnum", "Is an enum");
56 qRegisterMetaType<QList<PrinterDriver>>("QList<PrinterDriver>");56 qRegisterMetaType<QList<PrinterDriver>>("QList<PrinterDriver>");
57 qRegisterMetaType<QSharedPointer<PrinterJob>>("QSharedPointer<PrinterJob>");
57 qRegisterMetaType<QList<QSharedPointer<Printer>>>("QList<QSharedPointer<Printer>>");58 qRegisterMetaType<QList<QSharedPointer<Printer>>>("QList<QSharedPointer<Printer>>");
59 qRegisterMetaType<Device>("Device");
58}60}
5961
=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp'
--- modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp 2017-02-24 17:47:22 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printer/printer.cpp 2017-03-23 12:51:36 +0000
@@ -14,22 +14,26 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#include "i18n.h"
17#include "utils.h"18#include "utils.h"
1819
19#include "printer.h"20#include "printer.h"
2021
21#include <QDebug>22#include <QDebug>
23#include <QLocale>
22#include <QQmlEngine>24#include <QQmlEngine>
2325
24Printer::Printer(PrinterBackend *backend, QObject *parent)26Printer::Printer(PrinterBackend *backend, QObject *parent)
25 : QObject(parent)27 : QObject(parent)
26 , m_backend(backend)28 , m_backend(backend)
27{29{
28 loadColorModel();30 loadAttributes();
29 loadPrintQualities();
30 loadAcceptJobs();
3131
32 m_jobs.setParent(this);
32 m_jobs.filterOnPrinterName(name());33 m_jobs.filterOnPrinterName(name());
34
35 QObject::connect(m_backend, &PrinterBackend::printerStateChanged,
36 this, &Printer::onPrinterStateChanged);
33}37}
3438
35Printer::~Printer()39Printer::~Printer()
@@ -41,48 +45,87 @@
41{45{
42 if (!m_jobs.sourceModel()) {46 if (!m_jobs.sourceModel()) {
43 m_jobs.setSourceModel(jobModel);47 m_jobs.setSourceModel(jobModel);
44 m_jobs.sort(JobModel::Roles::IdRole);
45 }48 }
46}49}
4750
48void Printer::loadAcceptJobs()51void Printer::updateAcceptJobs(const QMap<QString, QVariant> &serverAttrs)
49{52{
50 auto opt = QStringLiteral("AcceptJobs");53 m_acceptJobs = serverAttrs.value(QStringLiteral("AcceptJobs")).toBool();
51 m_acceptJobs = m_backend->printerGetOption(name(), opt).toBool();
52}54}
5355
54void Printer::loadColorModel()56void Printer::updateColorModel(const QMap<QString, QVariant> &serverAttrs)
55{57{
56 auto defModel = QStringLiteral("DefaultColorModel");58 auto defModel = QStringLiteral("DefaultColorModel");
57 auto models = QStringLiteral("SupportedColorModels");59 auto models = QStringLiteral("SupportedColorModels");
58 auto result = m_backend->printerGetOptions(
59 name(), QStringList({defModel, models})
60 );
6160
62 m_defaultColorModel = result.value(defModel).value<ColorModel>();61 m_defaultColorModel = serverAttrs.value(defModel).value<ColorModel>();
63 m_supportedColorModels = result.value(models).value<QList<ColorModel>>();62 m_supportedColorModels = serverAttrs.value(models).value<QList<ColorModel>>();
6463
65 if (m_supportedColorModels.size() == 0) {64 if (m_supportedColorModels.size() == 0) {
66 m_supportedColorModels.append(m_defaultColorModel);65 m_supportedColorModels.append(m_defaultColorModel);
67 }66 }
68}67}
6968
70void Printer::loadPrintQualities()69void Printer::updatePrintQualities(const QMap<QString, QVariant> &serverAttrs)
71{70{
72 auto defQuality = QStringLiteral("DefaultPrintQuality");71 auto defQuality = QStringLiteral("DefaultPrintQuality");
73 auto qualities = QStringLiteral("SupportedPrintQualities");72 auto qualities = QStringLiteral("SupportedPrintQualities");
74 auto result = m_backend->printerGetOptions(
75 name(), QStringList({defQuality, qualities})
76 );
7773
78 m_supportedPrintQualities = result.value(qualities).value<QList<PrintQuality>>();74 m_supportedPrintQualities = serverAttrs.value(qualities).value<QList<PrintQuality>>();
79 m_defaultPrintQuality = result.value(defQuality).value<PrintQuality>();75 m_defaultPrintQuality = serverAttrs.value(defQuality).value<PrintQuality>();
8076
81 if (m_supportedPrintQualities.size() == 0) {77 if (m_supportedPrintQualities.size() == 0) {
82 m_supportedPrintQualities.append(m_defaultPrintQuality);78 m_supportedPrintQualities.append(m_defaultPrintQuality);
83 }79 }
84}80}
8581
82void Printer::updateLastMessage(const QMap<QString, QVariant> &serverAttrs)
83{
84 m_stateMessage = serverAttrs.value(QStringLiteral("StateMessage")).toString();
85}
86
87
88void Printer::updateDeviceUri(const QMap<QString, QVariant> &serverAttrs)
89{
90 m_deviceUri = serverAttrs.value(QStringLiteral("DeviceUri")).toString();
91}
92
93void Printer::updateCopies(const QMap<QString, QVariant> &serverAttrs)
94{
95 m_copies = serverAttrs.value(QStringLiteral("Copies")).toInt();
96 if (m_copies <= 0)
97 m_copies = 1;
98}
99
100void Printer::updateShared(const QMap<QString, QVariant> &serverAttrs)
101{
102 m_shared = serverAttrs.value(QStringLiteral("Shared")).toBool();
103}
104
105void Printer::loadAttributes()
106{
107 auto opts = QStringList({
108 QStringLiteral("AcceptJobs"),
109 QStringLiteral("DefaultColorModel"),
110 QStringLiteral("SupportedColorModels"),
111 QStringLiteral("DefaultPrintQuality"),
112 QStringLiteral("SupportedPrintQualities"),
113 QStringLiteral("StateMessage"),
114 QStringLiteral("DeviceUri"),
115 QStringLiteral("Copies"),
116 QStringLiteral("Shared"),
117 });
118 auto result = m_backend->printerGetOptions(name(), opts);
119
120 updateAcceptJobs(result);
121 updateColorModel(result);
122 updatePrintQualities(result);
123 updateLastMessage(result);
124 updateDeviceUri(result);
125 updateCopies(result);
126 updateShared(result);
127}
128
86ColorModel Printer::defaultColorModel() const129ColorModel Printer::defaultColorModel() const
87{130{
88 return m_defaultColorModel;131 return m_defaultColorModel;
@@ -135,11 +178,26 @@
135 return m_backend->printerName();178 return m_backend->printerName();
136}179}
137180
181QString Printer::deviceUri() const
182{
183 return m_deviceUri;
184}
185
186QString Printer::make() const
187{
188 return m_backend->makeAndModel();
189}
190
138QString Printer::description() const191QString Printer::description() const
139{192{
140 return m_backend->description();193 return m_backend->description();
141}194}
142195
196QString Printer::location() const
197{
198 return m_backend->location();
199}
200
143QPageSize Printer::defaultPageSize() const201QPageSize Printer::defaultPageSize() const
144{202{
145 return m_backend->defaultPageSize();203 return m_backend->defaultPageSize();
@@ -170,6 +228,11 @@
170 return m_backend->state();228 return m_backend->state();
171}229}
172230
231bool Printer::shared() const
232{
233 return m_shared;
234}
235
173bool Printer::acceptJobs() const236bool Printer::acceptJobs() const
174{237{
175 return m_acceptJobs;238 return m_acceptJobs;
@@ -180,11 +243,21 @@
180 return m_backend->holdsDefinition();243 return m_backend->holdsDefinition();
181}244}
182245
246bool Printer::isRemote() const
247{
248 return m_backend->isRemote();
249}
250
183PrinterEnum::PrinterType Printer::type() const251PrinterEnum::PrinterType Printer::type() const
184{252{
185 return m_backend->type();253 return m_backend->type();
186}254}
187255
256int Printer::copies() const
257{
258 return m_copies;
259}
260
188void Printer::setDefaultColorModel(const ColorModel &colorModel)261void Printer::setDefaultColorModel(const ColorModel &colorModel)
189{262{
190 if (defaultColorModel() == colorModel) {263 if (defaultColorModel() == colorModel) {
@@ -229,6 +302,7 @@
229 if (!reply.isEmpty()) {302 if (!reply.isEmpty()) {
230 qWarning() << Q_FUNC_INFO << "failed to set enabled:" << reply;303 qWarning() << Q_FUNC_INFO << "failed to set enabled:" << reply;
231 }304 }
305 m_backend->refresh();
232 }306 }
233}307}
234308
@@ -242,6 +316,16 @@
242 }316 }
243}317}
244318
319void Printer::setShared(const bool shared)
320{
321 if (this->shared() != shared) {
322 QString reply = m_backend->printerSetShared(name(), shared);
323 if (!reply.isEmpty()) {
324 qWarning() << Q_FUNC_INFO << "failed to set shared:" << reply;
325 }
326 }
327}
328
245void Printer::setDefaultPrintQuality(const PrintQuality &quality)329void Printer::setDefaultPrintQuality(const PrintQuality &quality)
246{330{
247 if (defaultPrintQuality() == quality) {331 if (defaultPrintQuality() == quality) {
@@ -278,6 +362,20 @@
278 m_backend->refresh();362 m_backend->refresh();
279}363}
280364
365void Printer::setCopies(const int &copies)
366{
367 if (this->copies() == copies) {
368 return;
369 }
370
371 m_backend->printerSetCopies(name(), copies);
372}
373
374QString Printer::lastMessage() const
375{
376 return m_stateMessage;
377}
378
281QAbstractItemModel* Printer::jobs()379QAbstractItemModel* Printer::jobs()
282{380{
283 auto ret = &m_jobs;381 auto ret = &m_jobs;
@@ -296,16 +394,44 @@
296 && type() == other->type()394 && type() == other->type()
297 && acceptJobs() == other->acceptJobs()395 && acceptJobs() == other->acceptJobs()
298 && enabled() == other->enabled()396 && enabled() == other->enabled()
299 && state() == other->state();397 && state() == other->state()
398 && lastMessage() == other->lastMessage()
399 && deviceUri() == other->deviceUri()
400 && shared() == other->shared()
401 && copies() == other->copies()
402 && isRemote() == other->isRemote();
300}403}
301404
302void Printer::updateFrom(QSharedPointer<Printer> other)405void Printer::updateFrom(QSharedPointer<Printer> other)
303{406{
304 PrinterBackend *tmp = m_backend;407 PrinterBackend *tmp = m_backend;
408
409 // Copy values from other printer which has been loaded in another thread
410 // Note: do not use loadAttributes otherwise can cause UI block
411 m_acceptJobs = other->m_acceptJobs;
305 m_backend = other->m_backend;412 m_backend = other->m_backend;
413 m_defaultColorModel = other->m_defaultColorModel;
414 m_defaultPrintQuality = other->m_defaultPrintQuality;
415 m_deviceUri = other->m_deviceUri;
416 m_shared = other->m_shared;
417 m_stateMessage = other->m_stateMessage;
418 m_supportedColorModels = other->m_supportedColorModels;
419 m_supportedPrintQualities = other->m_supportedPrintQualities;
420
306 other->m_backend = tmp;421 other->m_backend = tmp;
307422}
308 loadColorModel();423
309 loadPrintQualities();424void Printer::onPrinterStateChanged(
310 loadAcceptJobs();425 const QString &text, const QString &printerUri,
426 const QString &printerName, uint printerState,
427 const QString &printerStateReason, bool acceptingJobs)
428{
429 Q_UNUSED(printerUri);
430 Q_UNUSED(printerState);
431 Q_UNUSED(printerStateReason);
432 Q_UNUSED(acceptingJobs);
433
434 if (name() == printerName) {
435 m_stateMessage = text;
436 }
311}437}
312438
=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printer.h'
--- modules/Ubuntu/Components/Extras/Printers/printer/printer.h 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printer/printer.h 2017-03-23 12:51:36 +0000
@@ -49,17 +49,24 @@
49 QStringList supportedDuplexStrings() const;49 QStringList supportedDuplexStrings() const;
50 PrinterEnum::DuplexMode defaultDuplexMode() const;50 PrinterEnum::DuplexMode defaultDuplexMode() const;
51 QString name() const;51 QString name() const;
52 QString deviceUri() const;
53 QString make() const;
52 PrintQuality defaultPrintQuality() const;54 PrintQuality defaultPrintQuality() const;
53 QList<PrintQuality> supportedPrintQualities() const;55 QList<PrintQuality> supportedPrintQualities() const;
54 QString description() const;56 QString description() const;
57 QString location() const;
55 QPageSize defaultPageSize() const;58 QPageSize defaultPageSize() const;
56 QList<QPageSize> supportedPageSizes() const;59 QList<QPageSize> supportedPageSizes() const;
57 PrinterEnum::AccessControl accessControl() const;60 PrinterEnum::AccessControl accessControl() const;
58 PrinterEnum::ErrorPolicy errorPolicy() const;61 PrinterEnum::ErrorPolicy errorPolicy() const;
59 PrinterEnum::State state() const;62 PrinterEnum::State state() const;
63 bool shared() const;
60 bool acceptJobs() const;64 bool acceptJobs() const;
61 bool holdsDefinition() const;65 bool holdsDefinition() const;
66 bool isRemote() const;
67 QString lastMessage() const;
62 QAbstractItemModel* jobs();68 QAbstractItemModel* jobs();
69 int copies() const;
6370
64 PrinterEnum::PrinterType type() const;71 PrinterEnum::PrinterType type() const;
6572
@@ -68,9 +75,11 @@
68 void setDefaultDuplexMode(const PrinterEnum::DuplexMode &duplexMode);75 void setDefaultDuplexMode(const PrinterEnum::DuplexMode &duplexMode);
69 void setEnabled(const bool enabled);76 void setEnabled(const bool enabled);
70 void setAcceptJobs(const bool accepting);77 void setAcceptJobs(const bool accepting);
78 void setShared(const bool shared);
71 void setDefaultPrintQuality(const PrintQuality &quality);79 void setDefaultPrintQuality(const PrintQuality &quality);
72 void setDefaultPageSize(const QPageSize &pageSize);80 void setDefaultPageSize(const QPageSize &pageSize);
73 void setJobModel(JobModel* jobModel);81 void setJobModel(JobModel* jobModel);
82 void setCopies(const int &copies);
7483
75 bool deepCompare(QSharedPointer<Printer> other) const;84 bool deepCompare(QSharedPointer<Printer> other) const;
76 void updateFrom(QSharedPointer<Printer> other);85 void updateFrom(QSharedPointer<Printer> other);
@@ -79,10 +88,22 @@
79public Q_SLOTS:88public Q_SLOTS:
80 int printFile(const QString &filepath, const PrinterJob *options);89 int printFile(const QString &filepath, const PrinterJob *options);
8190
91private Q_SLOTS:
92 void onPrinterStateChanged(
93 const QString &text, const QString &printerUri,
94 const QString &printerName, uint printerState,
95 const QString &printerStateReason, bool acceptingJobs
96 );
97
82private:98private:
83 void loadAcceptJobs();99 void updateAcceptJobs(const QMap<QString, QVariant> &serverAttrs);
84 void loadColorModel();100 void updateColorModel(const QMap<QString, QVariant> &serverAttrs);
85 void loadPrintQualities();101 void updatePrintQualities(const QMap<QString, QVariant> &serverAttrs);
102 void updateLastMessage(const QMap<QString, QVariant> &serverAttrs);
103 void updateDeviceUri(const QMap<QString, QVariant> &serverAttrs);
104 void updateCopies(const QMap<QString, QVariant> &serverAttrs);
105 void updateShared(const QMap<QString, QVariant> &serverAttrs);
106 void loadAttributes();
86107
87 JobFilter m_jobs;108 JobFilter m_jobs;
88 PrinterBackend *m_backend;109 PrinterBackend *m_backend;
@@ -91,6 +112,11 @@
91 PrintQuality m_defaultPrintQuality;112 PrintQuality m_defaultPrintQuality;
92 QList<PrintQuality> m_supportedPrintQualities;113 QList<PrintQuality> m_supportedPrintQualities;
93 bool m_acceptJobs;114 bool m_acceptJobs;
115 bool m_shared;
116 QString m_deviceUri;
117 int m_copies;
118
119 QString m_stateMessage;
94};120};
95121
96#endif // USC_PRINTERS_PRINTER_H122#endif // USC_PRINTERS_PRINTER_H
97123
=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp'
--- modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp 2017-02-24 17:47:22 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printer/printerjob.cpp 2017-03-23 12:51:36 +0000
@@ -55,6 +55,8 @@
55 , m_title(QStringLiteral(""))55 , m_title(QStringLiteral(""))
56 , m_user("")56 , m_user("")
57{57{
58 connect(this, SIGNAL(printerAboutToChange(QSharedPointer<Printer>, QSharedPointer<Printer>)),
59 this, SLOT(onPrinterAboutToChange(QSharedPointer<Printer>, QSharedPointer<Printer>)));
58}60}
5961
60PrinterJob::~PrinterJob()62PrinterJob::~PrinterJob()
@@ -143,6 +145,69 @@
143 return m_landscape;145 return m_landscape;
144}146}
145147
148void PrinterJob::loadAttributes(const QMap<QString, QVariant> &attributes)
149{
150 // Load the extra attributes for the job
151 // NOTE: we don't need to type check them as they have been filtered for us
152
153 setCollate(attributes.value("Collate").toBool());
154 setCopies(attributes.value("copies").toInt());
155
156 // No colorModel will result in PrinterJob using defaultColorModel
157 QString colorModel = attributes.value("ColorModel").toString();
158 for (int i=0; i < m_printer->supportedColorModels().length(); i++) {
159 if (m_printer->supportedColorModels().at(i).name == colorModel) {
160 setColorModel(i);
161 }
162 }
163
164 setCompletedTime(attributes.value("CompletedTime").toDateTime());
165 setCreationTime(attributes.value("CreationTime").toDateTime());
166
167 // No duplexMode will result in PrinterJob using defaultDuplexMode
168 QString duplex = attributes.value("Duplex").toString();
169 PrinterEnum::DuplexMode duplexMode = Utils::ppdChoiceToDuplexMode(duplex);
170 for (int i=0; i < m_printer->supportedDuplexModes().length(); i++) {
171 if (m_printer->supportedDuplexModes().at(i) == duplexMode) {
172 setDuplexMode(i);
173 }
174 }
175
176 setImpressionsCompleted(attributes.value("impressionsCompleted").toInt());
177 setLandscape(attributes.value("landscape").toBool());
178 setMessages(attributes.value("messages").toStringList());
179
180 QStringList pageRanges = attributes.value("page-ranges").toStringList();
181 if (pageRanges.isEmpty()) {
182 setPrintRangeMode(PrinterEnum::PrintRange::AllPages);
183 setPrintRange(QStringLiteral(""));
184 } else {
185 setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
186 // Use groupSeparator as createSeparatedList adds "and" into the string
187 setPrintRange(pageRanges.join(QLocale::system().groupSeparator()));
188 }
189
190 setProcessingTime(attributes.value("ProcessingTime").toDateTime());
191
192 // No quality will result in PrinterJob using defaultPrintQuality
193 QString quality = attributes.value("quality").toString();
194 for (int i=0; i < m_printer->supportedPrintQualities().length(); i++) {
195 if (m_printer->supportedPrintQualities().at(i).name == quality) {
196 setQuality(i);
197 }
198 }
199
200 setReverse(attributes.value("OutputOrder").toString() == "Reverse");
201
202 // If there was a state then set it
203 if (attributes.contains("State")) {
204 setState(static_cast<PrinterEnum::JobState>(attributes.value("State").toInt()));
205 }
206
207 setSize(attributes.value("Size").toInt());
208 setUser(attributes.value("User").toString());
209}
210
146void PrinterJob::loadDefaults()211void PrinterJob::loadDefaults()
147{212{
148 if (!m_printer) {213 if (!m_printer) {
@@ -150,62 +215,17 @@
150 return;215 return;
151 }216 }
152217
153 qWarning() << Q_FUNC_INFO << jobId();
154
155 if (jobId() > 0) {218 if (jobId() > 0) {
156 // Load the extra attributes for the job219 loadAttributes(
157 // NOTE: we don't need to type check them as they have been filtered for us220 m_backend->printerGetJobAttributes(
158221 printerName(), jobId()
159 QMap<QString, QVariant> attributes = m_backend->printerGetJobAttributes(222 )
160 m_printer->name(), jobId());223 );
161224 } else {
162 setCollate(attributes.value("Collate").toBool());225 setColorModel(m_printer->supportedColorModels().indexOf(m_printer->defaultColorModel()));
163 setCopies(attributes.value("copies").toInt());226 setDuplexMode(m_printer->supportedDuplexModes().indexOf(m_printer->defaultDuplexMode()));
164227 setQuality(m_printer->supportedPrintQualities().indexOf(m_printer->defaultPrintQuality()));
165 // No colorModel will result in PrinterJob using defaultColorModel
166 QString colorModel = attributes.value("ColorModel").toString();
167 for (int i=0; i < m_printer->supportedColorModels().length(); i++) {
168 if (m_printer->supportedColorModels().at(i).originalOption == colorModel) {
169 setColorModel(i);
170 }
171 }
172
173 // No duplexMode will result in PrinterJob using defaultDuplexMode
174 QString duplex = attributes.value("Duplex").toString();
175 PrinterEnum::DuplexMode duplexMode = Utils::ppdChoiceToDuplexMode(duplex);
176 for (int i=0; i < m_printer->supportedDuplexModes().length(); i++) {
177 if (m_printer->supportedDuplexModes().at(i) == duplexMode) {
178 setDuplexMode(i);
179 }
180 }
181
182 setLandscape(attributes.value("landscape").toBool());
183 setMessages(attributes.value("messages").toStringList());
184
185 QStringList pageRanges = attributes.value("page-ranges").toStringList();
186 if (pageRanges.isEmpty()) {
187 setPrintRangeMode(PrinterEnum::PrintRange::AllPages);
188 setPrintRange(QStringLiteral(""));
189 } else {
190 setPrintRangeMode(PrinterEnum::PrintRange::PageRange);
191 // Use groupSeparator as createSeparatedList adds "and" into the string
192 setPrintRange(pageRanges.join(QLocale::system().groupSeparator()));
193 }
194
195 // No quality will result in PrinterJob using defaultPrintQuality
196 QString quality = attributes.value("quality").toString();
197 for (int i=0; i < m_printer->supportedPrintQualities().length(); i++) {
198 if (m_printer->supportedPrintQualities().at(i).name == quality) {
199 setQuality(i);
200 }
201 }
202
203 setReverse(attributes.value("OutputOrder").toString() == "Reverse");
204 }228 }
205
206 setColorModel(m_printer->supportedColorModels().indexOf(m_printer->defaultColorModel()));
207 setDuplexMode(m_printer->supportedDuplexModes().indexOf(m_printer->defaultDuplexMode()));
208 setQuality(m_printer->supportedPrintQualities().indexOf(m_printer->defaultPrintQuality()));
209}229}
210230
211QStringList PrinterJob::messages() const231QStringList PrinterJob::messages() const
@@ -373,16 +393,16 @@
373void PrinterJob::setPrinter(QSharedPointer<Printer> printer)393void PrinterJob::setPrinter(QSharedPointer<Printer> printer)
374{394{
375 if (m_printer != printer) {395 if (m_printer != printer) {
376 m_printer = printer;396 Q_EMIT printerAboutToChange(m_printer, printer);
397 m_printer = printer;
377398
378 if (printer->name() != m_printerName) {399 if (printer->name() != m_printerName) {
379 m_printerName = printer->name();400 m_printerName = printer->name();
380 Q_EMIT printerNameChanged();401 Q_EMIT printerNameChanged();
381 }402 }
382403
383 Q_EMIT printerChanged();404 Q_EMIT printerChanged();
384 }405 }
385 loadDefaults();
386}406}
387407
388void PrinterJob::setPrintRange(const QString &printRange)408void PrinterJob::setPrintRange(const QString &printRange)
@@ -478,33 +498,61 @@
478 // Return true if they are the same498 // Return true if they are the same
479 return collate() == other->collate()499 return collate() == other->collate()
480 && colorModel() == other->colorModel()500 && colorModel() == other->colorModel()
501 && completedTime() == other->completedTime()
481 && copies() == other->copies()502 && copies() == other->copies()
503 && creationTime() == other->creationTime()
482 && duplexMode() == other->duplexMode()504 && duplexMode() == other->duplexMode()
505 && impressionsCompleted() == other->impressionsCompleted()
483 && landscape() == other->landscape()506 && landscape() == other->landscape()
507 && messages() == other->messages()
484 && printRange() == other->printRange()508 && printRange() == other->printRange()
485 && printRangeMode() == other->printRangeMode()509 && printRangeMode() == other->printRangeMode()
510 && processingTime() == other->processingTime()
486 && quality() == other->quality()511 && quality() == other->quality()
487 && reverse() == other->reverse()512 && reverse() == other->reverse()
513 && size() == other->size()
488 && state() == other->state()514 && state() == other->state()
489 && title() == other->title();515 && title() == other->title()
516 && user() == other->user();
490}517}
491518
492void PrinterJob::updateFrom(QSharedPointer<PrinterJob> other)519void PrinterJob::updateFrom(QSharedPointer<PrinterJob> other)
493{520{
494 setCollate(other->collate());521 setCollate(other->collate());
495 setColorModel(other->colorModel());522 setColorModel(other->colorModel());
523 setCompletedTime(other->completedTime());
496 setCopies(other->copies());524 setCopies(other->copies());
525 setCreationTime(other->creationTime());
497 setDuplexMode(other->duplexMode());526 setDuplexMode(other->duplexMode());
527 setImpressionsCompleted(other->impressionsCompleted());
498 setLandscape(other->landscape());528 setLandscape(other->landscape());
529 setMessages(other->messages());
499 setPrintRange(other->printRange());530 setPrintRange(other->printRange());
500 setPrintRangeMode(other->printRangeMode());531 setPrintRangeMode(other->printRangeMode());
532 setProcessingTime(other->processingTime());
501 setQuality(other->quality());533 setQuality(other->quality());
502 setReverse(other->reverse());534 setReverse(other->reverse());
535 setSize(other->size());
503 setState(other->state());536 setState(other->state());
504 setTitle(other->title());537 setTitle(other->title());
538 setUser(other->user());
505}539}
506540
507QString PrinterJob::user() const541QString PrinterJob::user() const
508{542{
509 return m_user;543 return m_user;
510}544}
545
546void PrinterJob::onPrinterAboutToChange(QSharedPointer<Printer> old,
547 QSharedPointer<Printer> replacement)
548{
549 /* If we have an old printer, and the current copies value matches that
550 of the old printer's, we'll use the new printer's copy value.
551
552 The second case is if there was no old printer. */
553 bool haveOld = old && replacement && (copies() == old->copies());
554 bool noOld = !old && replacement;
555 if (haveOld || noOld) {
556 setCopies(replacement->copies());
557 }
558}
511559
=== modified file 'modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h'
--- modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printer/printerjob.h 2017-03-23 12:51:36 +0000
@@ -58,8 +58,6 @@
58 Q_PROPERTY(PrinterEnum::JobState state READ state NOTIFY stateChanged)58 Q_PROPERTY(PrinterEnum::JobState state READ state NOTIFY stateChanged)
59 Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)59 Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
60 Q_PROPERTY(QString user READ user NOTIFY userChanged)60 Q_PROPERTY(QString user READ user NOTIFY userChanged)
61
62 friend class PrinterCupsBackend;
63public:61public:
64 explicit PrinterJob(QString dest,62 explicit PrinterJob(QString dest,
65 PrinterBackend *backend,63 PrinterBackend *backend,
@@ -97,31 +95,34 @@
97 PrinterEnum::DuplexMode getDuplexMode() const;95 PrinterEnum::DuplexMode getDuplexMode() const;
98 ColorModel getColorModel() const;96 ColorModel getColorModel() const;
99 PrintQuality getPrintQuality() const;97 PrintQuality getPrintQuality() const;
98 void loadAttributes(const QMap<QString, QVariant>& attributes);
99 void loadDefaults();
100 Q_INVOKABLE void printFile(const QUrl &url);100 Q_INVOKABLE void printFile(const QUrl &url);
101 void setCollate(const bool collate);101 void setCollate(const bool collate);
102 void setColorModel(const int colorModel);102 void setColorModel(const int colorModel);
103 void setCompletedTime(const QDateTime &completedTime);
103 void setCopies(const int copies);104 void setCopies(const int copies);
105 void setCreationTime(const QDateTime &creationTime);
104 void setDuplexMode(const int duplexMode);106 void setDuplexMode(const int duplexMode);
105 void setImpressionsCompleted(const int &impressionsCompleted);107 void setImpressionsCompleted(const int &impressionsCompleted);
108 void setIsTwoSided(const bool isTwoSided);
106 void setLandscape(const bool landscape);109 void setLandscape(const bool landscape);
110 void setMessages(const QStringList &messages);
107 void setPrinter(QSharedPointer<Printer> printer);111 void setPrinter(QSharedPointer<Printer> printer);
108 void setPrintRange(const QString &printRange);112 void setPrintRange(const QString &printRange);
109 void setPrintRangeMode(const PrinterEnum::PrintRange printRangeMode);113 void setPrintRangeMode(const PrinterEnum::PrintRange printRangeMode);
114 void setProcessingTime(const QDateTime &processingTime);
110 void setQuality(const int quality);115 void setQuality(const int quality);
111 void setReverse(const bool reverse);116 void setReverse(const bool reverse);
117 void setSize(const int size);
118 void setState(const PrinterEnum::JobState &state);
112 void setTitle(const QString &title);119 void setTitle(const QString &title);
120 void setUser(const QString &user);
113121
114 void updateFrom(QSharedPointer<PrinterJob> other);122 void updateFrom(QSharedPointer<PrinterJob> other);
115private Q_SLOTS:123private Q_SLOTS:
116 void loadDefaults();124 void onPrinterAboutToChange(QSharedPointer<Printer> old,
117 void setCompletedTime(const QDateTime &completedTime);125 QSharedPointer<Printer> replacement);
118 void setCreationTime(const QDateTime &creationTime);
119 void setIsTwoSided(const bool isTwoSided);
120 void setMessages(const QStringList &messages);
121 void setProcessingTime(const QDateTime &processingTime);
122 void setSize(const int size);
123 void setState(const PrinterEnum::JobState &state);
124 void setUser(const QString &user);
125Q_SIGNALS:126Q_SIGNALS:
126 void collateChanged();127 void collateChanged();
127 void colorModelChanged();128 void colorModelChanged();
@@ -134,6 +135,8 @@
134 void isTwoSidedChanged();135 void isTwoSidedChanged();
135 void landscapeChanged();136 void landscapeChanged();
136 void messagesChanged();137 void messagesChanged();
138 void printerAboutToChange(QSharedPointer<Printer> old,
139 QSharedPointer<Printer> replacement);
137 void printerChanged();140 void printerChanged();
138 void printerNameChanged();141 void printerNameChanged();
139 void printRangeChanged();142 void printRangeChanged();
140143
=== renamed file 'modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.cpp' => 'modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.cpp'
--- modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.cpp 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.cpp 2017-03-23 12:51:36 +0000
@@ -14,9 +14,9 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#include "printersignalhandler.h"17#include "signalratelimiter.h"
1818
19PrinterSignalHandler::PrinterSignalHandler(int triggerEventDelay,19SignalRateLimiter::SignalRateLimiter(int triggerEventDelay,
20 QObject *parent)20 QObject *parent)
21 : QObject(parent)21 : QObject(parent)
22{22{
@@ -24,11 +24,11 @@
24 connect(&m_timer, SIGNAL(timeout()), this, SLOT(process()));24 connect(&m_timer, SIGNAL(timeout()), this, SLOT(process()));
25}25}
2626
27PrinterSignalHandler::~PrinterSignalHandler()27SignalRateLimiter::~SignalRateLimiter()
28{28{
29}29}
3030
31void PrinterSignalHandler::process()31void SignalRateLimiter::process()
32{32{
33 Q_FOREACH(auto printer, m_unprocessed) {33 Q_FOREACH(auto printer, m_unprocessed) {
34 Q_EMIT printerModified(printer);34 Q_EMIT printerModified(printer);
@@ -37,7 +37,7 @@
37 m_timer.stop();37 m_timer.stop();
38}38}
3939
40void PrinterSignalHandler::onPrinterModified(40void SignalRateLimiter::onPrinterModified(
41 const QString &text, const QString &printerUri,41 const QString &text, const QString &printerUri,
42 const QString &printerName, uint printerState,42 const QString &printerName, uint printerState,
43 const QString &printerStateReason, bool acceptingJobs)43 const QString &printerStateReason, bool acceptingJobs)
@@ -49,11 +49,22 @@
49 Q_UNUSED(printerStateReason);49 Q_UNUSED(printerStateReason);
50 Q_UNUSED(acceptingJobs);50 Q_UNUSED(acceptingJobs);
5151
52 // Track when the first item was added to the unprocessed queue
53 if (m_unprocessed.count() == 0) {
54 m_unprocessed_time = QDateTime::currentDateTime();
55 }
56
52 m_unprocessed << printerName;57 m_unprocessed << printerName;
53 m_timer.start();58 m_timer.start();
59
60 // Ensure that process is fired if we have reached four times
61 // longer than the timer, this is due to many signals coming in rapidly
62 if (m_unprocessed_time.msecsTo(QDateTime::currentDateTime()) > m_timer.interval() * 4) {
63 process();
64 }
54}65}
5566
56void PrinterSignalHandler::onPrinterStateChanged(67void SignalRateLimiter::onPrinterStateChanged(
57 const QString &text, const QString &printerUri,68 const QString &text, const QString &printerUri,
58 const QString &printerName, uint printerState,69 const QString &printerName, uint printerState,
59 const QString &printerStateReason, bool acceptingJobs)70 const QString &printerStateReason, bool acceptingJobs)
@@ -64,6 +75,17 @@
64 Q_UNUSED(printerStateReason);75 Q_UNUSED(printerStateReason);
65 Q_UNUSED(acceptingJobs);76 Q_UNUSED(acceptingJobs);
6677
78 // Track when the first item was added to the unprocessed queue
79 if (m_unprocessed.count() == 0) {
80 m_unprocessed_time = QDateTime::currentDateTime();
81 }
82
67 m_unprocessed << printerName;83 m_unprocessed << printerName;
68 m_timer.start();84 m_timer.start();
85
86 // Ensure that process is fired if we have reached four times
87 // longer than the timer, this is due to many signals coming in rapidly
88 if (m_unprocessed_time.msecsTo(QDateTime::currentDateTime()) > m_timer.interval() * 4) {
89 process();
90 }
69}91}
7092
=== renamed file 'modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.h' => 'modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.h'
--- modules/Ubuntu/Components/Extras/Printers/printer/printersignalhandler.h 2017-02-21 10:46:29 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printer/signalratelimiter.h 2017-03-23 12:51:36 +0000
@@ -14,24 +14,26 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#ifndef USC_PRINTER_SIGNAL_HANDLER_H17#ifndef USC_SIGNAL_RATE_LIMITER_H
18#define USC_PRINTER_SIGNAL_HANDLER_H18#define USC_SIGNAL_RATE_LIMITER_H
1919
20#include "printers_global.h"20#include "printers_global.h"
2121
22#include <QDateTime>
22#include <QObject>23#include <QObject>
23#include <QSet>24#include <QSet>
24#include <QTimer>25#include <QTimer>
2526
26class PRINTERS_DECL_EXPORT PrinterSignalHandler : public QObject27class PRINTERS_DECL_EXPORT SignalRateLimiter : public QObject
27{28{
28 Q_OBJECT29 Q_OBJECT
29 QTimer m_timer;30 QTimer m_timer;
30 QSet<QString> m_unprocessed;31 QSet<QString> m_unprocessed;
32 QDateTime m_unprocessed_time;
31public:33public:
32 explicit PrinterSignalHandler(int triggerEventDelay = 500,34 explicit SignalRateLimiter(int triggerEventDelay = 500,
33 QObject *parent = Q_NULLPTR);35 QObject *parent = Q_NULLPTR);
34 ~PrinterSignalHandler();36 ~SignalRateLimiter();
3537
36public Q_SLOTS:38public Q_SLOTS:
37 void onPrinterModified(39 void onPrinterModified(
@@ -52,4 +54,4 @@
52 void printerModified(const QString &printerName);54 void printerModified(const QString &printerName);
53};55};
5456
55#endif // USC_PRINTER_SIGNAL_HANDLER_H57#endif // USC_SIGNAL_RATE_LIMITERR_H
5658
=== modified file 'modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp'
--- modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp 2017-02-24 13:14:13 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp 2017-03-23 12:51:36 +0000
@@ -15,6 +15,7 @@
15 */15 */
1616
17#include "backend/backend_cups.h"17#include "backend/backend_cups.h"
18#include "i18n.h"
18#include "printers/printers.h"19#include "printers/printers.h"
19#include "cupsdnotifier.h" // Note: this file was generated.20#include "cupsdnotifier.h" // Note: this file was generated.
2021
@@ -33,6 +34,7 @@
33Printers::Printers(PrinterBackend *backend, QObject *parent)34Printers::Printers(PrinterBackend *backend, QObject *parent)
34 : QObject(parent)35 : QObject(parent)
35 , m_backend(backend)36 , m_backend(backend)
37 , m_devices(backend)
36 , m_drivers(backend)38 , m_drivers(backend)
37 , m_model(backend)39 , m_model(backend)
38 , m_jobs(backend)40 , m_jobs(backend)
@@ -56,8 +58,20 @@
56 const QModelIndex &parent, int first, int) {58 const QModelIndex &parent, int first, int) {
57 int jobId = m_jobs.data(m_jobs.index(first, 0, parent),59 int jobId = m_jobs.data(m_jobs.index(first, 0, parent),
58 JobModel::Roles::IdRole).toInt();60 JobModel::Roles::IdRole).toInt();
59 jobAdded(m_jobs.getJobById(jobId));61 QString printerName = m_jobs.data(
60 });62 m_jobs.index(first, 0, parent),
63 JobModel::Roles::PrinterNameRole
64 ).toString();
65
66 jobAdded(m_jobs.getJob(printerName, jobId));
67 });
68
69 // If the jobModel forces a refresh, load extended attributes for the job
70 connect(&m_jobs, &JobModel::forceJobRefresh, [this](
71 const QString &printerName, const int jobId) {
72 jobAdded(m_jobs.getJob(printerName, jobId));
73 });
74
61 connect(&m_model, &QAbstractItemModel::rowsInserted, [this](75 connect(&m_model, &QAbstractItemModel::rowsInserted, [this](
62 const QModelIndex &parent, int first, int) {76 const QModelIndex &parent, int first, int) {
63 auto printer = m_model.data(77 auto printer = m_model.data(
@@ -76,6 +90,17 @@
76 );90 );
77 }91 }
7892
93 // Ensure existing jobs have been added, incase some were added before
94 // the connect to rowsInserted was done
95 for (int i = 0; i < m_jobs.rowCount(); i++) {
96 jobAdded(
97 m_jobs.getJob(
98 m_jobs.data(m_jobs.index(i), JobModel::Roles::PrinterNameRole).toString(),
99 m_jobs.data(m_jobs.index(i), JobModel::IdRole).toInt()
100 )
101 );
102 }
103
79 if (m_backend->type() == PrinterEnum::PrinterType::CupsType) {104 if (m_backend->type() == PrinterEnum::PrinterType::CupsType) {
80 ((PrinterCupsBackend*) m_backend)->createSubscription();105 ((PrinterCupsBackend*) m_backend)->createSubscription();
81 }106 }
@@ -103,6 +128,41 @@
103 return ret;128 return ret;
104}129}
105130
131QAbstractItemModel* Printers::remotePrinters()
132{
133 /* Lazily initialize this model. Local printers are discerned from remotes
134 by checking if they are remote. */
135 if (!m_remotePrinters.sourceModel()) {
136 m_remotePrinters.setSourceModel(&m_model);
137 m_remotePrinters.filterOnRemote(true);
138 m_remotePrinters.filterOnPdf(false);
139 m_remotePrinters.invalidate();
140 m_remotePrinters.sort(0, Qt::DescendingOrder);
141 }
142
143 auto ret = &m_remotePrinters;
144 QQmlEngine::setObjectOwnership(ret, QQmlEngine::CppOwnership);
145 return ret;
146}
147
148QAbstractItemModel* Printers::localPrinters()
149{
150 /* Lazily initialize this model. Local printers are discerned from remotes
151 by checking if they are remote. */
152 if (!m_localPrinters.sourceModel()) {
153 m_localPrinters.setSourceModel(&m_model);
154 m_localPrinters.filterOnRemote(false);
155 m_localPrinters.filterOnPdf(false);
156 m_localPrinters.setSortRole(PrinterModel::Roles::DefaultPrinterRole);
157 m_localPrinters.invalidate();
158 m_localPrinters.sort(0, Qt::DescendingOrder);
159 }
160
161 auto ret = &m_localPrinters;
162 QQmlEngine::setObjectOwnership(ret, QQmlEngine::CppOwnership);
163 return ret;
164}
165
106QAbstractItemModel* Printers::printJobs()166QAbstractItemModel* Printers::printJobs()
107{167{
108 auto ret = &m_jobs;168 auto ret = &m_jobs;
@@ -117,6 +177,14 @@
117 return ret;177 return ret;
118}178}
119179
180QAbstractItemModel* Printers::devices()
181{
182 m_devices.load();
183 auto ret = &m_devices;
184 QQmlEngine::setObjectOwnership(ret, QQmlEngine::CppOwnership);
185 return ret;
186}
187
120QString Printers::driverFilter() const188QString Printers::driverFilter() const
121{189{
122 return m_drivers.filter();190 return m_drivers.filter();
@@ -143,11 +211,33 @@
143 return new PrinterJob(printerName, m_backend);211 return new PrinterJob(printerName, m_backend);
144}212}
145213
214QAbstractItemModel* Printers::createJobFilter()
215{
216 // Note: If called by QML, it gains ownership of the job filter.
217 JobFilter *filter = new JobFilter();
218 filter->setSourceModel(&m_jobs);
219
220 filter->setSortRole(JobModel::Roles::CreationTimeRole);
221 filter->sort(0, Qt::AscendingOrder);
222
223 return filter;
224}
225
146void Printers::cancelJob(const QString &printerName, const int jobId)226void Printers::cancelJob(const QString &printerName, const int jobId)
147{227{
148 m_backend->cancelJob(printerName, jobId);228 m_backend->cancelJob(printerName, jobId);
149}229}
150230
231void Printers::holdJob(const QString &printerName, const int jobId)
232{
233 m_backend->holdJob(printerName, jobId);
234}
235
236void Printers::releaseJob(const QString &printerName, const int jobId)
237{
238 m_backend->releaseJob(printerName, jobId);
239}
240
151void Printers::setDefaultPrinterName(const QString &name)241void Printers::setDefaultPrinterName(const QString &name)
152{242{
153 QString reply = m_backend->printerSetDefault(name);243 QString reply = m_backend->printerSetDefault(name);
@@ -164,6 +254,11 @@
164 }254 }
165}255}
166256
257void Printers::searchForDevices()
258{
259 m_devices.load();
260}
261
167bool Printers::addPrinter(const QString &name, const QString &ppd,262bool Printers::addPrinter(const QString &name, const QString &ppd,
168 const QString &device, const QString &description,263 const QString &device, const QString &description,
169 const QString &location)264 const QString &location)
@@ -174,6 +269,9 @@
174 m_lastMessage = reply;269 m_lastMessage = reply;
175 return false;270 return false;
176 }271 }
272
273 provisionPrinter(name);
274
177 return true;275 return true;
178}276}
179277
@@ -189,9 +287,19 @@
189 m_lastMessage = reply;287 m_lastMessage = reply;
190 return false;288 return false;
191 }289 }
290
291 provisionPrinter(name);
292
192 return true;293 return true;
193}294}
194295
296void Printers::provisionPrinter(const QString &name)
297{
298 // We mimic what System Config Printer does here.
299 m_backend->printerSetEnabled(name, true);
300 m_backend->printerSetAcceptJobs(name, true);
301}
302
195bool Printers::removePrinter(const QString &name)303bool Printers::removePrinter(const QString &name)
196{304{
197 QString reply = m_backend->printerDelete(name);305 QString reply = m_backend->printerDelete(name);
@@ -206,8 +314,21 @@
206void Printers::jobAdded(QSharedPointer<PrinterJob> job)314void Printers::jobAdded(QSharedPointer<PrinterJob> job)
207{315{
208 auto printer = m_model.getPrinterByName(job->printerName());316 auto printer = m_model.getPrinterByName(job->printerName());
209 if (printer && job)317
210 job->setPrinter(printer);318 // Check if we have a valid printer, does not need to be loaded as JobLoader
319 // creates it's own Backend.
320 if (printer && job) {
321 // TODO: this printer may not be fully loaded
322 // Which has the side affect of colorModel, duplex, quality not working
323 // in PrinterJob as Printer::supportedColorModels etc fail
324 // Potentially trigger loadPrinter and listen for the new printer?
325
326 // Set the printer to the job
327 m_jobs.updateJobPrinter(job, printer);
328
329 // Trigger JobLoader to load extended attributes in the background
330 m_backend->requestJobExtendedAttributes(printer, job);
331 }
211}332}
212333
213void Printers::printerAdded(QSharedPointer<Printer> printer)334void Printers::printerAdded(QSharedPointer<Printer> printer)
@@ -223,10 +344,9 @@
223 ).toString();344 ).toString();
224345
225 int jobId = m_jobs.data(idx, JobModel::Roles::IdRole).toInt();346 int jobId = m_jobs.data(idx, JobModel::Roles::IdRole).toInt();
226 auto job = m_jobs.getJobById(jobId);347 auto job = m_jobs.getJob(printerName, jobId);
227 if (printerName == printer->name() && !job->printer()) {348 if (printerName == printer->name() && !job->printer()) {
228 job->setPrinter(printer);349 jobAdded(job);
229 return;
230 }350 }
231 }351 }
232}352}
@@ -243,3 +363,28 @@
243 m_backend->requestPrinter(name);363 m_backend->requestPrinter(name);
244 }364 }
245}365}
366
367void Printers::printTestPage(const QString &name)
368{
369
370 auto printer = m_model.getPrinterByName(name);
371 if (!printer) {
372 qWarning() << Q_FUNC_INFO << "no known printer named" << name;
373 return;
374 }
375
376 auto page = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
377 "cups/data/default-testpage.pdf",
378 QStandardPaths::LocateFile);
379
380 if (page.isEmpty()) {
381 qCritical() << Q_FUNC_INFO << "Could not find test page.";
382 return;
383 }
384
385 auto job = new PrinterJob(name, m_backend);
386 job->setPrinter(printer);
387 job->setTitle(__("Test page"));
388 job->printFile(QUrl::fromLocalFile(page));
389 job->deleteLater();
390}
246391
=== modified file 'modules/Ubuntu/Components/Extras/Printers/printers/printers.h'
--- modules/Ubuntu/Components/Extras/Printers/printers/printers.h 2017-02-24 12:20:07 +0000
+++ modules/Ubuntu/Components/Extras/Printers/printers/printers.h 2017-03-23 12:51:36 +0000
@@ -19,6 +19,7 @@
1919
20#include "printers_global.h"20#include "printers_global.h"
2121
22#include "models/devicemodel.h"
22#include "models/drivermodel.h"23#include "models/drivermodel.h"
23#include "models/printermodel.h"24#include "models/printermodel.h"
24#include "printer/printer.h"25#include "printer/printer.h"
@@ -36,8 +37,11 @@
36 Q_OBJECT37 Q_OBJECT
37 Q_PROPERTY(QAbstractItemModel* allPrinters READ allPrinters CONSTANT)38 Q_PROPERTY(QAbstractItemModel* allPrinters READ allPrinters CONSTANT)
38 Q_PROPERTY(QAbstractItemModel* allPrintersWithPdf READ allPrintersWithPdf CONSTANT)39 Q_PROPERTY(QAbstractItemModel* allPrintersWithPdf READ allPrintersWithPdf CONSTANT)
40 Q_PROPERTY(QAbstractItemModel* remotePrinters READ remotePrinters CONSTANT)
41 Q_PROPERTY(QAbstractItemModel* localPrinters READ localPrinters CONSTANT)
39 Q_PROPERTY(QAbstractItemModel* printJobs READ printJobs CONSTANT)42 Q_PROPERTY(QAbstractItemModel* printJobs READ printJobs CONSTANT)
40 Q_PROPERTY(QAbstractItemModel* drivers READ drivers CONSTANT)43 Q_PROPERTY(QAbstractItemModel* drivers READ drivers CONSTANT)
44 Q_PROPERTY(QAbstractItemModel* devices READ devices CONSTANT)
41 Q_PROPERTY(QString driverFilter READ driverFilter WRITE setDriverFilter NOTIFY driverFilterChanged)45 Q_PROPERTY(QString driverFilter READ driverFilter WRITE setDriverFilter NOTIFY driverFilterChanged)
42 Q_PROPERTY(QString defaultPrinterName READ defaultPrinterName WRITE setDefaultPrinterName NOTIFY defaultPrinterNameChanged)46 Q_PROPERTY(QString defaultPrinterName READ defaultPrinterName WRITE setDefaultPrinterName NOTIFY defaultPrinterNameChanged)
43 Q_PROPERTY(QString lastMessage READ lastMessage CONSTANT)47 Q_PROPERTY(QString lastMessage READ lastMessage CONSTANT)
@@ -51,8 +55,11 @@
5155
52 QAbstractItemModel* allPrinters();56 QAbstractItemModel* allPrinters();
53 QAbstractItemModel* allPrintersWithPdf();57 QAbstractItemModel* allPrintersWithPdf();
58 QAbstractItemModel* remotePrinters();
59 QAbstractItemModel* localPrinters();
54 QAbstractItemModel* printJobs();60 QAbstractItemModel* printJobs();
55 QAbstractItemModel* drivers();61 QAbstractItemModel* drivers();
62 QAbstractItemModel* devices();
56 QString driverFilter() const;63 QString driverFilter() const;
57 QString defaultPrinterName() const;64 QString defaultPrinterName() const;
58 QString lastMessage() const;65 QString lastMessage() const;
@@ -62,7 +69,11 @@
6269
63public Q_SLOTS:70public Q_SLOTS:
64 PrinterJob* createJob(const QString &printerName);71 PrinterJob* createJob(const QString &printerName);
72 QAbstractItemModel* createJobFilter();
73
65 void cancelJob(const QString &printerName, const int jobId);74 void cancelJob(const QString &printerName, const int jobId);
75 void holdJob(const QString &printerName, const int jobId);
76 void releaseJob(const QString &printerName, const int jobId);
6677
67 /* Instructs us to start loading drivers and what have you. In most cases,78 /* Instructs us to start loading drivers and what have you. In most cases,
68 the user is likely to merely configure existing printers/jobs. Loading79 the user is likely to merely configure existing printers/jobs. Loading
@@ -70,6 +81,9 @@
70 add printers, this method should be called first. */81 add printers, this method should be called first. */
71 void prepareToAddPrinter();82 void prepareToAddPrinter();
7283
84 // Starts a search for devices on local and remote resources.
85 void searchForDevices();
86
73 bool addPrinter(const QString &name, const QString &ppd,87 bool addPrinter(const QString &name, const QString &ppd,
74 const QString &device, const QString &description,88 const QString &device, const QString &description,
75 const QString &location);89 const QString &location);
@@ -83,6 +97,8 @@
83 // Instruct us to start (eagerly) loading a printer.97 // Instruct us to start (eagerly) loading a printer.
84 void loadPrinter(const QString &name);98 void loadPrinter(const QString &name);
8599
100 void printTestPage(const QString &name);
101
86private Q_SLOTS:102private Q_SLOTS:
87 void jobAdded(QSharedPointer<PrinterJob> job);103 void jobAdded(QSharedPointer<PrinterJob> job);
88 void printerAdded(QSharedPointer<Printer> printer);104 void printerAdded(QSharedPointer<Printer> printer);
@@ -92,12 +108,16 @@
92 void driverFilterChanged();108 void driverFilterChanged();
93109
94private:110private:
111 void provisionPrinter(const QString &name);
95 PrinterBackend *m_backend;112 PrinterBackend *m_backend;
113 DeviceModel m_devices;
96 DriverModel m_drivers;114 DriverModel m_drivers;
97 PrinterModel m_model;115 PrinterModel m_model;
98 JobModel m_jobs;116 JobModel m_jobs;
99 PrinterFilter m_allPrinters;117 PrinterFilter m_allPrinters;
100 PrinterFilter m_allPrintersWithPdf;118 PrinterFilter m_allPrintersWithPdf;
119 PrinterFilter m_remotePrinters;
120 PrinterFilter m_localPrinters;
101 PrinterFilter m_recentPrinters;121 PrinterFilter m_recentPrinters;
102 QString m_lastMessage;122 QString m_lastMessage;
103};123};
104124
=== modified file 'modules/Ubuntu/Components/Extras/Printers/structs.h'
--- modules/Ubuntu/Components/Extras/Printers/structs.h 2017-02-23 14:04:26 +0000
+++ modules/Ubuntu/Components/Extras/Printers/structs.h 2017-03-23 12:51:36 +0000
@@ -84,6 +84,87 @@
84 }84 }
85};85};
8686
87struct Device
88{
89public:
90 QString cls;
91 QString id;
92 QString info;
93 QString makeModel;
94 QString uri;
95 QString location;
96 PrinterEnum::DeviceType type()
97 {
98 auto parts = uri.split(":", QString::SkipEmptyParts);
99 QString scheme = parts.size() > 0 ? parts[0] : QStringLiteral("");
100 if (scheme == QStringLiteral("dnssd"))
101 return PrinterEnum::DeviceType::DNSSDType;
102 else if (scheme == QStringLiteral("lpd"))
103 return PrinterEnum::DeviceType::LPDType;
104 else if (scheme == QStringLiteral("ipps"))
105 return PrinterEnum::DeviceType::IppSType;
106 else if (scheme == QStringLiteral("ipp14"))
107 return PrinterEnum::DeviceType::Ipp14Type;
108 else if (scheme == QStringLiteral("http"))
109 return PrinterEnum::DeviceType::HttpType;
110 else if (scheme == QStringLiteral("beh"))
111 return PrinterEnum::DeviceType::BehType;
112 else if (scheme == QStringLiteral("socket"))
113 return PrinterEnum::DeviceType::SocketType;
114 else if (scheme == QStringLiteral("https"))
115 return PrinterEnum::DeviceType::HttpsType;
116 else if (scheme == QStringLiteral("ipp"))
117 return PrinterEnum::DeviceType::IppType;
118 else if (scheme == QStringLiteral("hp"))
119 return PrinterEnum::DeviceType::HPType;
120 else if (scheme == QStringLiteral("usb"))
121 return PrinterEnum::DeviceType::USBType;
122 else if (scheme == QStringLiteral("hpfax"))
123 return PrinterEnum::DeviceType::HPFaxType;
124 else
125 return PrinterEnum::DeviceType::UnknownType;
126 }
127
128 QString toString() const {
129 /* 1. Split the id, which is of format "KEY:VAL; … KEYN:VALN;" into
130 ["KEY:VAL", …, "KEYN:VALN"]
131 2. Split each pair into
132 ["KEY", "VAL"] … ["KEYN", "VALN"]*/
133 QMap<QString, QString> idMap;
134 auto pairs = id.split(";");
135 Q_FOREACH(const QString &pair, pairs) {
136 auto keyValue = pair.split(":");
137
138 /* Sometimes key,val pairs are not terminated by ";". We just
139 use the first value in that case. E.g.:
140 "MFG:HP MDL:Laserfjert;"
141 Will give "HP" as MFG, and "" as MDL. */
142 if (keyValue.size() >= 2) {
143 idMap[keyValue[0]] = keyValue[1];
144 }
145 }
146 auto mfg = idMap.value("MFG", "");
147 auto mdl = idMap.value("MDL", "");
148
149 /* If the MDL field contains CMD, somebody forgot to terminate, and we
150 remove it. */
151 if (mdl.contains("CMD")) {
152 mdl = mdl.split("CMD")[0];
153 }
154
155 return QString("%1 %2").arg(mfg).arg(mdl);
156 }
157
158 bool operator==(const Device &other)
159 {
160 return ((cls == other.cls) && (id == other.id) && (info == other.info) &&
161 (makeModel == other.makeModel) && (uri == other.uri) &&
162 (location == other.location));
163 }
164};
165
166
167
87Q_DECLARE_TYPEINFO(ColorModel, Q_PRIMITIVE_TYPE);168Q_DECLARE_TYPEINFO(ColorModel, Q_PRIMITIVE_TYPE);
88Q_DECLARE_METATYPE(ColorModel)169Q_DECLARE_METATYPE(ColorModel)
89170
@@ -94,4 +175,7 @@
94Q_DECLARE_METATYPE(PrinterDriver)175Q_DECLARE_METATYPE(PrinterDriver)
95Q_DECLARE_METATYPE(QList<PrinterDriver>)176Q_DECLARE_METATYPE(QList<PrinterDriver>)
96177
178Q_DECLARE_TYPEINFO(Device, Q_MOVABLE_TYPE);
179Q_DECLARE_METATYPE(Device)
180
97#endif // USC_PRINTERS_STRUCTS_H181#endif // USC_PRINTERS_STRUCTS_H
98182
=== modified file 'po/ubuntu-ui-extras.pot'
--- po/ubuntu-ui-extras.pot 2017-02-21 10:46:29 +0000
+++ po/ubuntu-ui-extras.pot 2017-03-23 12:51:36 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: ubuntu-ui-extras\n"9"Project-Id-Version: ubuntu-ui-extras\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2017-02-21 10:42+0000\n"11"POT-Creation-Date: 2017-03-21 15:33+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,6 +17,14 @@
17"Content-Type: text/plain; charset=CHARSET\n"17"Content-Type: text/plain; charset=CHARSET\n"
18"Content-Transfer-Encoding: 8bit\n"18"Content-Transfer-Encoding: 8bit\n"
1919
20#: modules/Ubuntu/Components/Extras/Example/Printers.qml:106
21msgid "Aborted"
22msgstr ""
23
24#: modules/Ubuntu/Components/Extras/Example/Printers.qml:108
25msgid "Active"
26msgstr ""
27
20#: modules/Ubuntu/Components/Extras/PhotoEditor.qml:20628#: modules/Ubuntu/Components/Extras/PhotoEditor.qml:206
21#: modules/Ubuntu/Components/Extras/PhotoEditor/ExposureAdjuster.qml:8129#: modules/Ubuntu/Components/Extras/PhotoEditor/ExposureAdjuster.qml:81
22msgid "Cancel"30msgid "Cancel"
@@ -26,7 +34,7 @@
26msgid "Color"34msgid "Color"
27msgstr ""35msgstr ""
2836
29#: modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp:5337#: modules/Ubuntu/Components/Extras/Printers/models/printermodel.cpp:54
30msgid "Create PDF"38msgid "Create PDF"
31msgstr ""39msgstr ""
3240
@@ -43,10 +51,18 @@
43msgid "Enhancing photo..."51msgid "Enhancing photo..."
44msgstr ""52msgstr ""
4553
54#: modules/Ubuntu/Components/Extras/Example/Printers.qml:104
55msgid "Idle"
56msgstr ""
57
46#: modules/Ubuntu/Components/Extras/Printers/utils.h:6158#: modules/Ubuntu/Components/Extras/Printers/utils.h:61
47msgid "Long Edge (Standard)"59msgid "Long Edge (Standard)"
48msgstr ""60msgstr ""
4961
62#: modules/Ubuntu/Components/Extras/Example/Printers.qml:115
63msgid "No messages"
64msgstr ""
65
50#: modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp:4766#: modules/Ubuntu/Components/Extras/Printers/backend/backend_pdf.cpp:47
51msgid "Normal"67msgid "Normal"
52msgstr ""68msgstr ""
@@ -79,6 +95,14 @@
79msgid "Short Edge (Flip)"95msgid "Short Edge (Flip)"
80msgstr ""96msgstr ""
8197
98#: modules/Ubuntu/Components/Extras/Example/Printers.qml:110
99msgid "Stopped"
100msgstr ""
101
102#: modules/Ubuntu/Components/Extras/Printers/printers/printers.cpp:387
103msgid "Test page"
104msgstr ""
105
82#: modules/Ubuntu/Components/Extras/PhotoEditor.qml:197106#: modules/Ubuntu/Components/Extras/PhotoEditor.qml:197
83msgid "This will undo all edits, including those from previous sessions."107msgid "This will undo all edits, including those from previous sessions."
84msgstr ""108msgstr ""
85109
=== modified file 'tests/unittests/Printers/CMakeLists.txt'
--- tests/unittests/Printers/CMakeLists.txt 2017-02-21 16:55:36 +0000
+++ tests/unittests/Printers/CMakeLists.txt 2017-03-23 12:51:36 +0000
@@ -22,6 +22,8 @@
22add_executable(testPrintersPrinters tst_printers.cpp ${MOCK_SOURCES})22add_executable(testPrintersPrinters tst_printers.cpp ${MOCK_SOURCES})
23target_link_libraries(testPrintersPrinters UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)23target_link_libraries(testPrintersPrinters UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)
24add_test(tst_printers testPrintersPrinters)24add_test(tst_printers testPrintersPrinters)
25set_tests_properties(tst_printers PROPERTIES
26 ENVIRONMENT "XDG_DATA_DIRS=${CMAKE_CURRENT_SOURCE_DIR}/testdata")
2527
26add_executable(testPrintersPrinterModel tst_printermodel.cpp ${MOCK_SOURCES})28add_executable(testPrintersPrinterModel tst_printermodel.cpp ${MOCK_SOURCES})
27target_link_libraries(testPrintersPrinterModel UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)29target_link_libraries(testPrintersPrinterModel UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)
@@ -43,6 +45,14 @@
43target_link_libraries(testPrintersJobFilter UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)45target_link_libraries(testPrintersJobFilter UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)
44add_test(tst_jobfilter testPrintersJobFilter)46add_test(tst_jobfilter testPrintersJobFilter)
4547
46add_executable(testPrintersSignalHandler tst_signalhandler.cpp ${MOCK_SOURCES})48add_executable(testPrintersSignalRateLimiter tst_signalratelimiter.cpp ${MOCK_SOURCES})
47target_link_libraries(testPrintersSignalHandler UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)49target_link_libraries(testPrintersSignalRateLimiter UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)
48add_test(tst_signalhandler testPrintersSignalHandler)50add_test(tst_signalratelimiter testPrintersSignalRateLimiter)
51
52add_executable(testPrintersDevice tst_printerdevice.cpp ${MOCK_SOURCES})
53target_link_libraries(testPrintersDevice UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)
54add_test(tst_printerdevice testPrintersDevice)
55
56add_executable(testPrintersDeviceModel tst_printerdevicemodel.cpp ${MOCK_SOURCES})
57target_link_libraries(testPrintersDeviceModel UbuntuComponentsExtrasPrintersQml Qt5::Test Qt5::Gui)
58add_test(tst_printerdevicemodel testPrintersDeviceModel)
4959
=== modified file 'tests/unittests/Printers/mockbackend.h'
--- tests/unittests/Printers/mockbackend.h 2017-02-24 12:20:07 +0000
+++ tests/unittests/Printers/mockbackend.h 2017-03-23 12:51:36 +0000
@@ -40,7 +40,7 @@
4040
41 virtual bool holdsDefinition() const override41 virtual bool holdsDefinition() const override
42 {42 {
43 return true;43 return m_holdsDefinition;
44 }44 }
4545
46 virtual QString printerAdd(const QString &name,46 virtual QString printerAdd(const QString &name,
@@ -105,6 +105,19 @@
105 return returnValue;105 return returnValue;
106 }106 }
107107
108 virtual QString printerSetCopies(const QString &name, const int &copies)
109 {
110 printerOptions[name].insert("Copies", copies);
111 return returnValue;
112 }
113
114 virtual QString printerSetShared(const QString &name,
115 const bool shared) override
116 {
117 printerOptions[name].insert("Shared", shared);
118 return returnValue;
119 }
120
108 virtual QString printerSetInfo(const QString &name,121 virtual QString printerSetInfo(const QString &name,
109 const QString &info) override122 const QString &info) override
110 {123 {
@@ -163,6 +176,32 @@
163 }176 }
164 }177 }
165178
179 virtual void holdJob(const QString &printerName, const int jobId) override
180 {
181 // Change the faked job state
182 Q_FOREACH(auto job, m_jobs) {
183 if (job->printerName() == printerName
184 && job->jobId() == jobId) {
185 job->setState(PrinterEnum::JobState::Held);
186 }
187 }
188
189 Q_EMIT jobState("", "", printerName, 1, "", true, jobId, static_cast<uint>(PrinterEnum::JobState::Held), "", "", 1);
190 }
191
192 virtual void releaseJob(const QString &printerName, const int jobId) override
193 {
194 // Change the faked job state
195 Q_FOREACH(auto job, m_jobs) {
196 if (job->printerName() == printerName
197 && job->jobId() == jobId) {
198 job->setState(PrinterEnum::JobState::Pending);
199 }
200 }
201
202 Q_EMIT jobState("", "", printerName, 1, "", true, jobId, static_cast<uint>(PrinterEnum::JobState::Pending), "", "", 1);
203 }
204
166 virtual int printFileToDest(const QString &filepath,205 virtual int printFileToDest(const QString &filepath,
167 const QString &title,206 const QString &title,
168 const cups_dest_t *dest) override207 const cups_dest_t *dest) override
@@ -184,9 +223,39 @@
184 virtual QMap<QString, QVariant> printerGetJobAttributes(223 virtual QMap<QString, QVariant> printerGetJobAttributes(
185 const QString &name, const int jobId) override224 const QString &name, const int jobId) override
186 {225 {
187 Q_UNUSED(name);226 QMap<QString, QVariant> attributes;
188 Q_UNUSED(jobId);227
189 return QMap<QString, QVariant>();228 Q_FOREACH(auto job, m_jobs) {
229 if (job->printerName() == name
230 && job->jobId() == jobId) {
231 // Emulate reverse of PrinterJob::loadAttributes
232 // using local jobs defined in tests
233 attributes.insert("Collate", job->collate());
234 attributes.insert("copies", job->copies());
235 attributes.insert("ColorModel", job->getColorModel().name);
236 attributes.insert("CompletedTime", job->completedTime());
237 attributes.insert("CreationTime", job->creationTime());
238 attributes.insert("Duplex", Utils::duplexModeToPpdChoice(job->getDuplexMode()));
239 attributes.insert("impressionsCompleted", job->impressionsCompleted());
240 attributes.insert("landscape", job->landscape());
241 attributes.insert("messages", job->messages());
242 if (job->printRangeMode() == PrinterEnum::PrintRange::AllPages) {
243 attributes.insert("page-ranges", QStringList());
244 } else {
245 attributes.insert("page-ranges", job->printRange().split(QLocale::system().groupSeparator()));
246 }
247 attributes.insert("ProcessingTime", job->processingTime());
248 attributes.insert("Quality", job->getPrintQuality().name);
249 attributes.insert("OutputOrder", job->reverse() ? "Reverse" : "Normal");
250 attributes.insert("State", static_cast<int>(job->state()));
251 attributes.insert("Size", job->size());
252 attributes.insert("User", job->user());
253
254 break;
255 }
256 }
257
258 return attributes;
190 }259 }
191260
192 virtual QString printerName() const override261 virtual QString printerName() const override
@@ -209,6 +278,11 @@
209 return m_makeAndModel;278 return m_makeAndModel;
210 }279 }
211280
281 virtual bool isRemote() const override
282 {
283 return m_remote;
284 }
285
212 virtual PrinterEnum::State state() const override286 virtual PrinterEnum::State state() const override
213 {287 {
214 return m_state;288 return m_state;
@@ -287,6 +361,17 @@
287 m_requestedPrinters << printerName;361 m_requestedPrinters << printerName;
288 }362 }
289363
364 virtual void requestJobExtendedAttributes(QSharedPointer<Printer> printer, QSharedPointer<PrinterJob> job) override
365 {
366 QMap<QString, QVariant> attributes = printerGetJobAttributes(printer->name(), job->jobId());
367
368 Q_EMIT jobLoaded(printer->name(), job->jobId(), attributes);
369 }
370
371 virtual PrinterEnum::PrinterType type() const override
372 {
373 return m_type;
374 }
290375
291 void mockPrinterAdded(376 void mockPrinterAdded(
292 const QString &text,377 const QString &text,
@@ -339,6 +424,34 @@
339 );424 );
340 }425 }
341426
427 void mockJobCompleted(
428 const QString &text, const QString &printer_uri,
429 const QString &printer_name, uint printer_state,
430 const QString &printer_state_reasons, bool printer_is_accepting_jobs,
431 uint job_id, uint job_state, const QString &job_state_reasons,
432 const QString &job_name, uint job_impressions_completed)
433 {
434 Q_EMIT jobCompleted(
435 text, printer_uri, printer_name, printer_state,
436 printer_state_reasons, printer_is_accepting_jobs, job_id,
437 job_state, job_state_reasons, job_name, job_impressions_completed
438 );
439 }
440
441 void mockJobState(
442 const QString &text, const QString &printer_uri,
443 const QString &printer_name, uint printer_state,
444 const QString &printer_state_reasons, bool printer_is_accepting_jobs,
445 uint job_id, uint job_state, const QString &job_state_reasons,
446 const QString &job_name, uint job_impressions_completed)
447 {
448 Q_EMIT jobState(
449 text, printer_uri, printer_name, printer_state,
450 printer_state_reasons, printer_is_accepting_jobs, job_id,
451 job_state, job_state_reasons, job_name, job_impressions_completed
452 );
453 }
454
342 void mockDriversLoaded(const QList<PrinterDriver> &drivers)455 void mockDriversLoaded(const QList<PrinterDriver> &drivers)
343 {456 {
344 Q_EMIT printerDriversLoaded(drivers);457 Q_EMIT printerDriversLoaded(drivers);
@@ -354,6 +467,11 @@
354 Q_EMIT printerLoaded(printer);467 Q_EMIT printerLoaded(printer);
355 }468 }
356469
470 void mockDeviceFound(const Device &device)
471 {
472 Q_EMIT deviceFound(device);
473 }
474
357 QString returnValue = QString::null;475 QString returnValue = QString::null;
358476
359 // Map from printer to key/val.477 // Map from printer to key/val.
@@ -366,6 +484,9 @@
366 QMap<QString, PrinterEnum::ErrorPolicy> errorPolicies;484 QMap<QString, PrinterEnum::ErrorPolicy> errorPolicies;
367 QMap<QString, PrinterEnum::OperationPolicy> operationPolicies;485 QMap<QString, PrinterEnum::OperationPolicy> operationPolicies;
368486
487 bool m_holdsDefinition = true;
488 bool m_remote = false;
489
369 QString m_description = QString::null;490 QString m_description = QString::null;
370 QString m_location = QString::null;491 QString m_location = QString::null;
371 QString m_makeAndModel = QString::null;492 QString m_makeAndModel = QString::null;
@@ -383,6 +504,8 @@
383 QList<QSharedPointer<PrinterJob>> m_jobs;504 QList<QSharedPointer<PrinterJob>> m_jobs;
384 QStringList m_requestedPrinters;505 QStringList m_requestedPrinters;
385506
507 PrinterEnum::PrinterType m_type = PrinterEnum::PrinterType::ProxyType;
508
386Q_SIGNALS:509Q_SIGNALS:
387 void printToFile(const QString &filepath, const QString &title);510 void printToFile(const QString &filepath, const QString &title);
388};511};
389512
=== added directory 'tests/unittests/Printers/testdata'
=== added directory 'tests/unittests/Printers/testdata/cups'
=== added directory 'tests/unittests/Printers/testdata/cups/data'
=== added file 'tests/unittests/Printers/testdata/cups/data/default-testpage.pdf'
=== modified file 'tests/unittests/Printers/tst_jobfilter.cpp'
--- tests/unittests/Printers/tst_jobfilter.cpp 2017-02-21 10:46:29 +0000
+++ tests/unittests/Printers/tst_jobfilter.cpp 2017-03-23 12:51:36 +0000
@@ -32,10 +32,12 @@
32 QScopedPointer<MockPrinterBackend> backend(new MockPrinterBackend);32 QScopedPointer<MockPrinterBackend> backend(new MockPrinterBackend);
33 JobModel model(backend.data());33 JobModel model(backend.data());
3434
35 auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend.data()));35 auto job = QSharedPointer<PrinterJob>(
36 new PrinterJob("test-printer", backend.data(), 100)
37 );
36 backend->m_jobs << job;38 backend->m_jobs << job;
37 // Trigger update.39 // Trigger update.
38 backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);40 backend->mockJobCreated("", "", "test-printer", 1, "", true, 100, 3, "", "", 1);
3941
40 JobFilter filter;42 JobFilter filter;
41 filter.setSourceModel(&model);43 filter.setSourceModel(&model);
4244
=== modified file 'tests/unittests/Printers/tst_jobmodel.cpp'
--- tests/unittests/Printers/tst_jobmodel.cpp 2017-02-21 10:46:29 +0000
+++ tests/unittests/Printers/tst_jobmodel.cpp 2017-03-23 12:51:36 +0000
@@ -18,12 +18,14 @@
1818
19#include "backend/backend.h"19#include "backend/backend.h"
20#include "models/jobmodel.h"20#include "models/jobmodel.h"
21#include "printers/printers.h"
2122
22#include <QDebug>23#include <QDebug>
23#include <QObject>24#include <QObject>
24#include <QSignalSpy>25#include <QSignalSpy>
25#include <QTest>26#include <QTest>
2627
28
27class TestJobModel : public QObject29class TestJobModel : public QObject
28{30{
29 Q_OBJECT31 Q_OBJECT
@@ -31,15 +33,23 @@
31 void init()33 void init()
32 {34 {
33 m_backend = new MockPrinterBackend;35 m_backend = new MockPrinterBackend;
34 m_model = new JobModel(m_backend);36 m_printers = new Printers(m_backend);
37
38 m_model = static_cast<JobModel *>(m_printers->printJobs());
39
40 PrinterBackend* backend = new MockPrinterBackend("test-printer");
41 auto printer = QSharedPointer<Printer>(new Printer(backend));
42 m_backend->mockPrinterLoaded(printer);
35 }43 }
36 void cleanup()44 void cleanup()
37 {45 {
38 QSignalSpy destroyedSpy(m_model, SIGNAL(destroyed(QObject*)));46 QSignalSpy destroyedSpy(m_printers, SIGNAL(destroyed(QObject*)));
39 m_model->deleteLater();47 m_printers->deleteLater();
40 QTRY_COMPARE(destroyedSpy.count(), 1);48 QTRY_COMPARE(destroyedSpy.count(), 1);
41 delete m_backend;
42 }49 }
50
51 // Tests for adding/removing/changing things in the model
52
43 void testInsert()53 void testInsert()
44 {54 {
45 QSignalSpy countSpy(m_model, SIGNAL(countChanged()));55 QSignalSpy countSpy(m_model, SIGNAL(countChanged()));
@@ -68,7 +78,7 @@
68 catchall handler in the model. */78 catchall handler in the model. */
69 QSignalSpy removeSpy(m_model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));79 QSignalSpy removeSpy(m_model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));
70 m_backend->m_jobs.clear();80 m_backend->m_jobs.clear();
71 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);81 m_backend->mockJobCompleted("", "", "", 1, "", true, 100, 1, "", "", 1);
72 QCOMPARE(removeSpy.count(), 1);82 QCOMPARE(removeSpy.count(), 1);
7383
74 // Check item was removed84 // Check item was removed
@@ -76,44 +86,451 @@
76 QCOMPARE(args.at(1).toInt(), 0);86 QCOMPARE(args.at(1).toInt(), 0);
77 QCOMPARE(args.at(2).toInt(), 0);87 QCOMPARE(args.at(2).toInt(), 0);
78 }88 }
79 void testMove()
80 {
81 // Add two jobs.
82 auto job1 = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
83 auto job2 = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
84 m_backend->m_jobs << job1 << job2;
85 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
86
87 m_backend->m_jobs.move(0, 1);
88 // Triggers a move.
89 QSignalSpy moveSpy(m_model, SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)));
90 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
91 QCOMPARE(moveSpy.count(), 1);
92 QList<QVariant> args = moveSpy.at(0);
93 QCOMPARE(args.at(1).toInt(), 1);
94 QCOMPARE(args.at(2).toInt(), 1);
95 QCOMPARE(args.at(4).toInt(), 0);
96 }
97 void testModify()89 void testModify()
98 {90 {
99 auto jobBefore = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));91 auto jobBefore = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
92 int impressions_count = 1;
10093
101 m_backend->m_jobs << jobBefore;94 m_backend->m_jobs << jobBefore;
102 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);95 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", impressions_count);
103
104 auto jobAfter = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
105 jobAfter->setCopies(100);
106 m_backend->m_jobs.replace(0, jobAfter);
10796
108 // Triggers a change.97 // Triggers a change.
109 QSignalSpy changedSpy(m_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));98 QSignalSpy changedSpy(m_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
110 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);99
100 impressions_count = 5;
101 m_backend->mockJobState("", "", "", 1, "", true, 100, 1, "", "", impressions_count);
102
111 QCOMPARE(changedSpy.count(), 1);103 QCOMPARE(changedSpy.count(), 1);
112 }104 }
113105
106 // Tests for the roles in the model exposed to QML
107
108 void testIdRole()
109 {
110 auto job = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 100));
111 m_backend->m_jobs << job;
112 m_backend->mockJobCreated("", "", "", 1, "", true, 100, 1, "", "", 1);
113
114 QTRY_COMPARE(m_model->count(), 1);
115 QCOMPARE(job->jobId(), 100);
116 QCOMPARE(m_model->data(m_model->index(0), JobModel::IdRole).toInt(), 100);
117 }
118 void testCollateRole()
119 {
120 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
121 jobA->setCollate(false);
122
123 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
124 jobB->setCollate(true);
125
126 m_backend->m_jobs << jobA << jobB;
127 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
128 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
129
130 QTRY_COMPARE(m_model->count(), 2);
131
132 QCOMPARE(m_model->data(m_model->index(0), JobModel::CollateRole).toBool(), false);
133 QCOMPARE(m_model->data(m_model->index(1), JobModel::CollateRole).toBool(), true);
134 }
135 void testColorModelRole()
136 {
137 // FIXME: read comment in JobModel::updateJob
138 QSKIP("We are ignoring colorModel for now as it requires a loaded Printer for the PrinterJob.");
139
140 ColorModel a;
141 a.name = "KGray";
142 a.text = "Gray";
143
144 ColorModel b;
145 b.name = "RGB";
146 b.text = "";
147 QList<ColorModel> models({a, b});
148
149 PrinterBackend* backend = new MockPrinterBackend("a-printer");
150 ((MockPrinterBackend*) backend)->printerOptions["a-printer"].insert(
151 "SupportedColorModels", QVariant::fromValue(models)
152 );
153
154 auto printer = QSharedPointer<Printer>(new Printer(backend));
155 m_backend->mockPrinterLoaded(printer);
156// m_printers->m_printers << printer;
157
158 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 1));
159 jobA->setPrinter(printer);
160 jobA->loadDefaults();
161 jobA->setColorModel(models.indexOf(a));
162
163 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("a-printer", backend, 2));
164 jobB->setPrinter(printer);
165 jobB->loadDefaults();
166 jobB->setColorModel(models.indexOf(b));
167
168 m_backend->m_jobs << jobA << jobB;
169 m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 1, 1, "", "", 1);
170 m_backend->mockJobCreated("", "", "a-printer", 1, "", true, 2, 1, "", "", 1);
171
172 QTRY_COMPARE(m_model->count(), 2);
173 QCOMPARE(m_model->data(m_model->index(0), JobModel::ColorModelRole).toString(),
174 a.text);
175 QCOMPARE(m_model->data(m_model->index(1), JobModel::ColorModelRole).toString(),
176 b.name);
177 }
178 void testCompletedTimeRole()
179 {
180 QDateTime dateTimeA = QDateTime::currentDateTime();
181 QDateTime dateTimeB = QDateTime::currentDateTime().addSecs(100);
182
183 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
184 jobA->setCompletedTime(dateTimeA);
185
186 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
187 jobB->setCompletedTime(dateTimeB);
188
189 m_backend->m_jobs << jobA << jobB;
190 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
191 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
192
193 QTRY_COMPARE(m_model->count(), 2);
194 QCOMPARE(m_model->data(m_model->index(0), JobModel::CompletedTimeRole).toDateTime(),
195 dateTimeA);
196 QCOMPARE(m_model->data(m_model->index(1), JobModel::CompletedTimeRole).toDateTime(),
197 dateTimeB);
198 }
199 void testCopiesRole()
200 {
201 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
202 jobA->setCopies(2);
203
204 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
205 jobB->setCopies(5);
206
207 m_backend->m_jobs << jobA << jobB;
208 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
209 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
210
211 QTRY_COMPARE(m_model->count(), 2);
212 QCOMPARE(m_model->data(m_model->index(0), JobModel::CopiesRole).toInt(), 2);
213 QCOMPARE(m_model->data(m_model->index(1), JobModel::CopiesRole).toInt(), 5);
214 }
215 void testCreationTimeRole()
216 {
217 QDateTime dateTimeA = QDateTime::currentDateTime();
218 QDateTime dateTimeB = QDateTime::currentDateTime().addSecs(100);
219
220 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
221 jobA->setCreationTime(dateTimeA);
222
223 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
224 jobB->setCreationTime(dateTimeB);
225
226 m_backend->m_jobs << jobA << jobB;
227 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
228 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
229
230 QTRY_COMPARE(m_model->count(), 2);
231 QCOMPARE(m_model->data(m_model->index(0), JobModel::CreationTimeRole).toDateTime(),
232 dateTimeA);
233 QCOMPARE(m_model->data(m_model->index(1), JobModel::CreationTimeRole).toDateTime(),
234 dateTimeB);
235 }
236 void testDuplexRole()
237 {
238 // FIXME: read comment in JobModel::updateJob
239 QSKIP("We are ignoring duplex for now as it requires a loaded Printer for the PrinterJob.");
240
241 QList<PrinterEnum::DuplexMode> modes({
242 PrinterEnum::DuplexMode::DuplexNone,
243 PrinterEnum::DuplexMode::DuplexLongSide,
244 PrinterEnum::DuplexMode::DuplexShortSide,
245 });
246
247 ((MockPrinterBackend*) m_backend)->m_supportedDuplexModes = modes;
248
249 PrinterBackend* backend = new MockPrinterBackend("test-printer");
250 ((MockPrinterBackend*) backend)->m_supportedDuplexModes = modes;
251
252 auto printer = QSharedPointer<Printer>(new Printer(backend));
253 m_backend->mockPrinterLoaded(printer);
254
255 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 1));
256 jobA->setPrinter(printer);
257 jobA->setDuplexMode(modes.indexOf(PrinterEnum::DuplexMode::DuplexLongSide));
258
259 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", backend, 2));
260 jobB->setPrinter(printer);
261 jobB->setDuplexMode(modes.indexOf(PrinterEnum::DuplexMode::DuplexNone));
262
263 m_backend->m_jobs << jobA << jobB;
264 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", 1);
265 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", 1);
266
267 QTRY_COMPARE(m_model->count(), 2);
268 QCOMPARE(m_model->data(m_model->index(0), JobModel::DuplexRole).toString(),
269 Utils::duplexModeToUIString(PrinterEnum::DuplexMode::DuplexLongSide));
270 QCOMPARE(m_model->data(m_model->index(1), JobModel::DuplexRole).toString(),
271 Utils::duplexModeToUIString(PrinterEnum::DuplexMode::DuplexNone));
272 }
273 void testHeldRole()
274 {
275 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
276 jobA->setState(PrinterEnum::JobState::Pending);
277
278 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
279 jobB->setState(PrinterEnum::JobState::Held);
280
281 m_backend->m_jobs << jobA << jobB;
282 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, static_cast<uint>(jobA->state()), "", "", 1);
283 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, static_cast<uint>(jobB->state()), "", "", 1);
284
285 QTRY_COMPARE(m_model->count(), 2);
286 QCOMPARE(m_model->data(m_model->index(0), JobModel::HeldRole).toBool(), false);
287 QCOMPARE(m_model->data(m_model->index(1), JobModel::HeldRole).toBool(), true);
288 }
289 void testImpressionsCompletedRole()
290 {
291 auto jobA = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 1));
292 jobA->setImpressionsCompleted(2);
293
294 auto jobB = QSharedPointer<PrinterJob>(new PrinterJob("test-printer", m_backend, 2));
295 jobB->setImpressionsCompleted(5);
296
297 m_backend->m_jobs << jobA << jobB;
298 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 1, 1, "", "", jobA->impressionsCompleted());
299 m_backend->mockJobCreated("", "", "test-printer", 1, "", true, 2, 1, "", "", jobB->impressionsCompleted());
300
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: