Merge lp:~jonas-drange/ubuntu-settings-components/printer-add into lp:~phablet-team/ubuntu-settings-components/printer-components
- printer-add
- Merge into printer-components
Proposed by
Jonas G. Drange
Status: | Merged |
---|---|
Merged at revision: | 221 |
Proposed branch: | lp:~jonas-drange/ubuntu-settings-components/printer-add |
Merge into: | lp:~phablet-team/ubuntu-settings-components/printer-components |
Diff against target: |
1814 lines (+1229/-73) 21 files modified
examples/Printers.qml (+268/-3) plugins/Ubuntu/Settings/Printers/CMakeLists.txt (+3/-0) plugins/Ubuntu/Settings/Printers/backend/backend.cpp (+7/-3) plugins/Ubuntu/Settings/Printers/backend/backend.h (+11/-3) plugins/Ubuntu/Settings/Printers/backend/backend_cups.cpp (+15/-8) plugins/Ubuntu/Settings/Printers/backend/backend_cups.h (+4/-3) plugins/Ubuntu/Settings/Printers/cups/cupsfacade.cpp (+150/-14) plugins/Ubuntu/Settings/Printers/cups/cupsfacade.h (+54/-4) plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.cpp (+153/-0) plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.h (+31/-6) plugins/Ubuntu/Settings/Printers/models/drivermodel.cpp (+181/-0) plugins/Ubuntu/Settings/Printers/models/drivermodel.h (+83/-0) plugins/Ubuntu/Settings/Printers/plugin.cpp (+4/-1) plugins/Ubuntu/Settings/Printers/printer/printerjob.cpp (+1/-0) plugins/Ubuntu/Settings/Printers/printers/printers.cpp (+57/-15) plugins/Ubuntu/Settings/Printers/printers/printers.h (+23/-10) plugins/Ubuntu/Settings/Printers/structs.h (+18/-0) tests/unittests/Printers/CMakeLists.txt (+4/-0) tests/unittests/Printers/mockbackend.h (+17/-3) tests/unittests/Printers/tst_drivermodel.cpp (+136/-0) tests/unittests/Printers/tst_printers.cpp (+9/-0) |
To merge this branch: | bzr merge lp:~jonas-drange/ubuntu-settings-components/printer-add |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Hayzen (community) | Approve | ||
Review via email:
|
Commit message
* allows creation of printers in example qml, and by extension the API
* create printers by either providing a PPD file, or select a PPD from the database
* adds a DriverModel that holds printer drivers, which can be filtered
* adds testing of DriverModel
Description of the change
To post a comment you must log in.
- 227. By Jonas G. Drange
-
hides filter if providing PPD
- 228. By Jonas G. Drange
-
renames var to haystack, to fit with the narrative
- 229. By Jonas G. Drange
-
removes arbitrary size constraint on filter
- 230. By Jonas G. Drange
-
connects filterComplete to driversFilterCh
anged
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'examples/Printers.qml' |
2 | --- examples/Printers.qml 2017-01-22 18:34:20 +0000 |
3 | +++ examples/Printers.qml 2017-01-30 11:37:26 +0000 |
4 | @@ -35,8 +35,8 @@ |
5 | visible: false |
6 | property var printer |
7 | header: PageHeader { |
8 | - title: printer.name |
9 | - flickable: printerFlickable |
10 | + title: printer.name |
11 | + flickable: printerFlickable |
12 | } |
13 | |
14 | Flickable { |
15 | @@ -153,6 +153,15 @@ |
16 | header: PageHeader { |
17 | title: "Printers" |
18 | flickable: printerList |
19 | + trailingActionBar { |
20 | + actions: [ |
21 | + Action { |
22 | + iconName: "add" |
23 | + text: "Add printer" |
24 | + onTriggered: pageStack.push(addPrinterPageComponent) |
25 | + } |
26 | + ] |
27 | + } |
28 | } |
29 | visible: false |
30 | |
31 | @@ -179,7 +188,263 @@ |
32 | ProgressionSlot {} |
33 | } |
34 | onClicked: pageStack.push(printerPage, { printer: model }) |
35 | - Component.onCompleted: console.log("printer", model.name) |
36 | + } |
37 | + } |
38 | + } |
39 | + } |
40 | + |
41 | + Component { |
42 | + id: addPrinterPageComponent |
43 | + Page { |
44 | + id: addPrinterPage |
45 | + states: [ |
46 | + State { |
47 | + name: "success" |
48 | + PropertyChanges { |
49 | + target: okAction |
50 | + enabled: false |
51 | + } |
52 | + PropertyChanges { |
53 | + target: closeAction |
54 | + enabled: false |
55 | + } |
56 | + PropertyChanges { |
57 | + target: addPrinterCol |
58 | + enabled: false |
59 | + } |
60 | + StateChangeScript { |
61 | + script: okTimer.start() |
62 | + } |
63 | + }, |
64 | + State { |
65 | + name: "failure" |
66 | + PropertyChanges { |
67 | + target: errorMessageContainer |
68 | + visible: true |
69 | + } |
70 | + } |
71 | + ] |
72 | + header: PageHeader { |
73 | + title: "Add printer" |
74 | + flickable: addPrinterFlickable |
75 | + leadingActionBar.actions: [ |
76 | + Action { |
77 | + id: closeAction |
78 | + iconName: "close" |
79 | + text: "Abort" |
80 | + onTriggered: pageStack.pop() |
81 | + } |
82 | + ] |
83 | + trailingActionBar { |
84 | + actions: [ |
85 | + Action { |
86 | + id: okAction |
87 | + iconName: "ok" |
88 | + text: "Complete" |
89 | + onTriggered: { |
90 | + var ret; |
91 | + if (driverSelector.selectedIndex == 0) { |
92 | + ret = Printers.addPrinter( |
93 | + printerName.text, |
94 | + driversView.selectedDriver, |
95 | + printerUri.text, |
96 | + printerDescription.text, |
97 | + printerLocation.text |
98 | + ); |
99 | + } else { |
100 | + ret = Printers.addPrinterWithPpdFile( |
101 | + printerName.text, |
102 | + printerPpd.text, |
103 | + printerUri.text, |
104 | + printerDescription.text, |
105 | + printerLocation.text |
106 | + ); |
107 | + } |
108 | + if (ret) { |
109 | + addPrinterPage.state = "success" |
110 | + } else { |
111 | + errorMessage.text = Printers.lastMessage; |
112 | + addPrinterPage.state = "failure" |
113 | + } |
114 | + } |
115 | + } |
116 | + ] |
117 | + } |
118 | + } |
119 | + |
120 | + Component.onCompleted: { |
121 | + Printers.prepareToAddPrinter(); |
122 | + } |
123 | + |
124 | + Timer { |
125 | + id: okTimer |
126 | + interval: 2000 |
127 | + onTriggered: pageStack.pop(); |
128 | + } |
129 | + |
130 | + Flickable { |
131 | + id: addPrinterFlickable |
132 | + anchors.fill: parent |
133 | + |
134 | + Column { |
135 | + id: addPrinterCol |
136 | + property bool enabled: true |
137 | + anchors { |
138 | + left: parent.left |
139 | + right: parent.right |
140 | + } |
141 | + |
142 | + Item { |
143 | + id: errorMessageContainer |
144 | + visible: false |
145 | + anchors { |
146 | + left: parent.left |
147 | + right: parent.right |
148 | + margins: units.gu(2) |
149 | + } |
150 | + height: units.gu(6) |
151 | + Label { |
152 | + id: errorMessage |
153 | + anchors { |
154 | + top: parent.top |
155 | + topMargin: units.gu(2) |
156 | + horizontalCenter: parent.horizontalCenter |
157 | + } |
158 | + } |
159 | + |
160 | + } |
161 | + |
162 | + ListItems.Standard { |
163 | + text: "Device URI" |
164 | + control: TextField { |
165 | + id: printerUri |
166 | + placeholderText: "ipp://server.local/my-queue" |
167 | + } |
168 | + enabled: parent.enabled |
169 | + } |
170 | + |
171 | + ListItems.ValueSelector { |
172 | + id: driverSelector |
173 | + anchors { |
174 | + left: parent.left |
175 | + right: parent.right |
176 | + } |
177 | + text: "Choose driver" |
178 | + values: [ |
179 | + "Select printer from database", |
180 | + "Provide PPD file" |
181 | + ] |
182 | + enabled: parent.enabled |
183 | + } |
184 | + |
185 | + ListItems.Standard { |
186 | + anchors { |
187 | + left: parent.left |
188 | + right: parent.right |
189 | + } |
190 | + text: "Filter drivers" |
191 | + control: TextField { |
192 | + id: driverFilter |
193 | + onTextChanged: Printers.driverFilter = text |
194 | + } |
195 | + visible: driverSelector.selectedIndex == 0 |
196 | + enabled: parent.enabled |
197 | + } |
198 | + |
199 | + ListView { |
200 | + id: driversView |
201 | + property string selectedDriver |
202 | + property bool loading: true |
203 | + visible: driverSelector.selectedIndex == 0 |
204 | + model: Printers.drivers |
205 | + anchors { left: parent.left; right: parent.right } |
206 | + height: units.gu(30) |
207 | + clip: true |
208 | + enabled: parent.enabled |
209 | + highlightFollowsCurrentItem: false |
210 | + highlight: Rectangle { |
211 | + z: 0 |
212 | + y: driversView.currentItem.y |
213 | + width: driversView.currentItem.width |
214 | + height: driversView.currentItem.height |
215 | + color: theme.palette.selected.background |
216 | + } |
217 | + delegate: ListItem { |
218 | + height: driverLayout.height + (divider.visible ? divider.height : 0) |
219 | + ListItemLayout { |
220 | + id: driverLayout |
221 | + title.text: displayName |
222 | + subtitle.text: name |
223 | + summary.text: deviceId |
224 | + } |
225 | + onClicked: { |
226 | + driversView.selectedDriver = name |
227 | + driversView.currentIndex = index |
228 | + } |
229 | + } |
230 | + |
231 | + ActivityIndicator { |
232 | + anchors.centerIn: parent |
233 | + running: parent.loading |
234 | + } |
235 | + |
236 | + Connections { |
237 | + target: driversView |
238 | + onCountChanged: { |
239 | + target = null; |
240 | + driversView.loading = false; |
241 | + } |
242 | + } |
243 | + } |
244 | + |
245 | + ListItems.Standard { |
246 | + text: "PPD File" |
247 | + visible: driverSelector.selectedIndex == 1 |
248 | + control: TextField { |
249 | + id: printerPpd |
250 | + placeholderText: "/usr/share/cups/foo.ppd" |
251 | + } |
252 | + enabled: parent.enabled |
253 | + } |
254 | + |
255 | + ListItems.Standard { |
256 | + anchors { |
257 | + left: parent.left |
258 | + right: parent.right |
259 | + } |
260 | + text: "Printer name" |
261 | + control: TextField { |
262 | + id: printerName |
263 | + placeholderText: "laserjet" |
264 | + } |
265 | + enabled: parent.enabled |
266 | + } |
267 | + |
268 | + ListItems.Standard { |
269 | + anchors { |
270 | + left: parent.left |
271 | + right: parent.right |
272 | + } |
273 | + text: "Description (optional)" |
274 | + control: TextField { |
275 | + id: printerDescription |
276 | + placeholderText: "HP Laserjet with Duplexer" |
277 | + } |
278 | + enabled: parent.enabled |
279 | + } |
280 | + |
281 | + ListItems.Standard { |
282 | + anchors { |
283 | + left: parent.left |
284 | + right: parent.right |
285 | + } |
286 | + text: "Location (optional)" |
287 | + control: TextField { |
288 | + id: printerLocation |
289 | + placeholderText: "Lab 1" |
290 | + } |
291 | + enabled: parent.enabled |
292 | + } |
293 | } |
294 | } |
295 | } |
296 | |
297 | === modified file 'plugins/Ubuntu/Settings/Printers/CMakeLists.txt' |
298 | --- plugins/Ubuntu/Settings/Printers/CMakeLists.txt 2017-01-24 12:34:23 +0000 |
299 | +++ plugins/Ubuntu/Settings/Printers/CMakeLists.txt 2017-01-30 11:37:26 +0000 |
300 | @@ -7,6 +7,7 @@ |
301 | find_package(Qt5Gui REQUIRED) |
302 | find_package(Qt5PrintSupport REQUIRED) |
303 | find_package(Qt5Qml REQUIRED) |
304 | +find_package(Qt5Concurrent REQUIRED) |
305 | |
306 | add_library(UbuntuSettingsPrintersQml SHARED |
307 | backend/backend.cpp |
308 | @@ -16,6 +17,7 @@ |
309 | cups/cupspkhelper.cpp |
310 | enums.h |
311 | i18n.cpp |
312 | + models/drivermodel.cpp |
313 | models/printermodel.cpp |
314 | printer/printer.cpp |
315 | printer/printerjob.cpp |
316 | @@ -29,6 +31,7 @@ |
317 | Qt5::Gui |
318 | Qt5::PrintSupport |
319 | Qt5::Qml |
320 | + Qt5::Concurrent |
321 | ${CUPS_LIBRARIES} |
322 | ) |
323 | |
324 | |
325 | === modified file 'plugins/Ubuntu/Settings/Printers/backend/backend.cpp' |
326 | --- plugins/Ubuntu/Settings/Printers/backend/backend.cpp 2017-01-22 14:21:11 +0000 |
327 | +++ plugins/Ubuntu/Settings/Printers/backend/backend.cpp 2017-01-30 11:37:26 +0000 |
328 | @@ -37,8 +37,8 @@ |
329 | } |
330 | |
331 | QString PrinterBackend::printerAdd(const QString &name, |
332 | - const QUrl &uri, |
333 | - const QUrl &ppdFile, |
334 | + const QString &uri, |
335 | + const QString &ppdFile, |
336 | const QString &info, |
337 | const QString &location) |
338 | { |
339 | @@ -46,7 +46,7 @@ |
340 | } |
341 | |
342 | QString PrinterBackend::printerAddWithPpd(const QString &name, |
343 | - const QUrl &uri, |
344 | + const QString &uri, |
345 | const QString &ppdFileName, |
346 | const QString &info, |
347 | const QString &location) |
348 | @@ -281,6 +281,10 @@ |
349 | return QString(); |
350 | } |
351 | |
352 | +void PrinterBackend::requestAvailablePrinterDrivers() |
353 | +{ |
354 | +} |
355 | + |
356 | PrinterBackend::BackendType PrinterBackend::backendType() const |
357 | { |
358 | return BackendType::DefaultType; |
359 | |
360 | === modified file 'plugins/Ubuntu/Settings/Printers/backend/backend.h' |
361 | --- plugins/Ubuntu/Settings/Printers/backend/backend.h 2017-01-23 14:06:49 +0000 |
362 | +++ plugins/Ubuntu/Settings/Printers/backend/backend.h 2017-01-30 11:37:26 +0000 |
363 | @@ -50,13 +50,16 @@ |
364 | |
365 | virtual bool holdsDefinition() const; |
366 | |
367 | + // Add a printer using an already existing ppd. |
368 | virtual QString printerAdd(const QString &name, |
369 | - const QUrl &uri, |
370 | - const QUrl &ppdFile, |
371 | + const QString &uri, |
372 | + const QString &ppdFile, |
373 | const QString &info, |
374 | const QString &location); |
375 | + |
376 | + // Add a printer and provide a ppd file. |
377 | virtual QString printerAddWithPpd(const QString &name, |
378 | - const QUrl &uri, |
379 | + const QString &uri, |
380 | const QString &ppdFileName, |
381 | const QString &info, |
382 | const QString &location); |
383 | @@ -135,6 +138,8 @@ |
384 | virtual Printer* getPrinter(const QString &printerName); |
385 | virtual QString defaultPrinterName(); |
386 | |
387 | + virtual void requestAvailablePrinterDrivers(); |
388 | + |
389 | virtual BackendType backendType() const; |
390 | |
391 | public Q_SLOTS: |
392 | @@ -146,6 +151,9 @@ |
393 | void printerDeleted(const QString &name); |
394 | void printerStateChanged(const QString &name); |
395 | |
396 | + void printerDriversLoaded(const QList<PrinterDriver> &drivers); |
397 | + void printerDriversFailedToLoad(const QString &errorMessage); |
398 | + |
399 | protected: |
400 | const QString m_printerName; |
401 | }; |
402 | |
403 | === modified file 'plugins/Ubuntu/Settings/Printers/backend/backend_cups.cpp' |
404 | --- plugins/Ubuntu/Settings/Printers/backend/backend_cups.cpp 2017-01-24 12:42:52 +0000 |
405 | +++ plugins/Ubuntu/Settings/Printers/backend/backend_cups.cpp 2017-01-30 11:37:26 +0000 |
406 | @@ -19,14 +19,17 @@ |
407 | #include "i18n.h" |
408 | #include "utils.h" |
409 | |
410 | -#include <exception> |
411 | -#include <stdexcept> |
412 | |
413 | PrinterCupsBackend::PrinterCupsBackend(QObject *parent) |
414 | : PrinterCupsBackend(new CupsFacade(), QPrinterInfo(), parent) |
415 | { |
416 | // If we create the CupsFacade, we're in charge of RAII. |
417 | m_cups->setParent(this); |
418 | + |
419 | + connect(m_cups, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&)), |
420 | + this, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&))); |
421 | + connect(m_cups, SIGNAL(printerDriversFailedToLoad(const QString&)), |
422 | + this, SIGNAL(printerDriversFailedToLoad(const QString&))); |
423 | } |
424 | |
425 | PrinterCupsBackend::PrinterCupsBackend(CupsFacade *cups, QPrinterInfo info, |
426 | @@ -39,25 +42,24 @@ |
427 | |
428 | PrinterCupsBackend::~PrinterCupsBackend() |
429 | { |
430 | - |
431 | } |
432 | |
433 | QString PrinterCupsBackend::printerAdd(const QString &name, |
434 | - const QUrl &uri, |
435 | - const QUrl &ppdFile, |
436 | + const QString &uri, |
437 | + const QString &ppdFile, |
438 | const QString &info, |
439 | const QString &location) |
440 | { |
441 | - |
442 | + return m_cups->printerAdd(name, uri, ppdFile, info, location); |
443 | } |
444 | |
445 | QString PrinterCupsBackend::printerAddWithPpd(const QString &name, |
446 | - const QUrl &uri, |
447 | + const QString &uri, |
448 | const QString &ppdFileName, |
449 | const QString &info, |
450 | const QString &location) |
451 | { |
452 | - |
453 | + return m_cups->printerAddWithPpd(name, uri, ppdFileName, info, location); |
454 | } |
455 | |
456 | bool PrinterCupsBackend::holdsDefinition() const |
457 | @@ -312,6 +314,11 @@ |
458 | return QPrinterInfo::defaultPrinterName(); |
459 | } |
460 | |
461 | +void PrinterCupsBackend::requestAvailablePrinterDrivers() |
462 | +{ |
463 | + return m_cups->requestPrinterDrivers(); |
464 | +} |
465 | + |
466 | PrinterBackend::BackendType PrinterCupsBackend::backendType() const |
467 | { |
468 | return PrinterBackend::BackendType::CupsType; |
469 | |
470 | === modified file 'plugins/Ubuntu/Settings/Printers/backend/backend_cups.h' |
471 | --- plugins/Ubuntu/Settings/Printers/backend/backend_cups.h 2017-01-23 14:06:49 +0000 |
472 | +++ plugins/Ubuntu/Settings/Printers/backend/backend_cups.h 2017-01-30 11:37:26 +0000 |
473 | @@ -33,12 +33,12 @@ |
474 | virtual bool holdsDefinition() const override; |
475 | |
476 | virtual QString printerAdd(const QString &name, |
477 | - const QUrl &uri, |
478 | - const QUrl &ppdFile, |
479 | + const QString &uri, |
480 | + const QString &ppdFile, |
481 | const QString &info, |
482 | const QString &location) override; |
483 | virtual QString printerAddWithPpd(const QString &name, |
484 | - const QUrl &uri, |
485 | + const QString &uri, |
486 | const QString &ppdFileName, |
487 | const QString &info, |
488 | const QString &location) override; |
489 | @@ -116,6 +116,7 @@ |
490 | virtual QStringList availablePrinterNames() override; |
491 | virtual Printer* getPrinter(const QString &printerName) override; |
492 | virtual QString defaultPrinterName() override; |
493 | + virtual void requestAvailablePrinterDrivers() override; |
494 | |
495 | virtual PrinterBackend::BackendType backendType() const override; |
496 | |
497 | |
498 | === modified file 'plugins/Ubuntu/Settings/Printers/cups/cupsfacade.cpp' |
499 | --- plugins/Ubuntu/Settings/Printers/cups/cupsfacade.cpp 2017-01-25 15:37:42 +0000 |
500 | +++ plugins/Ubuntu/Settings/Printers/cups/cupsfacade.cpp 2017-01-30 11:37:26 +0000 |
501 | @@ -23,6 +23,7 @@ |
502 | #include <cups/ppd.h> |
503 | |
504 | #include <QDebug> |
505 | +#include <QThread> |
506 | |
507 | #define __CUPS_ADD_OPTION(dest, name, value) dest->num_options = \ |
508 | cupsAddOption(name, value, dest->num_options, &dest->options); |
509 | @@ -33,34 +34,30 @@ |
510 | |
511 | CupsFacade::~CupsFacade() |
512 | { |
513 | - |
514 | + cancelPrinterDriverRequest(); |
515 | } |
516 | |
517 | QString CupsFacade::printerAdd(const QString &name, |
518 | - const QUrl &uri, |
519 | - const QUrl &ppdFile, |
520 | + const QString &uri, |
521 | + const QString &ppdFile, |
522 | const QString &info, |
523 | const QString &location) |
524 | { |
525 | - Q_UNUSED(name); |
526 | - Q_UNUSED(uri); |
527 | - Q_UNUSED(ppdFile); |
528 | - Q_UNUSED(info); |
529 | - Q_UNUSED(location); |
530 | + if (!helper.printerAdd(name, uri, ppdFile, info, location)) { |
531 | + return helper.getLastError(); |
532 | + } |
533 | return QString(); |
534 | } |
535 | |
536 | QString CupsFacade::printerAddWithPpd(const QString &name, |
537 | - const QUrl &uri, |
538 | + const QString &uri, |
539 | const QString &ppdFileName, |
540 | const QString &info, |
541 | const QString &location) |
542 | { |
543 | - Q_UNUSED(name); |
544 | - Q_UNUSED(uri); |
545 | - Q_UNUSED(ppdFileName); |
546 | - Q_UNUSED(info); |
547 | - Q_UNUSED(location); |
548 | + if (!helper.printerAddWithPpdFile(name, uri, ppdFileName, info, location)) { |
549 | + return helper.getLastError(); |
550 | + } |
551 | return QString(); |
552 | } |
553 | |
554 | @@ -377,3 +374,142 @@ |
555 | dest->num_options, |
556 | dest->options); |
557 | } |
558 | + |
559 | +void CupsFacade::requestPrinterDrivers( |
560 | + const QString &deviceId, const QString &language, const QString &makeModel, |
561 | + const QString &product, const QStringList &includeSchemes, |
562 | + const QStringList &excludeSchemes |
563 | +) |
564 | +{ |
565 | + auto thread = new QThread; |
566 | + auto loader = new PrinterDriverLoader(deviceId, language, makeModel, |
567 | + product, includeSchemes, |
568 | + excludeSchemes); |
569 | + loader->moveToThread(thread); |
570 | + connect(loader, SIGNAL(error(const QString&)), |
571 | + this, SIGNAL(printerDriversFailedToLoad(const QString&))); |
572 | + connect(this, SIGNAL(requestPrinterDriverCancel()), loader, SLOT(cancel())); |
573 | + connect(thread, SIGNAL(started()), loader, SLOT(process())); |
574 | + connect(loader, SIGNAL(finished()), thread, SLOT(quit())); |
575 | + connect(loader, SIGNAL(finished()), loader, SLOT(deleteLater())); |
576 | + connect(loader, SIGNAL(loaded(const QList<PrinterDriver>&)), |
577 | + this, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&))); |
578 | + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); |
579 | + thread->start(); |
580 | + } |
581 | + |
582 | +void CupsFacade::cancelPrinterDriverRequest() |
583 | +{ |
584 | + Q_EMIT requestPrinterDriverCancel(); |
585 | +} |
586 | + |
587 | +PrinterDriverLoader::PrinterDriverLoader( |
588 | + const QString &deviceId, const QString &language, |
589 | + const QString &makeModel, const QString &product, |
590 | + const QStringList &includeSchemes, const QStringList &excludeSchemes) |
591 | + : m_deviceId(deviceId) |
592 | + , m_language(language) |
593 | + , m_makeModel(makeModel) |
594 | + , m_product(product) |
595 | + , m_includeSchemes(includeSchemes) |
596 | + , m_excludeSchemes(excludeSchemes) |
597 | +{ |
598 | +} |
599 | + |
600 | +PrinterDriverLoader::~PrinterDriverLoader() |
601 | +{ |
602 | +} |
603 | + |
604 | +void PrinterDriverLoader::process() |
605 | +{ |
606 | + m_running = true; |
607 | + |
608 | + ipp_t* response = helper.createPrinterDriversRequest( |
609 | + m_deviceId, m_language, m_makeModel, m_product, m_includeSchemes, |
610 | + m_excludeSchemes |
611 | + ); |
612 | + |
613 | + // Note: if the response somehow fails, we return. |
614 | + if (!response || ippGetStatusCode(response) > IPP_OK_CONFLICT) { |
615 | + QString err(cupsLastErrorString()); |
616 | + qWarning() << __PRETTY_FUNCTION__ << "Cups HTTP error:" << err; |
617 | + |
618 | + if (response) |
619 | + ippDelete(response); |
620 | + |
621 | + Q_EMIT error(err); |
622 | + Q_EMIT finished(); |
623 | + return; |
624 | + } |
625 | + |
626 | + ipp_attribute_t *attr; |
627 | + QByteArray ppdDeviceId; |
628 | + QByteArray ppdLanguage; |
629 | + QByteArray ppdMakeModel; |
630 | + QByteArray ppdName; |
631 | + |
632 | + // cups_option_t option; |
633 | + QList<PrinterDriver> drivers; |
634 | + |
635 | + for (attr = ippFirstAttribute(response); attr != NULL && m_running; attr = ippNextAttribute(response)) { |
636 | + |
637 | + while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_PRINTER) |
638 | + attr = ippNextAttribute(response); |
639 | + |
640 | + if (attr == NULL) |
641 | + break; |
642 | + |
643 | + // Pull the needed attributes from this PPD... |
644 | + ppdDeviceId = "NONE"; |
645 | + ppdLanguage.clear(); |
646 | + ppdMakeModel.clear(); |
647 | + ppdName.clear(); |
648 | + |
649 | + while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_PRINTER) { |
650 | + if (!strcmp(ippGetName(attr), "ppd-device-id") && |
651 | + ippGetValueTag(attr) == IPP_TAG_TEXT) { |
652 | + ppdDeviceId = ippGetString(attr, 0, NULL); |
653 | + } else if (!strcmp(ippGetName(attr), "ppd-natural-language") && |
654 | + ippGetValueTag(attr) == IPP_TAG_LANGUAGE) { |
655 | + ppdLanguage = ippGetString(attr, 0, NULL); |
656 | + |
657 | + } else if (!strcmp(ippGetName(attr), "ppd-make-and-model") && |
658 | + ippGetValueTag(attr) == IPP_TAG_TEXT) { |
659 | + ppdMakeModel = ippGetString(attr, 0, NULL); |
660 | + } else if (!strcmp(ippGetName(attr), "ppd-name") && |
661 | + ippGetValueTag(attr) == IPP_TAG_NAME) { |
662 | + |
663 | + ppdName = ippGetString(attr, 0, NULL); |
664 | + } |
665 | + |
666 | + attr = ippNextAttribute(response); |
667 | + } |
668 | + |
669 | + // See if we have everything needed... |
670 | + if (ppdLanguage.isEmpty() || ppdMakeModel.isEmpty() || |
671 | + ppdName.isEmpty()) { |
672 | + if (attr == NULL) |
673 | + break; |
674 | + else |
675 | + continue; |
676 | + } |
677 | + |
678 | + PrinterDriver m; |
679 | + m.name = ppdName; |
680 | + m.deviceId = ppdDeviceId; |
681 | + m.makeModel = ppdMakeModel; |
682 | + m.language = ppdLanguage; |
683 | + |
684 | + drivers.append(m); |
685 | + } |
686 | + |
687 | + ippDelete(response); |
688 | + |
689 | + Q_EMIT loaded(drivers); |
690 | + Q_EMIT finished(); |
691 | +} |
692 | + |
693 | +void PrinterDriverLoader::cancel() |
694 | +{ |
695 | + m_running = false; |
696 | +} |
697 | |
698 | === modified file 'plugins/Ubuntu/Settings/Printers/cups/cupsfacade.h' |
699 | --- plugins/Ubuntu/Settings/Printers/cups/cupsfacade.h 2017-01-22 14:21:11 +0000 |
700 | +++ plugins/Ubuntu/Settings/Printers/cups/cupsfacade.h 2017-01-30 11:37:26 +0000 |
701 | @@ -30,7 +30,6 @@ |
702 | #include <QObject> |
703 | #include <QString> |
704 | #include <QStringList> |
705 | -#include <QUrl> |
706 | #include <QVariant> |
707 | |
708 | class PrinterJob; |
709 | @@ -41,12 +40,12 @@ |
710 | explicit CupsFacade(QObject *parent = Q_NULLPTR); |
711 | ~CupsFacade(); |
712 | QString printerAdd(const QString &name, |
713 | - const QUrl &uri, |
714 | - const QUrl &ppdFile, |
715 | + const QString &uri, |
716 | + const QString &ppdFile, |
717 | const QString &info, |
718 | const QString &location); |
719 | QString printerAddWithPpd(const QString &name, |
720 | - const QUrl &uri, |
721 | + const QString &uri, |
722 | const QString &ppdFileName, |
723 | const QString &info, |
724 | const QString &location); |
725 | @@ -90,12 +89,28 @@ |
726 | QList<PrintQuality> printerGetSupportedQualities(const QString &name) const; |
727 | int printFileToDest(const QString &filepath, const QString &title, |
728 | const cups_dest_t *dest); |
729 | + |
730 | +public Q_SLOTS: |
731 | + void requestPrinterDrivers( |
732 | + const QString &deviceId = "", |
733 | + const QString &language = "", |
734 | + const QString &makeModel = "", |
735 | + const QString &product = "", |
736 | + const QStringList &includeSchemes = QStringList(), |
737 | + const QStringList &excludeSchemes = QStringList() |
738 | + ); |
739 | + void cancelPrinterDriverRequest(); |
740 | + |
741 | Q_SIGNALS: |
742 | void printerAdded(const QString &name); |
743 | void printerModified(const QString &name, const bool ppdChanged); |
744 | void printerDeleted(const QString &name); |
745 | void printerStateChanged(const QString &name); |
746 | |
747 | + void requestPrinterDriverCancel(); |
748 | + void printerDriversLoaded(const QList<PrinterDriver> &drivers); |
749 | + void printerDriversFailedToLoad(const QString &errorMessage); |
750 | + |
751 | private: |
752 | QString getPrinterName(const QString &name) const; |
753 | QString getPrinterInstance(const QString &name) const; |
754 | @@ -107,4 +122,39 @@ |
755 | CupsPkHelper helper; |
756 | }; |
757 | |
758 | +class PrinterDriverLoader : public QObject |
759 | +{ |
760 | + Q_OBJECT |
761 | +public: |
762 | + PrinterDriverLoader( |
763 | + const QString &deviceId = "", |
764 | + const QString &language = "", |
765 | + const QString &makeModel = "", |
766 | + const QString &product = "", |
767 | + const QStringList &includeSchemes = QStringList(), |
768 | + const QStringList &excludeSchemes = QStringList()); |
769 | + ~PrinterDriverLoader(); |
770 | + |
771 | +public Q_SLOTS: |
772 | + void process(); |
773 | + void cancel(); |
774 | + |
775 | +Q_SIGNALS: |
776 | + void finished(); |
777 | + void loaded(const QList<PrinterDriver> &drivers); |
778 | + void error(const QString &error); |
779 | + |
780 | +private: |
781 | + QString m_deviceId = QString::null; |
782 | + QString m_language = QString::null; |
783 | + QString m_makeModel = QString::null; |
784 | + QString m_product = QString::null; |
785 | + QStringList m_includeSchemes; |
786 | + QStringList m_excludeSchemes; |
787 | + |
788 | + bool m_running = false; |
789 | + CupsPkHelper helper; |
790 | +}; |
791 | + |
792 | + |
793 | #endif // USC_PRINTERS_CUPSFACADE_H |
794 | |
795 | === modified file 'plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.cpp' |
796 | --- plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.cpp 2017-01-17 15:14:25 +0000 |
797 | +++ plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.cpp 2017-01-30 11:37:26 +0000 |
798 | @@ -44,6 +44,127 @@ |
799 | httpClose(m_connection); |
800 | } |
801 | |
802 | +bool CupsPkHelper::printerAdd(const QString &printerName, |
803 | + const QString &printerUri, |
804 | + const QString &ppdFile, |
805 | + const QString &info, |
806 | + const QString &location) |
807 | +{ |
808 | + ipp_t *request; |
809 | + |
810 | + if (!isPrinterNameValid(printerName)) { |
811 | + setInternalStatus(QString("%1 is not a valid printer name.").arg(printerName)); |
812 | + return false; |
813 | + } |
814 | + |
815 | + if (!isStringValid(info)) { |
816 | + setInternalStatus(QString("%1 is not a valid description.").arg(info)); |
817 | + return false; |
818 | + } |
819 | + |
820 | + if (!isStringValid(location)) { |
821 | + setInternalStatus(QString("%1 is not a valid location.").arg(location)); |
822 | + return false; |
823 | + } |
824 | + |
825 | + if (!isStringValid(ppdFile)) { |
826 | + setInternalStatus(QString("%1 is not a valid ppd file.").arg(ppdFile)); |
827 | + return false; |
828 | + } |
829 | + |
830 | + if (!isStringValid(printerUri)) { |
831 | + setInternalStatus(QString("%1 is not a valid printer uri.").arg(printerUri)); |
832 | + return false; |
833 | + } |
834 | + |
835 | + |
836 | + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); |
837 | + addPrinterUri(request, printerName); |
838 | + addRequestingUsername(request, NULL); |
839 | + |
840 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, |
841 | + "printer-name", NULL, printerName.toUtf8()); |
842 | + |
843 | + if (!ppdFile.isEmpty()) { |
844 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, |
845 | + "ppd-name", NULL, ppdFile.toUtf8()); |
846 | + } |
847 | + if (!printerUri.isEmpty()) { |
848 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, |
849 | + "device-uri", NULL, printerUri.toUtf8()); |
850 | + } |
851 | + if (!info.isEmpty()) { |
852 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, |
853 | + "printer-info", NULL, info.toUtf8()); |
854 | + } |
855 | + if (!location.isEmpty()) { |
856 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, |
857 | + "printer-location", NULL, location.toUtf8()); |
858 | + } |
859 | + |
860 | + return sendRequest(request, CphResourceAdmin); |
861 | +} |
862 | + |
863 | +bool CupsPkHelper::printerAddWithPpdFile(const QString &printerName, |
864 | + const QString &printerUri, |
865 | + const QString &ppdFileName, |
866 | + const QString &info, |
867 | + const QString &location) |
868 | +{ |
869 | + ipp_t *request; |
870 | + |
871 | + if (!isPrinterNameValid(printerName)) { |
872 | + setInternalStatus(QString("%1 is not a valid printer name.").arg(printerName)); |
873 | + return false; |
874 | + } |
875 | + |
876 | + if (!isStringValid(info)) { |
877 | + setInternalStatus(QString("%1 is not a valid description.").arg(info)); |
878 | + return false; |
879 | + } |
880 | + |
881 | + if (!isStringValid(location)) { |
882 | + setInternalStatus(QString("%1 is not a valid location.").arg(location)); |
883 | + return false; |
884 | + } |
885 | + |
886 | + if (!isStringValid(ppdFileName)) { |
887 | + setInternalStatus(QString("%1 is not a valid ppd file name.").arg(ppdFileName)); |
888 | + return false; |
889 | + } |
890 | + |
891 | + if (!isStringValid(printerUri)) { |
892 | + setInternalStatus(QString("%1 is not a valid printer uri.").arg(printerUri)); |
893 | + return false; |
894 | + } |
895 | + |
896 | + request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); |
897 | + addPrinterUri(request, printerName); |
898 | + addRequestingUsername(request, NULL); |
899 | + |
900 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, |
901 | + "printer-name", NULL, printerName.toUtf8()); |
902 | + |
903 | + /* In this specific case of ADD_MODIFY, the URI can be NULL/empty since |
904 | + * we provide a complete PPD. And cups fails if we pass an empty |
905 | + * string. */ |
906 | + if (!printerUri.isEmpty()) { |
907 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, |
908 | + "device-uri", NULL, printerUri.toUtf8()); |
909 | + } |
910 | + |
911 | + if (!info.isEmpty()) { |
912 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, |
913 | + "printer-info", NULL, info.toUtf8()); |
914 | + } |
915 | + if (!location.isEmpty()) { |
916 | + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, |
917 | + "printer-location", NULL, location.toUtf8()); |
918 | + } |
919 | + |
920 | + return postRequest(request, ppdFileName.toUtf8(), CphResourceAdmin); |
921 | +} |
922 | + |
923 | bool CupsPkHelper::printerClassSetInfo(const QString &name, |
924 | const QString &info) |
925 | { |
926 | @@ -582,3 +703,35 @@ |
927 | instance.toUtf8()); |
928 | return dest; |
929 | } |
930 | + |
931 | +ipp_t* CupsPkHelper::createPrinterDriversRequest( |
932 | + const QString &deviceId, const QString &language, const QString &makeModel, |
933 | + const QString &product, const QStringList &includeSchemes, |
934 | + const QStringList &excludeSchemes |
935 | +) |
936 | +{ |
937 | + Q_UNUSED(includeSchemes); |
938 | + Q_UNUSED(excludeSchemes); |
939 | + |
940 | + ipp_t *request; |
941 | + |
942 | + request = ippNewRequest(CUPS_GET_PPDS); |
943 | + |
944 | + if (!deviceId.isEmpty()) |
945 | + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-device-id", |
946 | + NULL, deviceId.toUtf8()); |
947 | + if (!language.isEmpty()) |
948 | + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "ppd-language", |
949 | + NULL, language.toUtf8()); |
950 | + if (!makeModel.isEmpty()) |
951 | + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make-and-model", |
952 | + NULL, makeModel.toUtf8()); |
953 | + if (!product.isEmpty()) |
954 | + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-product", |
955 | + NULL, product.toUtf8()); |
956 | + |
957 | + // Do the request and get return the response. |
958 | + const QString resourceChar = getResource(CphResourceRoot); |
959 | + return cupsDoRequest(m_connection, request, |
960 | + resourceChar.toUtf8()); |
961 | +} |
962 | |
963 | === modified file 'plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.h' |
964 | --- plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.h 2017-01-17 15:14:25 +0000 |
965 | +++ plugins/Ubuntu/Settings/Printers/cups/cupspkhelper.h 2017-01-30 11:37:26 +0000 |
966 | @@ -14,12 +14,16 @@ |
967 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
968 | */ |
969 | |
970 | +#ifndef USC_PRINTERS_CUPSPKHELPER_H |
971 | +#define USC_PRINTERS_CUPSPKHELPER_H |
972 | + |
973 | +#include "structs.h" |
974 | + |
975 | #include <cups/cups.h> |
976 | #include <cups/http.h> |
977 | #include <cups/ipp.h> |
978 | #include <cups/ppd.h> |
979 | |
980 | - |
981 | #include <QString> |
982 | #include <QStringList> |
983 | |
984 | @@ -31,11 +35,10 @@ |
985 | |
986 | /* This code is only a shim for systems not running the daemon provided by |
987 | cups-pk-helper. Once provided on all platforms, this code should be replaced |
988 | -by proper dbus bindings, and subsequently be set on fire. */ |
989 | +by proper dbus bindings, and subsequently be set on fire. |
990 | |
991 | -/* TODO: rename to CupsPkHelperShim to emphasize its transient nature. |
992 | - FIXME: set m_internalStatus to mutable and make most of the "is..." methods |
993 | - const. |
994 | +TODO: rename to CupsPkHelperShim to emphasize its transient nature. |
995 | +FIXME: make most of the "is..." methods const. |
996 | */ |
997 | class CupsPkHelper |
998 | { |
999 | @@ -43,6 +46,16 @@ |
1000 | explicit CupsPkHelper(); |
1001 | ~CupsPkHelper(); |
1002 | |
1003 | + bool printerAdd(const QString &printerName, |
1004 | + const QString &printerUri, |
1005 | + const QString &ppdFile, |
1006 | + const QString &info, |
1007 | + const QString &location); |
1008 | + bool printerAddWithPpdFile(const QString &printerName, |
1009 | + const QString &printerUri, |
1010 | + const QString &ppdFileName, |
1011 | + const QString &info, |
1012 | + const QString &location); |
1013 | bool printerClassSetInfo(const QString &name, const QString &info); |
1014 | bool printerClassSetOption(const QString &name, const QString &option, |
1015 | const QStringList &values); |
1016 | @@ -51,6 +64,16 @@ |
1017 | |
1018 | QString getLastError() const; |
1019 | |
1020 | + // This response needs to be free by the caller. |
1021 | + ipp_t* createPrinterDriversRequest( |
1022 | + const QString &deviceId = "", |
1023 | + const QString &language = "", |
1024 | + const QString &makeModel = "", |
1025 | + const QString &product = "", |
1026 | + const QStringList &includeSchemes = QStringList(), |
1027 | + const QStringList &excludeSchemes = QStringList() |
1028 | + ); |
1029 | + |
1030 | private: |
1031 | enum CphResource |
1032 | { |
1033 | @@ -74,7 +97,6 @@ |
1034 | const int maxLength = 512); |
1035 | static bool isStringPrintable(const QString &string, const bool checkNull, |
1036 | const int maxLength); |
1037 | - |
1038 | QString preparePpdForOptions(const QString &ppdfile, |
1039 | cups_option_t *options, |
1040 | int numOptions); |
1041 | @@ -91,3 +113,6 @@ |
1042 | ipp_status_t m_lastStatus = IPP_OK; |
1043 | mutable QString m_internalStatus = QString::null; |
1044 | }; |
1045 | + |
1046 | + |
1047 | +#endif // USC_PRINTERS_CUPSPKHELPER_H |
1048 | |
1049 | === added file 'plugins/Ubuntu/Settings/Printers/models/drivermodel.cpp' |
1050 | --- plugins/Ubuntu/Settings/Printers/models/drivermodel.cpp 1970-01-01 00:00:00 +0000 |
1051 | +++ plugins/Ubuntu/Settings/Printers/models/drivermodel.cpp 2017-01-30 11:37:26 +0000 |
1052 | @@ -0,0 +1,181 @@ |
1053 | +/* |
1054 | + * Copyright (C) 2017 Canonical, Ltd. |
1055 | + * |
1056 | + * This program is free software; you can redistribute it and/or modify |
1057 | + * it under the terms of the GNU Lesser General Public License as published by |
1058 | + * the Free Software Foundation; version 3. |
1059 | + * |
1060 | + * This program is distributed in the hope that it will be useful, |
1061 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1062 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1063 | + * GNU Lesser General Public License for more details. |
1064 | + * |
1065 | + * You should have received a copy of the GNU Lesser General Public License |
1066 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1067 | + */ |
1068 | + |
1069 | +#include "backend/backend_cups.h" |
1070 | +#include "cups/cupsfacade.h" |
1071 | +#include "models/drivermodel.h" |
1072 | + |
1073 | +#include <QDebug> |
1074 | +#include <QtConcurrent> |
1075 | + |
1076 | +DriverModel::DriverModel(QObject *parent) |
1077 | + : DriverModel(new PrinterCupsBackend, parent) |
1078 | +{ |
1079 | +} |
1080 | + |
1081 | +DriverModel::DriverModel(PrinterBackend *backend, QObject *parent) |
1082 | + : QAbstractListModel(parent) |
1083 | + , m_backend(backend) |
1084 | +{ |
1085 | + connect(m_backend, SIGNAL(printerDriversLoaded(const QList<PrinterDriver>&)), |
1086 | + this, SLOT(printerDriversLoaded(const QList<PrinterDriver>&))); |
1087 | + |
1088 | + QObject::connect(&m_watcher, |
1089 | + &QFutureWatcher<PrinterDriver>::finished, |
1090 | + this, |
1091 | + &DriverModel::filterFinished); |
1092 | + |
1093 | +} |
1094 | + |
1095 | +DriverModel::~DriverModel() |
1096 | +{ |
1097 | + cancel(); |
1098 | +} |
1099 | + |
1100 | +int DriverModel::rowCount(const QModelIndex &parent) const |
1101 | +{ |
1102 | + Q_UNUSED(parent); |
1103 | + return m_drivers.size(); |
1104 | +} |
1105 | + |
1106 | +int DriverModel::count() const |
1107 | +{ |
1108 | + return rowCount(); |
1109 | +} |
1110 | + |
1111 | +QVariant DriverModel::data(const QModelIndex &index, int role) const |
1112 | +{ |
1113 | + QVariant ret; |
1114 | + |
1115 | + if ((0 <= index.row()) && (index.row() < m_drivers.size())) { |
1116 | + |
1117 | + auto driver = m_drivers[index.row()]; |
1118 | + |
1119 | + switch (role) { |
1120 | + case Qt::DisplayRole: |
1121 | + ret = driver.toString(); |
1122 | + break; |
1123 | + case NameRole: |
1124 | + ret = driver.name; |
1125 | + break; |
1126 | + case DeviceIdRole: |
1127 | + ret = driver.deviceId; |
1128 | + break; |
1129 | + case LanguageRole: |
1130 | + ret = driver.language; |
1131 | + break; |
1132 | + case MakeModelRole: |
1133 | + ret = driver.makeModel; |
1134 | + break; |
1135 | + } |
1136 | + } |
1137 | + |
1138 | + return ret; |
1139 | +} |
1140 | + |
1141 | +QHash<int, QByteArray> DriverModel::roleNames() const |
1142 | +{ |
1143 | + static QHash<int,QByteArray> names; |
1144 | + |
1145 | + if (Q_UNLIKELY(names.empty())) { |
1146 | + names[Qt::DisplayRole] = "displayName"; |
1147 | + names[NameRole] = "name"; |
1148 | + names[DeviceIdRole] = "deviceId"; |
1149 | + names[LanguageRole] = "language"; |
1150 | + names[MakeModelRole] = "makeModel"; |
1151 | + } |
1152 | + |
1153 | + return names; |
1154 | +} |
1155 | + |
1156 | +void DriverModel::setFilter(const QString& pattern) |
1157 | +{ |
1158 | + QList<QByteArray> needles; |
1159 | + Q_FOREACH(const QString patternPart, pattern.toLower().split(" ")) { |
1160 | + needles.append(patternPart.toUtf8()); |
1161 | + } |
1162 | + QList<PrinterDriver> list; |
1163 | + |
1164 | + if (m_watcher.isRunning()) |
1165 | + m_watcher.cancel(); |
1166 | + |
1167 | + if (pattern.isEmpty()) { |
1168 | + setModel(m_originalDrivers); |
1169 | + m_filter = pattern; |
1170 | + return; |
1171 | + } |
1172 | + |
1173 | + if (!m_filter.isEmpty() && !m_drivers.isEmpty() && |
1174 | + pattern.startsWith(m_filter)) |
1175 | + list = m_drivers; // search in the smaller list |
1176 | + else |
1177 | + list = m_originalDrivers; //search in the whole list |
1178 | + |
1179 | + m_filter = pattern; |
1180 | + |
1181 | + QFuture<PrinterDriver> future(QtConcurrent::filtered(list, |
1182 | + [needles] (const PrinterDriver &driver) { |
1183 | + QByteArray haystack = driver.makeModel.toLower(); |
1184 | + Q_FOREACH(const QByteArray needle, needles) { |
1185 | + if (!haystack.contains(needle)) { |
1186 | + return false; |
1187 | + } |
1188 | + } |
1189 | + return true; |
1190 | + } |
1191 | + ) |
1192 | + ); |
1193 | + |
1194 | + Q_EMIT filterBegin(); |
1195 | + |
1196 | + m_watcher.setFuture(future); |
1197 | +} |
1198 | + |
1199 | +QString DriverModel::filter() const |
1200 | +{ |
1201 | + return m_filter; |
1202 | +} |
1203 | + |
1204 | +void DriverModel::filterFinished() |
1205 | +{ |
1206 | + setModel(m_watcher.future().results()); |
1207 | +} |
1208 | + |
1209 | +void DriverModel::load() |
1210 | +{ |
1211 | + m_backend->requestAvailablePrinterDrivers(); |
1212 | +} |
1213 | + |
1214 | +void DriverModel::cancel() |
1215 | +{ |
1216 | + if (m_watcher.isRunning()) |
1217 | + m_watcher.cancel(); |
1218 | +} |
1219 | + |
1220 | +void DriverModel::printerDriversLoaded(const QList<PrinterDriver> &drivers) |
1221 | +{ |
1222 | + m_originalDrivers = drivers; |
1223 | + setModel(m_originalDrivers); |
1224 | +} |
1225 | + |
1226 | +void DriverModel::setModel(const QList<PrinterDriver> &drivers) |
1227 | +{ |
1228 | + beginResetModel(); |
1229 | + m_drivers = drivers; |
1230 | + endResetModel(); |
1231 | + |
1232 | + Q_EMIT filterComplete(); |
1233 | +} |
1234 | |
1235 | === added file 'plugins/Ubuntu/Settings/Printers/models/drivermodel.h' |
1236 | --- plugins/Ubuntu/Settings/Printers/models/drivermodel.h 1970-01-01 00:00:00 +0000 |
1237 | +++ plugins/Ubuntu/Settings/Printers/models/drivermodel.h 2017-01-30 11:37:26 +0000 |
1238 | @@ -0,0 +1,83 @@ |
1239 | +/* |
1240 | + * Copyright (C) 2017 Canonical, Ltd. |
1241 | + * |
1242 | + * This program is free software; you can redistribute it and/or modify |
1243 | + * it under the terms of the GNU Lesser General Public License as published by |
1244 | + * the Free Software Foundation; version 3. |
1245 | + * |
1246 | + * This program is distributed in the hope that it will be useful, |
1247 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1248 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1249 | + * GNU Lesser General Public License for more details. |
1250 | + * |
1251 | + * You should have received a copy of the GNU Lesser General Public License |
1252 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1253 | + */ |
1254 | + |
1255 | +#ifndef USC_PRINTER_DRIVERMODEL_H |
1256 | +#define USC_PRINTER_DRIVERMODEL_H |
1257 | + |
1258 | +#include "printers_global.h" |
1259 | + |
1260 | +#include "structs.h" |
1261 | + |
1262 | +#include <QAbstractListModel> |
1263 | +#include <QFutureWatcher> |
1264 | +#include <QModelIndex> |
1265 | +#include <QObject> |
1266 | +#include <QVariant> |
1267 | + |
1268 | +class PRINTERS_DECL_EXPORT DriverModel : public QAbstractListModel |
1269 | +{ |
1270 | + Q_OBJECT |
1271 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
1272 | +public: |
1273 | + explicit DriverModel(QObject *parent = Q_NULLPTR); |
1274 | + explicit DriverModel(PrinterBackend *backend, QObject *parent = Q_NULLPTR); |
1275 | + ~DriverModel(); |
1276 | + |
1277 | + enum Roles |
1278 | + { |
1279 | + // Qt::DisplayRole holds driver name |
1280 | + NameRole = Qt::UserRole, |
1281 | + DeviceIdRole, |
1282 | + LanguageRole, |
1283 | + MakeModelRole, |
1284 | + LastRole = MakeModelRole, |
1285 | + }; |
1286 | + |
1287 | + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
1288 | + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
1289 | + virtual QHash<int, QByteArray> roleNames() const override; |
1290 | + |
1291 | + int count() const; |
1292 | + |
1293 | + QString filter() const; |
1294 | + void setFilter(const QString& pattern); |
1295 | + |
1296 | +public Q_SLOTS: |
1297 | + // Start loading the model. |
1298 | + void load(); |
1299 | + |
1300 | + // Cancel loading of the model. |
1301 | + void cancel(); |
1302 | + |
1303 | +private Q_SLOTS: |
1304 | + void printerDriversLoaded(const QList<PrinterDriver> &drivers); |
1305 | + void filterFinished(); |
1306 | + |
1307 | +Q_SIGNALS: |
1308 | + void countChanged(); |
1309 | + void filterBegin(); |
1310 | + void filterComplete(); |
1311 | + |
1312 | +private: |
1313 | + void setModel(const QList<PrinterDriver> &drivers); |
1314 | + PrinterBackend *m_backend; |
1315 | + QList<PrinterDriver> m_drivers; |
1316 | + QList<PrinterDriver> m_originalDrivers; |
1317 | + QString m_filter; |
1318 | + QFutureWatcher<PrinterDriver> m_watcher; |
1319 | +}; |
1320 | + |
1321 | +#endif // USC_PRINTER_DRIVERMODEL_H |
1322 | |
1323 | === modified file 'plugins/Ubuntu/Settings/Printers/plugin.cpp' |
1324 | --- plugins/Ubuntu/Settings/Printers/plugin.cpp 2017-01-24 12:34:23 +0000 |
1325 | +++ plugins/Ubuntu/Settings/Printers/plugin.cpp 2017-01-30 11:37:26 +0000 |
1326 | @@ -18,13 +18,15 @@ |
1327 | |
1328 | #include "enums.h" |
1329 | #include "i18n.h" |
1330 | +#include "structs.h" |
1331 | + |
1332 | // #include "models/printermodel.h" |
1333 | #include "printer/printer.h" |
1334 | #include "printer/printerjob.h" |
1335 | #include "printers/printers.h" |
1336 | |
1337 | #include <QtQml/qqml.h> |
1338 | -#include <QSharedPointer> |
1339 | +#include <QList> |
1340 | |
1341 | #define I18N_DOMAIN "ubuntu-settings-components" |
1342 | |
1343 | @@ -49,4 +51,5 @@ |
1344 | qmlRegisterType<PrinterJob>(uri, 0, 1, "PrinterJob"); |
1345 | |
1346 | qmlRegisterUncreatableType<PrinterEnum>(uri, 0, 1, "PrinterEnum", "Is an enum"); |
1347 | + qRegisterMetaType<QList<PrinterDriver>>("QList<PrinterDriver>"); |
1348 | } |
1349 | |
1350 | === modified file 'plugins/Ubuntu/Settings/Printers/printer/printerjob.cpp' |
1351 | --- plugins/Ubuntu/Settings/Printers/printer/printerjob.cpp 2017-01-26 16:19:54 +0000 |
1352 | +++ plugins/Ubuntu/Settings/Printers/printer/printerjob.cpp 2017-01-30 11:37:26 +0000 |
1353 | @@ -15,6 +15,7 @@ |
1354 | */ |
1355 | |
1356 | #include <QtCore/QDebug> |
1357 | +#include <QUrl> |
1358 | |
1359 | #include "backend/backend_cups.h" |
1360 | #include "models/printermodel.h" |
1361 | |
1362 | === modified file 'plugins/Ubuntu/Settings/Printers/printers/printers.cpp' |
1363 | --- plugins/Ubuntu/Settings/Printers/printers/printers.cpp 2017-01-22 19:31:39 +0000 |
1364 | +++ plugins/Ubuntu/Settings/Printers/printers/printers.cpp 2017-01-30 11:37:26 +0000 |
1365 | @@ -28,6 +28,7 @@ |
1366 | QObject *parent) |
1367 | : QObject(parent) |
1368 | , m_backend(backend) |
1369 | + , m_drivers(backend) |
1370 | , m_model(backend, printerUpdateIntervalMSecs) |
1371 | { |
1372 | m_allPrinters.setSourceModel(&m_model); |
1373 | @@ -41,6 +42,9 @@ |
1374 | |
1375 | // Let Qt be in charge of RAII. |
1376 | m_backend->setParent(this); |
1377 | + |
1378 | + connect(&m_drivers, SIGNAL(filterComplete()), |
1379 | + this, SIGNAL(driverFilterChanged())); |
1380 | } |
1381 | |
1382 | Printers::~Printers() |
1383 | @@ -71,11 +75,33 @@ |
1384 | |
1385 | } |
1386 | |
1387 | +QAbstractItemModel* Printers::drivers() |
1388 | +{ |
1389 | + auto ret = &m_drivers; |
1390 | + QQmlEngine::setObjectOwnership(ret, QQmlEngine::CppOwnership); |
1391 | + return ret; |
1392 | +} |
1393 | + |
1394 | +QString Printers::driverFilter() const |
1395 | +{ |
1396 | + return m_drivers.filter(); |
1397 | +} |
1398 | + |
1399 | +void Printers::setDriverFilter(const QString &filter) |
1400 | +{ |
1401 | + m_drivers.setFilter(filter); |
1402 | +} |
1403 | + |
1404 | QString Printers::defaultPrinterName() const |
1405 | { |
1406 | |
1407 | } |
1408 | |
1409 | +QString Printers::lastMessage() const |
1410 | +{ |
1411 | + return m_lastMessage; |
1412 | +} |
1413 | + |
1414 | void Printers::setDefaultPrinterName(const QString &name) |
1415 | { |
1416 | |
1417 | @@ -90,21 +116,37 @@ |
1418 | |
1419 | } |
1420 | |
1421 | -QSharedPointer<Printer> Printers::addPrinter(const QString &name, |
1422 | - const QUrl &ppd, |
1423 | - const QUrl &device, |
1424 | - const QString &description, |
1425 | - const QString &location) |
1426 | -{ |
1427 | - |
1428 | -} |
1429 | - |
1430 | -QSharedPointer<Printer> Printers::addPrinter(const QString &name, |
1431 | - const QUrl &device, |
1432 | - const QString &description, |
1433 | - const QString &location) |
1434 | -{ |
1435 | - |
1436 | +void Printers::prepareToAddPrinter() |
1437 | +{ |
1438 | + m_drivers.load(); |
1439 | +} |
1440 | + |
1441 | +bool Printers::addPrinter(const QString &name, const QString &ppd, |
1442 | + const QString &device, const QString &description, |
1443 | + const QString &location) |
1444 | +{ |
1445 | + QString reply = m_backend->printerAdd(name, device, ppd, description, |
1446 | + location); |
1447 | + if (!reply.isEmpty()) { |
1448 | + m_lastMessage = reply; |
1449 | + return false; |
1450 | + } |
1451 | + return true; |
1452 | +} |
1453 | + |
1454 | +bool Printers::addPrinterWithPpdFile(const QString &name, |
1455 | + const QString &ppdFileName, |
1456 | + const QString &device, |
1457 | + const QString &description, |
1458 | + const QString &location) |
1459 | +{ |
1460 | + QString reply = m_backend->printerAddWithPpd(name, device, ppdFileName, |
1461 | + description, location); |
1462 | + if (!reply.isEmpty()) { |
1463 | + m_lastMessage = reply; |
1464 | + return false; |
1465 | + } |
1466 | + return true; |
1467 | } |
1468 | |
1469 | bool Printers::removePrinter(const QString &name) |
1470 | |
1471 | === modified file 'plugins/Ubuntu/Settings/Printers/printers/printers.h' |
1472 | --- plugins/Ubuntu/Settings/Printers/printers/printers.h 2017-01-22 19:31:39 +0000 |
1473 | +++ plugins/Ubuntu/Settings/Printers/printers/printers.h 2017-01-30 11:37:26 +0000 |
1474 | @@ -20,6 +20,7 @@ |
1475 | #include "printers_global.h" |
1476 | |
1477 | #include "cups/cupsfacade.h" |
1478 | +#include "models/drivermodel.h" |
1479 | #include "models/printermodel.h" |
1480 | #include "printer/printer.h" |
1481 | |
1482 | @@ -28,7 +29,6 @@ |
1483 | #include <QScopedPointer> |
1484 | #include <QSharedPointer> |
1485 | #include <QString> |
1486 | -#include <QUrl> |
1487 | |
1488 | class PRINTERS_DECL_EXPORT Printers : public QObject |
1489 | { |
1490 | @@ -37,7 +37,10 @@ |
1491 | Q_PROPERTY(QAbstractItemModel* allPrintersWithPdf READ allPrintersWithPdf CONSTANT) |
1492 | Q_PROPERTY(QAbstractItemModel* recentPrinters READ recentPrinters CONSTANT) |
1493 | Q_PROPERTY(QAbstractItemModel* printJobs READ printJobs CONSTANT) |
1494 | + Q_PROPERTY(QAbstractItemModel* drivers READ drivers CONSTANT) |
1495 | + Q_PROPERTY (QString driverFilter READ driverFilter WRITE setDriverFilter NOTIFY driverFilterChanged) |
1496 | Q_PROPERTY(QString defaultPrinterName READ defaultPrinterName WRITE setDefaultPrinterName NOTIFY defaultPrinterNameChanged) |
1497 | + Q_PROPERTY(QString lastMessage READ lastMessage CONSTANT) |
1498 | |
1499 | public: |
1500 | explicit Printers(int printerUpdateIntervalMSecs = 5000, QObject *parent = nullptr); |
1501 | @@ -52,36 +55,46 @@ |
1502 | QAbstractItemModel* allPrintersWithPdf(); |
1503 | QAbstractItemModel* recentPrinters(); |
1504 | QAbstractItemModel* printJobs(); |
1505 | + QAbstractItemModel* drivers(); |
1506 | + QString driverFilter() const; |
1507 | QString defaultPrinterName() const; |
1508 | + QString lastMessage() const; |
1509 | |
1510 | void setDefaultPrinterName(const QString &name); |
1511 | + void setDriverFilter(const QString &filter); |
1512 | |
1513 | public Q_SLOTS: |
1514 | QSharedPointer<Printer> getPrinterByName(const QString &name); |
1515 | QSharedPointer<Printer> getJobOwner(const int &jobId); |
1516 | |
1517 | - QSharedPointer<Printer> addPrinter(const QString &name, |
1518 | - const QUrl &ppd, |
1519 | - const QUrl &device, |
1520 | - const QString &description, |
1521 | - const QString &location); |
1522 | + /* Instructs us to start loading drivers and what have you. In most cases, |
1523 | + the user is likely to merely configure existing printers/jobs. Loading |
1524 | + (at least) 12.000 drivers isn't relevant to those scenarios, so in order to |
1525 | + add printers, this method should be called first. */ |
1526 | + void prepareToAddPrinter(); |
1527 | |
1528 | - QSharedPointer<Printer> addPrinter(const QString &name, |
1529 | - const QUrl &device, |
1530 | - const QString &description, |
1531 | - const QString &location); |
1532 | + bool addPrinter(const QString &name, const QString &ppd, |
1533 | + const QString &device, const QString &description, |
1534 | + const QString &location); |
1535 | + bool addPrinterWithPpdFile(const QString &name, const QString &ppdFileName, |
1536 | + const QString &device, |
1537 | + const QString &description, |
1538 | + const QString &location); |
1539 | |
1540 | bool removePrinter(const QString &name); |
1541 | |
1542 | Q_SIGNALS: |
1543 | void defaultPrinterNameChanged(); |
1544 | + void driverFilterChanged(); |
1545 | |
1546 | private: |
1547 | PrinterBackend *m_backend; |
1548 | + DriverModel m_drivers; |
1549 | PrinterModel m_model; |
1550 | PrinterFilter m_allPrinters; |
1551 | PrinterFilter m_allPrintersWithPdf; |
1552 | PrinterFilter m_recentPrinters; |
1553 | + QString m_lastMessage; |
1554 | }; |
1555 | |
1556 | #endif // USC_PRINTERS_H |
1557 | |
1558 | === modified file 'plugins/Ubuntu/Settings/Printers/structs.h' |
1559 | --- plugins/Ubuntu/Settings/Printers/structs.h 2017-01-24 12:34:23 +0000 |
1560 | +++ plugins/Ubuntu/Settings/Printers/structs.h 2017-01-30 11:37:26 +0000 |
1561 | @@ -72,10 +72,28 @@ |
1562 | } |
1563 | }; |
1564 | |
1565 | +struct PrinterDriver |
1566 | +{ |
1567 | +public: |
1568 | + QByteArray name; |
1569 | + QByteArray deviceId; |
1570 | + QByteArray language; |
1571 | + QByteArray makeModel; |
1572 | + |
1573 | + QString toString() const { |
1574 | + return QString("%1 [%2]").arg(QString::fromUtf8(makeModel)) |
1575 | + .arg(QString::fromUtf8(language)); |
1576 | + } |
1577 | +}; |
1578 | + |
1579 | Q_DECLARE_TYPEINFO(ColorModel, Q_PRIMITIVE_TYPE); |
1580 | Q_DECLARE_METATYPE(ColorModel) |
1581 | |
1582 | Q_DECLARE_TYPEINFO(PrintQuality, Q_PRIMITIVE_TYPE); |
1583 | Q_DECLARE_METATYPE(PrintQuality) |
1584 | |
1585 | +Q_DECLARE_TYPEINFO(PrinterDriver, Q_MOVABLE_TYPE); |
1586 | +Q_DECLARE_METATYPE(PrinterDriver) |
1587 | +Q_DECLARE_METATYPE(QList<PrinterDriver>) |
1588 | + |
1589 | #endif // USC_PRINTERS_STRUCTS_H |
1590 | |
1591 | === modified file 'tests/unittests/Printers/CMakeLists.txt' |
1592 | --- tests/unittests/Printers/CMakeLists.txt 2017-01-22 14:21:11 +0000 |
1593 | +++ tests/unittests/Printers/CMakeLists.txt 2017-01-30 11:37:26 +0000 |
1594 | @@ -28,3 +28,7 @@ |
1595 | add_executable(testPrintersPrinterFilter tst_printerfilter.cpp ${MOCK_SOURCES}) |
1596 | target_link_libraries(testPrintersPrinterFilter UbuntuSettingsPrintersQml Qt5::Test Qt5::Gui) |
1597 | add_test(tst_printerfilter testPrintersPrinterFilter) |
1598 | + |
1599 | +add_executable(testPrintersDriverModel tst_drivermodel.cpp ${MOCK_SOURCES}) |
1600 | +target_link_libraries(testPrintersDriverModel UbuntuSettingsPrintersQml Qt5::Test Qt5::Gui) |
1601 | +add_test(tst_drivermodel testPrintersDriverModel) |
1602 | |
1603 | === modified file 'tests/unittests/Printers/mockbackend.h' |
1604 | --- tests/unittests/Printers/mockbackend.h 2017-01-23 19:41:11 +0000 |
1605 | +++ tests/unittests/Printers/mockbackend.h 2017-01-30 11:37:26 +0000 |
1606 | @@ -35,8 +35,8 @@ |
1607 | } |
1608 | |
1609 | virtual QString printerAdd(const QString &name, |
1610 | - const QUrl &uri, |
1611 | - const QUrl &ppdFile, |
1612 | + const QString &uri, |
1613 | + const QString &ppdFile, |
1614 | const QString &info, |
1615 | const QString &location) override |
1616 | { |
1617 | @@ -49,7 +49,7 @@ |
1618 | } |
1619 | |
1620 | virtual QString printerAddWithPpd(const QString &name, |
1621 | - const QUrl &uri, |
1622 | + const QString &uri, |
1623 | const QString &ppdFileName, |
1624 | const QString &info, |
1625 | const QString &location) override |
1626 | @@ -309,6 +309,10 @@ |
1627 | return m_defaultPrinterName; |
1628 | } |
1629 | |
1630 | + virtual void requestAvailablePrinterDrivers() override |
1631 | + { |
1632 | + } |
1633 | + |
1634 | virtual BackendType backendType() const override |
1635 | { |
1636 | return m_backendType; |
1637 | @@ -335,6 +339,16 @@ |
1638 | Q_EMIT printerStateChanged(name); |
1639 | } |
1640 | |
1641 | + void mockDriversLoaded(const QList<PrinterDriver> &drivers) |
1642 | + { |
1643 | + Q_EMIT printerDriversLoaded(drivers); |
1644 | + } |
1645 | + |
1646 | + void mockDriversLoaded(const QString &errorMessage) |
1647 | + { |
1648 | + Q_EMIT printerDriversFailedToLoad(errorMessage); |
1649 | + } |
1650 | + |
1651 | QString returnValue = QString::null; |
1652 | |
1653 | // Map from printer to key/val. |
1654 | |
1655 | === added file 'tests/unittests/Printers/tst_drivermodel.cpp' |
1656 | --- tests/unittests/Printers/tst_drivermodel.cpp 1970-01-01 00:00:00 +0000 |
1657 | +++ tests/unittests/Printers/tst_drivermodel.cpp 2017-01-30 11:37:26 +0000 |
1658 | @@ -0,0 +1,136 @@ |
1659 | +/* |
1660 | + * Copyright (C) 2017 Canonical, Ltd. |
1661 | + * |
1662 | + * This program is free software; you can redistribute it and/or modify |
1663 | + * it under the terms of the GNU Lesser General Public License as published by |
1664 | + * the Free Software Foundation; version 3. |
1665 | + * |
1666 | + * This program is distributed in the hope that it will be useful, |
1667 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1668 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1669 | + * GNU Lesser General Public License for more details. |
1670 | + * |
1671 | + * You should have received a copy of the GNU Lesser General Public License |
1672 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1673 | + */ |
1674 | + |
1675 | +#include "mockbackend.h" |
1676 | + |
1677 | +#include "backend/backend.h" |
1678 | +#include "models/drivermodel.h" |
1679 | + |
1680 | +#include <QDebug> |
1681 | +#include <QObject> |
1682 | +#include <QSignalSpy> |
1683 | +#include <QTest> |
1684 | + |
1685 | +class TestDriverModel : public QObject |
1686 | +{ |
1687 | + Q_OBJECT |
1688 | +private Q_SLOTS: |
1689 | + void init() |
1690 | + { |
1691 | + m_backend = new MockPrinterBackend; |
1692 | + m_model = new DriverModel(m_backend); |
1693 | + } |
1694 | + void cleanup() |
1695 | + { |
1696 | + QSignalSpy destroyedSpy(m_model, SIGNAL(destroyed(QObject*))); |
1697 | + m_model->deleteLater(); |
1698 | + QTRY_COMPARE(destroyedSpy.count(), 1); |
1699 | + delete m_backend; |
1700 | + } |
1701 | + void testDrivers_data() |
1702 | + { |
1703 | + QTest::addColumn<QList<PrinterDriver>>("drivers"); |
1704 | + QTest::addColumn<int>("expectedCount"); |
1705 | + { |
1706 | + QList<PrinterDriver> drivers; |
1707 | + QTest::newRow("none") << drivers << 0; |
1708 | + } |
1709 | + { |
1710 | + QList<PrinterDriver> drivers({PrinterDriver(), PrinterDriver()}); |
1711 | + QTest::newRow("some") << drivers << 2; |
1712 | + } |
1713 | + } |
1714 | + void testDrivers() |
1715 | + { |
1716 | + QFETCH(QList<PrinterDriver>, drivers); |
1717 | + QFETCH(int, expectedCount); |
1718 | + |
1719 | + m_model->load(); |
1720 | + getBackend()->mockDriversLoaded(drivers); |
1721 | + QCOMPARE(m_model->rowCount(), expectedCount); |
1722 | + } |
1723 | + void testFiltering_data() |
1724 | + { |
1725 | + QTest::addColumn<QList<PrinterDriver>>("drivers"); |
1726 | + QTest::addColumn<QList<PrinterDriver>>("expectedDrivers"); |
1727 | + QTest::addColumn<QString>("filter"); |
1728 | + |
1729 | + { |
1730 | + QList<PrinterDriver> drivers; |
1731 | + QList<PrinterDriver> expectedDrivers; |
1732 | + |
1733 | + PrinterDriver canon; |
1734 | + canon.makeModel = "Canon Foojet"; |
1735 | + |
1736 | + PrinterDriver hp; |
1737 | + hp.makeModel = "HP Laserfjert"; |
1738 | + |
1739 | + drivers << canon << hp; |
1740 | + expectedDrivers << hp; |
1741 | + |
1742 | + QTest::newRow("filter hp") << drivers << expectedDrivers << "hp"; |
1743 | + } |
1744 | + { |
1745 | + QList<PrinterDriver> drivers; |
1746 | + QList<PrinterDriver> expectedDrivers; |
1747 | + |
1748 | + PrinterDriver canon; |
1749 | + canon.makeModel = "Canon 4500 Foojet"; |
1750 | + |
1751 | + PrinterDriver canon2; |
1752 | + canon2.makeModel = "rabble rabble canon 4500 masterjet"; |
1753 | + |
1754 | + PrinterDriver hp; |
1755 | + hp.makeModel = "HP Laserfjert"; |
1756 | + |
1757 | + drivers << canon << canon2 << hp; |
1758 | + expectedDrivers << canon << canon2; |
1759 | + |
1760 | + QTest::newRow("filter canon 4500 printers") << drivers << expectedDrivers << "canon 4500"; |
1761 | + } |
1762 | + } |
1763 | + void testFiltering() |
1764 | + { |
1765 | + QFETCH(QList<PrinterDriver>, drivers); |
1766 | + QFETCH(QList<PrinterDriver>, expectedDrivers); |
1767 | + QFETCH(QString, filter); |
1768 | + |
1769 | + m_model->load(); |
1770 | + getBackend()->mockDriversLoaded(drivers); |
1771 | + |
1772 | + QSignalSpy filterCompleteSpy(m_model, SIGNAL(filterComplete())); |
1773 | + m_model->setFilter(filter); |
1774 | + QTRY_COMPARE(filterCompleteSpy.count(), 1); |
1775 | + |
1776 | + QCOMPARE(m_model->rowCount(), expectedDrivers.size()); |
1777 | + for (int i = 0; i < m_model->rowCount(); i++) { |
1778 | + QCOMPARE( |
1779 | + expectedDrivers.at(i).makeModel, |
1780 | + m_model->data(m_model->index(i), DriverModel::Roles::MakeModelRole).toByteArray() |
1781 | + ); |
1782 | + } |
1783 | + } |
1784 | +private: |
1785 | + PrinterBackend *m_backend; |
1786 | + DriverModel *m_model; |
1787 | + MockPrinterBackend* getBackend() |
1788 | + { |
1789 | + return (MockPrinterBackend*) m_backend; |
1790 | + } |
1791 | +}; |
1792 | + |
1793 | +QTEST_GUILESS_MAIN(TestDriverModel) |
1794 | +#include "tst_drivermodel.moc" |
1795 | |
1796 | === modified file 'tests/unittests/Printers/tst_printers.cpp' |
1797 | --- tests/unittests/Printers/tst_printers.cpp 2017-01-22 14:21:11 +0000 |
1798 | +++ tests/unittests/Printers/tst_printers.cpp 2017-01-30 11:37:26 +0000 |
1799 | @@ -99,6 +99,15 @@ |
1800 | ); |
1801 | } |
1802 | } |
1803 | + void testPrinterDrivers() |
1804 | + { |
1805 | + QString targetFilter("foo"); |
1806 | + Printers printers(new MockPrinterBackend); |
1807 | + printers.setDriverFilter(targetFilter); |
1808 | + |
1809 | + DriverModel *drivers = (DriverModel*) printers.drivers(); |
1810 | + QCOMPARE(drivers->filter(), targetFilter); |
1811 | + } |
1812 | }; |
1813 | |
1814 | QTEST_GUILESS_MAIN(TestPrinters) |
This works by manually specifying the device URI, picking the right driver, setting a name.
In the future it'd be good to have network discovery, auto selection of drivers from an IP address etc