Merge lp:~jonas-drange/ubuntu-settings-components/asyncness into lp:~phablet-team/ubuntu-settings-components/printer-components

Proposed by Jonas G. Drange
Status: Merged
Approved by: Andrew Hayzen
Approved revision: 253
Merged at revision: 230
Proposed branch: lp:~jonas-drange/ubuntu-settings-components/asyncness
Merge into: lp:~phablet-team/ubuntu-settings-components/printer-components
Diff against target: 6455 lines (+2445/-1898)
39 files modified
examples/Printers.qml (+153/-1)
plugins/Ubuntu/Settings/Printers/CMakeLists.txt (+9/-4)
plugins/Ubuntu/Settings/Printers/backend/backend.cpp (+39/-50)
plugins/Ubuntu/Settings/Printers/backend/backend.h (+26/-26)
plugins/Ubuntu/Settings/Printers/backend/backend_cups.cpp (+449/-184)
plugins/Ubuntu/Settings/Printers/backend/backend_cups.h (+33/-23)
plugins/Ubuntu/Settings/Printers/backend/backend_pdf.cpp (+31/-39)
plugins/Ubuntu/Settings/Printers/backend/backend_pdf.h (+5/-11)
plugins/Ubuntu/Settings/Printers/cups/cupsfacade.cpp (+0/-640)
plugins/Ubuntu/Settings/Printers/cups/cupsfacade.h (+0/-166)
plugins/Ubuntu/Settings/Printers/cups/ippclient.cpp (+157/-87)
plugins/Ubuntu/Settings/Printers/cups/ippclient.h (+25/-27)
plugins/Ubuntu/Settings/Printers/cups/printerdriverloader.cpp (+128/-0)
plugins/Ubuntu/Settings/Printers/cups/printerdriverloader.h (+61/-0)
plugins/Ubuntu/Settings/Printers/cups/printerloader.cpp (+53/-0)
plugins/Ubuntu/Settings/Printers/cups/printerloader.h (+49/-0)
plugins/Ubuntu/Settings/Printers/enums.h (+8/-0)
plugins/Ubuntu/Settings/Printers/models/drivermodel.cpp (+1/-7)
plugins/Ubuntu/Settings/Printers/models/drivermodel.h (+0/-1)
plugins/Ubuntu/Settings/Printers/models/jobmodel.cpp (+88/-23)
plugins/Ubuntu/Settings/Printers/models/jobmodel.h (+35/-5)
plugins/Ubuntu/Settings/Printers/models/printermodel.cpp (+187/-136)
plugins/Ubuntu/Settings/Printers/models/printermodel.h (+36/-10)
plugins/Ubuntu/Settings/Printers/plugin.cpp (+4/-1)
plugins/Ubuntu/Settings/Printers/printer/printer.cpp (+81/-56)
plugins/Ubuntu/Settings/Printers/printer/printer.h (+17/-34)
plugins/Ubuntu/Settings/Printers/printer/printerjob.cpp (+115/-79)
plugins/Ubuntu/Settings/Printers/printer/printerjob.h (+20/-15)
plugins/Ubuntu/Settings/Printers/printers/printers.cpp (+86/-10)
plugins/Ubuntu/Settings/Printers/printers/printers.h (+10/-3)
tests/unittests/Printers/CMakeLists.txt (+8/-0)
tests/unittests/Printers/mockbackend.h (+62/-40)
tests/unittests/Printers/tst_jobfilter.cpp (+55/-0)
tests/unittests/Printers/tst_jobmodel.cpp (+120/-0)
tests/unittests/Printers/tst_printer.cpp (+82/-38)
tests/unittests/Printers/tst_printerfilter.cpp (+44/-12)
tests/unittests/Printers/tst_printerjob.cpp (+17/-15)
tests/unittests/Printers/tst_printermodel.cpp (+73/-119)
tests/unittests/Printers/tst_printers.cpp (+78/-36)
To merge this branch: bzr merge lp:~jonas-drange/ubuntu-settings-components/asyncness
Reviewer Review Type Date Requested Status
Andrew Hayzen (community) Approve
Review via email: mp+316786@code.launchpad.net

Commit message

* rename CupsPkHelper to IppClient
* drop CupsFacade and move everything to PrinterCupsBackend
* add delete functionality
* move PrinterDriverLoader into it's own file
* add PrintersLoader
* break PrintJob API (force clients to use Printers.createJob(printerName)
* fix some read/write bugs that caused unnecessary cups communication
* Add JobFilter
* Moves JobModel to Printers so there is only one.
* Printer::jobs() is now a proxy (filter), lazily coupled with a source model.

To post a comment you must log in.
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

As the diff is so long and LP is truncating, but I still wanted to put my comments inline. I've generated a diff with my first round comments here http://pastebin.ubuntu.com/24002329/

Also removing a 'generic' printer still freezes the example app for me, this is what i see in the cups logs http://pastebin.ubuntu.com/24002348/

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

> Is there any reason you can't show the printerPageLoaded to start the loading? and then show the ActivityIndicator as an overlay while printer.isLoaded is false?

Yes, it's to stay the warnings. It also will load the printer page a lot quicker. But it's also just an example :)

> QUESTION: Hah! is this to start the lazy load? wonder if there is a better way todo this?

Would love a suggestion. :)

> NOTE: can you check the following and remove if it does?
>>> Cups will notify us (I think.)

It will, removed.

> QUESTION: how costly is this? maybe there could be two private methods:
>> getDest(printerName, instance) and getPpdFile(printerName, instance)

Good idea! Done.

> what is this used or?
>> if (m_printerName.isEmpty()) {
>> throw std::invalid_argument("Trying to refresh unnamed printer.");

It's used to catch bugs. If it throws, then we got in a situation where a printer that's expected to work, has no name, which is an exception and can't be handled properly by that piece of code.

> QUESTION: could the above not be the following to make it a 1 liner?

Done

> FIXME: can the values be set in the member initializer list?
> const QStringList m_knownQualityOptions = QStringList({

Done

>FIXME: can the -1 be set in the member initializer list?
> int m_cupsSubscriptionId = -1;

Done

> NOTE: maybe instead move this inside an else case for the above if
> to make it more clear this is the !accept route and then the comment can
> be removed

Done

> QUESTION: should we call it dest? maybe printerName is better?

Done

> QUESTION: is owner used anymore? is this now user?
> OwnerRole,

It was the owning printer, but now the printer does not own a JobModel anymore (just a proxy), so I've removed it.

> QUESTION: I think the 1 should be 'from'? So it should read like the following
>> !beginMoveRows(QModelIndex(), from, from, QModelIndex(), to)
> As in the examples on http://doc.qt.io/qt-5/qabstractitemmodel.html#beginMoveRows
> they have beginMoveRows(parent, 2, 2, parent, 0); to move one row?

Yup, done

> QUESTION: i think we said that this should be the default case?
> so if anything other than the above cases is hit, lazy load starts

You're right, done.

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

I've found supportedPrintQualities doesn't work looks like it is missing setting the ret value in printerGetOptions. This diff fixes it http://pastebin.ubuntu.com/24013170/

review: Needs Fixing
253. By Jonas G. Drange

addresses andrews comments

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

Thanks for those extra fixes to quality and duplex, I think this looks good now and there are follow-up branches fixing further issues. So lets land this :-)

review: Approve

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

Subscribers

People subscribed via source and target branches