diff --git a/cmake/FindWrapCPDB.cmake b/cmake/FindWrapCPDB.cmake new file mode 100644 index 000000000000..c5a5a14067fa --- /dev/null +++ b/cmake/FindWrapCPDB.cmake @@ -0,0 +1,3 @@ +# Create an empty interface library for WrapCPDB when CPDB is not available +add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED GLOBAL) +set(WrapCPDB_FOUND TRUE) diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp index 3b6a21140da3..da3bdbb689e9 100644 --- a/src/gui/painting/qpagesize.cpp +++ b/src/gui/painting/qpagesize.cpp @@ -692,6 +692,8 @@ class QPageSizePrivate : public QSharedData const QString &name, QPageSize::SizeMatchPolicy matchPolicy); QPageSizePrivate(const QString &key, const QSize &size, const QString &name); + QPageSizePrivate(const QString &key, const QSizeF &size, + QPageSize::Unit units, const QString &name); QPageSizePrivate(int windowsId, const QSize &pointSize, const QString &name); ~QPageSizePrivate(); @@ -773,6 +775,15 @@ QPageSizePrivate::QPageSizePrivate(const QString &key, const QSize &pointSize, c } } +QPageSizePrivate::QPageSizePrivate(const QString &key, const QSizeF &size, + QPageSize::Unit units, const QString &name) + : m_id(QPageSize::Custom), + m_windowsId(0) +{ + init(size, units, name); + m_key = key; +} + QPageSizePrivate::QPageSizePrivate(int windowsId, const QSize &pointSize, const QString &name) : m_id(QPageSize::Custom), m_windowsId(0), @@ -1156,6 +1167,18 @@ QPageSize::QPageSize(const QString &key, const QSize &pointSize, const QString & { } +/*! + \internal + + Create page with given key, size, units and name, for use by printer plugin. +*/ + +QPageSize::QPageSize(const QString &key, const QSizeF &size, + QPageSize::Unit units, const QString &name) + : d(new QPageSizePrivate(key, size, units, name)) +{ +} + /*! \internal diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h index 221863aad7ea..160c87d252ab 100644 --- a/src/gui/painting/qpagesize.h +++ b/src/gui/painting/qpagesize.h @@ -257,6 +257,8 @@ class Q_GUI_EXPORT QPageSize { return !(lhs == rhs); } QPageSize(const QString &key, const QSize &pointSize, const QString &name); + QPageSize(const QString &key, const QSizeF &size, + QPageSize::Unit units, const QString &name); QPageSize(int windowsId, const QSize &pointSize, const QString &name); QPageSize(QPageSizePrivate &dd); QSharedDataPointer d; diff --git a/src/plugins/printsupport/CMakeLists.txt b/src/plugins/printsupport/CMakeLists.txt index 77366847622d..c0156b218ce7 100644 --- a/src/plugins/printsupport/CMakeLists.txt +++ b/src/plugins/printsupport/CMakeLists.txt @@ -1,6 +1,11 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -if(QT_FEATURE_cups AND UNIX AND NOT APPLE) +# Generated from printsupport.pro. + +if(QT_FEATURE_cpdb AND UNIX AND NOT APPLE) + add_subdirectory(cpdb) +endif() +if (QT_FEATURE_cups AND UNIX AND NOT APPLE) add_subdirectory(cups) endif() diff --git a/src/plugins/printsupport/cpdb/CMakeLists.txt b/src/plugins/printsupport/cpdb/CMakeLists.txt new file mode 100644 index 000000000000..c288d17ee7a9 --- /dev/null +++ b/src/plugins/printsupport/cpdb/CMakeLists.txt @@ -0,0 +1,24 @@ + +qt_find_package(WrapCPDB + PROVIDED_TARGETS WrapCPDB::WrapCPDB MODULE_NAME printsupport QMAKE_LIB cpdb) + +qt_internal_add_plugin(QCpdbPrinterSupportPlugin + OUTPUT_NAME cpdbprintersupport + PLUGIN_TYPE printsupport + SOURCES + main.cpp + qcpdb.cpp qcpdb_p.h + qcpdbprintengine.cpp qcpdbprintengine_p.h + qcpdbprintersupport.cpp qcpdbprintersupport_p.h + qcpdbprintdevice.cpp qcpdbprintdevice.h + INCLUDE_DIRECTORIES + ../../../printsupport/kernel + LIBRARIES + WrapCPDB::WrapCPDB + Qt::Core + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + Qt::PrintSupport + Qt::PrintSupportPrivate +) diff --git a/src/plugins/printsupport/cpdb/cpdb.json b/src/plugins/printsupport/cpdb/cpdb.json new file mode 100644 index 000000000000..f017a99b62a4 --- /dev/null +++ b/src/plugins/printsupport/cpdb/cpdb.json @@ -0,0 +1,4 @@ +{ + "Keys": [ "cpdbprintersupport" ], + "Priority": 80 +} diff --git a/src/plugins/printsupport/cpdb/main.cpp b/src/plugins/printsupport/cpdb/main.cpp new file mode 100644 index 000000000000..bb01f5e54e06 --- /dev/null +++ b/src/plugins/printsupport/cpdb/main.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qcpdbprintersupport_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt::StringLiterals; + +class QCpdbPrinterSupportPlugin : public QPlatformPrinterSupportPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QPlatformPrinterSupportFactoryInterface_iid FILE "cpdb.json") + +public: + QStringList keys() const; + QPlatformPrinterSupport *create(const QString &) override; +}; + +QStringList QCpdbPrinterSupportPlugin::keys() const +{ + return QStringList(QStringLiteral("cpdbprintersupport")); +} + +QPlatformPrinterSupport *QCpdbPrinterSupportPlugin::create(const QString &key) +{ + if (key.compare(key, "cpdbprintersupport"_L1, Qt::CaseInsensitive) == 0) + return new QCpdbPrinterSupport; + return 0; +} + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/printsupport/cpdb/qcpdb.cpp b/src/plugins/printsupport/cpdb/qcpdb.cpp new file mode 100644 index 000000000000..a82070827fec --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdb.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qcpdb_p.h" + +QT_BEGIN_NAMESPACE + +const char *QCPDBSupport::translateOption(cpdb_printer_obj_t * printerObj, const char *optionName) +{ + + QByteArray locale = QLocale().bcp47Name().toLocal8Bit().replace('-', '_'); + return cpdbGetOptionTranslation(printerObj, optionName, locale.constData()); +} + +const char *QCPDBSupport::translateChoice(cpdb_printer_obj_t *printerObj, const char *optionName, const char *choiceName) +{ + QByteArray locale = QLocale().bcp47Name().toLocal8Bit().replace('-', '_'); + return cpdbGetChoiceTranslation(printerObj, optionName, choiceName, locale.constData()); +} + +const char *QCPDBSupport::translateGroup(cpdb_printer_obj_t *printerObj, const char *groupName) +{ + QByteArray locale = QLocale().bcp47Name().toLocal8Bit().replace('-', '_'); + return cpdbGetOptionTranslation(printerObj, groupName, locale.constData()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/printsupport/cpdb/qcpdb_p.h b/src/plugins/printsupport/cpdb/qcpdb_p.h new file mode 100644 index 000000000000..e81a1bbd7b42 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdb_p.h @@ -0,0 +1,75 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QCPDBSUPPORT_H +#define QCPDBSUPPORT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// to version without notice, or even be removed. +// +// We mean it. +// +// + +#include +#include +#include +#include + +#include + +QT_REQUIRE_CONFIG(cpdb); + +QT_BEGIN_NAMESPACE + +class QPrintDevice; + +#define PDPK_CpdbPrinterObj QPrintDevice::PrintDevicePropertyKey(QPrintDevice::PDPK_CustomBase + 0x10) + +class QCPDBSupport +{ +public: + constexpr static qreal pointsMultiplier = 2.83464566929; // 1mm to points + + static const char *translateOption(cpdb_printer_obj_t *printerObj, const char *optionName); + static const char *translateChoice(cpdb_printer_obj_t *printerObj, const char *optionName, const char *choiceName); + static const char *translateGroup(cpdb_printer_obj_t *printerObj, const char *groupName); + + const static inline QHash numUpDist = { + {"1", "1x1"}, + {"2", "2x1"}, + {"4", "2x2"}, + {"6", "2x3"}, + {"9", "3x3"}, + {"16", "4x4"}, + + {"1x1", "1"}, + {"2x1", "2"}, + {"2x2", "4"}, + {"2x3", "6"}, + {"3x3", "9"}, + {"4x4", "16"}, + }; + + const static inline QHash duplexMap = { + {CPDB_SIDES_ONE_SIDED, QPrint::DuplexNone}, + {CPDB_SIDES_TWO_SIDED_SHORT, QPrint::DuplexShortSide}, + {CPDB_SIDES_TWO_SIDED_LONG, QPrint::DuplexLongSide} + }; + + const static inline QHash qDuplexMap = { + {QPrint::DuplexNone, CPDB_SIDES_ONE_SIDED}, + {QPrint::DuplexShortSide, CPDB_SIDES_TWO_SIDED_SHORT}, + {QPrint::DuplexLongSide, CPDB_SIDES_TWO_SIDED_LONG} + }; +}; + + +QT_END_NAMESPACE + +#endif // QCPDBSUPPORT_H diff --git a/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp b/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp new file mode 100644 index 000000000000..f3c4e42560af --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp @@ -0,0 +1,685 @@ +// Copyright (C) 2022-2023 Gaurav Guleria om> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qcpdbprintdevice.h" + +#include + +#include "qcpdbprintersupport_p.h" + +#if QT_CONFIG(mimetype) +#include +#endif + +using namespace Qt::StringLiterals; + +QCpdbPrintDevice::QCpdbPrintDevice(cpdb_printer_obj_t * const printerObj) + : m_printerObj(printerObj) +{ + if (printerObj) { + m_name = printerObj->name; + m_id = printerObj->id; + m_location = printerObj->location; + m_makeAndModel = printerObj->make_and_model; + + cpdb_option_t *opt = cpdbGetOption(printerObj, CPDB_OPTION_COPIES); + if (opt && opt->num_supported > 0) { + QList copiesRange = QByteArray(opt->supported_values[0]).split('-'); + bool ok; + int maxCopies = copiesRange.last().toInt(&ok); + if (ok && maxCopies > 1) { + m_supportsMultipleCopies = true; + } + } + + opt = cpdbGetOption(printerObj, CPDB_OPTION_COLLATE); + if (opt && opt->num_supported > 1) + m_supportsCollateCopies = true; + } +} + +QCpdbPrintDevice::~QCpdbPrintDevice() = default; + +bool QCpdbPrintDevice::isValid() const +{ + return (m_printerObj != nullptr); +} + +bool QCpdbPrintDevice::isDefault() const +{ + if (QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get()) + return (ps->defaultPrintDeviceId() == m_printerObj->id); + return false; +} + +QPrint::DeviceState QCpdbPrintDevice::state() const +{ + const QByteArray state = cpdbGetState(m_printerObj); + if (state == CPDB_STATE_IDLE) + return QPrint::Idle; + if (state == CPDB_STATE_PRINTING) + return QPrint::Active; + if (state == CPDB_STATE_STOPPED) + return QPrint::Aborted; + return QPrint::Error; +} + +void QCpdbPrintDevice::loadPageSizes() const +{ + m_pageSizes.clear(); + m_havePageSizes = true; + + if (const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_MEDIA)) { + m_pageSizes.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + int width, length; + if (!cpdbGetMediaSize(m_printerObj, opt->supported_values[i], &width, &length)) + continue; + + const QByteArray value = opt->supported_values[i]; + auto key = QString::fromLocal8Bit(value); + auto size = QSizeF(width/100.0, length/100.0); + auto name = QString::fromLocal8Bit(QCPDBSupport::translateChoice(m_printerObj, + CPDB_OPTION_MEDIA, + value.constData())); + auto pageSize = createPageSize(key, size, QPageSize::Millimeter, name); + if (value.startsWith("custom_min")) + m_minimumPhysicalPageSize = pageSize.sizePoints(); + else if (value.startsWith("custom_max")) + m_maximumPhysicalPageSize = pageSize.sizePoints(); + else + m_pageSizes << pageSize; + } + } +} + +QPageSize QCpdbPrintDevice::defaultPageSize() const +{ + if (const char *defaultVal = cpdbGetDefault(m_printerObj, CPDB_OPTION_MEDIA)) { + int width, length; + if (cpdbGetMediaSize(m_printerObj, defaultVal, &width, &length)) { + auto key = QString::fromLocal8Bit(defaultVal); + auto size = QSizeF(width/100.0, length/100.0); + auto name = QString::fromLocal8Bit(QCPDBSupport::translateChoice(m_printerObj, + CPDB_OPTION_MEDIA, + defaultVal)); + return createPageSize(key, size, QPageSize::Millimeter, name); + } + } + + return QPlatformPrintDevice::defaultPageSize(); +} + +QMarginsF QCpdbPrintDevice::printableMargins(const QPageSize &pageSize, + QPageLayout::Orientation orientation, + int resolution) const +{ + Q_UNUSED(orientation); + Q_UNUSED(resolution); + + cpdb_margin_t *margins; + const QByteArray media = pageSize.key().toLocal8Bit(); + int num_margins = cpdbGetMediaMargins(m_printerObj, media.constData(), &margins); + if (num_margins > 0) { + qreal left = margins[0].left / 100.0 * QCPDBSupport::pointsMultiplier; + qreal right = margins[0].right / 100.0 * QCPDBSupport::pointsMultiplier; + qreal top = margins[0].top / 100.0 * QCPDBSupport::pointsMultiplier; + qreal bottom = margins[0].bottom / 100.0 * QCPDBSupport::pointsMultiplier; + return QMarginsF(left, top, right, bottom); + } + + return QMarginsF(); +} + +void QCpdbPrintDevice::loadResolutions() const +{ + m_resolutions.clear(); + m_haveResolutions = true; + + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_RESOLUTION); + if (opt && opt->num_supported > 1) { + m_resolutions.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + QByteArray resolution = opt->supported_values[i]; + // example: 300dpi + if (resolution.size() > 3) + resolution.chop(3); + bool ok; + int value = resolution.toInt(&ok); + if (ok) + m_resolutions << value; + } + } +} + +int QCpdbPrintDevice::defaultResolution() const +{ + QByteArray defaultVal = cpdbGetDefault(m_printerObj, CPDB_OPTION_RESOLUTION); + if (defaultVal.size() > 3) + defaultVal.chop(3); + bool ok; + int value = defaultVal.toInt(&ok); + if (ok) + return value; + + return QPlatformPrintDevice::defaultResolution(); +} + +void QCpdbPrintDevice::loadDuplexModes() const +{ + m_duplexModes.clear(); + m_haveDuplexModes = true; + + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_SIDES); + if (opt && opt->num_supported > 1) { + m_duplexModes.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + const QByteArray value = opt->supported_values[i]; + if (QCPDBSupport::duplexMap.contains(value)) + m_duplexModes << QCPDBSupport::duplexMap[value]; + } + } +} + +QPrint::DuplexMode QCpdbPrintDevice::defaultDuplexMode() const +{ + const QByteArray defaultVal = cpdbGetDefault(m_printerObj, CPDB_OPTION_SIDES); + if (defaultVal == CPDB_SIDES_ONE_SIDED) + return QPrint::DuplexNone; + if (defaultVal == CPDB_SIDES_TWO_SIDED_SHORT) + return QPrint::DuplexShortSide; + if (defaultVal == CPDB_SIDES_TWO_SIDED_LONG) + return QPrint::DuplexLongSide; + + return QPlatformPrintDevice::defaultDuplexMode(); +} + +void QCpdbPrintDevice::loadColorModes() const +{ + m_colorModes.clear(); + m_haveColorModes = true; + + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_COLOR_MODE); + if (opt && opt->num_supported > 1) { + m_colorModes.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + const QByteArray value = opt->supported_values[i]; + if (value == CPDB_COLOR_MODE_BW) + m_colorModes << QPrint::GrayScale; + else if (value == CPDB_COLOR_MODE_COLOR) + m_colorModes << QPrint::Color; + } + } +} + +QPrint::ColorMode QCpdbPrintDevice::defaultColorMode() const +{ + const QByteArray defaultVal = cpdbGetDefault(m_printerObj, CPDB_OPTION_COLOR_MODE); + if (defaultVal == CPDB_COLOR_MODE_COLOR) + return QPrint::Color; + if (defaultVal == CPDB_COLOR_MODE_BW) + return QPrint::GrayScale; + + return QPlatformPrintDevice::defaultColorMode(); +} + +void QCpdbPrintDevice::loadInputSlots() const +{ + m_inputSlots.clear(); + m_haveInputSlots = true; + + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_MEDIA_SOURCE); + if (opt && opt->num_supported > 1) { + m_inputSlots.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + QPrint::InputSlot inputSlot; + inputSlot.key = opt->supported_values[i]; + inputSlot.name = QCPDBSupport::translateChoice(m_printerObj, CPDB_OPTION_MEDIA_SOURCE, opt->supported_values[i]); + inputSlot.id = QPrint::CustomInputSlot; + inputSlot.windowsId = DMBIN_USER; + m_inputSlots << inputSlot; + } + } +} + +QPrint::InputSlot QCpdbPrintDevice::defaultInputSlot() const +{ + const QByteArray defaultVal = cpdbGetDefault(m_printerObj, CPDB_OPTION_MEDIA_SOURCE); + if (!defaultVal.isNull()) { + QPrint::InputSlot inputSlot; + inputSlot.key = defaultVal; + inputSlot.name = QCPDBSupport::translateChoice(m_printerObj, CPDB_OPTION_MEDIA_SOURCE, defaultVal.constData()); + inputSlot.id = QPrint::CustomInputSlot; + inputSlot.windowsId = DMBIN_USER; + return inputSlot; + } + + return QPlatformPrintDevice::defaultInputSlot(); +} + +void QCpdbPrintDevice::loadOutputBins() const +{ + m_outputBins.clear(); + m_haveOutputBins = true; + + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_OUTPUT_BIN); + if (opt && opt->num_supported > 1) { + m_outputBins.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + QPrint::OutputBin outputBin; + outputBin.key = opt->supported_values[i]; + outputBin.name = QCPDBSupport::translateChoice(m_printerObj, CPDB_OPTION_OUTPUT_BIN, opt->supported_values[i]); + outputBin.id = QPrint::CustomOutputBin; + m_outputBins << outputBin; + } + } +} + +QPrint::OutputBin QCpdbPrintDevice::defaultOutputBin() const +{ + QByteArray defaultVal = cpdbGetDefault(m_printerObj, CPDB_OPTION_OUTPUT_BIN); + if (!defaultVal.isNull()) { + QPrint::OutputBin outputBin; + outputBin.key = defaultVal; + outputBin.name = QCPDBSupport::translateChoice(m_printerObj, CPDB_OPTION_OUTPUT_BIN, defaultVal.constData()); + outputBin.id = QPrint::CustomOutputBin; + return outputBin; + } + + return QPlatformPrintDevice::defaultOutputBin(); +} + +void QCpdbPrintDevice::loadMimeTypes() const +{ + QMimeDatabase db; + m_mimeTypes.append(db.mimeTypeForName(u"application/pdf"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"application/postscript"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"image/gif"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"image/png"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"image/jpeg"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"image/tiff"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"text/html"_s)); + m_mimeTypes.append(db.mimeTypeForName(u"text/plain"_s)); + m_haveMimeTypes = true; +} + +bool QCpdbPrintDevice::isFeatureAvailable(QPrintDevice::PrintDevicePropertyKey key, const QVariant ¶ms) const +{ + if (key == QPrintDevice::PDPK_Duplex) { + if (params.toByteArray() == "conflict") + return false; + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_SIDES); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_PageSet) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_PAGE_SET); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_PageRange) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_PAGE_RANGES); + return (opt); + } + + if (key == QPrintDevice::PDPK_JobHold) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL); + if (params.toByteArray() == "#specific#") + return true; + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_JobBillingInfo) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_BILLING_INFO); + return (opt != nullptr); + } + + if (key == QPrintDevice::PDPK_JobPriority) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_PRIORITY); + return (opt != nullptr); + } + + if (key == QPrintDevice::PDPK_JobStartCoverPage) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_SHEETS); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_JobEndCoverPage) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_SHEETS); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_AdvancedOptions) { + const cpdb_options_t *opts = cpdbGetAllOptions(m_printerObj); + return (opts != nullptr); + } + + if (key == QPrintDevice::PDPK_OptionConflict) { + return false; + } + + if (key == QPrintDevice::PDPK_NumberUp) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_NumberUpLayout) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_PageSize) { + if (params.toByteArray() == "conflict") + return false; + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_MEDIA); + return (opt && opt->num_supported > 1); + } + + if (key == QPrintDevice::PDPK_AdvancedColorMode) { + return false; + } + + return QPlatformPrintDevice::isFeatureAvailable(key, params); +} + +QVariant QCpdbPrintDevice::property(QPrintDevice::PrintDevicePropertyKey key) const +{ + if (key == PDPK_CpdbPrinterObj) { + return QVariant::fromValue(m_printerObj); + } + + if (key == QPrintDevice::PDPK_PageSet) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_PAGE_SET); + if (opt && opt->num_supported > 1) { + QPrint::OptionCombo option; + option.name = opt->option_name; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + option.defaultChoice = qMax(0, option.choices.indexOf(opt->default_value)); + return QVariant::fromValue(option); + } + } + + if (key == QPrintDevice::PDPK_JobHold) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL); + if (opt && opt->num_supported > 1) { + QPrint::OptionCombo option; + option.name = opt->option_name; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + option.defaultChoice = qMax(0, option.choices.indexOf(opt->default_value)); + return QVariant::fromValue(option); + } + } + + if (key == QPrintDevice::PDPK_JobBillingInfo) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_BILLING_INFO); + if (opt) { + auto defaultVal = QString::fromUtf8(opt->default_value); + return QVariant(defaultVal); + } + } + + if (key == QPrintDevice::PDPK_JobPriority) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_PRIORITY); + bool ok; + int defaultVal = QByteArray(opt->default_value).toInt(&ok); + if (ok) { + return QVariant(defaultVal); + } + } + + if (key == QPrintDevice::PDPK_JobStartCoverPage) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_SHEETS); + if (opt && opt->num_supported > 1) { + QPrint::OptionCombo option; + option.name = opt->option_name; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + QByteArray defaultValues = opt->default_value; + option.defaultChoice = qMax(0, option.choices.indexOf(defaultValues.split(',')[0])); + return QVariant::fromValue(option); + } + } + + if (key == QPrintDevice::PDPK_JobEndCoverPage) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_SHEETS); + if (opt && opt->num_supported > 1) { + QPrint::OptionCombo option; + option.name = opt->option_name; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + QByteArray defaultValues = opt->default_value; + option.defaultChoice = qMax(0, option.choices.indexOf(defaultValues.split(',')[1])); + return QVariant::fromValue(option); + } + } + + if (key == QPrintDevice::PDPK_AdvancedOptions) { + const cpdb_options_t *opts = cpdbGetAllOptions(m_printerObj); + if (opts) { + GHashTableIter iter; + gpointer key, value; + QHash optionsGroups; + g_hash_table_iter_init(&iter, opts->table); + while (g_hash_table_iter_next(&iter, &key, &value)) { + QByteArray optionName = static_cast(key); + const cpdb_option_t *opt = static_cast(value); + + if (!m_nonAdvancedOptions.contains(optionName) && opt && opt->num_supported > 1) { + QByteArray groupName = opt->group_name; + optionsGroups[groupName].groupName = groupName; + optionsGroups[groupName].displayGroup = QString(QCPDBSupport::translateGroup(m_printerObj, opt->group_name)); + + QPrint::OptionCombo option; + option.name = optionName; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + option.defaultChoice = qMax(0, option.choices.indexOf(opt->default_value)); + optionsGroups[groupName].options.push_back(option); + } + } + return QVariant::fromValue(optionsGroups.values()); + } + } + + if (key == QPrintDevice::PDPK_OptionConflict) { + return QVariant::fromValue(nullptr); + } + + if (key == QPrintDevice::PDPK_NumberUp) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP); + if (opt && opt->num_supported > 1) { + QPrint::OptionCombo option; + option.name = opt->option_name; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + if (QCPDBSupport::numUpDist.contains(option.choices[i])) + option.choices[i] = QCPDBSupport::numUpDist.value(option.choices[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + option.defaultChoice = qMax(0, option.choices.indexOf(opt->default_value)); + return QVariant::fromValue(option); + } + } + if (key == QPrintDevice::PDPK_NumberUpLayout) { + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT); + if (opt && opt->num_supported > 1) { + QPrint::OptionCombo option; + option.name = opt->option_name; + option.displayName = QString(QCPDBSupport::translateOption(m_printerObj, opt->option_name)); + option.choices.reserve(opt->num_supported); + option.displayChoices.reserve(opt->num_supported); + for (int i = 0; i < opt->num_supported; i++) { + option.choices.push_back(opt->supported_values[i]); + option.displayChoices.emplace_back( + QCPDBSupport::translateChoice(m_printerObj, opt->option_name, opt->supported_values[i])); + } + option.defaultChoice = qMax(0, option.choices.indexOf(opt->default_value)); + return QVariant::fromValue(option); + } + } + + return QPlatformPrintDevice::property(key); +} + +bool QCpdbPrintDevice::setProperty(QPrintDevice::PrintDevicePropertyKey key, const QVariant &value) +{ + if (key == QPrintDevice::PDPK_Duplex) { + auto choice = qvariant_cast(value); + if (QCPDBSupport::qDuplexMap.contains(choice)) { + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_SIDES, QCPDBSupport::qDuplexMap.value(choice)); + return true; + } + return false; + } + + if (key == QPrintDevice::PDPK_PageSet) { + auto choice = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_PAGE_SET, choice); + return true; + } + + if (key == QPrintDevice::PDPK_PageRange) { + auto choice = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_PAGE_RANGES, choice.toUtf8()); + return true; + } + + if (key == QPrintDevice::PDPK_JobHold) { + auto choice = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL, choice); + return true; + } + + if (key == QPrintDevice::PDPK_JobBillingInfo) { + auto choice = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_BILLING_INFO, choice.toUtf8()); + return true; + } + + if (key == QPrintDevice::PDPK_JobPriority) { + int priority = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_PRIORITY, QByteArray::number(priority)); + return true; + } + + if (key == QPrintDevice::PDPK_JobStartCoverPage) { + auto choice = qvariant_cast(value); + QByteArray currentSetting = cpdbGetCurrent(m_printerObj, CPDB_OPTION_JOB_SHEETS); + if (!currentSetting.contains(',')) // JobSheets option setting must be in format + return false; + QByteArray newSetting = choice + "," + currentSetting.split(',')[1]; + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_SHEETS, newSetting); + return true; + } + + if (key == QPrintDevice::PDPK_JobEndCoverPage) { + auto choice = qvariant_cast(value); + QByteArray currentSetting = cpdbGetCurrent(m_printerObj, CPDB_OPTION_JOB_SHEETS); + if (!currentSetting.contains(',')) // JobSheets option setting must be in format + return false; + QByteArray newSetting = currentSetting.split(',')[0] + "," + choice; + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_SHEETS, newSetting); + return true; + } + + if (key == QPrintDevice::PDPK_AdvancedOptions) { + if (value.canConvert() && value.toByteArray() == "#clear#") { + GList *keys = g_hash_table_get_keys(m_printerObj->settings->table); + GList *iter = keys; + while (iter != NULL) { + const char *key = (const char *) iter->data; + if (!m_nonAdvancedOptions.contains(QByteArray(key))) + cpdbClearSettingFromPrinter(m_printerObj, key); + iter = iter->next; + } + g_list_free(keys); + return true; + } + auto setting = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, setting.name, setting.choice); + return true; + } + + if (key == QPrintDevice::PDPK_NumberUp) { + auto choice = qvariant_cast(value); + if (!choice.contains('x')) { + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP, choice); + return true; + } else if (QCPDBSupport::numUpDist.contains(choice)) { + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP, QCPDBSupport::numUpDist.value(choice)); + return true; + } + return false; + } + + if (key == QPrintDevice::PDPK_NumberUpLayout) { + auto choice = qvariant_cast(value); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT, choice); + return true; + } + + if (key == QPrintDevice::PDPK_PageSize) { + auto choice = qvariant_cast(value); + if (choice != "#custom#") { + cpdbClearSetting(m_printerObj->settings, CPDB_OPTION_MEDIA_COL); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_MEDIA, choice); + } + return true; + } + + if (key == QPrintDevice::PDPK_PageLayout) { + auto choice = qvariant_cast(value); + + int width = choice.size.width() * 100.0; + int height = choice.size.height() * 100.0; + int left = choice.margins.left() * 100.0; + int right = choice.margins.right() * 100.0; + int top = choice.margins.top() * 100.0; + int bottom = choice.margins.bottom() * 100.0; + + QString mediaCol = QStringLiteral("{media-size={x-dimension=%1 y-dimension=%2} media-bottom-margin=%3" + " media-left-margin=%4 media-right-margin=%5 media-top-margin=%6}") + .arg(width).arg(height).arg(bottom).arg(left).arg(right).arg(top); + + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_MEDIA_COL, mediaCol.toLocal8Bit().constData()); + return true; + } + + return QPlatformPrintDevice::setProperty(key, value); +} diff --git a/src/plugins/printsupport/cpdb/qcpdbprintdevice.h b/src/plugins/printsupport/cpdb/qcpdbprintdevice.h new file mode 100644 index 000000000000..53e4cbc43eb2 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintdevice.h @@ -0,0 +1,100 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QCPDBPRINTDEVICE_H +#define QCPDBPRINTDEVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QCpdbPrintDevice : public QPlatformPrintDevice +{ +public: + explicit QCpdbPrintDevice(cpdb_printer_obj_t * const printerObj); + virtual ~QCpdbPrintDevice(); + + bool isValid() const override; + bool isDefault() const override; + + QPrint::DeviceState state() const override; + + QPageSize defaultPageSize() const override; + + QMarginsF printableMargins(const QPageSize &pageSize, QPageLayout::Orientation orientation, + int resolution) const override; + + int defaultResolution() const override; + + QPrint::InputSlot defaultInputSlot() const override; + + QPrint::OutputBin defaultOutputBin() const override; + + QPrint::DuplexMode defaultDuplexMode() const override; + + QPrint::ColorMode defaultColorMode() const override; + + QVariant property(QPrintDevice::PrintDevicePropertyKey key) const override; + bool setProperty(QPrintDevice::PrintDevicePropertyKey key, const QVariant &value) override; + bool isFeatureAvailable(QPrintDevice::PrintDevicePropertyKey key, const QVariant ¶ms) const override; + +protected: + void loadPageSizes() const override; + void loadResolutions() const override; + void loadInputSlots() const override; + void loadOutputBins() const override; + void loadDuplexModes() const override; + void loadColorModes() const override; +#if QT_CONFIG(mimetype) + void loadMimeTypes() const override; +#endif + +private: + cpdb_printer_obj_t *m_printerObj; + // options exlcuded from the advanced tab in print properties dialog, + // because they have been displayed elsewhere in the dialog + const QSet m_nonAdvancedOptions{ + CPDB_OPTION_PAGE_RANGES, + CPDB_OPTION_PAGE_SET, + CPDB_OPTION_COPIES, + CPDB_OPTION_PAGE_DELIVERY, + CPDB_OPTION_COLLATE, + CPDB_OPTION_SIDES, + CPDB_OPTION_COLOR_MODE, + CPDB_OPTION_MEDIA, + CPDB_OPTION_ORIENTATION, + CPDB_OPTION_MARGIN_LEFT, + CPDB_OPTION_MARGIN_RIGHT, + CPDB_OPTION_MARGIN_TOP, + CPDB_OPTION_MARGIN_BOTTOM, + CPDB_OPTION_NUMBER_UP, + CPDB_OPTION_NUMBER_UP_LAYOUT, + CPDB_OPTION_JOB_HOLD_UNTIL, + CPDB_OPTION_JOB_PRIORITY, + CPDB_OPTION_BILLING_INFO, + CPDB_OPTION_JOB_SHEETS, + CPDB_OPTION_FIDELITY, + "borderless" + }; +}; + +QT_END_NAMESPACE + +#endif // QCPDBPRINTDEVICE_H diff --git a/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp b/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp new file mode 100644 index 000000000000..b644d4f01391 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp @@ -0,0 +1,232 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qcpdbprintengine_p.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "private/qcore_unix_p.h" // overrides QT_OPEN + +QT_BEGIN_NAMESPACE +extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits); + +QCpdbPrintEngine::QCpdbPrintEngine(QPrinter::PrinterMode m, const QString &deviceId) + : QPdfPrintEngine(*new QCpdbPrintEnginePrivate(m)) +{ + Q_D(QCpdbPrintEngine); + d->changePrinter(deviceId); + state = QPrinter::Idle; +} + +QCpdbPrintEngine::~QCpdbPrintEngine() = default; + +void QCpdbPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value) +{ + Q_D(QCpdbPrintEngine); + + switch (key) { + case PPK_Duplex: { + QPrint::DuplexMode mode = QPrint::DuplexMode(value.toInt()); + if (d->m_printDevice.supportedDuplexModes().contains(mode)) { + d->duplex = mode; + d->duplexRequestedExplicitly = true; + } + break; + } + case PPK_PrinterName: + d->changePrinter(value.toString()); + break; + default: + QPdfPrintEngine::setProperty(key, value); + break; + } +} + +QVariant QCpdbPrintEngine::property(PrintEnginePropertyKey key) const +{ + Q_D(const QCpdbPrintEngine); + + QVariant ret; + switch (key) { + case PPK_SupportsMultipleCopies: + ret = true; + break; + case PPK_NumberOfCopies: + ret = 1; + break; + case PPK_Duplex: + ret = d->duplex; + break; + default: + ret = QPdfPrintEngine::property(key); + break; + } + + return ret; +} + +QCpdbPrintEnginePrivate::QCpdbPrintEnginePrivate(QPrinter::PrinterMode m) + : QPdfPrintEnginePrivate(m) + , duplex(QPrint::DuplexNone) +{ +} + +QCpdbPrintEnginePrivate::~QCpdbPrintEnginePrivate() +{ +} + +bool QCpdbPrintEnginePrivate::openPrintDevice() +{ + if (outDevice) + return false; + + if (!outputFileName.isEmpty()) { + QFile *file = new QFile(outputFileName); + if (!file->open(QFile::WriteOnly|QFile::Truncate)) { + delete file; + return false; + } + outDevice = file; + } else { + cpdbTempFile = new QTemporaryFile(); + if (!cpdbTempFile->open()) { + delete cpdbTempFile; + cpdbTempFile = nullptr; + return false; + } + outDevice = cpdbTempFile; + } + + return true; +} + +void QCpdbPrintEnginePrivate::closePrintDevice() +{ + if (!cpdbTempFile) { + QPdfPrintEnginePrivate::closePrintDevice(); + } else { + cpdbTempFile->close(); + + // Should never have got here without a printer, but check anyway + if (printerName.isEmpty()) { + qWarning("Could not determine printer to print to"); + delete cpdbTempFile; + outDevice = nullptr; + return; + } + + // Set up print options. + QList> options; + + options.append({CPDB_OPTION_MEDIA, m_pageLayout.pageSize().key().toLocal8Bit()}); + + if (copies > 1) { + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_COPIES, + QString::number(copies).toLocal8Bit().constData()); + if (collate) + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_COLLATE, CPDB_COLLATE_ENABLED); + else + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_COLLATE, CPDB_COLLATE_DISABLED); + } + + switch (pageOrder) { + case QPrinter::FirstPageFirst: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_PAGE_DELIVERY, CPDB_PAGE_DELIVERY_SAME); + break; + case QPrinter::LastPageFirst: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_PAGE_DELIVERY, CPDB_PAGE_DELIVERY_REVERSE); + break; + } + + switch (duplex) { + case QPrint::DuplexNone: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_SIDES, CPDB_SIDES_ONE_SIDED); + break; + case QPrint::DuplexLongSide: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_SIDES, CPDB_SIDES_TWO_SIDED_LONG); + break; + case QPrint::DuplexShortSide: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_SIDES, CPDB_SIDES_TWO_SIDED_SHORT); + break; + case QPrint::DuplexAuto: + if (m_pageLayout.orientation() == QPageLayout::Portrait) + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_SIDES, CPDB_SIDES_TWO_SIDED_LONG); + else + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_SIDES, CPDB_SIDES_TWO_SIDED_SHORT); + break; + } + + switch (m_pageLayout.orientation()) { + case QPageLayout::Portrait: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_ORIENTATION, CPDB_ORIENTATION_PORTRAIT); + break; + case QPageLayout::Landscape: + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_ORIENTATION, CPDB_ORIENTATION_LANDSCAPE); + break; + } + + // Print the file + cpdbPrintFile(m_printerObj, cpdbTempFile->fileName().toLocal8Bit().constData()); + + delete cpdbTempFile; + outDevice = cpdbTempFile = nullptr; + } +} + +void QCpdbPrintEnginePrivate::changePrinter(const QString &newPrinter) +{ + // Don't waste time if same printer name + if (newPrinter == printerName) + return; + + // Should never have reached here if no plugin available, but check just in case + QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get(); + if (!ps) + return; + + // Try create the printer, only use it if it returns valid + QPrintDevice printDevice = ps->createPrintDevice(newPrinter); + if (!printDevice.isValid()) + return; + + m_printDevice.swap(printDevice); + m_printerObj = qvariant_cast(m_printDevice.property(PDPK_CpdbPrinterObj)); + printerName = m_printDevice.id(); + + // in case a duplex value was explicitly set, check if new printer supports current value, + // otherwise use device default + if (!duplexRequestedExplicitly || !m_printDevice.supportedDuplexModes().contains(duplex)) { + duplex = m_printDevice.defaultDuplexMode(); + duplexRequestedExplicitly = false; + } + +// QPrint::ColorMode colorMode = grayscale ? QPrint::GrayScale : QPrint::Color; +// if (!m_printDevice.supportedColorModes().contains(colorMode)) +// grayscale = (m_printDevice.defaultColorMode() == QPrint::GrayScale); + + // Get the equivalent page size for this printer as supported names may be different + if (m_printDevice.supportedPageSize(m_pageLayout.pageSize()).isValid()) + setPageSize(m_pageLayout.pageSize()); + else + setPageSize(QPageSize(m_pageLayout.pageSize().size(QPageSize::Millimeter), QPageSize::Millimeter)); +} + +void QCpdbPrintEnginePrivate::setPageSize(const QPageSize &pageSize) +{ + if (pageSize.isValid()) { + // Find if the requested page size has a matching printer page size, if so use its defined name instead + QPageSize printerPageSize = m_printDevice.supportedPageSize(pageSize); + QPageSize usePageSize = printerPageSize.isValid() ? printerPageSize : pageSize; + QMarginsF printable = m_printDevice.printableMargins(usePageSize, m_pageLayout.orientation(), resolution); + m_pageLayout.setPageSize(usePageSize, qt_convertMargins(printable, QPageLayout::Point, m_pageLayout.units())); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h b/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h new file mode 100644 index 000000000000..9191284e085c --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h @@ -0,0 +1,74 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QCPDBPRINTENGINE_H +#define QCPDBPRINTENGINE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "QtPrintSupport/qprintengine.h" + +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QCpdbPrintEnginePrivate; + +class QCpdbPrintEngine : public QPdfPrintEngine +{ + Q_DECLARE_PRIVATE(QCpdbPrintEngine) +public: + QCpdbPrintEngine(QPrinter::PrinterMode m, const QString &deviceId); + virtual ~QCpdbPrintEngine(); + + // reimplementations QPdfPrintEngine + void setProperty(PrintEnginePropertyKey key, const QVariant &value) override; + QVariant property(PrintEnginePropertyKey key) const override; + // end reimplementations QPdfPrintEngine + +private: + Q_DISABLE_COPY_MOVE(QCpdbPrintEngine) +}; + +class QCpdbPrintEnginePrivate : public QPdfPrintEnginePrivate +{ + Q_DECLARE_PUBLIC(QCpdbPrintEngine) +public: + QCpdbPrintEnginePrivate(QPrinter::PrinterMode m); + ~QCpdbPrintEnginePrivate(); + + bool openPrintDevice() override; + void closePrintDevice() override; + +private: + Q_DISABLE_COPY_MOVE(QCpdbPrintEnginePrivate) + + void changePrinter(const QString &newPrinter); + void setPageSize(const QPageSize &pageSize); + + QPrintDevice m_printDevice; + cpdb_printer_obj_t *m_printerObj = nullptr; + QTemporaryFile *cpdbTempFile = nullptr; + QPrint::DuplexMode duplex; + bool duplexRequestedExplicitly = false; +}; + +QT_END_NAMESPACE + +#endif // QCPDBPRINTENGINE_H diff --git a/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp b/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp new file mode 100644 index 000000000000..102df3fd48db --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qcpdbprintersupport_p.h" + +#include "qcpdbprintengine_p.h" +#include "qcpdbprintdevice.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +extern "C" { + +static void printerUpdateCallback(cpdb_frontend_obj_t *frontendObj, cpdb_printer_obj_t *printerObj, cpdb_printer_update_t change) +{ + Q_UNUSED(frontendObj); + + switch (change) { + case CPDB_CHANGE_PRINTER_REMOVED: + cpdbDeletePrinterObj(printerObj); + break; + default: + break; + } +} + +} // extern "C" + +QCpdbPrinterSupport::QCpdbPrinterSupport() + : QPlatformPrinterSupport() +{ + cpdbInit(); + cpdb_printer_callback printerCb = static_cast(printerUpdateCallback); + + QByteArray instanceName = "Qt"; + frontendObj = cpdbGetNewFrontendObj(instanceName.constData(), printerCb); + cpdbIgnoreLastSavedSettings(frontendObj); + cpdbConnectToDBus(frontendObj); +} + +QCpdbPrinterSupport::~QCpdbPrinterSupport() +{ + cpdbDeleteFrontendObj(frontendObj); +} + +QPrintEngine *QCpdbPrinterSupport::createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId) +{ + return new QCpdbPrintEngine(printerMode, (deviceId.isEmpty() ? defaultPrintDeviceId() : deviceId)); +} + +QPaintEngine *QCpdbPrinterSupport::createPaintEngine(QPrintEngine *engine, QPrinter::PrinterMode printerMode) +{ + Q_UNUSED(printerMode); + return static_cast(engine); +} + +QPrintDevice QCpdbPrinterSupport::createPrintDevice(const QString &id) +{ + GHashTableIter iter; + gpointer key, value; + cpdb_printer_obj_t *printerObj = nullptr; + g_hash_table_iter_init(&iter, frontendObj->printer); + while (g_hash_table_iter_next(&iter, &key, &value)) { + cpdb_printer_obj_t *printerObjIter = static_cast(value); + if (id == printerObjIter->id) { + printerObj = printerObjIter; + break; + } + } + return QPlatformPrinterSupport::createPrintDevice(new QCpdbPrintDevice(printerObj)); +} + +QStringList QCpdbPrinterSupport::availablePrintDeviceIds() const +{ + QStringList list; + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init (&iter, frontendObj->printer); + while (g_hash_table_iter_next(&iter, &key, &value)) { + auto printerObj = static_cast(value); + // Ignore CPDB FILE backend, since we are using Qt's native "Print To File (PDF)" printer + if (qstrcmp(printerObj->backend_name, "FILE") != 0) + list << printerObj->id; + } + return list; +} + +QString QCpdbPrinterSupport::defaultPrintDeviceId() const +{ + if (cpdb_printer_obj_t *printerObj = cpdbGetDefaultPrinter(frontendObj)) + return QString(printerObj->id); + + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h b/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h new file mode 100644 index 000000000000..b5ef41938913 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h @@ -0,0 +1,45 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QCPDBPRINTERSUPPORT_H +#define QCPDBPRINTERSUPPORT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QCpdbPrinterSupport : public QPlatformPrinterSupport +{ +public: + QCpdbPrinterSupport(); + ~QCpdbPrinterSupport(); + + QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode p, const QString &deviceId = QString()) override; + QPaintEngine *createPaintEngine(QPrintEngine *printEngine, QPrinter::PrinterMode) override; + + QPrintDevice createPrintDevice(const QString &id) override; + QStringList availablePrintDeviceIds() const override; + QString defaultPrintDeviceId() const override; + + cpdb_frontend_obj_t *frontendObj; + +private: + +}; + +QT_END_NAMESPACE + +#endif // QCPDBPRINTERSUPPORT_H diff --git a/src/plugins/printsupport/cups/CMakeLists.txt b/src/plugins/printsupport/cups/CMakeLists.txt index 6811fca10a20..aef48adffb60 100644 --- a/src/plugins/printsupport/cups/CMakeLists.txt +++ b/src/plugins/printsupport/cups/CMakeLists.txt @@ -17,6 +17,7 @@ qt_internal_add_plugin(QCupsPrinterSupportPlugin PLUGIN_TYPE printsupport SOURCES main.cpp + qcups.cpp qcups_p.h qcupsprintengine.cpp qcupsprintengine_p.h qcupsprintersupport.cpp qcupsprintersupport_p.h qppdprintdevice.cpp qppdprintdevice.h diff --git a/src/plugins/printsupport/cups/cups.json b/src/plugins/printsupport/cups/cups.json index f578375d091e..b6070be5deda 100644 --- a/src/plugins/printsupport/cups/cups.json +++ b/src/plugins/printsupport/cups/cups.json @@ -1,3 +1,4 @@ { - "Keys": [ "cupsprintersupport" ] + "Keys": [ "cupsprintersupport" ], + "Priority": 50 } diff --git a/src/printsupport/kernel/qcups.cpp b/src/plugins/printsupport/cups/qcups.cpp similarity index 92% rename from src/printsupport/kernel/qcups.cpp rename to src/plugins/printsupport/cups/qcups.cpp index 231b81649906..5588370fd8a0 100644 --- a/src/printsupport/kernel/qcups.cpp +++ b/src/plugins/printsupport/cups/qcups.cpp @@ -253,4 +253,28 @@ void QCUPSSupport::setPageRange(QPrinter *printer, const QString &pageRange) setCupsOption(printer, QStringLiteral("page-ranges"), pageRange); } +bool QCUPSSupport::isBlacklistedGroup(const ppd_group_t *group) noexcept +{ + return qstrcmp(group->name, "InstallableOptions") == 0; +} + +bool QCUPSSupport::isBlacklistedOption(const char *keyword) noexcept +{ + // We already let the user set these options elsewhere + const char *cupsOptionBlacklist[] = { + "Collate", + "Copies", + "OutputOrder", + "PageRegion", + "PageSize", + "Duplex" // handled by the main dialog + }; + auto equals = [](const char *keyword) { + return [keyword](const char *candidate) { + return qstrcmp(keyword, candidate) == 0; + }; + }; + return std::any_of(std::begin(cupsOptionBlacklist), std::end(cupsOptionBlacklist), equals(keyword)); +} + QT_END_NAMESPACE diff --git a/src/printsupport/kernel/qcups_p.h b/src/plugins/printsupport/cups/qcups_p.h similarity index 97% rename from src/printsupport/kernel/qcups_p.h rename to src/plugins/printsupport/cups/qcups_p.h index 4570935ba17e..5933d4e0efb6 100644 --- a/src/printsupport/kernel/qcups_p.h +++ b/src/plugins/printsupport/cups/qcups_p.h @@ -22,8 +22,6 @@ #include "QtPrintSupport/qprinter.h" #include "QtCore/qdatetime.h" -QT_REQUIRE_CONFIG(cups); - QT_BEGIN_NAMESPACE class QPrintDevice; @@ -42,7 +40,7 @@ class QPrintDevice; #define PDPK_CupsJobHoldUntil QPrintDevice::PrintDevicePropertyKey(QPrintDevice::PDPK_CustomBase + 5) #define PDPK_PpdChoiceIsInstallableConflict QPrintDevice::PrintDevicePropertyKey(QPrintDevice::PDPK_CustomBase + 6) -class Q_PRINTSUPPORT_EXPORT QCUPSSupport +class QCUPSSupport { public: // Enum for values of job-hold-until option @@ -111,6 +109,9 @@ class Q_PRINTSUPPORT_EXPORT QCUPSSupport static void setPageRange(QPrinter *printer, int pageFrom, int pageTo); static void setPageRange(QPrinter *printer, const QString &pageRange); + static bool isBlacklistedGroup(const ppd_group_t *group) noexcept; + static bool isBlacklistedOption(const char *keyword) noexcept; + struct JobSheets { JobSheets(BannerPage s = NoBanner, BannerPage e = NoBanner) diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp index 97e51b17b041..e3908566d74b 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine.cpp +++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp @@ -10,7 +10,7 @@ #include #include #include -#include "private/qcups_p.h" // Only needed for PPK_CupsOptions +#include "qcups_p.h" // Only needed for PPK_CupsOptions #include #include diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp index 95813c90fa75..c3bc8d019f96 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.cpp +++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp @@ -4,12 +4,14 @@ #include "qppdprintdevice.h" #include "qcupsprintersupport_p.h" -#include "private/qcups_p.h" // Only needed for PDPK_* +#include "qcups_p.h" // Only needed for PDPK_* #if QT_CONFIG(mimetype) #include #endif +#include + #ifndef QT_LINUXBASE // LSB merges everything into cups.h #include #endif @@ -410,28 +412,342 @@ QPrint::ColorMode QPpdPrintDevice::defaultColorMode() const QVariant QPpdPrintDevice::property(QPrintDevice::PrintDevicePropertyKey key) const { - if (key == PDPK_PpdFile) + if (key == PDPK_PpdFile) { return QVariant::fromValue(m_ppd); - else if (key == PDPK_CupsJobPriority) - return printerOption(QStringLiteral("job-priority")); - else if (key == PDPK_CupsJobSheets) - return printerOption(QStringLiteral("job-sheets")); - else if (key == PDPK_CupsJobBilling) - return printerOption(QStringLiteral("job-billing")); - else if (key == PDPK_CupsJobHoldUntil) - return printerOption(QStringLiteral("job-hold-until")); + } + + if (key == QPrintDevice::PDPK_PageSet) { + QPrint::OptionCombo option; + option.name = "page-set"; + option.displayName = QPrintDialog::tr("Page Set"); + option.choices + << "all" + << "odd" + << "even"; + option.displayChoices + << QPrintDialog::tr("All Pages") + << QPrintDialog::tr("Odd Pages") + << QPrintDialog::tr("Even Pages"); + option.defaultChoice = 0; + return QVariant::fromValue(option); + } + + if (key == QPrintDevice::PDPK_JobHold) { + QPrint::OptionCombo option; + option.name = "job-hold-until"; + option.choices + << "no-hold" + << "indefinite" + << "day-time" + << "night" + << "second-shift" + << "third-shift" + << "weekend"; + option.displayChoices + << QPrintDialog::tr("Print Immediately") + << QPrintDialog::tr("Hold Indefinitely") + << QPrintDialog::tr("Day (06:00 to 17:59)") + << QPrintDialog::tr("Night (18:00 to 05:59)") + << QPrintDialog::tr("Second Shift (16:00 to 23:59)") + << QPrintDialog::tr("Third Shift (00:00 to 07:59)") + << QPrintDialog::tr("Weekend (Saturday to Sunday)") + << QPrintDialog::tr("Specific Time"); + + QByteArray defaultVal = printerOption(QString(option.name)).toUtf8(); + option.defaultChoice = qMax(option.choices.indexOf(defaultVal), 0); + return QVariant::fromValue(option); + } + + if (key == QPrintDevice::PDPK_JobBillingInfo) { + return QVariant::fromValue(printerOption(QStringLiteral("job-billing"))); + } + + if (key == QPrintDevice::PDPK_JobPriority) { + bool ok; + int defaultVal = printerOption(QStringLiteral("job-priority")).toInt(&ok); + if (!ok || defaultVal > 100 || defaultVal < 0) + defaultVal = 50; + return QVariant(defaultVal); + } + + if (key == QPrintDevice::PDPK_JobStartCoverPage) { + QPrint::OptionCombo option; + option.name = "job-sheets"; + option.choices + << "none" + << "standard" + << "unclassified" + << "confidential" + << "classified" + << "secret" + << "topsecret"; + option.displayChoices + << QPrintDialog::tr("None", "CUPS Banner page") + << QPrintDialog::tr("Standard", "CUPS Banner page") + << QPrintDialog::tr("Unclassified", "CUPS Banner page") + << QPrintDialog::tr("Confidential", "CUPS Banner page") + << QPrintDialog::tr("Classified", "CUPS Banner page") + << QPrintDialog::tr("Secret", "CUPS Banner page") + << QPrintDialog::tr("Top Secret", "CUPS Banner page"); + + QByteArray defaultVal = printerOption(QString(option.name)).toUtf8(); + option.defaultChoice = qMax(option.choices.indexOf(defaultVal), 0); + return QVariant::fromValue(option); + } + + if (key == QPrintDevice::PDPK_JobEndCoverPage) { + QPrint::OptionCombo option; + option.name = "job-sheets"; + option.choices + << "none" + << "standard" + << "unclassified" + << "confidential" + << "classified" + << "secret" + << "topsecret"; + option.displayChoices + << QPrintDialog::tr("None", "CUPS Banner page") + << QPrintDialog::tr("Standard", "CUPS Banner page") + << QPrintDialog::tr("Unclassified", "CUPS Banner page") + << QPrintDialog::tr("Confidential", "CUPS Banner page") + << QPrintDialog::tr("Classified", "CUPS Banner page") + << QPrintDialog::tr("Secret", "CUPS Banner page") + << QPrintDialog::tr("Top Secret", "CUPS Banner page"); + + QByteArray defaultVal = printerOption(QString(option.name)).toUtf8(); + option.defaultChoice = qMax(option.choices.indexOf(defaultVal), 0); + return QVariant::fromValue(option); + } + + if (key == QPrintDevice::PDPK_AdvancedOptions) { + QList optionsGroups; + if (!m_ppd) + return QVariant::fromValue(optionsGroups); + + auto toUnicode = QStringDecoder(m_ppd->lang_encoding, QStringDecoder::Flag::Stateless); + if (!toUnicode.isValid()) { + qWarning() << "QPrinSupport: Cups uses unsupported encoding" << m_ppd->lang_encoding; + toUnicode = QStringDecoder(QStringDecoder::Utf8, QStringDecoder::Flag::Stateless); + } + for (int i = 0; i < m_ppd->num_groups; ++i) { + + const ppd_group_t *group = &m_ppd->groups[i]; + if (QCUPSSupport::isBlacklistedGroup(group)) + continue; + + QPrint::OptionCombosGroup optionsGroup; + optionsGroup.groupName = group->name; + optionsGroup.displayGroup = toUnicode(group->text); + + for (int i = 0; i < group->num_options; ++i) { + const ppd_option_t *option = &group->options[i]; + + if (QCUPSSupport::isBlacklistedOption(option->keyword) || option->num_choices <= 1) + continue; + + QPrint::OptionCombo optionCombo; + optionCombo.name = option->keyword; + optionCombo.displayName = option->text; + + optionCombo.choices.reserve(option->num_choices); + optionCombo.displayChoices.reserve(option->num_choices); + optionCombo.defaultChoice = -1; + + bool foundMarkedChoice = false; + bool markedChoiceNotAvailable = false; + for (int i = 0; i < option->num_choices; ++i) { + const ppd_choice_t *choice = &option->choices[i]; + const bool choiceIsInstallableConflict = ppdInstallableConflict(m_ppd, option->keyword, choice->choice); + if (choiceIsInstallableConflict && static_cast(choice->marked) == 1) { + markedChoiceNotAvailable = true; + } else if (!choiceIsInstallableConflict) { + optionCombo.choices.push_back(choice->choice); + optionCombo.displayChoices.push_back(toUnicode(choice->text)); + if (static_cast(choice->marked) == 1) { + optionCombo.defaultChoice = optionCombo.choices.size() - 1; + foundMarkedChoice = true; + } else if (!foundMarkedChoice && qstrcmp(choice->choice, option->defchoice) == 0) { + optionCombo.defaultChoice = optionCombo.choices.size() - 1; + } + } + } + + if (markedChoiceNotAvailable) { + // If the user default option is not available because of it conflicting with + // the installed options, we need to set the internal ppd value to the value + // being shown in the combo + optionCombo.defaultChoice = qMax(optionCombo.defaultChoice, 0); + ppdMarkOption(m_ppd, optionCombo.name, optionCombo.choices[optionCombo.defaultChoice]); + } + + optionsGroup.options.push_back(optionCombo); + } + optionsGroups.push_back(optionsGroup); + } + return QVariant::fromValue(optionsGroups); + } + + if (key == QPrintDevice::PDPK_OptionConflict) { + QByteArray pagesPerSheet = this->getCupsOption(QStringLiteral("number-up")).toUtf8(); + QByteArray pageSet = this->getCupsOption(QStringLiteral("page-set")).toUtf8(); + if (pagesPerSheet != "1x1" && pageSet != "all") + return QVariant(QPrintDialog::tr("Options 'Pages Per Sheet' and 'Page Set' cannot be used together.\nPlease turn one of those options off.")); + + return QVariant::fromValue(nullptr); + } + + if (key == QPrintDevice::PDPK_NumberUp) { + QPrint::OptionCombo option; + option.name = "number-up"; + option.choices + << "1x1" + << "2x1" + << "2x2" + << "2x3" + << "3x3" + << "4x4"; + option.displayChoices + << QPrintDialog::tr("1 (1x1)") + << QPrintDialog::tr("2 (2x1)") + << QPrintDialog::tr("4 (2x2)") + << QPrintDialog::tr("6 (2x3)") + << QPrintDialog::tr("9 (3x3)") + << QPrintDialog::tr("16 (4x4)"); + + option.defaultChoice = 0; + return QVariant::fromValue(option); + } + if (key == QPrintDevice::PDPK_NumberUpLayout) { + QPrint::OptionCombo option; + option.name = "number-up-layout"; + option.choices + << "lrtb" + << "lrbt" + << "rlbt" + << "rltb" + << "btlr" + << "btrl" + << "tblr" + << "tbrl"; + option.displayChoices + << QPrintDialog::tr("Left to Right, Top to Bottom") + << QPrintDialog::tr("Left to Right, Bottom to Top") + << QPrintDialog::tr("Right to Left, Bottom to Top") + << QPrintDialog::tr("Right to Left, Top to Bottom") + << QPrintDialog::tr("Bottom to Top, Left to Right") + << QPrintDialog::tr("Bottom to Top, Right to Left") + << QPrintDialog::tr("Top to Bottom, Left to Right") + << QPrintDialog::tr("Top to Bottom, Right to Left"); + + option.defaultChoice = 0; + return QVariant::fromValue(option); + } return QPlatformPrintDevice::property(key); } bool QPpdPrintDevice::setProperty(QPrintDevice::PrintDevicePropertyKey key, const QVariant &value) { - if (key == PDPK_PpdOption) { - const QStringList values = value.toStringList(); - if (values.size() == 2) { - ppdMarkOption(m_ppd, values[0].toLatin1(), values[1].toLatin1()); + if (key == QPrintDevice::PDPK_Duplex) { + auto choice = qvariant_cast(value); + bool marked = false; + if (choice == QPrint::DuplexNone) { + ppdMarkOption(m_ppd, "Duplex", "None"); + marked = true; + } else if (choice == QPrint::DuplexLongSide) { + ppdMarkOption(m_ppd, "Duplex", "DuplexNoTumble"); + marked = true; + } else if (choice == QPrint::DuplexShortSide) { + ppdMarkOption(m_ppd, "Duplex", "DuplexTumble"); + marked = true; + } + return marked; + } + + if (key == QPrintDevice::PDPK_PageSet) { + auto choice = qvariant_cast(value); + setCupsOption(QStringLiteral("page-set"), choice); + return true; + } + + if (key == QPrintDevice::PDPK_PageRange) { + auto choice = qvariant_cast(value); + setCupsOption(QStringLiteral("page-ranges"), choice); + return true; + } + + if (key == QPrintDevice::PDPK_JobHold) { + auto choice = qvariant_cast(value); + setCupsOption(QStringLiteral("job-hold-until"), choice); + return true; + } + + if (key == QPrintDevice::PDPK_JobBillingInfo) { + auto choice = qvariant_cast(value); + setCupsOption(QStringLiteral("job-billing"), choice); + return true; + } + + if (key == QPrintDevice::PDPK_JobPriority) { + int priority = qvariant_cast(value); + setCupsOption(QStringLiteral("job-priority"), QString::number(priority)); + return true; + } + + if (key == QPrintDevice::PDPK_JobStartCoverPage) { + auto choice = qvariant_cast(value); + QString currentSetting = this->getCupsOption(QStringLiteral("job-sheets")); + if (!currentSetting.contains(u',')) { + QString defaultSheet = printerOption(QStringLiteral("job-sheets")); + currentSetting = defaultSheet + u',' + defaultSheet; + } + QString newSetting = choice + u',' + currentSetting.split(u',')[1]; + setCupsOption(QStringLiteral("job-sheets"), newSetting); + return true; + } + + if (key == QPrintDevice::PDPK_JobEndCoverPage) { + auto choice = qvariant_cast(value); + QString currentSetting = this->getCupsOption(QStringLiteral("job-sheets")); + if (!currentSetting.contains(u',')) { + QString defaultSheet = printerOption(QStringLiteral("job-sheets")); + currentSetting = defaultSheet + u',' + defaultSheet; + } + QString newSetting = currentSetting.split(u',')[0] + u',' + choice; + setCupsOption(QStringLiteral("job-sheets"), newSetting.toUtf8()); + return true; + } + + if (key == QPrintDevice::PDPK_AdvancedOptions) { + if (value.canConvert() && value.toByteArray() == "#clear#") { + m_cupsOptions = QStringList(); return true; } + auto setting = qvariant_cast(value); + ppdMarkOption(m_ppd, setting.name, setting.choice); + return true; + } + + if (key == QPrintDevice::PDPK_NumberUp) { + auto choice = qvariant_cast(value); + setCupsOption(QStringLiteral("number-up"), choice); + } + + if (key == QPrintDevice::PDPK_NumberUpLayout) { + auto choice = qvariant_cast(value); + setCupsOption(QStringLiteral("number-up-layout"), choice); + return true; + } + + if (key == QPrintDevice::PDPK_PageSize) { + auto choice = qvariant_cast(value); + if (choice == "#custom#") { + ppdMarkOption(m_ppd, "PageSize", "Custom"); + } else { + ppdMarkOption(m_ppd, "PageSize", choice); + } + return true; } return QPlatformPrintDevice::setProperty(key, value); @@ -439,10 +755,41 @@ bool QPpdPrintDevice::setProperty(QPrintDevice::PrintDevicePropertyKey key, cons bool QPpdPrintDevice::isFeatureAvailable(QPrintDevice::PrintDevicePropertyKey key, const QVariant ¶ms) const { - if (key == PDPK_PpdChoiceIsInstallableConflict) { - const QStringList values = params.toStringList(); - if (values.size() == 2) - return ppdInstallableConflict(m_ppd, values[0].toLatin1(), values[1].toLatin1()); + if (key == QPrintDevice::PDPK_Duplex) { + auto duplexPpdOption = findPpdOption("Duplex"); + if (params.toByteArray() == "conflict") + return (duplexPpdOption && duplexPpdOption->conflicted); + return (duplexPpdOption != nullptr); + } + + if (key == QPrintDevice::PDPK_PageSet + || key == QPrintDevice::PDPK_PageRange + || key == QPrintDevice::PDPK_JobHold + || key == QPrintDevice::PDPK_JobBillingInfo + || key == QPrintDevice::PDPK_JobPriority + || key == QPrintDevice::PDPK_JobStartCoverPage + || key == QPrintDevice::PDPK_JobEndCoverPage + || key == QPrintDevice::PDPK_AdvancedOptions + || key == QPrintDevice::PDPK_NumberUp + || key == QPrintDevice::PDPK_NumberUpLayout + || key == QPrintDevice::PDPK_AdvancedColorMode) { + return true; + } + + if (key == QPrintDevice::PDPK_AdvancedOptions) { + return (m_ppd != nullptr); + } + + if (key == QPrintDevice::PDPK_OptionConflict) { + auto setting = qvariant_cast(params); + return ppdInstallableConflict(m_ppd, setting.name, setting.choice); + } + + if (key == QPrintDevice::PDPK_PageSize) { + auto pageSizePpdOption = findPpdOption("PageSize"); + if (params.toByteArray() == "conflict") + return (pageSizePpdOption && pageSizePpdOption->conflicted); + return (pageSizePpdOption != nullptr); } return QPlatformPrintDevice::isFeatureAvailable(key, params); @@ -466,11 +813,47 @@ void QPpdPrintDevice::loadMimeTypes() const } #endif +void QPpdPrintDevice::setCupsOption(const QString &option, const QString &value) +{ + if (m_cupsOptions.contains(option)) { + m_cupsOptions.replace(m_cupsOptions.indexOf(option) + 1, value); + } else { + m_cupsOptions.append(option); + m_cupsOptions.append(value); + } +} + +QString QPpdPrintDevice::getCupsOption(const QString &option) const +{ + if (m_cupsOptions.contains(option)) { + return m_cupsOptions.at(m_cupsOptions.indexOf(option) + 1); + } + return QString(); +} + QString QPpdPrintDevice::printerOption(const QString &key) const { return cupsGetOption(key.toUtf8(), m_cupsDest->num_options, m_cupsDest->options); } +ppd_option_t *QPpdPrintDevice::findPpdOption(const char *optionName) const +{ + if (m_ppd) { + for (int i = 0; i < m_ppd->num_groups; ++i) { + ppd_group_t *group = &m_ppd->groups[i]; + + for (int i = 0; i < group->num_options; ++i) { + ppd_option_t *option = &group->options[i]; + + if (qstrcmp(option->keyword, optionName) == 0) + return option; + } + } + } + + return nullptr; +} + cups_ptype_e QPpdPrintDevice::printerTypeFlags() const { return static_cast(printerOption("printer-type").toUInt()); diff --git a/src/plugins/printsupport/cups/qppdprintdevice.h b/src/plugins/printsupport/cups/qppdprintdevice.h index ea8f5f2768f5..9025a3129572 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.h +++ b/src/plugins/printsupport/cups/qppdprintdevice.h @@ -68,13 +68,17 @@ class QPpdPrintDevice : public QPlatformPrintDevice #endif private: + QString getCupsOption(const QString &option) const; + void setCupsOption(const QString &option, const QString &value); QString printerOption(const QString &key) const; + ppd_option_t *findPpdOption(const char *optionName) const; cups_ptype_e printerTypeFlags() const; cups_dest_t *m_cupsDest; ppd_file_t *m_ppd; QByteArray m_cupsName; QByteArray m_cupsInstance; + QStringList m_cupsOptions; QMarginsF m_customMargins; mutable QHash m_printableMargins; }; diff --git a/src/printsupport/CMakeLists.txt b/src/printsupport/CMakeLists.txt index 0e6e1cc012d4..045c1f4c0911 100644 --- a/src/printsupport/CMakeLists.txt +++ b/src/printsupport/CMakeLists.txt @@ -84,6 +84,19 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printpreviewwidget widgets/qprintpreviewwidget.cpp widgets/qprintpreviewwidget.h ) +#qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cpdb AND UNIX AND NOT APPLE +# LIBRARIES +# WrapCPDB::WrapCPDB +#) + +qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cpdbjobwidget AND UNIX AND NOT APPLE + SOURCES + LIBRARIES + WrapCPDB::WrapCPDB + ENABLE_AUTOGEN_TOOLS + uic +) + qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cups AND UNIX AND NOT APPLE SOURCES kernel/qcups.cpp kernel/qcups_p.h @@ -102,12 +115,15 @@ if(QT_FEATURE_cups AND UNIX AND NOT APPLE) qt_record_extra_third_party_dependency(PrintSupport Cups::Cups) endif() -qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cupsjobwidget AND UNIX AND NOT APPLE +qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cpdbjobwidget AND UNIX AND NOT APPLE SOURCES - widgets/qcupsjobwidget.cpp widgets/qcupsjobwidget.ui widgets/qcupsjobwidget_p.h ENABLE_AUTOGEN_TOOLS uic ) +#qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cups AND UNIX AND NOT APPLE +# SOURCES +# kernel/qcups.cpp kernel/qcups_p.h +#) qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printdialog SOURCES @@ -119,6 +135,12 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printdialog uic ) +qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printjobwidget AND UNIX AND NOT APPLE + SOURCES + widgets/qprintjobwidget.cpp widgets/qprintjobwidget.ui widgets/qprintjobwidget_p.h + +) + if(QT_FEATURE_printdialog) # Resources: set(qprintdialog_resource_files @@ -194,14 +216,12 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printdialog AND WIN3 qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printdialog AND UNIX AND NOT MACOS SOURCES dialogs/qpagesetupdialog_unix.cpp dialogs/qpagesetupdialog_unix_p.h - dialogs/qprintdialog_unix.cpp dialogs/qprintpropertieswidget.ui dialogs/qprintsettingsoutput.ui dialogs/qprintwidget.ui - NO_UNITY_BUILD_SOURCES dialogs/qprintdialog_unix.cpp # Clashes with CUPS headers INCLUDE_DIRECTORIES - ${QtBase_SOURCE_DIR}/src/plugins/printsupport/cups + ${QtBase_SOURCE_DIR}/src/plugins/printsupport/cpdb ENABLE_AUTOGEN_TOOLS uic ) diff --git a/src/printsupport/configure.cmake b/src/printsupport/configure.cmake index bdd370694a16..80954567f9a4 100644 --- a/src/printsupport/configure.cmake +++ b/src/printsupport/configure.cmake @@ -16,6 +16,9 @@ else() endif() qt_find_package(Cups PROVIDED_TARGETS Cups::Cups MODULE_NAME printsupport QMAKE_LIB cups ${mark_cups_optional}) +qt_find_package(Cups PROVIDED_TARGETS Cups::Cups MODULE_NAME printsupport QMAKE_LIB cups) +qt_find_package(WrapCPDB PROVIDED_TARGETS WrapCPDB::WrapCPDB MODULE_NAME printsupport QMAKE_LIB cpdb) + #### Tests @@ -30,17 +33,18 @@ qt_feature("cups" PUBLIC PRIVATE CONDITION Cups_FOUND AND QT_FEATURE_printer AND QT_FEATURE_datestring ) qt_feature_definition("cups" "QT_NO_CUPS" NEGATE VALUE "1") -qt_feature("cupsjobwidget" PUBLIC PRIVATE - SECTION "Widgets" - LABEL "CUPS job control widget" - CONDITION ( QT_FEATURE_buttongroup ) AND ( QT_FEATURE_calendarwidget ) AND ( QT_FEATURE_checkbox ) AND ( QT_FEATURE_combobox ) AND ( QT_FEATURE_cups ) AND ( QT_FEATURE_datetimeedit ) AND ( QT_FEATURE_groupbox ) AND ( QT_FEATURE_tablewidget ) -) -qt_feature_definition("cupsjobwidget" "QT_NO_CUPSJOBWIDGET" NEGATE VALUE "1") qt_feature("cupspassworddialog" PRIVATE SECTION "Widgets" LABEL "CUPS password dialog" CONDITION ( QT_FEATURE_dialogbuttonbox ) AND ( QT_FEATURE_formlayout ) AND ( QT_FEATURE_lineedit ) ) +qt_feature("cpdb" PUBLIC PRIVATE + SECTION "Painting" + LABEL "CPDB" + PURPOSE "Provides Common Print Dialog Backend support" + CONDITION WrapCPDB_FOUND AND QT_FEATURE_printer AND QT_FEATURE_datestring +) +qt_feature_definition("cpdb" "QT_NO_CPDB" NEGATE VALUE "1") qt_feature("printer" PUBLIC SECTION "Painting" LABEL "QPrinter" @@ -68,7 +72,22 @@ qt_feature("printpreviewdialog" PUBLIC PURPOSE "Provides a dialog for previewing and configuring page layouts for printer output." CONDITION QT_FEATURE_printpreviewwidget AND QT_FEATURE_printdialog AND QT_FEATURE_toolbar AND QT_FEATURE_formlayout ) +qt_feature("printjobwidget" PUBLIC PRIVATE + SECTION "Widgets" + LABEL "Print job control widget" + CONDITION ( QT_FEATURE_buttongroup ) AND ( QT_FEATURE_calendarwidget ) AND ( QT_FEATURE_checkbox ) AND ( QT_FEATURE_combobox ) AND ( QT_FEATURE_cups OR QT_FEATURE_cpdb ) AND ( QT_FEATURE_datetimeedit ) AND ( QT_FEATURE_groupbox ) AND ( QT_FEATURE_tablewidget ) +) +qt_feature_definition("printjobwidget" "QT_NO_PRINTJOBWIDGET" NEGATE VALUE "1") qt_feature_definition("printpreviewdialog" "QT_NO_PRINTPREVIEWDIALOG" NEGATE VALUE "1") qt_configure_add_summary_section(NAME "Qt PrintSupport") -qt_configure_add_summary_entry(ARGS "cups") qt_configure_end_summary_section() # end of "Qt PrintSupport" section + +# CPDB features (backend-agnostic flags) +qt_feature("cpdb" PUBLIC + CONDITION TRUE + LABEL "Common Print Dialog Backends support" +) +qt_feature("cpdbjobwidget" PRIVATE + CONDITION TRUE + LABEL "CPDB print job options widget" +) diff --git a/src/printsupport/dialogs/qabstractprintdialog.cpp b/src/printsupport/dialogs/qabstractprintdialog.cpp index 30276a6121f4..587145d3531c 100644 --- a/src/printsupport/dialogs/qabstractprintdialog.cpp +++ b/src/printsupport/dialogs/qabstractprintdialog.cpp @@ -287,7 +287,6 @@ void QAbstractPrintDialogPrivate::setPrinter(QPrinter *newPrinter) \endtable The printer dialog (shown above in Plastique style) enables access to common - printing properties. On X11 platforms that use the CUPS printing system, the settings for each available printer can be modified via the dialog's \uicontrol{Properties} push button. @@ -374,6 +373,8 @@ void QPrintDialog::done(int result) }, Qt::SingleShotConnection); } QDialog::done(result); + if (result == Accepted) + Q_EMIT accepted(printer()); if (d->receiverToDisconnectOnClose) { disconnect(this, SIGNAL(accepted(QPrinter*)), d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose); diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp index 6c65eafc2170..57f37ae6af93 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp +++ b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp @@ -7,9 +7,9 @@ #include #include -#if QT_CONFIG(cups) -#include -#endif +//#if QT_CONFIG(cups) +//#include +//#endif #include "qpainter.h" #include "qprintdialog.h" @@ -58,7 +58,6 @@ struct PaperSourceNames }; #endif - // QPagePreview // - Private widget to display preview of page layout // - Embedded in QPageSetupWidget @@ -124,7 +123,7 @@ class QPagePreview : public QWidget p.setFont(font); p.setPen(palette().color(QPalette::Dark)); QString text("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."_L1); - for (int i=0; i<3; ++i) + for (int i=0; i<2; ++i) text += text; const int spacing = pageRect.width() * 0.1; @@ -202,9 +201,6 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent) m_pagePreview(nullptr), m_printer(nullptr), m_printDevice(nullptr), -#if QT_CONFIG(cups) - m_pageSizePpdOption(nullptr), -#endif m_outputFormat(QPrinter::PdfFormat), m_units(QPageLayout::Point), m_savedUnits(QPageLayout::Point), @@ -235,7 +231,6 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent) m_ui.reversePortrait->setVisible(false); initUnits(); - initPagesPerSheet(); connect(m_ui.unitCombo, &QComboBox::activated, this, &QPageSetupWidget::unitChanged); @@ -271,45 +266,29 @@ void QPageSetupWidget::initUnits() // Init the Pages Per Sheet (n-up) combo boxes if using CUPS void QPageSetupWidget::initPagesPerSheet() { -#if QT_CONFIG(cups) - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Left to Right, Top to Bottom"), - QVariant::fromValue(QCUPSSupport::LeftToRightTopToBottom)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Left to Right, Bottom to Top"), - QVariant::fromValue(QCUPSSupport::LeftToRightBottomToTop)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Right to Left, Bottom to Top"), - QVariant::fromValue(QCUPSSupport::RightToLeftBottomToTop)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Right to Left, Top to Bottom"), - QVariant::fromValue(QCUPSSupport::RightToLeftTopToBottom)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Bottom to Top, Left to Right"), - QVariant::fromValue(QCUPSSupport::BottomToTopLeftToRight)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Bottom to Top, Right to Left"), - QVariant::fromValue(QCUPSSupport::BottomToTopRightToLeft)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Top to Bottom, Left to Right"), - QVariant::fromValue(QCUPSSupport::TopToBottomLeftToRight)); - m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Top to Bottom, Right to Left"), - QVariant::fromValue(QCUPSSupport::TopToBottomRightToLeft)); - - m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("1 (1x1)"), - QVariant::fromValue(QCUPSSupport::OnePagePerSheet)); - m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("2 (2x1)"), - QVariant::fromValue(QCUPSSupport::TwoPagesPerSheet)); - m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("4 (2x2)"), - QVariant::fromValue(QCUPSSupport::FourPagesPerSheet)); - m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("6 (2x3)"), - QVariant::fromValue(QCUPSSupport::SixPagesPerSheet)); - m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("9 (3x3)"), - QVariant::fromValue(QCUPSSupport::NinePagesPerSheet)); - m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("16 (4x4)"), - QVariant::fromValue(QCUPSSupport::SixteenPagesPerSheet)); - - // Set to QCUPSSupport::OnePagePerSheet - m_ui.pagesPerSheetCombo->setCurrentIndex(0); - // Set to QCUPSSupport::LeftToRightTopToBottom - m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(0); -#else - // Disable if CUPS wasn't found - m_ui.pagesPerSheetButtonGroup->hide(); -#endif + if (m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_NumberUp, QVariant())) { + m_ui.pagesPerSheetCombo->clear(); + m_ui.pagesPerSheetCombo->setVisible(true); + auto option = qvariant_cast(m_printDevice->property(QPrintDevice::PDPK_NumberUp)); + for (int i = 0; i < option.choices.size(); ++i) { + m_ui.pagesPerSheetCombo->addItem(option.displayChoices[i], QVariant::fromValue(option.choices[i])); + } + m_ui.pagesPerSheetCombo->setCurrentIndex(option.defaultChoice); + } else { + m_ui.pagesPerSheetCombo->setVisible(false); + } + + if (m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_NumberUpLayout, QVariant())) { + m_ui.pagesPerSheetLayoutCombo->clear(); + m_ui.pagesPerSheetLayoutCombo->setVisible(true); + auto option = qvariant_cast(m_printDevice->property(QPrintDevice::PDPK_NumberUpLayout)); + for (int i = 0; i < option.choices.size(); ++i) { + m_ui.pagesPerSheetLayoutCombo->addItem(option.displayChoices[i], QVariant::fromValue(option.choices[i])); + } + m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(option.defaultChoice); + } else { + m_ui.pagesPerSheetLayoutCombo->setVisible(false); + } } void QPageSetupWidget::initPageSizes() @@ -366,11 +345,6 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, m_printer = printer; m_printDevice = printDevice; -#if QT_CONFIG(cups) - // find the PageSize cups option - m_pageSizePpdOption = m_printDevice ? QCUPSSupport::findPpdOption("PageSize", m_printDevice) : nullptr; -#endif - // Initialize the layout to the current QPrinter layout m_pageLayout = m_printer->pageLayout(); @@ -386,6 +360,7 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, m_outputFormat = outputFormat; m_printerName = printerName; + initPagesPerSheet(); initPageSizes(); updateWidget(); updateSavedValues(); @@ -495,14 +470,26 @@ void QPageSetupWidget::updateWidget() void QPageSetupWidget::setupPrinter() const { m_printer->setPageLayout(m_pageLayout); + m_printer->setPageOrientation(m_pageLayout.orientation()); -#if QT_CONFIG(cups) - QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast(m_ui.pagesPerSheetCombo->currentData() -); - QCUPSSupport::PagesPerSheetLayout pagesPerSheetLayout = qvariant_cast(m_ui.pagesPerSheetLayoutCombo->currentData() -); - QCUPSSupport::setPagesPerSheetLayout(m_printer, pagesPerSheet, pagesPerSheetLayout); -#endif + + if (m_ui.pageSizeCombo->currentIndex() != m_realCustomPageSizeIndex) { + m_printDevice->setProperty(QPrintDevice::PDPK_PageSize, QVariant(m_pageLayout.pageSize().key().toLocal8Bit())); + } else { + m_printDevice->setProperty(QPrintDevice::PDPK_PageSize, QVariant(QByteArray("#custom#"))); + } + + QSizeF size = m_pageLayout.pageSize().size(QPageSize::Millimeter); + QMarginsF margins = m_pageLayout.margins(QPageLayout::Millimeter); + QPrint::PageLayout pageLayout = {size, margins}; + m_printDevice->setProperty(QPrintDevice::PDPK_PageLayout, QVariant::fromValue(pageLayout)); + + if (m_ui.pagesPerSheetCombo->isVisible()) + m_printDevice->setProperty(QPrintDevice::PDPK_NumberUp, m_ui.pagesPerSheetCombo->currentData()); + + if (m_ui.pagesPerSheetCombo->isVisible()) + m_printDevice->setProperty(QPrintDevice::PDPK_NumberUpLayout, m_ui.pagesPerSheetLayoutCombo->currentData()); + #ifdef PSD_ENABLE_PAPERSOURCE m_printer->setPaperSource((QPrinter::PaperSource)m_ui.paperSource->currentIndex()); #endif @@ -528,23 +515,18 @@ void QPageSetupWidget::revertToSavedValues() m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(m_savedPagesPerSheetLayout); } -#if QT_CONFIG(cups) -bool QPageSetupWidget::hasPpdConflict() const +bool QPageSetupWidget::hasOptionConflict() const { - if (m_pageSizePpdOption) { - if (m_pageSizePpdOption->conflicted) { - const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr); - const int pixmap_size = m_ui.pageSizeCombo->sizeHint().height() * .75; - m_ui.pageSizeWarningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size)); - } else { - m_ui.pageSizeWarningLabel->setPixmap(QPixmap()); - } - return m_pageSizePpdOption->conflicted; + const bool conflict = m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_PageSize, QVariant(QByteArray("conflict"))); + if (conflict) { + const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr); + const int pixmap_size = m_ui.pageSizeCombo->sizeHint().height() * .75; + m_ui.pageSizeWarningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size)); + } else { + m_ui.pageSizeWarningLabel->setPixmap(QPixmap()); } - - return false; + return conflict; } -#endif // Updates size/preview after the combobox has been changed. void QPageSetupWidget::pageSizeChanged() @@ -553,26 +535,7 @@ void QPageSetupWidget::pageSizeChanged() if (m_ui.pageSizeCombo->currentIndex() != m_realCustomPageSizeIndex) { pageSize = qvariant_cast(m_ui.pageSizeCombo->currentData()); -#if QT_CONFIG(cups) - if (m_pageSizePpdOption) { - ppd_file_t *ppd = qvariant_cast(m_printDevice->property(PDPK_PpdFile)); - QStringDecoder toUtf16(ppd->lang_encoding, QStringDecoder::Flag::Stateless); - if (!toUtf16.isValid()) { - qWarning() << "QPrinSupport: Cups uses unsupported encoding" << ppd->lang_encoding; - toUtf16 = QStringDecoder(QStringDecoder::Utf8); - } - for (int i = 0; i < m_pageSizePpdOption->num_choices; ++i) { - const ppd_choice_t *choice = &m_pageSizePpdOption->choices[i]; - if (toUtf16(choice->text) == m_ui.pageSizeCombo->currentText()) { - const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword) - << QString::fromLatin1(choice->choice); - m_printDevice->setProperty(PDPK_PpdOption, values); - emit ppdOptionChanged(); - break; - } - } - } -#endif + m_printDevice->setProperty(QPrintDevice::PDPK_PageSize, QVariant(pageSize.key().toLocal8Bit())); } else { QSizeF customSize; @@ -582,14 +545,7 @@ void QPageSetupWidget::pageSizeChanged() customSize = QSizeF(m_ui.pageWidth->value(), m_ui.pageHeight->value()); pageSize = QPageSize(customSize, QPageSize::Unit(m_units)); -#if QT_CONFIG(cups) - if (m_pageSizePpdOption) { - const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword) - << QStringLiteral("Custom"); - m_printDevice->setProperty(PDPK_PpdOption, values); - emit ppdOptionChanged(); - } -#endif + m_printDevice->setProperty(QPrintDevice::PDPK_PageSize, QVariant(QByteArray("#custom#"))); } // We always need to update the m_pageSizePpdOption when the page size changes @@ -616,28 +572,15 @@ void QPageSetupWidget::pageOrientationChanged() void QPageSetupWidget::pagesPerSheetChanged() { -#if QT_CONFIG(cups) - switch (m_ui.pagesPerSheetCombo->currentData().toInt()) { - case QCUPSSupport::OnePagePerSheet: - m_pagePreview->setPagePreviewLayout(1, 1); - break; - case QCUPSSupport::TwoPagesPerSheet: - m_pagePreview->setPagePreviewLayout(1, 2); - break; - case QCUPSSupport::FourPagesPerSheet: - m_pagePreview->setPagePreviewLayout(2, 2); - break; - case QCUPSSupport::SixPagesPerSheet: - m_pagePreview->setPagePreviewLayout(3, 2); - break; - case QCUPSSupport::NinePagesPerSheet: - m_pagePreview->setPagePreviewLayout(3, 3); - break; - case QCUPSSupport::SixteenPagesPerSheet: - m_pagePreview->setPagePreviewLayout(4, 4); - break; + const auto value = m_ui.pagesPerSheetCombo->currentData().toByteArray(); + + // To support print preview, backends must supply the option choices as '{columns}x{rows}' + // Example: '3x3' for 9 pages per sheet + if (value.contains('x')) { + auto distribution = value.split('x'); + int columns = distribution[0].toInt(), rows = distribution[1].toInt(); + m_pagePreview->setPagePreviewLayout(rows, columns); } -#endif } void QPageSetupWidget::unitChanged() diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h index 0fe3a2e559fd..4332caf8dfe5 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h +++ b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h @@ -43,14 +43,15 @@ class QPageSetupWidget : public QWidget { void updateSavedValues(); void revertToSavedValues(); -#if QT_CONFIG(cups) - bool hasPpdConflict() const; + bool hasOptionConflict() const; +//#if QT_CONFIG(cups) +// bool hasPpdConflict() const; -signals: - void ppdOptionChanged(); -#endif +//Q_SIGNALS: +// void ppdOptionChanged(); +//#endif -private slots: +private Q_SLOTS: void pageSizeChanged(); void pageOrientationChanged(); void pagesPerSheetChanged(); @@ -72,9 +73,12 @@ private slots: QPagePreview *m_pagePreview; QPrinter *m_printer; QPrintDevice *m_printDevice; -#if QT_CONFIG(cups) - ppd_option_t *m_pageSizePpdOption; -#endif +//#if QT_CONFIG(cpdb) +// cpdb_printer_obj_t *m_printerObj; +//#endif +//#if QT_CONFIG(cups) +// ppd_option_t *m_pageSizePpdOption; +//#endif QPrinter::OutputFormat m_outputFormat; QString m_printerName; QPageLayout m_pageLayout; diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index bdaa5fa03f54..6568c8b008d4 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -42,13 +42,14 @@ #include "ui_qprintsettingsoutput.h" #include "ui_qprintwidget.h" -#if QT_CONFIG(cups) + +#endif +#endif + Q_DECLARE_METATYPE(const ppd_option_t *) -#include -#if QT_CONFIG(cupsjobwidget) -#include "qcupsjobwidget_p.h" #endif #endif +#include "qprintjobwidget_p.h" /* @@ -103,7 +104,7 @@ class QPrintPropertiesDialog : public QDialog void setupPrinter() const; -private slots: +private Q_SLOTS: void reject() override; void accept() override; @@ -111,28 +112,43 @@ private slots: void showEvent(QShowEvent *event) override; friend class QUnixPrintWidgetPrivate; -#if QT_CONFIG(cups) +#endif QPrinter *m_printer; #endif Ui::QPrintPropertiesWidget widget; QDialogButtonBox *m_buttons; -#if QT_CONFIG(cupsjobwidget) - QCupsJobWidget *m_jobOptions; #endif -#if QT_CONFIG(cups) + bool optionBlackListed(const QByteArray &optionName) const; + bool createAdvancedOptionsWidget(); + + QSet m_blackListedOptions; + QList m_advancedOptionsCombos; +#endif + bool createAdvancedOptionsWidget(); - void setPrinterAdvancedCupsOptions() const; void revertAdvancedOptionsToSavedValues() const; void advancedOptionsUpdateSavedValues() const; bool anyPpdOptionConflict() const; bool anyAdvancedOptionConflict() const; - QPrintDevice *m_currentPrintDevice; - QStringDecoder toUnicode; + Ui::QPrintPropertiesWidget widget; + QDialogButtonBox *m_buttons; + + Ui::QPrintPropertiesWidget widget; + QDialogButtonBox *m_buttons; + QPrintDevice *m_currentPrintDevice; QList m_advancedOptionsCombos; -#endif + QPrintJobWidget *m_jobOptions; + + QWidget* createJobOptionsWidget(QPrintDevice *currentPrintDevice); + QWidget* createAdvancedOptionsWidget(QPrintDevice *currentPrintDevice); + void setPrinterAdvancedOptions() const; + void advancedOptionsUpdateSavedValues() const; + void revertAdvancedOptionsToSavedValues() const; + bool anyOptionConflict() const; + bool anyAdvancedOptionConflict() const; }; class QUnixPrintWidgetPrivate; @@ -180,7 +196,8 @@ class QUnixPrintWidgetPrivate void updateWidget(); -#if QT_CONFIG(cups) +#endif + void setPpdDuplex(QPrinter::DuplexMode mode); ppd_option_t *m_duplexPpdOption; #endif @@ -208,7 +225,6 @@ class QPrintDialogPrivate : public QAbstractPrintDialogPrivate #endif void _q_collapseOrExpandDialog(); -#if QT_CONFIG(cups) void updatePpdDuplexOption(QRadioButton *radio); #endif void setupPrinter(); @@ -223,7 +239,9 @@ class QPrintDialogPrivate : public QAbstractPrintDialogPrivate QPushButton *collapseButton; QPrinter::OutputFormat printerOutputFormat; private: - void setExplicitDuplexMode(QPrint::DuplexMode duplexMode); + friend class QUnixPrintWidgetPrivate; + + void setExplicitDuplexMode(QRadioButton *radio); // duplex mode explicitly set by user, QPrint::DuplexAuto otherwise QPrint::DuplexMode explicitDuplexMode; }; @@ -244,9 +262,12 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * QPrinter::OutputFormat outputFormat, const QString &printerName, QAbstractPrintDialog *parent) : QDialog(parent) -#if QT_CONFIG(cups) + , m_printerObj(nullptr) +#endif , m_printer(printer) #endif + , m_currentPrintDevice(currentPrintDevice) + , m_jobOptions(nullptr) { setWindowTitle(tr("Printer Properties")); QVBoxLayout *lay = new QVBoxLayout(this); @@ -261,13 +282,15 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * widget.pageSetup->setPrinter(printer, currentPrintDevice, outputFormat, printerName); -#if QT_CONFIG(cupsjobwidget) - m_jobOptions = new QCupsJobWidget(printer, currentPrintDevice); +#endif + + widget.tabs->insertTab(1, m_jobOptions, tr("Job Options")); + } +#endif widget.tabs->insertTab(1, m_jobOptions, tr("Job Options")); #endif - const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage); -#if QT_CONFIG(cups) + m_currentPrintDevice = currentPrintDevice; const bool anyWidgetCreated = createAdvancedOptionsWidget(); @@ -277,10 +300,52 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * widget.conflictsLabel->setVisible(anyPpdOptionConflict()); }); + // blacklist options for advanced tab, which have been added at other places + m_blackListedOptions + << "borderless"; + + const bool anyWidgetCreated = createAdvancedOptionsWidget(); + widget.tabs->setTabEnabled(advancedTabIndex, anyWidgetCreated); + widget.conflictsLabel->setVisible(false); #else Q_UNUSED(currentPrintDevice); - widget.tabs->setTabEnabled(advancedTabIndex, false); #endif + if (currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobHold, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobBillingInfo, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobPriority, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobStartCoverPage, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobEndCoverPage, QVariant())) + { + m_jobOptions = new QPrintJobWidget(printer, currentPrintDevice, this); + widget.tabs->insertTab(1, m_jobOptions, tr("Job Options")); + } + + if (currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_AdvancedOptions, QVariant())) { + widget.tabs->setTabEnabled(advancedTabIndex, true); + widget.scrollArea->setWidget(createAdvancedOptionsWidget(currentPrintDevice)); + } else { + widget.tabs->setTabEnabled(advancedTabIndex, false); + } + + if (currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobHold, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobBillingInfo, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobPriority, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobStartCoverPage, QVariant()) + || currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_JobEndCoverPage, QVariant())) + { + m_jobOptions = new QPrintJobWidget(printer, currentPrintDevice, this); + widget.tabs->insertTab(1, m_jobOptions, tr("Job Options")); + } + + const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage); + if (currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_AdvancedOptions, QVariant())) { + widget.tabs->setTabEnabled(advancedTabIndex, true); + widget.scrollArea->setWidget(createAdvancedOptionsWidget(currentPrintDevice)); + } else { + widget.tabs->setTabEnabled(advancedTabIndex, false); + } + + widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); } QPrintPropertiesDialog::~QPrintPropertiesDialog() @@ -289,41 +354,47 @@ QPrintPropertiesDialog::~QPrintPropertiesDialog() void QPrintPropertiesDialog::setupPrinter() const { -#if QT_CONFIG(cups) - QCUPSSupport::clearCupsOptions(m_printer); #endif - widget.pageSetup->setupPrinter(); -#if QT_CONFIG(cupsjobwidget) - m_jobOptions->setupPrinter(); + // setup advanced options first, so as to process borderless option #endif + widget.pageSetup->setupPrinter(); + if (m_jobOptions) + m_currentPrintDevice->setProperty(QPrintDevice::PDPK_AdvancedOptions, QVariant(QByteArray("#clear#"))); + + widget.pageSetup->setupPrinter(); + m_currentPrintDevice->setProperty(QPrintDevice::PDPK_AdvancedOptions, QVariant(QByteArray("#clear#"))); + + widget.pageSetup->setupPrinter(); + + if (m_jobOptions) { + m_jobOptions->setupPrinter(); + } -#if QT_CONFIG(cups) // Set Color by default, that will change if the "ColorModel" property is available m_printer->setColorMode(QPrinter::Color); - setPrinterAdvancedCupsOptions(); #endif + setPrinterAdvancedOptions(); } void QPrintPropertiesDialog::reject() { widget.pageSetup->revertToSavedValues(); -#if QT_CONFIG(cupsjobwidget) - m_jobOptions->revertToSavedValues(); -#endif + if (m_jobOptions) + m_jobOptions->revertToSavedValues(); -#if QT_CONFIG(cups) revertAdvancedOptionsToSavedValues(); -#endif + QDialog::reject(); } void QPrintPropertiesDialog::accept() { -#if QT_CONFIG(cups) && QT_CONFIG(messagebox) if (widget.pageSetup->hasPpdConflict()) { +#if QT_CONFIG(messagebox) + if (widget.pageSetup->hasOptionConflict()) { widget.tabs->setCurrentWidget(widget.tabPage); const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Page Setup Conflicts"), tr("There are conflicts in page setup options. Do you want to fix them?"), @@ -331,7 +402,6 @@ void QPrintPropertiesDialog::accept() if (answer != QMessageBox::No) return; } else if (anyAdvancedOptionConflict()) { - widget.tabs->setCurrentWidget(widget.cupsPropertiesPage); const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Advanced Option Conflicts"), tr("There are conflicts in some advanced options. Do you want to fix them?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); @@ -341,43 +411,173 @@ void QPrintPropertiesDialog::accept() advancedOptionsUpdateSavedValues(); #endif -#if QT_CONFIG(cupsjobwidget) - m_jobOptions->updateSavedValues(); + if (m_jobOptions) + m_jobOptions->updateSavedValues(); #endif widget.pageSetup->updateSavedValues(); + if (m_jobOptions) + m_jobOptions->updateSavedValues(); + + advancedOptionsUpdateSavedValues(); + QDialog::accept(); } void QPrintPropertiesDialog::showEvent(QShowEvent *event) { -#if QT_CONFIG(cups) widget.conflictsLabel->setVisible(anyPpdOptionConflict()); #endif QDialog::showEvent(event); } -#if QT_CONFIG(cups) + + +bool QPrintPropertiesDialog::optionBlackListed(const QByteArray &optionName) const +{ + return m_blackListedOptions.contains(optionName); +} + +bool QPrintPropertiesDialog::createAdvancedOptionsWidget() +{ + bool anyWidgetCreated = false; + auto *holdingWidget = new QWidget(); + auto vboxLayout = new QVBoxLayout(holdingWidget); + holdingWidget->setLayout(vboxLayout); + + QHash groupsTable; + auto getFormLayout = [&groupsTable, &vboxLayout] (const QByteArray &groupName, const QByteArray &displayGroup) { + QFormLayout *formLayout = nullptr; + if (groupsTable.find(groupName) == groupsTable.end()) { + auto groupBox = new QGroupBox(QString::fromLocal8Bit(displayGroup)); + formLayout = new QFormLayout(groupBox); + groupBox->setLayout(formLayout); + vboxLayout->addWidget(groupBox); + groupsTable[groupName] = formLayout; + } else { + formLayout = groupsTable[groupName]; + } + return formLayout; + }; + + if (opts) { + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init(&iter, opts->table); + while (g_hash_table_iter_next(&iter, &key, &value)) { + QByteArray optionName = static_cast(key); + + if (!optionBlackListed(optionName) && opt && opt->num_supported > 1) { + anyWidgetCreated = true; + + QByteArray groupName = opt->group_name; + auto formLayout = getFormLayout(groupName, displayGroup); + + auto *optionLabel = new QLabel(QString::fromLocal8Bit(displayName)); + + auto *choicesCb = new QComboBox(); + for (int i = 0; i < opt->num_supported; i++) { + QByteArray value = opt->supported_values[i]; + choicesCb->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(value)); + } + + QByteArray defaultVal = opt->default_value; + int idx = choicesCb->findData(QVariant::fromValue(defaultVal)); + if (idx >= 0) + choicesCb->setCurrentIndex(idx); + + + m_advancedOptionsCombos << choicesCb; + formLayout->addRow(optionLabel, choicesCb); + } + } + + bool supportsBorderless = true; + for (QByteArray &optName : optNames) { + bool found = false; + for (int i = 0; i < opt->num_supported; i++) { + if (qstrcmp(opt->supported_values[i], "0") == 0) { + found = true; + break; + } + } + if (!found || opt->num_supported <= 1) { + supportsBorderless = false; + break; + } + } + + if (supportsBorderless) { + anyWidgetCreated = true; + + auto formLayout = getFormLayout(groupName, displayGroup); + + QByteArray optionName = "borderless"; + QString displayName = tr("Borderless"); + auto *optionLabel = new QLabel(displayName); + + auto *choicesCb = new QComboBox(); + choicesCb->addItem(tr("On"), QVariant::fromValue(QByteArray("true"))); + choicesCb->addItem(tr("Off"), QVariant::fromValue(QByteArray("false"))); + choicesCb->setCurrentIndex(1); + + + m_advancedOptionsCombos << choicesCb; + formLayout->addRow(optionLabel, choicesCb); + } + + + + } + + if (anyWidgetCreated) { + vboxLayout->addStretch(); + widget.scrollArea->setWidget(holdingWidget); + } else { + delete vboxLayout; + delete holdingWidget; + } + + return anyWidgetCreated; +} + +{ + for (const QComboBox *choicesCb : m_advancedOptionsCombos) { + QByteArray value = qvariant_cast(choicesCb->currentData()); + } +} + +#endif + // Used to store the ppd_option_t for each QComboBox that represents an advanced option static const char *ppdOptionProperty = "_q_ppd_option"; + widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); + QDialog::showEvent(event); +} + + widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); + QDialog::showEvent(event); +} + +// Used to store the option name for each QComboBox that represents an advanced option +static const char *optionNameProperty = "_q_print_option_name"; // Used to store the originally selected choice index for each QComboBox that represents an advanced option -static const char *ppdOriginallySelectedChoiceProperty = "_q_ppd_originally_selected_choice"; +static const char *originallySelectedChoiceProperty = "_q_print_originally_selected_choice"; // Used to store the warning label pointer for each QComboBox that represents an advanced option static const char *warningLabelProperty = "_q_warning_label"; -static bool isBlacklistedGroup(const ppd_group_t *group) noexcept +QWidget* QPrintPropertiesDialog::createAdvancedOptionsWidget(QPrintDevice *currentPrintDevice) { - return qstrcmp(group->name, "InstallableOptions") == 0; -}; + auto advancedOptionsGroups = + qvariant_cast>(currentPrintDevice->property(QPrintDevice::PDPK_AdvancedOptions)); static bool isBlacklistedOption(const char *keyword) noexcept { // We already let the user set these options elsewhere - const char *cupsOptionBlacklist[] = { "Collate", "Copies", "OutputOrder", @@ -390,118 +590,80 @@ static bool isBlacklistedOption(const char *keyword) noexcept return qstrcmp(keyword, candidate) == 0; }; }; - return std::any_of(std::begin(cupsOptionBlacklist), std::end(cupsOptionBlacklist), equals(keyword)); }; bool QPrintPropertiesDialog::createAdvancedOptionsWidget() { bool anyWidgetCreated = false; - - ppd_file_t *ppd = qvariant_cast(m_currentPrintDevice->property(PDPK_PpdFile)); + auto *holdingWidget = new QWidget(); + auto vboxLayout = new QVBoxLayout(holdingWidget); + holdingWidget->setLayout(vboxLayout); + + for (const auto& advancedOptionsGroup : advancedOptionsGroups) { + auto groupBox = new QGroupBox(advancedOptionsGroup.displayGroup); + auto formLayout = new QFormLayout(groupBox); + groupBox->setLayout(formLayout); + + for (const auto& advancedOption : advancedOptionsGroup.options) { + if (advancedOption.choices.size() <= 1) + continue; + anyWidgetCreated = true; if (ppd) { toUnicode = QStringDecoder(ppd->lang_encoding, QStringDecoder::Flag::Stateless); if (!toUnicode.isValid()) { - qWarning() << "QPrinSupport: Cups uses unsupported encoding" << ppd->lang_encoding; toUnicode = QStringDecoder(QStringDecoder::Utf8, QStringDecoder::Flag::Stateless); } + auto *optionLabel = new QLabel(advancedOption.displayName); + auto *choicesCb = new QComboBox(); - QWidget *holdingWidget = new QWidget(); - QVBoxLayout *layout = new QVBoxLayout(holdingWidget); - - for (int i = 0; i < ppd->num_groups; ++i) { - const ppd_group_t *group = &ppd->groups[i]; - - if (!isBlacklistedGroup(group)) { - QFormLayout *groupLayout = new QFormLayout(); - - for (int i = 0; i < group->num_options; ++i) { - const ppd_option_t *option = &group->options[i]; - - if (!isBlacklistedOption(option->keyword)) { - QComboBox *choicesCb = new QComboBox(); - - const auto setPpdOptionFromCombo = [this, choicesCb, option] { - // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array - // because some of them may not be present in the list because they conflict with the - // installable options so use the index passed on addItem - const int selectedChoiceIndex = choicesCb->currentData().toInt(); - const auto values = QStringList{} << QString::fromLatin1(option->keyword) - << QString::fromLatin1(option->choices[selectedChoiceIndex].choice); - m_currentPrintDevice->setProperty(PDPK_PpdOption, values); - widget.conflictsLabel->setVisible(anyPpdOptionConflict()); - }; - - bool foundMarkedChoice = false; - bool markedChoiceNotAvailable = false; - for (int i = 0; i < option->num_choices; ++i) { - const ppd_choice_t *choice = &option->choices[i]; - const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(choice->choice); - const bool choiceIsInstallableConflict = m_currentPrintDevice->isFeatureAvailable(PDPK_PpdChoiceIsInstallableConflict, values); - if (choiceIsInstallableConflict && static_cast(choice->marked) == 1) { - markedChoiceNotAvailable = true; - } else if (!choiceIsInstallableConflict) { - choicesCb->addItem(toUnicode(choice->text), i); - if (static_cast(choice->marked) == 1) { - choicesCb->setCurrentIndex(choicesCb->count() - 1); - choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i)); - foundMarkedChoice = true; - } else if (!foundMarkedChoice && qstrcmp(choice->choice, option->defchoice) == 0) { - choicesCb->setCurrentIndex(choicesCb->count() - 1); - choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i)); - } - } - } - - if (markedChoiceNotAvailable) { - // If the user default option is not available because of it conflicting with - // the installed options, we need to set the internal ppd value to the value - // being shown in the combo - setPpdOptionFromCombo(); - } - - if (choicesCb->count() > 1) { - - connect(choicesCb, &QComboBox::currentIndexChanged, this, setPpdOptionFromCombo); - - // We need an extra label at the end to show the conflict warning - QWidget *choicesCbWithLabel = new QWidget(); - QHBoxLayout *choicesCbWithLabelLayout = new QHBoxLayout(choicesCbWithLabel); - choicesCbWithLabelLayout->setContentsMargins(0, 0, 0, 0); - QLabel *warningLabel = new QLabel(); - choicesCbWithLabelLayout->addWidget(choicesCb); - choicesCbWithLabelLayout->addWidget(warningLabel); - - QLabel *optionLabel = new QLabel(toUnicode(option->text)); - groupLayout->addRow(optionLabel, choicesCbWithLabel); - anyWidgetCreated = true; - choicesCb->setProperty(ppdOptionProperty, QVariant::fromValue(option)); - choicesCb->setProperty(warningLabelProperty, QVariant::fromValue(warningLabel)); - m_advancedOptionsCombos << choicesCb; - } else { - delete choicesCb; - } - } - } - - if (groupLayout->rowCount() > 0) { - QGroupBox *groupBox = new QGroupBox(toUnicode(group->text)); - groupBox->setLayout(groupLayout); - layout->addWidget(groupBox); - } else { - delete groupLayout; - } + for (int i = 0; i < advancedOption.choices.size(); i++) { + choicesCb->addItem(advancedOption.displayChoices[i], QVariant::fromValue(advancedOption.choices[i])); } + choicesCb->setCurrentIndex(advancedOption.defaultChoice); + widget.conflictsLabel->setVisible(anyOptionConflict()); + + choicesCb->setProperty(originallySelectedChoiceProperty, choicesCb->currentData()); + choicesCb->setProperty(optionNameProperty, QVariant::fromValue(advancedOption.name)); + + const auto setAdvancedOptionFromCombo = [this, choicesCb] { + QByteArray optionName = qvariant_cast(choicesCb->property(optionNameProperty)); + QByteArray optionChoice = qvariant_cast(choicesCb->currentData()); + QPrint::OptionSetting optionSetting = {optionName, optionChoice}; + m_currentPrintDevice->setProperty(QPrintDevice::PDPK_AdvancedOptions, QVariant::fromValue(optionSetting)); + widget.conflictsLabel->setVisible(anyOptionConflict()); + }; + connect(choicesCb, &QComboBox::currentIndexChanged, this, setAdvancedOptionFromCombo); + + // We need an extra label at the end to show the conflict warning + QWidget *choicesCbWithLabel = new QWidget(); + QHBoxLayout *choicesCbWithLabelLayout = new QHBoxLayout(choicesCbWithLabel); + choicesCbWithLabelLayout->setContentsMargins(0, 0, 0, 0); + QLabel *warningLabel = new QLabel(); + choicesCbWithLabelLayout->addWidget(choicesCb); + choicesCbWithLabelLayout->addWidget(warningLabel); + choicesCb->setProperty(warningLabelProperty, QVariant::fromValue(warningLabel)); + + m_advancedOptionsCombos << choicesCb; + formLayout->addRow(optionLabel, choicesCbWithLabel); } + + if (formLayout->rowCount() > 0) + vboxLayout->addWidget(groupBox); + else + delete groupBox; - layout->addStretch(); - widget.scrollArea->setWidget(holdingWidget); } - return anyWidgetCreated; + if (!anyWidgetCreated) { + delete holdingWidget; + return nullptr; + } + + vboxLayout->addStretch(); + return holdingWidget; } -void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const { for (const QComboBox *choicesCb : m_advancedOptionsCombos) { const ppd_option_t *option = qvariant_cast(choicesCb->property(ppdOptionProperty)); @@ -516,31 +678,40 @@ void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const m_printer->setColorMode(qstrcmp(selectedChoice, "Gray") == 0 ? QPrinter::GrayScale : QPrinter::Color); if (qstrcmp(option->defchoice, selectedChoice) != 0) - QCUPSSupport::setCupsOption(m_printer, QString::fromLatin1(option->keyword), QString::fromLatin1(selectedChoice)); +void QPrintPropertiesDialog::setPrinterAdvancedOptions() const +{ + for (const QComboBox *choicesCb : m_advancedOptionsCombos) { +void QPrintPropertiesDialog::setPrinterAdvancedOptions() const +{ + for (const QComboBox *choicesCb : m_advancedOptionsCombos) { + QByteArray optionName = qvariant_cast(choicesCb->property(optionNameProperty)); + QByteArray optionChoice = qvariant_cast(choicesCb->currentData()); + QPrint::OptionSetting optionSetting = {optionName, optionChoice}; + m_currentPrintDevice->setProperty(QPrintDevice::PDPK_AdvancedOptions, QVariant::fromValue(optionSetting)); } } void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const { for (QComboBox *choicesCb : m_advancedOptionsCombos) { - const int originallySelectedChoice = qvariant_cast(choicesCb->property(ppdOriginallySelectedChoiceProperty)); - const int newComboIndexToSelect = choicesCb->findData(originallySelectedChoice); - choicesCb->setCurrentIndex(newComboIndexToSelect); - // The currentIndexChanged lambda takes care of resetting the ppd option + const QVariant originallySelectedChoice = choicesCb->property(originallySelectedChoiceProperty); + const int index = choicesCb->findData(originallySelectedChoice); + if (index > 0) + choicesCb->setCurrentIndex(index); } - widget.conflictsLabel->setVisible(anyPpdOptionConflict()); + widget.conflictsLabel->setVisible(anyOptionConflict()); } void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const { for (QComboBox *choicesCb : m_advancedOptionsCombos) - choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, choicesCb->currentData()); + choicesCb->setProperty(originallySelectedChoiceProperty, choicesCb->currentData()); } -bool QPrintPropertiesDialog::anyPpdOptionConflict() const +bool QPrintPropertiesDialog::anyOptionConflict() const { // we need to execute both since besides returning true/false they update the warning icons - const bool pageSetupConflicts = widget.pageSetup->hasPpdConflict(); + const bool pageSetupConflicts = widget.pageSetup->hasOptionConflict(); const bool advancedOptionConflicts = anyAdvancedOptionConflict(); return pageSetupConflicts || advancedOptionConflicts; } @@ -552,9 +723,13 @@ bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const bool anyConflicted = false; for (const QComboBox *choicesCb : m_advancedOptionsCombos) { - const ppd_option_t *option = qvariant_cast(choicesCb->property(ppdOptionProperty)); + QByteArray optionName = qvariant_cast(choicesCb->property(optionNameProperty)); + QByteArray optionChoice = qvariant_cast(choicesCb->currentData()); + QPrint::OptionSetting optionSetting = {optionName, optionChoice}; + QLabel *warningLabel = qvariant_cast(choicesCb->property(warningLabelProperty)); - if (option->conflicted) { + const bool conflict = m_currentPrintDevice->isFeatureAvailable(QPrintDevice::PDPK_OptionConflict, QVariant::fromValue(optionSetting)); + if (conflict) { anyConflicted = true; const int pixmap_size = choicesCb->sizeHint().height() * .75; warningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size)); @@ -566,8 +741,6 @@ bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const return anyConflicted; } -#endif - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -603,12 +776,7 @@ void QPrintDialogPrivate::init() options.grayscale->setIconSize(QSize(32, 32)); options.grayscale->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-gray-scale.png"_L1)); -#if QT_CONFIG(cups) - // Add Page Set widget if CUPS is available - options.pageSetCombo->addItem(tr("All Pages"), QVariant::fromValue(QCUPSSupport::AllPages)); - options.pageSetCombo->addItem(tr("Odd Pages"), QVariant::fromValue(QCUPSSupport::OddPages)); - options.pageSetCombo->addItem(tr("Even Pages"), QVariant::fromValue(QCUPSSupport::EvenPages)); -#else +#endif delete options.pagesRadioButton; delete options.pagesLineEdit; options.pagesRadioButton = nullptr; @@ -650,88 +818,130 @@ void QPrintDialogPrivate::init() QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexLongSide); }); QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexShortSide); }); -#if QT_CONFIG(cups) QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); }); QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); }); QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); }); #endif + QObject::connect(options.noDuplex, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(options.noDuplex); }); + QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(options.duplexLong); }); + QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(options.duplexShort); }); } // initialize printer options void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputFormat) { - Q_Q(QPrintDialog); - QPrinter *p = q->printer(); - printerOutputFormat = outputFormat; - - // printer supports duplex mode? - const auto supportedDuplexMode = top->d->m_currentPrintDevice.supportedDuplexModes(); - options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide)); - options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide)); - + Q_Q(QPrintDialog); + QPrinter *p = q->printer(); + printerOutputFormat = outputFormat; + + // printer supports duplex mode? + const auto supportedDuplexMode = top->d->m_currentPrintDevice.supportedDuplexModes(); + options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide)); + options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide)); + + // support feature PDPK_AdvancedColorMode if you want to display Color option separately + // among other advanced options in QPrintProperties dialog (eg. CUPS) + if (top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_AdvancedColorMode, QVariant())) { + options.colorMode->setEnabled(false); + } else { + options.colorMode->setEnabled(true); if (p->colorMode() == QPrinter::Color) options.color->setChecked(true); else options.grayscale->setChecked(true); + } - // duplex priorities to be as follows: - // 1) a user-selected duplex value in the dialog has highest priority - // 2) duplex value set in the QPrinter - QPrint::DuplexMode duplex; - if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode)) - duplex = explicitDuplexMode; - else - duplex = static_cast(p->duplex()); - switch (duplex) { - case QPrint::DuplexNone: - options.noDuplex->setChecked(true); break; - case QPrint::DuplexLongSide: - case QPrint::DuplexAuto: - options.duplexLong->setChecked(true); break; - case QPrint::DuplexShortSide: - options.duplexShort->setChecked(true); break; + // duplex priorities to be as follows: + // 1) a user-selected duplex value in the dialog has highest priority + // 2) duplex value set in the QPrinter + QPrint::DuplexMode duplex; + if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode)) + duplex = explicitDuplexMode; + else + duplex = static_cast(p->duplex()); + switch (duplex) { + case QPrint::DuplexNone: + options.noDuplex->setChecked(true); + break; + case QPrint::DuplexLongSide: + case QPrint::DuplexAuto: + options.duplexLong->setChecked(true); + break; + case QPrint::DuplexShortSide: + options.duplexShort->setChecked(true); + break; + } + options.copies->setValue(p->copyCount()); + options.collate->setChecked(p->collateCopies()); + options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst); + + if (outputFormat == QPrinter::PdfFormat || options.printSelection->isChecked() + || options.printCurrentPage->isChecked()) + + options.pageSetCombo->setEnabled(false); + else + options.pageSetCombo->setEnabled(top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_PageSet, QVariant())); + + bool showPageSet = false; + if (opt && opt->num_supported > 1) { + showPageSet = true; + options.pageSetLabel->setEnabled(true); + options.pageSetCombo->clear(); + for (int i = 0; i < opt->num_supported; i++) { + QByteArray value = opt->supported_values[i]; + opt->option_name, + opt->supported_values[i]); + options.pageSetCombo->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(value)); } - options.copies->setValue(p->copyCount()); - options.collate->setChecked(p->collateCopies()); - options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst); - if (outputFormat == QPrinter::PdfFormat || options.printSelection->isChecked() - || options.printCurrentPage->isChecked()) + QByteArray defaultVal = opt->default_value; + int idx = options.pageSetCombo->findData(QVariant::fromValue(defaultVal)); + if (idx >= 0) + options.pageSetCombo->setCurrentIndex(idx); + auto pageSetOption = + qvariant_cast(top->d->m_currentPrintDevice.property(QPrintDevice::PDPK_PageSet)); + for (int i = 0; i < pageSetOption.choices.size(); i++) { + options.pageSetCombo->addItem(pageSetOption.displayChoices[i], QVariant::fromValue(pageSetOption.choices[i])); + } + options.pageSetCombo->setCurrentIndex(pageSetOption.defaultChoice); - options.pageSetCombo->setEnabled(false); - else - options.pageSetCombo->setEnabled(true); + options.pagesRadioButton->setEnabled(showPageRanges); + options.pagesLineEdit->setEnabled(showPageRanges); +#endif -#if QT_CONFIG(cups) - // Disable complex page ranges widget when printing to pdf - // It doesn't work since it relies on cups to do the heavy lifting and cups - // is not used when printing to PDF - options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat); + // Disable complex page ranges widget when printing to pdf + // is not used when printing to PDF + options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat); - // Disable color options on main dialog if not printing to file, it will be handled by CUPS advanced dialog - options.colorMode->setVisible(outputFormat == QPrinter::PdfFormat); + options.colorMode->setVisible(outputFormat == QPrinter::PdfFormat); #endif } -#if QT_CONFIG(cups) void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio) + options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat + && top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_PageRange, QVariant())); +} + + options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat + && top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_PageRange, QVariant())); +} + +void QPrintDialogPrivate::setExplicitDuplexMode(QRadioButton *radio) { const bool checked = radio->isChecked(); if (checked) { - if (radio == options.noDuplex) top->d->setPpdDuplex(QPrinter::DuplexNone); - else if (radio == options.duplexLong) top->d->setPpdDuplex(QPrinter::DuplexLongSide); - else if (radio == options.duplexShort) top->d->setPpdDuplex(QPrinter::DuplexShortSide); + if (radio == options.noDuplex) + explicitDuplexMode = QPrint::DuplexNone; + else if (radio == options.duplexLong) + explicitDuplexMode = QPrint::DuplexLongSide; + else if (radio == options.duplexShort) + explicitDuplexMode = QPrint::DuplexShortSide; + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_Duplex, QVariant::fromValue(explicitDuplexMode)); } - const bool conflict = checked && top->d->m_duplexPpdOption && top->d->m_duplexPpdOption->conflicted; - radio->setIcon(conflict ? QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr) : QIcon()); -} -#endif - -void QPrintDialogPrivate::setExplicitDuplexMode(const QPrint::DuplexMode duplexMode) -{ - explicitDuplexMode = duplexMode; + const bool conflict = checked && top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_Duplex, QVariant(QByteArray("conflict"))); + radio->setIcon(conflict ? QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr) : QIcon()); } void QPrintDialogPrivate::setupPrinter() @@ -752,7 +962,6 @@ void QPrintDialogPrivate::setupPrinter() p->setDuplex(QPrinter::DuplexShortSide); } -#if QT_CONFIG(cups) // When printing to a device the colorMode will be set by the advanced panel if (p->outputFormat() == QPrinter::PdfFormat) #endif @@ -775,52 +984,101 @@ void QPrintDialogPrivate::setupPrinter() p->setPrintRange(QPrinter::PageRange); p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value())); } else { - // This case happens when CUPS server-side page range is enabled // Setting the range to the printer occurs below p->setPrintRange(QPrinter::AllPages); p->setPageRanges(QPageRanges()); } } -#if QT_CONFIG(cups) if (options.pagesRadioButton->isChecked()) { const QPageRanges ranges = QPageRanges::fromString(options.pagesLineEdit->text()); p->setPrintRange(QPrinter::AllPages); p->setPageRanges(QPageRanges()); // server-side page filtering - QCUPSSupport::setPageRange(p, ranges.toString()); } // page set if (p->printRange() == QPrinter::AllPages || p->printRange() == QPrinter::PageRange) { //If the application is selecting pages and the first page number is even then need to adjust the odd-even accordingly - QCUPSSupport::PageSet pageSet = qvariant_cast(options.pageSetCombo->itemData(options.pageSetCombo->currentIndex())); if (q->testOption(QPrintDialog::PrintPageRange) && p->printRange() == QPrinter::PageRange && (q->fromPage() % 2 == 0)) { switch (pageSet) { - case QCUPSSupport::AllPages: break; - case QCUPSSupport::OddPages: - QCUPSSupport::setPageSet(p, QCUPSSupport::EvenPages); break; - case QCUPSSupport::EvenPages: - QCUPSSupport::setPageSet(p, QCUPSSupport::OddPages); break; } - } else if (pageSet != QCUPSSupport::AllPages) { - QCUPSSupport::setPageSet(p, pageSet); } // server-side page range, since we set the page range on the printer to 0-0/AllPages above, // we need to take the values directly from the widget as q->fromPage() will return 0 if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked()) - QCUPSSupport::setPageRange(p, options.from->value(), qMax(options.from->value(), options.to->value())); } #endif + if (options.pagesRadioButton->isEnabled()) { + QString pageRange; + if (options.pagesRadioButton->isChecked()) { + pageRange = options.pagesLineEdit->text(); + const QPageRanges ranges = QPageRanges::fromString(pageRange); + if (!ranges.isEmpty()) { + p->setPrintRange(QPrinter::PageRange); + p->setPageRanges(ranges); + } + } else if (options.printRange->isChecked() && !q->testOption(QPrintDialog::PrintPageRange)) { + pageRange = tr("%1-%2").arg(options.from->value()).arg(qMax(options.from->value(),options.to->value())); + } + } + + QByteArray pageSet = qvariant_cast(options.pageSetCombo->itemData(options.pageSetCombo->currentIndex())); + + if (options.color->isChecked()) + else +#endif + if (options.pagesRadioButton->isEnabled() && options.pagesRadioButton->isChecked()) { + QString pageRange = options.pagesLineEdit->text(); + const QPageRanges ranges = QPageRanges::fromString(pageRange); + if (!ranges.isEmpty()) { + p->setPrintRange(QPrinter::PageRange); + p->setPageRanges(ranges); + } + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_PageRange, pageRange); + } + if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked()) { + QString pageRange = tr("%1-%2").arg(options.from->value()).arg(qMax(options.from->value(),options.to->value())); + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_PageRange, pageRange); + } + + if (options.pageSetCombo->isEnabled()) { + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_PageSet, + options.pageSetCombo->itemData(options.pageSetCombo->currentIndex())); + } + + if (options.pagesRadioButton->isEnabled() && options.pagesRadioButton->isChecked()) { + QString pageRange = options.pagesLineEdit->text(); + const QPageRanges ranges = QPageRanges::fromString(pageRange); + if (!ranges.isEmpty()) { + p->setPrintRange(QPrinter::PageRange); + p->setPageRanges(ranges); + } + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_PageRange, pageRange); + } + if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked()) { + QString pageRange = tr("%1-%2").arg(options.from->value()).arg(qMax(options.from->value(),options.to->value())); + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_PageRange, pageRange); + } + + if (options.pageSetCombo->isEnabled()) { + top->d->m_currentPrintDevice.setProperty(QPrintDevice::PDPK_PageSet, + options.pageSetCombo->itemData(options.pageSetCombo->currentIndex())); + } + + if (options.colorMode->isEnabled()) { + p->setColorMode(options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale); + } + // copies p->setCopyCount(options.copies->value()); p->setCollateCopies(options.collate->isChecked()); @@ -872,9 +1130,32 @@ void QPrintDialogPrivate::updateWidgets() options.printRange->setEnabled(q->testOption(QPrintDialog::PrintPageRange)); options.printSelection->setVisible(q->testOption(QPrintDialog::PrintSelection)); options.printCurrentPage->setVisible(q->testOption(QPrintDialog::PrintCurrentPage)); + options.collate->setVisible(q->testOption(QPrintDialog::PrintCollateCopies)); -#if QT_CONFIG(cups) + bool showPageSet = (opt && opt->num_supported > 1); + options.pageSetLabel->setVisible(showPageSet); + options.pageSetCombo->setVisible(showPageSet); +#endif + bool showPageSet = top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_PageSet, QVariant()); + // Don't display Page Set if only Selection or Current Page are enabled + if (!q->testOption(QPrintDialog::PrintPageRange) + && (q->testOption(QPrintDialog::PrintSelection) || q->testOption(QPrintDialog::PrintCurrentPage))) { + options.pageSetCombo->setVisible(false); + options.pageSetLabel->setVisible(false); + } else { + options.pageSetCombo->setVisible(showPageSet); + options.pageSetLabel->setVisible(showPageSet); + } + + // If the print device can handle server side pages selection, + // display the page range widgets + if (!q->testOption(QPrintDialog::PrintPageRange) + && top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_PageRange, QVariant())) { + options.gbPrintRange->setVisible(true); + options.printRange->setEnabled(true); + } + // Don't display Page Set if only Selection or Current Page are enabled if (!q->testOption(QPrintDialog::PrintPageRange) && (q->testOption(QPrintDialog::PrintSelection) || q->testOption(QPrintDialog::PrintCurrentPage))) { @@ -886,7 +1167,6 @@ void QPrintDialogPrivate::updateWidgets() } if (!q->testOption(QPrintDialog::PrintPageRange)) { - // If we can do CUPS server side pages selection, // display the page range widgets options.gbPrintRange->setVisible(true); options.printRange->setEnabled(true); @@ -988,7 +1268,6 @@ int QPrintDialog::exec() void QPrintDialog::accept() { Q_D(QPrintDialog); -#if QT_CONFIG(cups) && QT_CONFIG(messagebox) if (d->options.pagesRadioButton->isChecked()) { const QString rangesText = d->options.pagesLineEdit->text(); if (rangesText.isEmpty() || QPageRanges::fromString(rangesText).isEmpty()) { @@ -999,8 +1278,21 @@ void QPrintDialog::accept() QMessageBox::Ok, QMessageBox::Ok); return; } + d->setupPrinter(); + +#if QT_CONFIG(messagebox) + if (d->options.pagesRadioButton->isChecked() && printer()->pageRanges().isEmpty()) { + QMessageBox::critical(this, tr("Invalid Pages Definition"), + tr("%1 does not follow the correct syntax. Please use ',' to separate " + "ranges and pages, '-' to define ranges and make sure ranges do " + "not intersect with each other.").arg(d->options.pagesLineEdit->text()), + QMessageBox::Ok, QMessageBox::Ok); + return; } +#endif + if (d->top->d->m_duplexPpdOption && d->top->d->m_duplexPpdOption->conflicted) { + if (qvariant_cast(d->top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_Duplex, QVariant(QByteArray("conflict"))))) { const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Duplex Settings Conflicts"), tr("There are conflicts in duplex settings. Do you want to fix them?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); @@ -1008,7 +1300,7 @@ void QPrintDialog::accept() return; } #endif - d->setupPrinter(); + QDialog::accept(); } @@ -1029,7 +1321,8 @@ void QPrintDialog::accept() */ QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn) : parent(p), propertiesDialog(nullptr), printer(prn), -#if QT_CONFIG(cups) + m_printerObj(nullptr), +#endif m_duplexPpdOption(nullptr), #endif optionsPane(nullptr), filePrintersAdded(false) @@ -1075,6 +1368,7 @@ QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter * void QUnixPrintWidgetPrivate::updateWidget() { const bool printToFile = q == nullptr || q->testOption(QPrintDialog::PrintToFile); + if (printToFile && !filePrintersAdded) { if (widget.printers->count()) widget.printers->insertSeparator(widget.printers->count()); @@ -1125,7 +1419,8 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) propertiesDialog = nullptr; } -#if QT_CONFIG(cups) + m_printerObj = nullptr; +#endif m_duplexPpdOption = nullptr; #endif @@ -1151,8 +1446,10 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) printer->setOutputFormat(QPrinter::NativeFormat); QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get(); - if (ps) + if (ps) { m_currentPrintDevice = ps->createPrintDevice(widget.printers->itemText(index)); +#endif + } else m_currentPrintDevice = QPrintDevice(); @@ -1164,8 +1461,6 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) optionsPane->selectPrinter(QPrinter::NativeFormat); } -#if QT_CONFIG(cups) - m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice); #endif } @@ -1222,22 +1517,19 @@ bool QUnixPrintWidgetPrivate::checkFields() } } -#if QT_CONFIG(cups) if (propertiesDialog) { - QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast(propertiesDialog->widget.pageSetup->m_ui.pagesPerSheetCombo ->currentData()); - QCUPSSupport::PageSet pageSet = qvariant_cast(optionsPane->options.pageSetCombo->currentData()); - if (pagesPerSheet != QCUPSSupport::OnePagePerSheet - && pageSet != QCUPSSupport::AllPages) { QMessageBox::warning(q, q->windowTitle(), QPrintDialog::tr("Options 'Pages Per Sheet' and 'Page Set' cannot be used together.\nPlease turn one of those options off.")); + QVariant conflict = m_currentPrintDevice.property(QPrintDevice::PDPK_OptionConflict); + if (!conflict.isNull()) { + QMessageBox::warning(q, q->windowTitle(), conflict.toString()); return false; } } -#endif // Every test passed. Accept the dialog. return true; @@ -1262,7 +1554,6 @@ void QUnixPrintWidgetPrivate::setupPrinterProperties() propertiesDialog = new QPrintPropertiesDialog(q->printer(), &m_currentPrintDevice, outputFormat, printerName, q); } -#if QT_CONFIG(cups) void QUnixPrintWidgetPrivate::setPpdDuplex(QPrinter::DuplexMode mode) { auto values = QStringList{} << QStringLiteral("Duplex"); @@ -1280,12 +1571,14 @@ void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked() setupPrinterProperties(); propertiesDialog->exec(); -#if QT_CONFIG(cups) // update the warning icon on the duplex options if needed optionsPane->updatePpdDuplexOption(optionsPane->options.noDuplex); optionsPane->updatePpdDuplexOption(optionsPane->options.duplexLong); optionsPane->updatePpdDuplexOption(optionsPane->options.duplexShort); #endif + optionsPane->setExplicitDuplexMode(optionsPane->options.noDuplex); + optionsPane->setExplicitDuplexMode(optionsPane->options.duplexLong); + optionsPane->setExplicitDuplexMode(optionsPane->options.duplexShort); } void QUnixPrintWidgetPrivate::setupPrinter() @@ -1374,12 +1667,10 @@ void QUnixPrintWidget::updatePrinter() d->setupPrinter(); } -#if QT_CONFIG(cups) //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -#endif // QT_CONFIG(cups) #endif // defined (Q_OS_UNIX) QT_END_NAMESPACE diff --git a/src/printsupport/dialogs/qprintpreviewdialog.cpp b/src/printsupport/dialogs/qprintpreviewdialog.cpp index 86742c4906e9..02073aed9eae 100644 --- a/src/printsupport/dialogs/qprintpreviewdialog.cpp +++ b/src/printsupport/dialogs/qprintpreviewdialog.cpp @@ -105,7 +105,7 @@ class LineEdit : public QLineEdit QLineEdit::focusOutEvent(e); } -private slots: +private Q_SLOTS: void handleReturnPressed() { origText = text(); diff --git a/src/printsupport/kernel/qplatformprintdevice.cpp b/src/printsupport/kernel/qplatformprintdevice.cpp index a2ee51f88729..898848d8b0f6 100644 --- a/src/printsupport/kernel/qplatformprintdevice.cpp +++ b/src/printsupport/kernel/qplatformprintdevice.cpp @@ -364,6 +364,12 @@ QPageSize QPlatformPrintDevice::createPageSize(const QString &key, const QSize & return QPageSize(key, size, localizedName); } +QPageSize QPlatformPrintDevice::createPageSize(const QString &key, const QSizeF &size, + QPageSize::Unit units, const QString &localizedName) +{ + return QPageSize(key, size, units, localizedName); +} + QPageSize QPlatformPrintDevice::createPageSize(int windowsId, const QSize &size, const QString &localizedName) { return QPageSize(windowsId, size, localizedName); diff --git a/src/printsupport/kernel/qplatformprintdevice.h b/src/printsupport/kernel/qplatformprintdevice.h index a8d9c10f7f48..d580f7a90d2d 100644 --- a/src/printsupport/kernel/qplatformprintdevice.h +++ b/src/printsupport/kernel/qplatformprintdevice.h @@ -97,6 +97,8 @@ class Q_PRINTSUPPORT_EXPORT QPlatformPrintDevice static QPageSize createPageSize(const QString &key, const QSize &size, const QString &localizedName); static QPageSize createPageSize(int windowsId, const QSize &size, const QString &localizedName); + static QPageSize createPageSize(const QString &key, const QSizeF &size, + QPageSize::Unit units, const QString &localizedName); protected: virtual void loadPageSizes() const; diff --git a/src/printsupport/kernel/qplatformprintplugin.cpp b/src/printsupport/kernel/qplatformprintplugin.cpp index 37222eb039d3..141c56657ba6 100644 --- a/src/printsupport/kernel/qplatformprintplugin.cpp +++ b/src/printsupport/kernel/qplatformprintplugin.cpp @@ -51,16 +51,61 @@ static void cleanupPrinterSupport() QPlatformPrinterSupport *QPlatformPrinterSupportPlugin::get() { if (!printerSupport) { - const QMultiMap keyMap = loader()->keyMap(); + + + QFactoryLoader *l = loader(); + + // Load plugin metadata + QMultiMap plugins; + QList meta = l->metaData(); + for (int i = 0; i < meta.size(); ++i) { + QCborMap obj = meta.at(i).value(QtPluginMetaDataKeys::MetaData).toMap(); + obj.insert(QLatin1String("index"), i); + QCborValue keys = obj.value(QStringLiteral("Keys")); + if (keys.isArray() && !keys.toArray().empty()) + plugins.insert(keys.toArray()[0].toString(), obj); + else if (keys.isString()) + plugins.insert(keys.toString(), obj); + } + + qInfo() << "Available print plugins"; + for (auto key : plugins.keys()) { + qInfo() << key; + } + + // Search for user specified print plugin + const QMultiMap keyMap = l->keyMap(); QMultiMap::const_iterator it = keyMap.cbegin(); + bool pluginFound = false; if (!qEnvironmentVariableIsEmpty("QT_PRINTER_MODULE")) { QString module = qEnvironmentVariable("QT_PRINTER_MODULE"); QMultiMap::const_iterator it2 = std::find_if(keyMap.cbegin(), keyMap.cend(), [module](const QString &value){ return value == module; }); - if (it2 == keyMap.cend()) + if (it2 == keyMap.cend()) { qWarning() << "Unable to load printer plugin" << module; + } else { + pluginFound = true; + it = it2; + } + } + + // Search for highest priority plugin if user didn't specify one + if (!pluginFound) { + int priority = -1; + QString key; + for (const auto &&[keyIter, metadata] : plugins.asKeyValueRange()) { + const int pluginPriority = metadata.value(QStringLiteral("Priority")).toInteger(); + if (pluginPriority > priority) { + priority = pluginPriority; + key = keyIter; + } + } + QMultiMap::const_iterator it2 = std::find_if(keyMap.cbegin(), keyMap.cend(), [key](const QString &value){ return value == key; }); + if (it2 == keyMap.cend()) + qWarning() << "Unable to load printer plugin" << key; else it = it2; } + if (it != keyMap.cend()) printerSupport = qLoadPlugin(loader(), it.value()); if (printerSupport) diff --git a/src/printsupport/kernel/qprint_p.h b/src/printsupport/kernel/qprint_p.h index 0a94aa8db371..4ed56f7ea2e9 100644 --- a/src/printsupport/kernel/qprint_p.h +++ b/src/printsupport/kernel/qprint_p.h @@ -118,8 +118,35 @@ namespace QPrint { QPrint::OutputBinId id; }; + struct OptionCombo { + QByteArray name; + QString displayName; + QList choices; + QList displayChoices; + int defaultChoice; + }; + + struct OptionSetting { + QByteArray name; + QByteArray choice; + }; + + struct OptionCombosGroup { + QByteArray groupName; + QString displayGroup; + QList options; + }; + + struct PageLayout { + QSizeF size; + QMarginsF margins; + }; } +Q_DECLARE_METATYPE(QPrint::OptionCombo) +Q_DECLARE_METATYPE(QPrint::OptionSetting) +Q_DECLARE_METATYPE(QPrint::OptionCombosGroup) + struct InputSlotMap { QPrint::InputSlotId id; int windowsId; diff --git a/src/printsupport/kernel/qprintdevice_p.h b/src/printsupport/kernel/qprintdevice_p.h index ec4b9c59fc74..93db21a2040d 100644 --- a/src/printsupport/kernel/qprintdevice_p.h +++ b/src/printsupport/kernel/qprintdevice_p.h @@ -94,7 +94,23 @@ class Q_PRINTSUPPORT_EXPORT QPrintDevice QList supportedColorModes() const; enum PrintDevicePropertyKey { - PDPK_CustomBase = 0xff00 + PDPK_Duplex, + PDPK_PageSet, + PDPK_PageRange, + PDPK_JobHold, + PDPK_JobBillingInfo, + PDPK_JobPriority, + PDPK_JobStartCoverPage, + PDPK_JobEndCoverPage, + PDPK_AdvancedOptions, + PDPK_OptionConflict, + PDPK_NumberUp, + PDPK_NumberUpLayout, + PDPK_PageSize, + PDPK_PageLayout, + PDPK_AdvancedColorMode, + PDPK_Locale, + PDPK_CustomBase }; QVariant property(PrintDevicePropertyKey key) const; diff --git a/src/printsupport/kernel/qprintengine_pdf_p.h b/src/printsupport/kernel/qprintengine_pdf_p.h index dbf50080a4e7..f8b6aa72255a 100644 --- a/src/printsupport/kernel/qprintengine_pdf_p.h +++ b/src/printsupport/kernel/qprintengine_pdf_p.h @@ -89,6 +89,8 @@ class Q_PRINTSUPPORT_EXPORT QPdfPrintEnginePrivate : public QPdfEnginePrivate friend class QCupsPrintEngine; friend class QCupsPrintEnginePrivate; + friend class QCpdbPrintEngine; + friend class QCpdbPrintEnginePrivate; QString printerName; QString printProgram; diff --git a/src/printsupport/qt_cmdline.cmake b/src/printsupport/qt_cmdline.cmake index dfbe5febe46d..4545bcfa4195 100644 --- a/src/printsupport/qt_cmdline.cmake +++ b/src/printsupport/qt_cmdline.cmake @@ -1 +1,2 @@ qt_commandline_option(cups TYPE boolean) +qt_commandline_option(cpdb TYPE boolean) diff --git a/src/printsupport/widgets/qcupsjobwidget.cpp b/src/printsupport/widgets/qcupsjobwidget.cpp deleted file mode 100644 index dea528658396..000000000000 --- a/src/printsupport/widgets/qcupsjobwidget.cpp +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - - -#include "qcupsjobwidget_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -/*! - \internal - \class QCupsJobWidget - - A widget to add to QPrintDialog to enable extra CUPS options - such as Job Scheduling, Job Priority or Job Billing - \ingroup printing - \inmodule QtPrintSupport - */ - -QCupsJobWidget::QCupsJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent) - : QWidget(parent), - m_printer(printer), - m_printDevice(printDevice) -{ - m_ui.setupUi(this); - //set all the default values - initJobHold(); - initJobBilling(); - initJobPriority(); - initBannerPages(); - - updateSavedValues(); -} - -QCupsJobWidget::~QCupsJobWidget() -{ -} - -void QCupsJobWidget::setupPrinter() -{ - QCUPSSupport::setJobHold(m_printer, jobHold(), jobHoldTime()); - QCUPSSupport::setJobBilling(m_printer, jobBilling()); - QCUPSSupport::setJobPriority(m_printer, jobPriority()); - QCUPSSupport::setBannerPages(m_printer, startBannerPage(), endBannerPage()); -} - -void QCupsJobWidget::updateSavedValues() -{ - m_savedJobHoldWithTime = { jobHold(), jobHoldTime() }; - m_savedJobBilling = jobBilling(); - m_savedPriority = jobPriority(); - m_savedJobSheets = { startBannerPage(), endBannerPage() }; -} - -void QCupsJobWidget::revertToSavedValues() -{ - setJobHold(m_savedJobHoldWithTime.jobHold, m_savedJobHoldWithTime.time); - toggleJobHoldTime(); - - setJobBilling(m_savedJobBilling); - - setJobPriority(m_savedPriority); - - setStartBannerPage(m_savedJobSheets.startBannerPage); - setEndBannerPage(m_savedJobSheets.endBannerPage); -} - -void QCupsJobWidget::initJobHold() -{ - m_ui.jobHoldComboBox->addItem(tr("Print Immediately"), QVariant::fromValue(QCUPSSupport::NoHold)); - m_ui.jobHoldComboBox->addItem(tr("Hold Indefinitely"), QVariant::fromValue(QCUPSSupport::Indefinite)); - m_ui.jobHoldComboBox->addItem(tr("Day (06:00 to 17:59)"), QVariant::fromValue(QCUPSSupport::DayTime)); - m_ui.jobHoldComboBox->addItem(tr("Night (18:00 to 05:59)"), QVariant::fromValue(QCUPSSupport::Night)); - m_ui.jobHoldComboBox->addItem(tr("Second Shift (16:00 to 23:59)"), QVariant::fromValue(QCUPSSupport::SecondShift)); - m_ui.jobHoldComboBox->addItem(tr("Third Shift (00:00 to 07:59)"), QVariant::fromValue(QCUPSSupport::ThirdShift)); - m_ui.jobHoldComboBox->addItem(tr("Weekend (Saturday to Sunday)"), QVariant::fromValue(QCUPSSupport::Weekend)); - m_ui.jobHoldComboBox->addItem(tr("Specific Time"), QVariant::fromValue(QCUPSSupport::SpecificTime)); - - connect(m_ui.jobHoldComboBox, &QComboBox::currentIndexChanged, this, &QCupsJobWidget::toggleJobHoldTime); - - QCUPSSupport::JobHoldUntilWithTime jobHoldWithTime; - - if (m_printDevice) { - const QString jobHoldUntilString = m_printDevice->property(PDPK_CupsJobHoldUntil).toString(); - jobHoldWithTime = QCUPSSupport::parseJobHoldUntil(jobHoldUntilString); - } - - setJobHold(jobHoldWithTime.jobHold, jobHoldWithTime.time); - toggleJobHoldTime(); -} - -void QCupsJobWidget::setJobHold(QCUPSSupport::JobHoldUntil jobHold, QTime holdUntilTime) -{ - if (jobHold == QCUPSSupport::SpecificTime && holdUntilTime.isNull()) { - jobHold = QCUPSSupport::NoHold; - toggleJobHoldTime(); - } - m_ui.jobHoldComboBox->setCurrentIndex(m_ui.jobHoldComboBox->findData(QVariant::fromValue(jobHold))); - m_ui.jobHoldTimeEdit->setTime(holdUntilTime); -} - -QCUPSSupport::JobHoldUntil QCupsJobWidget::jobHold() const -{ - return qvariant_cast(m_ui.jobHoldComboBox->itemData(m_ui.jobHoldComboBox->currentIndex())); -} - -void QCupsJobWidget::toggleJobHoldTime() -{ - if (jobHold() == QCUPSSupport::SpecificTime) - m_ui.jobHoldTimeEdit->setEnabled(true); - else - m_ui.jobHoldTimeEdit->setEnabled(false); -} - -QTime QCupsJobWidget::jobHoldTime() const -{ - return m_ui.jobHoldTimeEdit->time(); -} - -void QCupsJobWidget::initJobBilling() -{ - QString jobBilling; - if (m_printDevice) - jobBilling = m_printDevice->property(PDPK_CupsJobBilling).toString(); - - setJobBilling(jobBilling); -} - -void QCupsJobWidget::setJobBilling(const QString &jobBilling) -{ - m_ui.jobBillingLineEdit->setText(jobBilling); -} - -QString QCupsJobWidget::jobBilling() const -{ - return m_ui.jobBillingLineEdit->text(); -} - -void QCupsJobWidget::initJobPriority() -{ - int priority = -1; - if (m_printDevice) { - bool ok; - priority = m_printDevice->property(PDPK_CupsJobPriority).toInt(&ok); - if (!ok) - priority = -1; - } - - if (priority < 0 || priority > 100) - priority = 50; - - setJobPriority(priority); -} - -void QCupsJobWidget::setJobPriority(int jobPriority) -{ - m_ui.jobPrioritySpinBox->setValue(jobPriority); -} - -int QCupsJobWidget::jobPriority() const -{ - return m_ui.jobPrioritySpinBox->value(); -} - -void QCupsJobWidget::initBannerPages() -{ - m_ui.startBannerPageCombo->addItem(tr("None", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::NoBanner)); - m_ui.startBannerPageCombo->addItem(tr("Standard", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Standard)); - m_ui.startBannerPageCombo->addItem(tr("Unclassified", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Unclassified)); - m_ui.startBannerPageCombo->addItem(tr("Confidential", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Confidential)); - m_ui.startBannerPageCombo->addItem(tr("Classified", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Classified)); - m_ui.startBannerPageCombo->addItem(tr("Secret", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Secret)); - m_ui.startBannerPageCombo->addItem(tr("Top Secret", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::TopSecret)); - - m_ui.endBannerPageCombo->addItem(tr("None", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::NoBanner)); - m_ui.endBannerPageCombo->addItem(tr("Standard", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Standard)); - m_ui.endBannerPageCombo->addItem(tr("Unclassified", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Unclassified)); - m_ui.endBannerPageCombo->addItem(tr("Confidential", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Confidential)); - m_ui.endBannerPageCombo->addItem(tr("Classified", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Classified)); - m_ui.endBannerPageCombo->addItem(tr("Secret", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::Secret)); - m_ui.endBannerPageCombo->addItem(tr("Top Secret", "CUPS Banner page"), QVariant::fromValue(QCUPSSupport::TopSecret)); - - QCUPSSupport::JobSheets jobSheets; - - if (m_printDevice) { - const QString jobSheetsString = m_printDevice->property(PDPK_CupsJobSheets).toString(); - jobSheets = QCUPSSupport::parseJobSheets(jobSheetsString); - } - - setStartBannerPage(jobSheets.startBannerPage); - setEndBannerPage(jobSheets.endBannerPage); -} - -void QCupsJobWidget::setStartBannerPage(const QCUPSSupport::BannerPage bannerPage) -{ - m_ui.startBannerPageCombo->setCurrentIndex(m_ui.startBannerPageCombo->findData(QVariant::fromValue(bannerPage))); -} - -QCUPSSupport::BannerPage QCupsJobWidget::startBannerPage() const -{ - return qvariant_cast(m_ui.startBannerPageCombo->itemData(m_ui.startBannerPageCombo->currentIndex())); -} - -void QCupsJobWidget::setEndBannerPage(const QCUPSSupport::BannerPage bannerPage) -{ - m_ui.endBannerPageCombo->setCurrentIndex(m_ui.endBannerPageCombo->findData(QVariant::fromValue(bannerPage))); -} - -QCUPSSupport::BannerPage QCupsJobWidget::endBannerPage() const -{ - return qvariant_cast(m_ui.endBannerPageCombo->itemData(m_ui.endBannerPageCombo->currentIndex())); -} - -QT_END_NAMESPACE - -#include "moc_qcupsjobwidget_p.cpp" diff --git a/src/printsupport/widgets/qprintjobwidget.cpp b/src/printsupport/widgets/qprintjobwidget.cpp new file mode 100644 index 000000000000..98a170a8f334 --- /dev/null +++ b/src/printsupport/widgets/qprintjobwidget.cpp @@ -0,0 +1,235 @@ +// Copyright (C) 2022-2023 Gaurav Guleria +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qprintjobwidget_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QPrintJobWidget + + A widget to add to QPrintDialog to enable extra job options + such as Job Scheduling, Job Priority or Job Billing + \ingroup printing + \inmodule QtPrintSupport + */ + +QPrintJobWidget::QPrintJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent) + : QWidget(parent), + m_printer(printer), + m_printDevice(printDevice) +{ + m_ui.setupUi(this); + + // set all the default values + initJobHold(); + initJobBilling(); + initJobPriority(); + initBannerPages(); + + updateSavedValues(); +} + +QPrintJobWidget::~QPrintJobWidget() +{ +} + +void QPrintJobWidget::updateSavedValues() +{ + m_savedJobHoldWithTime = QPair(jobHold(),jobHoldTime()); + m_savedJobBilling = jobBilling(); + m_savedPriority = jobPriority(); + m_savedJobSheets = QPair(startBannerPage(),endBannerPage()); +} + +void QPrintJobWidget::revertToSavedValues() +{ + setJobHold(m_savedJobHoldWithTime.first, m_savedJobHoldWithTime.second); + toggleJobHoldTime(); + setJobBilling(m_savedJobBilling); + setJobPriority(m_savedPriority); + setStartBannerPage(m_savedJobSheets.first); + setEndBannerPage(m_savedJobSheets.second); +} + +void QPrintJobWidget::setupPrinter() +{ + if (m_ui.startBannerPageCombo->isEnabled() && m_ui.endBannerPageCombo->isEnabled()) { + m_printDevice->setProperty(QPrintDevice::PDPK_JobStartCoverPage, QVariant(startBannerPage())); + m_printDevice->setProperty(QPrintDevice::PDPK_JobEndCoverPage, QVariant(endBannerPage())); + } + + if (m_ui.jobHoldComboBox->isEnabled()) { + QByteArray jobHoldVal = jobHold(); + QByteArray jobHoldUntil = jobHoldVal; + if (jobHoldVal == "#specific#") { + QTime holdUntilTime = jobHoldTime(); + QDateTime localDateTime = QDateTime::currentDateTime(); + + if (holdUntilTime < localDateTime.time()) + localDateTime = localDateTime.addDays(1); + localDateTime.setTime(holdUntilTime); + jobHoldUntil = localDateTime.toUTC().time().toString(u"HH:mm").toLocal8Bit(); + } + m_printDevice->setProperty(QPrintDevice::PDPK_JobHold, QVariant(jobHoldUntil)); + } + + if (m_ui.jobPrioritySpinBox->isEnabled()) + m_printDevice->setProperty(QPrintDevice::PDPK_JobPriority, QVariant(jobPriority())); + + if (m_ui.jobBillingLineEdit->isEnabled()) + m_printDevice->setProperty(QPrintDevice::PDPK_JobBillingInfo, QVariant(jobBilling())); +} + +void QPrintJobWidget::initJobHold() +{ + if (!m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_JobHold, QVariant())) { + m_ui.jobHoldComboBox->setEnabled(false); + return; + } + + auto jobHold = qvariant_cast(m_printDevice->property(QPrintDevice::PDPK_JobHold)); + for (int i = 0; i < jobHold.choices.size(); i++) { + m_ui.jobHoldComboBox->addItem(jobHold.displayChoices[i], QVariant(jobHold.choices[i])); + } + m_ui.jobHoldComboBox->setCurrentIndex(jobHold.defaultChoice); + + auto specificVal = QVariant(QByteArray("#specific#")); + if (m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_JobHold, specificVal)) { + m_ui.jobHoldComboBox->addItem(tr("Specific Time"), specificVal); + } + + toggleJobHoldTime(); + connect(m_ui.jobHoldComboBox, &QComboBox::currentIndexChanged, this, &QPrintJobWidget::toggleJobHoldTime); +} + +void QPrintJobWidget::initJobBilling() +{ + if (!m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_JobBillingInfo, QVariant())) { + m_ui.jobBillingLineEdit->setEnabled(false); + return; + } + setJobBilling(m_printDevice->property(QPrintDevice::PDPK_JobBillingInfo).toString()); +} + +void QPrintJobWidget::initJobPriority() +{ + if (!m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_JobPriority, QVariant())) { + m_ui.jobPrioritySpinBox->setEnabled(false); + return; + } + bool ok; + int defaultPriority = m_printDevice->property(QPrintDevice::PDPK_JobPriority).toInt(&ok); + if (ok && defaultPriority > 0) + setJobPriority(defaultPriority); + else + setJobPriority(50); +} + +void QPrintJobWidget::initBannerPages() +{ + if (!m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_JobStartCoverPage, QVariant())) { + m_ui.startBannerPageCombo->setEnabled(false); + } else { + auto startCover = qvariant_cast(m_printDevice->property(QPrintDevice::PDPK_JobStartCoverPage)); + for (int i = 0; i < startCover.choices.size(); i++) { + m_ui.startBannerPageCombo->addItem(startCover.displayChoices[i], QVariant(startCover.choices[i])); + } + m_ui.startBannerPageCombo->setCurrentIndex(startCover.defaultChoice); + } + + if (!m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_JobEndCoverPage, QVariant())) { + m_ui.endBannerPageCombo->setEnabled(false); + } else { + auto endCover = qvariant_cast(m_printDevice->property(QPrintDevice::PDPK_JobEndCoverPage)); + for (int i = 0; i < endCover.choices.size(); i++) { + m_ui.endBannerPageCombo->addItem(endCover.displayChoices[i], QVariant(endCover.choices[i])); + } + m_ui.endBannerPageCombo->setCurrentIndex(endCover.defaultChoice); + } +} + +QByteArray QPrintJobWidget::jobHold() const +{ + return qvariant_cast(m_ui.jobHoldComboBox->itemData(m_ui.jobHoldComboBox->currentIndex())); +} + +QTime QPrintJobWidget::jobHoldTime() const +{ + return m_ui.jobHoldTimeEdit->time(); +} + +QString QPrintJobWidget::jobBilling() const +{ + return m_ui.jobBillingLineEdit->text(); +} + +int QPrintJobWidget::jobPriority() const +{ + return m_ui.jobPrioritySpinBox->value(); +} + +QByteArray QPrintJobWidget::startBannerPage() const +{ + return qvariant_cast(m_ui.startBannerPageCombo->itemData(m_ui.startBannerPageCombo->currentIndex())); +} + +QByteArray QPrintJobWidget::endBannerPage() const +{ + return qvariant_cast(m_ui.endBannerPageCombo->itemData(m_ui.endBannerPageCombo->currentIndex())); +} + +void QPrintJobWidget::setJobBilling(const QString &jobBilling) +{ + m_ui.jobBillingLineEdit->setText(jobBilling); +} + +void QPrintJobWidget::setJobPriority(int jobPriority) +{ + m_ui.jobPrioritySpinBox->setValue(jobPriority); +} + +void QPrintJobWidget::setStartBannerPage(const QByteArray &bannerPage) +{ + int index = m_ui.startBannerPageCombo->findData(QVariant(bannerPage)); + if (index > 0) + m_ui.startBannerPageCombo->setCurrentIndex(index); +} + +void QPrintJobWidget::setEndBannerPage(const QByteArray &bannerPage) +{ + int index = m_ui.endBannerPageCombo->findData(QVariant(bannerPage)); + if (index > 0) + m_ui.endBannerPageCombo->setCurrentIndex(index); +} + +void QPrintJobWidget::setJobHold(const QByteArray &jobHold, const QTime &holdUntilTime) +{ + m_ui.jobHoldComboBox->setCurrentIndex(m_ui.jobHoldComboBox->findData(QVariant(jobHold))); + m_ui.jobHoldTimeEdit->setTime(holdUntilTime); +} + +void QPrintJobWidget::toggleJobHoldTime() +{ + if (jobHold() == "#specific#") + m_ui.jobHoldTimeEdit->setEnabled(true); + else + m_ui.jobHoldTimeEdit->setEnabled(false); +} + +QT_END_NAMESPACE + +#include "moc_qprintjobwidget_p.cpp" diff --git a/src/printsupport/widgets/qcupsjobwidget.ui b/src/printsupport/widgets/qprintjobwidget.ui similarity index 60% rename from src/printsupport/widgets/qcupsjobwidget.ui rename to src/printsupport/widgets/qprintjobwidget.ui index 7450c0629fa3..91a024870907 100644 --- a/src/printsupport/widgets/qcupsjobwidget.ui +++ b/src/printsupport/widgets/qprintjobwidget.ui @@ -1,7 +1,8 @@ - - QCupsJobWidget - - + + + QPrintJobWidget + + 0 0 @@ -9,62 +10,62 @@ 294 - + Job - - + + Job Control - - - - + + + + Scheduled printing: - - + + - - + + - - - + + + Billing information: - - + + - - - + + + Job priority: - - - + + + 100 - + 50 - - - + + + Qt::Horizontal - + 180 20 @@ -105,11 +106,11 @@ - - + + Qt::Vertical - + 20 13 diff --git a/src/printsupport/widgets/qcupsjobwidget_p.h b/src/printsupport/widgets/qprintjobwidget_p.h similarity index 52% rename from src/printsupport/widgets/qcupsjobwidget_p.h rename to src/printsupport/widgets/qprintjobwidget_p.h index 22d190edc8f9..7efc405a263a 100644 --- a/src/printsupport/widgets/qcupsjobwidget_p.h +++ b/src/printsupport/widgets/qprintjobwidget_p.h @@ -1,9 +1,9 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2022-2023 Gaurav Guleria // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#ifndef QCUPSJOBWIDGET_P_H -#define QCUPSJOBWIDGET_P_H +#ifndef QPRINTJOBWIDGET_P_H +#define QPRINTJOBWIDGET_P_H // // W A R N I N G @@ -18,11 +18,8 @@ // #include -#include -QT_REQUIRE_CONFIG(cupsjobwidget); - -#include +#include QT_BEGIN_NAMESPACE @@ -31,37 +28,37 @@ class QTime; class QPrinter; class QPrintDevice; -class QCupsJobWidget : public QWidget +class QPrintJobWidget : public QWidget { Q_OBJECT public: - explicit QCupsJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent = nullptr); - ~QCupsJobWidget(); + explicit QPrintJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent = nullptr); + ~QPrintJobWidget(); void setupPrinter(); + void updateSavedValues(); void revertToSavedValues(); + Q_DISABLE_COPY_MOVE(QPrintJobWidget) + private Q_SLOTS: void toggleJobHoldTime(); private: - void setJobHold(QCUPSSupport::JobHoldUntil jobHold = QCUPSSupport::NoHold, QTime holdUntilTime = QTime()); - QCUPSSupport::JobHoldUntil jobHold() const; + QByteArray jobHold() const; QTime jobHoldTime() const; - - void setJobBilling(const QString &jobBilling = QString()); QString jobBilling() const; - - void setJobPriority(int priority = 50); int jobPriority() const; + QByteArray startBannerPage() const; + QByteArray endBannerPage() const; - void setStartBannerPage(const QCUPSSupport::BannerPage bannerPage = QCUPSSupport::NoBanner); - QCUPSSupport::BannerPage startBannerPage() const; - - void setEndBannerPage(const QCUPSSupport::BannerPage bannerPage = QCUPSSupport::NoBanner); - QCUPSSupport::BannerPage endBannerPage() const; + void setJobHold(const QByteArray &jobHold, const QTime &holdUntilTime); + void setJobBilling(const QString &jobBilling = QString()); + void setJobPriority(int priority = 50); + void setStartBannerPage(const QByteArray &bannerPage); + void setEndBannerPage(const QByteArray &bannerPage); void initJobHold(); void initJobBilling(); @@ -70,16 +67,14 @@ private Q_SLOTS: QPrinter *m_printer; QPrintDevice *m_printDevice; - Ui::QCupsJobWidget m_ui; + Ui::QPrintJobWidget m_ui; - QCUPSSupport::JobHoldUntilWithTime m_savedJobHoldWithTime; + QPair m_savedJobHoldWithTime; QString m_savedJobBilling; int m_savedPriority; - QCUPSSupport::JobSheets m_savedJobSheets; - - Q_DISABLE_COPY_MOVE(QCupsJobWidget) + QPair m_savedJobSheets; }; QT_END_NAMESPACE -#endif // QCUPSJOBWIDGET_P_H +#endif // QPRINTJOBWIDGET_P_H diff --git a/src/printsupport/widgets/qprintpreviewwidget.cpp b/src/printsupport/widgets/qprintpreviewwidget.cpp index eb111a6efcff..9dadb7ac089a 100644 --- a/src/printsupport/widgets/qprintpreviewwidget.cpp +++ b/src/printsupport/widgets/qprintpreviewwidget.cpp @@ -115,7 +115,7 @@ class GraphicsView : public QGraphicsView setFrameStyle(QFrame::NoFrame); #endif } -signals: +Q_SIGNALS: void resized(); protected: @@ -125,13 +125,13 @@ class GraphicsView : public QGraphicsView const QSignalBlocker blocker(verticalScrollBar()); // Don't change page, QTBUG-14517 QGraphicsView::resizeEvent(e); } - emit resized(); + Q_EMIT resized(); } void showEvent(QShowEvent* e) override { QGraphicsView::showEvent(e); - emit resized(); + Q_EMIT resized(); } }; @@ -237,7 +237,7 @@ void QPrintPreviewWidgetPrivate::_q_fit(bool doFitting) } zoomFactor = graphicsView->transform().m11() * (float(printer->logicalDpiY()) / q->logicalDpiY()); - emit q->previewChanged(); + Q_EMIT q->previewChanged(); } void QPrintPreviewWidgetPrivate::_q_updateCurrentPage() @@ -250,7 +250,7 @@ void QPrintPreviewWidgetPrivate::_q_updateCurrentPage() int newPage = calcCurrentPage(); if (newPage != curPage) { curPage = newPage; - emit q->previewChanged(); + Q_EMIT q->previewChanged(); } } @@ -365,7 +365,7 @@ void QPrintPreviewWidgetPrivate::generatePreview() if (printer->d_func()->previewMode()) return; printer->d_func()->setPreviewMode(true); - emit q->paintRequested(printer); + Q_EMIT q->paintRequested(printer); printer->d_func()->setPreviewMode(false); pictures = printer->d_func()->previewPages(); populateScene(); // i.e. setPreviewPrintedPictures() e.l. @@ -373,7 +373,7 @@ void QPrintPreviewWidgetPrivate::generatePreview() curPage = pages.size() > 0 ? qBound(1, curPage, pages.size()) : 1; if (fitting) _q_fit(); - emit q->previewChanged(); + Q_EMIT q->previewChanged(); } void QPrintPreviewWidgetPrivate::setCurrentPage(int pageNumber) @@ -548,7 +548,7 @@ void QPrintPreviewWidget::setViewMode(ViewMode mode) d->fitting = false; d->zoomMode = QPrintPreviewWidget::CustomZoom; d->zoomFactor = d->graphicsView->transform().m11() * (float(d->printer->logicalDpiY()) / logicalDpiY()); - emit previewChanged(); + Q_EMIT previewChanged(); } else { d->fitting = true; d->_q_fit(); @@ -583,7 +583,7 @@ void QPrintPreviewWidget::print() { Q_D(QPrintPreviewWidget); // ### make use of the generated pages - emit paintRequested(d->printer); + Q_EMIT paintRequested(d->printer); } /*! diff --git a/src/widgets/util/qcompleter_p.h b/src/widgets/util/qcompleter_p.h index a88996f18093..9e1630a8c9d3 100644 --- a/src/widgets/util/qcompleter_p.h +++ b/src/widgets/util/qcompleter_p.h @@ -212,7 +212,7 @@ class QCompletionModel : public QAbstractProxyModel Q_DECLARE_PRIVATE(QCompletionModel) -signals: +Q_SIGNALS: void rowsAdded(); public Q_SLOTS: