Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qcupsprintengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <qpa/qplatformprintplugin.h>
7#include <qpa/qplatformprintersupport.h>
8
9#include <qiodevice.h>
10#include <qfile.h>
11#include <qdebug.h>
12#include <qbuffer.h>
13#include "private/qcups_p.h" // Only needed for PPK_CupsOptions
14#include <QtGui/qpagelayout.h>
15
16#include <cups/cups.h>
17
18#include "private/qcore_unix_p.h" // overrides QT_OPEN
19
21
22extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits);
23
31
35
37{
39
40 switch (int(key)) {
41 case PPK_PageSize:
42 d->setPageSize(QPageSize(QPageSize::PageSizeId(value.toInt())));
43 break;
45 d->setPageSize(QPageSize(QPageSize::id(value.toInt())));
46 break;
48 d->setPageSize(QPageSize(value.toSizeF(), QPageSize::Point));
49 break;
50 case PPK_PaperName:
51 // Get the named page size from the printer if supported
52 d->setPageSize(d->m_printDevice.supportedPageSize(value.toString()));
53 break;
54 case PPK_Duplex: {
56 if (d->m_printDevice.supportedDuplexModes().contains(mode)) {
57 d->duplex = mode;
58 d->duplexRequestedExplicitly = true;
59 }
60 break;
61 }
62 case PPK_PrinterName:
63 d->changePrinter(value.toString());
64 break;
65 case PPK_CupsOptions:
66 d->cupsOptions = value.toStringList();
67 break;
68 case PPK_QPageSize:
69 d->setPageSize(qvariant_cast<QPageSize>(value));
70 break;
71 case PPK_QPageLayout: {
72 QPageLayout pageLayout = qvariant_cast<QPageLayout>(value);
73 if (pageLayout.isValid() && (d->m_printDevice.isValidPageLayout(pageLayout, d->resolution)
74 || d->m_printDevice.supportsCustomPageSizes()
75 || d->m_printDevice.supportedPageSizes().isEmpty())) {
76 // supportedPageSizes().isEmpty() because QPageSetupWidget::initPageSizes says
77 // "If no available printer page sizes, populate with all page sizes"
78 d->m_pageLayout = pageLayout;
80 }
81 break;
82 }
83 default:
85 break;
86 }
87}
88
90{
91 Q_D(const QCupsPrintEngine);
92
94 switch (int(key)) {
96 // CUPS server always supports multiple copies, even if individual m_printDevice doesn't
97 ret = true;
98 break;
100 ret = 1;
101 break;
102 case PPK_CupsOptions:
103 ret = d->cupsOptions;
104 break;
105 case PPK_Duplex:
106 ret = d->duplex;
107 break;
108 default:
110 break;
111 }
112 return ret;
113}
114
115
121
125
127{
128 if (outDevice)
129 return false;
130
131 if (!outputFileName.isEmpty()) {
134 delete file;
135 return false;
136 }
137 outDevice = file;
138 } else {
139 char filename[512];
140 fd = cupsTempFd(filename, 512);
141 if (fd < 0) {
142 qWarning("QPdfPrinter: Could not open temporary file to print");
143 return false;
144 }
145 cupsTempFile = QString::fromLocal8Bit(filename);
146 outDevice = new QFile();
147 if (!static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly)) {
148 qWarning("QPdfPrinter: Could not open CUPS temporary file descriptor: %s",
150 delete outDevice;
151 outDevice = nullptr;
152
153#if defined(Q_OS_WIN) && defined(Q_CC_MSVC)
154 ::_close(fd);
155#else
156 ::close(fd);
157#endif
158 fd = -1;
159 return false;
160 }
161 }
162
163 return true;
164}
165
167{
169
170 if (!cupsTempFile.isEmpty()) {
171 QString tempFile = cupsTempFile;
172 cupsTempFile.clear();
173
174 // Should never have got here without a printer, but check anyway
175 if (printerName.isEmpty()) {
176 qWarning("Could not determine printer to print to");
178 return;
179 }
180
181 // Set up print options.
182 QList<QPair<QByteArray, QByteArray> > options;
183 QList<cups_option_t> cupsOptStruct;
184
185 options.append(QPair<QByteArray, QByteArray>("media", m_pageLayout.pageSize().key().toLocal8Bit()));
186
187 if (copies > 1)
188 options.append(QPair<QByteArray, QByteArray>("copies", QString::number(copies).toLocal8Bit()));
189
190 if (copies > 1 && collate)
191 options.append(QPair<QByteArray, QByteArray>("Collate", "True"));
192
193 switch (duplex) {
195 options.append(QPair<QByteArray, QByteArray>("sides", "one-sided"));
196 break;
199 options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-long-edge"));
200 else
201 options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-short-edge"));
202 break;
204 options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-long-edge"));
205 break;
207 options.append(QPair<QByteArray, QByteArray>("sides", "two-sided-short-edge"));
208 break;
209 }
210
212 options.append(QPair<QByteArray, QByteArray>("landscape", ""));
213
214 QStringList::const_iterator it = cupsOptions.constBegin();
215 while (it != cupsOptions.constEnd()) {
216 options.append(QPair<QByteArray, QByteArray>((*it).toLocal8Bit(), (*(it+1)).toLocal8Bit()));
217 it += 2;
218 }
219
220 const int numOptions = options.size();
221 cupsOptStruct.reserve(numOptions);
222 for (int c = 0; c < numOptions; ++c) {
223 cups_option_t opt;
224 opt.name = options[c].first.data();
225 opt.value = options[c].second.data();
226 cupsOptStruct.append(opt);
227 }
228
229 // Print the file
230 // Cups expect the printer original name without instance, the full name is used only to retrieve the configuration
231 const auto parts = QStringView{printerName}.split(u'/');
232 const auto printerOriginalName = parts.at(0);
233 cups_option_t* optPtr = cupsOptStruct.size() ? &cupsOptStruct.first() : 0;
234 cupsPrintFile(printerOriginalName.toLocal8Bit().constData(), tempFile.toLocal8Bit().constData(),
235 title.toLocal8Bit().constData(), cupsOptStruct.size(), optPtr);
236
238 }
239}
240
241void QCupsPrintEnginePrivate::changePrinter(const QString &newPrinter)
242{
243 // Don't waste time if same printer name
244 if (newPrinter == printerName)
245 return;
246
247 // Should never have reached here if no plugin available, but check just in case
249 if (!ps)
250 return;
251
252 // Try create the printer, only use it if it returns valid
253 QPrintDevice printDevice = ps->createPrintDevice(newPrinter);
254 if (!printDevice.isValid())
255 return;
256 m_printDevice.swap(printDevice);
257 printerName = m_printDevice.id();
258
259 // in case a duplex value was explicitly set, check if new printer supports current value,
260 // otherwise use device default
261 if (!duplexRequestedExplicitly || !m_printDevice.supportedDuplexModes().contains(duplex)) {
262 duplex = m_printDevice.defaultDuplexMode();
263 duplexRequestedExplicitly = false;
264 }
265 QPrint::ColorMode colorMode = static_cast<QPrint::ColorMode>(printerColorMode());
266 if (!m_printDevice.supportedColorModes().contains(colorMode)) {
267 colorModel = (m_printDevice.defaultColorMode() == QPrint::GrayScale)
269 : QPdfEngine::ColorModel::RGB;
270 }
271
272 // Get the equivalent page size for this printer as supported names may be different
273 if (m_printDevice.supportedPageSize(m_pageLayout.pageSize()).isValid())
274 setPageSize(m_pageLayout.pageSize());
275 else
277}
278
279void QCupsPrintEnginePrivate::setPageSize(const QPageSize &pageSize)
280{
281 if (pageSize.isValid()) {
282 // Find if the requested page size has a matching printer page size, if so use its defined name instead
283 QPageSize printerPageSize = m_printDevice.supportedPageSize(pageSize);
284 QPageSize usePageSize = printerPageSize.isValid() ? printerPageSize : pageSize;
285 QMarginsF printable = m_printDevice.printableMargins(usePageSize, m_pageLayout.orientation(), resolution);
287 }
288}
289
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
QVariant property(PrintEnginePropertyKey key) const override
Returns the print engine's property specified by key.
QCupsPrintEngine(QPrinter::PrinterMode m, const QString &deviceId)
void setProperty(PrintEnginePropertyKey key, const QVariant &value) override
Sets the print engine's property specified by key to the given value.
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
bool remove()
Removes the file specified by fileName().
Definition qfile.cpp:419
QString errorString() const
Returns a human-readable description of the last device error that occurred.
\inmodule QtCore
Definition qmargins.h:270
\inmodule QtGui
Definition qpagelayout.h:20
Unit units() const
Returns the units the page layout is currently defined in.
bool isValid() const
Returns true if this page layout is valid.
Unit
This enum type is used to specify the measurement unit for page layout and margins.
Definition qpagelayout.h:24
Orientation orientation() const
Returns the page orientation of the page layout.
void setPageSize(const QPageSize &pageSize, const QMarginsF &minMargins=QMarginsF(0, 0, 0, 0))
Sets the page size of the page layout to pageSize.
QPageSize pageSize() const
Returns the page size of the page layout.
\inmodule QtGui
Definition qpagesize.h:22
bool isValid() const
Returns true if this page size is valid.
QString key() const
Returns the unique key of the page size.
QSizeF size(Unit units) const
Returns the size of the page in the required units.
PageSizeId id() const
Returns the standard QPageSize::PageSizeId of the page, or QPageSize::Custom.
PageSizeId
This enum type lists the available page sizes as defined in the Postscript PPD standard.
Definition qpagesize.h:25
QString title
Definition qpdf_p.h:263
QPageLayout m_pageLayout
Definition qpdf_p.h:269
QPdfEngine::ColorModel colorModel
Definition qpdf_p.h:251
QString outputFileName
Definition qpdf_p.h:262
QIODevice * outDevice
Definition qpdf_p.h:258
QPageLayout pageLayout() const
Definition qpdf.cpp:1380
friend class QCupsPrintEnginePrivate
QPrinter::ColorMode printerColorMode() const
QPrinter::PrinterState state
virtual void setProperty(PrintEnginePropertyKey key, const QVariant &value) override
Sets the print engine's property specified by key to the given value.
virtual QVariant property(PrintEnginePropertyKey key) const override
Returns the print engine's property specified by key.
static QPlatformPrinterSupport * get()
The QPlatformPrinterSupport class provides an abstraction for print support.
virtual QPrintDevice createPrintDevice(const QString &id)
QPageSize supportedPageSize(const QPageSize &pageSize) const
void swap(QPrintDevice &other)
QList< QPrint::DuplexMode > supportedDuplexModes() const
QPrint::DuplexMode defaultDuplexMode() const
QList< QPrint::ColorMode > supportedColorModes() const
QPrint::ColorMode defaultColorMode() const
QMarginsF printableMargins(const QPageSize &pageSize, QPageLayout::Orientation orientation, int resolution) const
QString id() const
PrintEnginePropertyKey
This enum is used to communicate properties between the print engine and QPrinter.
@ PPK_SupportsMultipleCopies
PrinterMode
This enum describes the mode the printer should work in.
Definition qprinter.h:31
\inmodule QtCore
Definition qstringview.h:78
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:8249
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
QByteArray toLocal8Bit() const &
Definition qstring.h:638
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
Definition qvariant.h:65
QSet< QString >::iterator it
QStyleOptionButton opt
ColorMode
Definition qprint_p.h:72
@ GrayScale
Definition qprint_p.h:73
DuplexMode
Definition qprint_p.h:64
@ DuplexLongSide
Definition qprint_p.h:67
@ DuplexShortSide
Definition qprint_p.h:68
@ DuplexNone
Definition qprint_p.h:65
@ DuplexAuto
Definition qprint_p.h:66
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE const char tempFile[]
#define PPK_CupsOptions
Definition qcups_p.h:35
QT_BEGIN_NAMESPACE QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
return ret
GLenum mode
const GLfloat * m
GLuint64 key
GLuint64 GLenum GLint fd
const GLubyte * c
Q_GUI_EXPORT QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)
#define qPrintable(string)
Definition qstring.h:1531
static char * toLocal8Bit(char *out, QStringView in, QStringConverter::State *state)
QFile file
[0]
file open(QIODevice::ReadOnly)
bool contains(const AT &t) const noexcept
Definition qlist.h:45