From 42967e18116eee6ace4f63cb06deff75b6eacffa Mon Sep 17 00:00:00 2001 From: Gaurav Guleria Date: Sun, 9 Oct 2022 16:57:41 +0530 Subject: [PATCH 01/10] Add CPDB support to Qt print dialog The Common Print Dialog Backends (CPDB) concept has GUI-toolkit-independent backends for each print technology (CUPS, Print to File, cloud printing services, ...) and each print dialog (GTK, Qt, Chromium, Firefox, ...) is supposed to use this backend, so that changes in print technologies can be centrally and quickly covered by changing the backends and everything new gets available in all print dialogs. This commit provides Qt print dialog implementation which adds support for the CPDB concept. It communincates with all the installed CPDB backends and so gives support for all these print technologies to the Qt print dialog. To make use of CPDB, Qt should be configured with cpdb and cpdbjobwidget enabled and other print technologies (eg. cups and cupsjobwidget) disabled to prevent printer duplication. Change-Id: Ic97c41979040adb6e9ffab540c09edadb6b5de3e --- cmake/FindWrapCPDB.cmake | 25 ++ src/gui/painting/qpagesize.cpp | 23 + src/gui/painting/qpagesize.h | 2 + src/plugins/printsupport/CMakeLists.txt | 6 +- src/plugins/printsupport/cpdb/CMakeLists.txt | 23 + src/plugins/printsupport/cpdb/cpdb.json | 3 + src/plugins/printsupport/cpdb/main.cpp | 37 ++ .../printsupport/cpdb/qcpdbprintdevice.cpp | 329 +++++++++++++++ .../printsupport/cpdb/qcpdbprintdevice.h | 73 ++++ .../printsupport/cpdb/qcpdbprintengine.cpp | 232 +++++++++++ .../printsupport/cpdb/qcpdbprintengine_p.h | 75 ++++ .../printsupport/cpdb/qcpdbprintersupport.cpp | 101 +++++ .../printsupport/cpdb/qcpdbprintersupport_p.h | 45 ++ src/printsupport/CMakeLists.txt | 18 +- src/printsupport/configure.cmake | 17 + .../dialogs/qabstractprintdialog.cpp | 3 +- .../dialogs/qpagesetupdialog_unix.cpp | 96 ++++- .../dialogs/qpagesetupdialog_unix_p.h | 12 +- .../dialogs/qprintdialog_unix.cpp | 393 ++++++++++++------ .../dialogs/qprintpreviewdialog.cpp | 2 +- src/printsupport/kernel/qcpdb.cpp | 27 ++ src/printsupport/kernel/qcpdb_p.h | 44 ++ .../kernel/qplatformprintdevice.cpp | 6 + .../kernel/qplatformprintdevice.h | 2 + src/printsupport/kernel/qprintengine_pdf_p.h | 2 + src/printsupport/qt_cmdline.cmake | 1 + src/printsupport/widgets/qcpdbjobwidget.cpp | 208 +++++++++ src/printsupport/widgets/qcpdbjobwidget_p.h | 77 ++++ .../widgets/qprintpreviewwidget.cpp | 18 +- src/widgets/util/qcompleter_p.h | 2 +- 30 files changed, 1760 insertions(+), 142 deletions(-) create mode 100644 cmake/FindWrapCPDB.cmake create mode 100644 src/plugins/printsupport/cpdb/CMakeLists.txt create mode 100644 src/plugins/printsupport/cpdb/cpdb.json create mode 100644 src/plugins/printsupport/cpdb/main.cpp create mode 100644 src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp create mode 100644 src/plugins/printsupport/cpdb/qcpdbprintdevice.h create mode 100644 src/plugins/printsupport/cpdb/qcpdbprintengine.cpp create mode 100644 src/plugins/printsupport/cpdb/qcpdbprintengine_p.h create mode 100644 src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp create mode 100644 src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h create mode 100644 src/printsupport/kernel/qcpdb.cpp create mode 100644 src/printsupport/kernel/qcpdb_p.h create mode 100644 src/printsupport/widgets/qcpdbjobwidget.cpp create mode 100644 src/printsupport/widgets/qcpdbjobwidget_p.h diff --git a/cmake/FindWrapCPDB.cmake b/cmake/FindWrapCPDB.cmake new file mode 100644 index 000000000000..2e55fef9f3cc --- /dev/null +++ b/cmake/FindWrapCPDB.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if (TARGET WrapCPDB::WrapCPDB) + set(WrapCPDB_FOUND ON) + return() +endif() + +find_package(PkgConfig QUIET) +if (PKG_CONFIG_FOUND) + pkg_check_modules(CPDB QUIET cpdb-frontend) + if (CPDB_FOUND) + add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED) + target_compile_definitions(WrapCPDB::WrapCPDB INTERFACE -DQT_NO_KEYWORDS) + set_target_properties(WrapCPDB::WrapCPDB PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${CPDB_INCLUDE_DIRS}") + set_target_properties(WrapCPDB::WrapCPDB PROPERTIES + INTERFACE_LINK_LIBRARIES "${CPDB_LIBRARIES}") + endif() +endif() + +find_package_handle_standard_args(WrapCPDB + REQUIRED_VARS CPDB_INCLUDE_DIRS CPDB_LIBRARIES + VERSION_VAR CPDB_VERSION) + 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..c12a6ce5c2c1 100644 --- a/src/plugins/printsupport/CMakeLists.txt +++ b/src/plugins/printsupport/CMakeLists.txt @@ -1,6 +1,10 @@ # 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) +elseif(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..a45468c372dd --- /dev/null +++ b/src/plugins/printsupport/cpdb/CMakeLists.txt @@ -0,0 +1,23 @@ + +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 + 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..c5e0fe9e9816 --- /dev/null +++ b/src/plugins/printsupport/cpdb/cpdb.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "cpdbprintersupport" ] +} 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/qcpdbprintdevice.cpp b/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp new file mode 100644 index 000000000000..48815e67dd13 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp @@ -0,0 +1,329 @@ +// 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 (value == CPDB_SIDES_ONE_SIDED) + m_duplexModes << QPrint::DuplexNone; + else if (value == CPDB_SIDES_TWO_SIDED_SHORT) + m_duplexModes << QPrint::DuplexShortSide; + else if (value == CPDB_SIDES_TWO_SIDED_LONG) + m_duplexModes << QPrint::DuplexLongSide; + } + } +} + +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 +{ + Q_UNUSED(key); + Q_UNUSED(params); + + return true; +} + +QVariant QCpdbPrintDevice::property(QPrintDevice::PrintDevicePropertyKey key) const +{ + if (key == PDPK_CpdbPrinterObj) + return QVariant::fromValue(m_printerObj); + + return QPlatformPrintDevice::property(key); +} + +bool QCpdbPrintDevice::setProperty(QPrintDevice::PrintDevicePropertyKey key, const QVariant &value) +{ + 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..e2213c7511f1 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintdevice.h @@ -0,0 +1,73 @@ +// 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 + +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; +}; + +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..8fb82ecd04f7 --- /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..1e9921401b04 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintengine_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 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..568b624fc1c8 --- /dev/null +++ b/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp @@ -0,0 +1,101 @@ +// 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); + cpdbConnectToDBus(frontendObj); + cpdbIgnoreLastSavedSettings(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..a1005edd9491 --- /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/printsupport/CMakeLists.txt b/src/printsupport/CMakeLists.txt index 0e6e1cc012d4..927c4624667b 100644 --- a/src/printsupport/CMakeLists.txt +++ b/src/printsupport/CMakeLists.txt @@ -84,6 +84,22 @@ 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 + SOURCES + kernel/qcpdb.cpp kernel/qcpdb_p.h + LIBRARIES + WrapCPDB::WrapCPDB +) + +qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cpdbjobwidget AND UNIX AND NOT APPLE + SOURCES + widgets/qcpdbjobwidget.cpp widgets/qcupsjobwidget.ui widgets/qcpdbjobwidget_p.h + 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 @@ -201,7 +217,7 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printdialog AND UNIX 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..2c62238d726f 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 @@ -41,6 +44,19 @@ qt_feature("cupspassworddialog" PRIVATE 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 AND NOT QT_FEATURE_cups +) +qt_feature_definition("cpdb" "QT_NO_CPDB" NEGATE VALUE "1") +qt_feature("cpdbjobwidget" PUBLIC PRIVATE + SECTION "Widgets" + LABEL "CPDB job control widget" + CONDITION ( QT_FEATURE_buttongroup ) AND ( QT_FEATURE_calendarwidget ) AND ( QT_FEATURE_checkbox ) AND ( QT_FEATURE_combobox ) AND ( QT_FEATURE_cpdb ) AND ( QT_FEATURE_datetimeedit ) AND ( QT_FEATURE_groupbox ) AND ( QT_FEATURE_tablewidget ) +) +qt_feature_definition("cpdbjobwidget" "QT_NO_CPDBJOBWIDGET" NEGATE VALUE "1") qt_feature("printer" PUBLIC SECTION "Painting" LABEL "QPrinter" @@ -70,5 +86,6 @@ qt_feature("printpreviewdialog" PUBLIC ) qt_feature_definition("printpreviewdialog" "QT_NO_PRINTPREVIEWDIALOG" NEGATE VALUE "1") qt_configure_add_summary_section(NAME "Qt PrintSupport") +qt_configure_add_summary_entry(ARGS "cpdb") qt_configure_add_summary_entry(ARGS "cups") qt_configure_end_summary_section() # end of "Qt PrintSupport" section 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..659757533021 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp +++ b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp @@ -58,7 +58,6 @@ struct PaperSourceNames }; #endif - // QPagePreview // - Private widget to display preview of page layout // - Embedded in QPageSetupWidget @@ -202,6 +201,9 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent) m_pagePreview(nullptr), m_printer(nullptr), m_printDevice(nullptr), +#if QT_CONFIG(cpdb) + m_printerObj(nullptr), +#endif #if QT_CONFIG(cups) m_pageSizePpdOption(nullptr), #endif @@ -235,7 +237,6 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent) m_ui.reversePortrait->setVisible(false); initUnits(); - initPagesPerSheet(); connect(m_ui.unitCombo, &QComboBox::activated, this, &QPageSetupWidget::unitChanged); @@ -271,7 +272,51 @@ void QPageSetupWidget::initUnits() // Init the Pages Per Sheet (n-up) combo boxes if using CUPS void QPageSetupWidget::initPagesPerSheet() { -#if QT_CONFIG(cups) +#if QT_CONFIG(cpdb) + bool showNumUp = false; + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP); + if (opt && opt->num_supported > 1) { + showNumUp = true; + m_ui.pagesPerSheetCombo->clear(); + for (int i = 0; i < opt->num_supported; i++) { + QByteArray value = opt->supported_values[i]; + QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, + CPDB_OPTION_NUMBER_UP, + opt->supported_values[i]); + m_ui.pagesPerSheetCombo->addItem(QString::fromLocal8Bit(displayVal), + QVariant::fromValue(value)); + } + + QByteArray defaultVal = opt->default_value; + int idx = m_ui.pagesPerSheetCombo->findData(QVariant::fromValue(defaultVal)); + if (idx >= 0) + m_ui.pagesPerSheetCombo->setCurrentIndex(idx); + } + m_ui.pagesPerSheetCombo->setVisible(showNumUp); + + bool showNumUpLayout = false; + opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT); + if (opt && opt->num_supported > 1) { + showNumUpLayout = true; + m_ui.pagesPerSheetLayoutCombo->clear(); + for (int i = 0; i < opt->num_supported; i++) { + QByteArray value = opt->supported_values[i]; + QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, + CPDB_OPTION_NUMBER_UP_LAYOUT, + opt->supported_values[i]); + m_ui.pagesPerSheetLayoutCombo->addItem(QString::fromLocal8Bit(displayVal), + QVariant::fromValue(value)); + } + + QByteArray defaultVal = opt->default_value; + int idx = m_ui.pagesPerSheetLayoutCombo->findData(QVariant::fromValue(defaultVal)); + if (idx >= 0) + m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(idx); + } + m_ui.pagesPerSheetLayoutCombo->setVisible(showNumUpLayout); + + m_ui.pagesPerSheetButtonGroup->setVisible(showNumUp || showNumUpLayout); +#elif 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"), @@ -366,7 +411,13 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, m_printer = printer; m_printDevice = printDevice; -#if QT_CONFIG(cups) +#if QT_CONFIG(cpdb) + QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get(); + if (ps) { + QPrintDevice printDevice = ps->createPrintDevice(printerName); + m_printerObj = qvariant_cast(printDevice.property(PDPK_CpdbPrinterObj)); + } +#elif QT_CONFIG(cups) // find the PageSize cups option m_pageSizePpdOption = m_printDevice ? QCUPSSupport::findPpdOption("PageSize", m_printDevice) : nullptr; #endif @@ -386,6 +437,7 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, m_outputFormat = outputFormat; m_printerName = printerName; + initPagesPerSheet(); initPageSizes(); updateWidget(); updateSavedValues(); @@ -495,7 +547,39 @@ void QPageSetupWidget::updateWidget() void QPageSetupWidget::setupPrinter() const { m_printer->setPageLayout(m_pageLayout); + +#if QT_CONFIG(cpdb) + QSizeF size = m_pageLayout.pageSize().size(QPageSize::Millimeter); + QMarginsF margins = m_pageLayout.margins(QPageLayout::Millimeter); + + int width = size.width() * 100.0; + int height = size.height() * 100.0; + int left = margins.left() * 100.0; + int right = margins.right() * 100.0; + int top = margins.top() * 100.0; + int bottom = margins.bottom() * 100.0; + + char *borderless = cpdbGetSetting(m_printerObj, "borderless"); + if (qstrcmp(borderless, "true") == 0) { + left = right = top = bottom = 0; + cpdbClearSetting(m_printerObj->settings, "borderless"); + } + + QString value = 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, value.toLocal8Bit().constData()); +#endif + m_printer->setPageOrientation(m_pageLayout.orientation()); + +#if QT_CONFIG(cpdb) + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP, + qvariant_cast(m_ui.pagesPerSheetCombo->currentData())); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT, + qvariant_cast(m_ui.pagesPerSheetLayoutCombo->currentData())); +#endif #if QT_CONFIG(cups) QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast(m_ui.pagesPerSheetCombo->currentData() ); @@ -567,7 +651,7 @@ void QPageSetupWidget::pageSizeChanged() const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword) << QString::fromLatin1(choice->choice); m_printDevice->setProperty(PDPK_PpdOption, values); - emit ppdOptionChanged(); + Q_EMIT ppdOptionChanged(); break; } } @@ -587,7 +671,7 @@ void QPageSetupWidget::pageSizeChanged() const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword) << QStringLiteral("Custom"); m_printDevice->setProperty(PDPK_PpdOption, values); - emit ppdOptionChanged(); + Q_EMIT ppdOptionChanged(); } #endif } diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h index 0fe3a2e559fd..b39de1ce5de1 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h +++ b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h @@ -17,6 +17,11 @@ #include +#if QT_CONFIG(cpdb) +#include +#include +#endif + #include "qprinter.h" #include "kernel/qprint_p.h" @@ -46,11 +51,11 @@ class QPageSetupWidget : public QWidget { #if QT_CONFIG(cups) bool hasPpdConflict() const; -signals: +Q_SIGNALS: void ppdOptionChanged(); #endif -private slots: +private Q_SLOTS: void pageSizeChanged(); void pageOrientationChanged(); void pagesPerSheetChanged(); @@ -72,6 +77,9 @@ private slots: QPagePreview *m_pagePreview; QPrinter *m_printer; QPrintDevice *m_printDevice; +#if QT_CONFIG(cpdb) + cpdb_printer_obj_t *m_printerObj; +#endif #if QT_CONFIG(cups) ppd_option_t *m_pageSizePpdOption; #endif diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index bdaa5fa03f54..9665fd1b06f9 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -42,11 +42,11 @@ #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 @@ -103,7 +103,7 @@ class QPrintPropertiesDialog : public QDialog void setupPrinter() const; -private slots: +private Q_SLOTS: void reject() override; void accept() override; @@ -111,18 +111,21 @@ 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; @@ -133,6 +136,7 @@ private slots: QStringDecoder toUnicode; QList m_advancedOptionsCombos; #endif + }; class QUnixPrintWidgetPrivate; @@ -180,7 +184,8 @@ class QUnixPrintWidgetPrivate void updateWidget(); -#if QT_CONFIG(cups) +#endif + void setPpdDuplex(QPrinter::DuplexMode mode); ppd_option_t *m_duplexPpdOption; #endif @@ -208,7 +213,6 @@ class QPrintDialogPrivate : public QAbstractPrintDialogPrivate #endif void _q_collapseOrExpandDialog(); -#if QT_CONFIG(cups) void updatePpdDuplexOption(QRadioButton *radio); #endif void setupPrinter(); @@ -244,8 +248,11 @@ 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_jobOptions(nullptr) #endif { setWindowTitle(tr("Printer Properties")); @@ -261,13 +268,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,9 +286,15 @@ 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 } @@ -289,20 +304,18 @@ QPrintPropertiesDialog::~QPrintPropertiesDialog() void QPrintPropertiesDialog::setupPrinter() const { -#if QT_CONFIG(cups) - QCUPSSupport::clearCupsOptions(m_printer); #endif + // setup advanced options first, so as to process borderless option +#endif widget.pageSetup->setupPrinter(); -#if QT_CONFIG(cupsjobwidget) - m_jobOptions->setupPrinter(); + if (m_jobOptions) + m_jobOptions->setupPrinter(); #endif -#if QT_CONFIG(cups) // Set Color by default, that will change if the "ColorModel" property is available m_printer->setColorMode(QPrinter::Color); - setPrinterAdvancedCupsOptions(); #endif } @@ -310,11 +323,10 @@ void QPrintPropertiesDialog::reject() { widget.pageSetup->revertToSavedValues(); -#if QT_CONFIG(cupsjobwidget) - m_jobOptions->revertToSavedValues(); + if (m_jobOptions) + m_jobOptions->revertToSavedValues(); #endif -#if QT_CONFIG(cups) revertAdvancedOptionsToSavedValues(); #endif QDialog::reject(); @@ -322,7 +334,6 @@ void QPrintPropertiesDialog::reject() void QPrintPropertiesDialog::accept() { -#if QT_CONFIG(cups) && QT_CONFIG(messagebox) if (widget.pageSetup->hasPpdConflict()) { widget.tabs->setCurrentWidget(widget.tabPage); const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Page Setup Conflicts"), @@ -331,7 +342,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,8 +351,8 @@ void QPrintPropertiesDialog::accept() advancedOptionsUpdateSavedValues(); #endif -#if QT_CONFIG(cupsjobwidget) - m_jobOptions->updateSavedValues(); + if (m_jobOptions) + m_jobOptions->updateSavedValues(); #endif widget.pageSetup->updateSavedValues(); @@ -352,13 +362,129 @@ void QPrintPropertiesDialog::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"; @@ -377,7 +503,6 @@ static bool isBlacklistedGroup(const ppd_group_t *group) noexcept static bool isBlacklistedOption(const char *keyword) noexcept { // We already let the user set these options elsewhere - const char *cupsOptionBlacklist[] = { "Collate", "Copies", "OutputOrder", @@ -390,7 +515,6 @@ 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() @@ -402,7 +526,6 @@ bool QPrintPropertiesDialog::createAdvancedOptionsWidget() 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); } @@ -501,7 +624,6 @@ bool QPrintPropertiesDialog::createAdvancedOptionsWidget() return anyWidgetCreated; } -void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const { for (const QComboBox *choicesCb : m_advancedOptionsCombos) { const ppd_option_t *option = qvariant_cast(choicesCb->property(ppdOptionProperty)); @@ -516,7 +638,6 @@ 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)); } } @@ -603,12 +724,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,7 +766,6 @@ 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); }); @@ -660,60 +775,83 @@ void QPrintDialogPrivate::init() // initialize printer options void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputFormat) { - Q_Q(QPrintDialog); - QPrinter *p = q->printer(); - printerOutputFormat = 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)); + // 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)); - 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; + 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; + } + 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(true); + + 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); + } + options.pageSetCombo->setEnabled(showPageSet); + options.pageSetLabel->setEnabled(showPageSet); - 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) { @@ -752,7 +890,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 +912,60 @@ 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 + // copies p->setCopyCount(options.copies->value()); p->setCollateCopies(options.collate->isChecked()); @@ -872,9 +1017,14 @@ 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 + // 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 +1036,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 +1137,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,7 +1147,18 @@ void QPrintDialog::accept() QMessageBox::Ok, QMessageBox::Ok); return; } + d->setupPrinter(); + + 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) { const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Duplex Settings Conflicts"), tr("There are conflicts in duplex settings. Do you want to fix them?"), @@ -1008,7 +1167,7 @@ void QPrintDialog::accept() return; } #endif - d->setupPrinter(); + QDialog::accept(); } @@ -1029,7 +1188,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 +1235,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 +1286,8 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) propertiesDialog = nullptr; } -#if QT_CONFIG(cups) + m_printerObj = nullptr; +#endif m_duplexPpdOption = nullptr; #endif @@ -1151,8 +1313,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 +1328,6 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) optionsPane->selectPrinter(QPrinter::NativeFormat); } -#if QT_CONFIG(cups) - m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice); #endif } @@ -1222,16 +1384,11 @@ 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.")); return false; @@ -1262,7 +1419,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,7 +1436,6 @@ 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); @@ -1374,12 +1529,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/qcpdb.cpp b/src/printsupport/kernel/qcpdb.cpp new file mode 100644 index 000000000000..a82070827fec --- /dev/null +++ b/src/printsupport/kernel/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/printsupport/kernel/qcpdb_p.h b/src/printsupport/kernel/qcpdb_p.h new file mode 100644 index 000000000000..e71a8a52ec15 --- /dev/null +++ b/src/printsupport/kernel/qcpdb_p.h @@ -0,0 +1,44 @@ +// 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 + +QT_REQUIRE_CONFIG(cpdb); + +QT_BEGIN_NAMESPACE + +class QPrintDevice; + +#define PDPK_CpdbPrinterObj QPrintDevice::PrintDevicePropertyKey(QPrintDevice::PDPK_CustomBase + 0x10) + +class Q_PRINTSUPPORT_EXPORT 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); +}; + +QT_END_NAMESPACE + +#endif // QCPDBSUPPORT_H 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/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/qcpdbjobwidget.cpp b/src/printsupport/widgets/qcpdbjobwidget.cpp new file mode 100644 index 000000000000..bbcadd998dd2 --- /dev/null +++ b/src/printsupport/widgets/qcpdbjobwidget.cpp @@ -0,0 +1,208 @@ +// 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 "qcpdbjobwidget_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QCpdbJobWidget + + A widget to add to QPrintDialog to enable extra job options + such as Job Scheduling, Job Priority or Job Billing + \ingroup printing + \inmodule QtPrintSupport + */ + +QCpdbJobWidget::QCpdbJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent) + : QWidget(parent), + m_printer(printer) +{ + m_ui.setupUi(this); + m_printerObj = qvariant_cast(printDevice->property(PDPK_CpdbPrinterObj)); + + // set all the default values + initJobHold(); + initJobBilling(); + initJobPriority(); + initBannerPages(); +} + +QCpdbJobWidget::~QCpdbJobWidget() +{ +} + +void QCpdbJobWidget::setupPrinter() +{ + if (m_ui.startBannerPageCombo->isEnabled() && m_ui.endBannerPageCombo->isEnabled()) { + QByteArray jobSheets = startBannerPage() + "," + endBannerPage(); + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_SHEETS, jobSheets.constData()); + } + + 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(); + } + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL, jobHoldUntil.constData()); + } + + if (m_ui.jobPrioritySpinBox->isEnabled()) + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_PRIORITY, + QByteArray::number(jobPriority()).constData()); + + if (m_ui.jobBillingLineEdit->isEnabled()) + cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_BILLING_INFO, + jobBilling().toLocal8Bit().constData()); +} + +void QCpdbJobWidget::initJobHold() +{ + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL); + + if (opt && opt->num_supported > 0) { + for (int i = 0; i < opt->num_supported; i++) { + QByteArray value = opt->supported_values[i]; + QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, + CPDB_OPTION_JOB_HOLD_UNTIL, + opt->supported_values[i]); + m_ui.jobHoldComboBox->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(value)); + } + + QByteArray value = "specific"; + m_ui.jobHoldComboBox->addItem(tr("Specific Time"), QVariant::fromValue(value)); + + QByteArray defaultVal = opt->default_value; + int idx = m_ui.jobHoldComboBox->findData(QVariant::fromValue(defaultVal)); + if (idx >= 0) + m_ui.jobHoldComboBox->setCurrentIndex(idx); + + } else { + m_ui.jobHoldComboBox->setEnabled(false); + } + + toggleJobHoldTime(); + connect(m_ui.jobHoldComboBox, &QComboBox::currentIndexChanged, this, &QCpdbJobWidget::toggleJobHoldTime); +} + +void QCpdbJobWidget::initJobBilling() +{ + setJobBilling(); +} + +void QCpdbJobWidget::initJobPriority() +{ + const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_PRIORITY); + if (opt) { + QByteArray defaultVal = opt->default_value; + bool ok; + int priority = defaultVal.toInt(&ok); + if (ok && priority > 0) + setJobPriority(priority); + else + setJobPriority(50); + } else { + m_ui.jobPrioritySpinBox->setEnabled(false); + } +} + +void QCpdbJobWidget::initBannerPages() +{ + cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_SHEETS); + + if (opt && opt->num_supported > 1) { + for (int i = 0; i < opt->num_supported; i++) { + QByteArray val = opt->supported_values[i]; + QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, + CPDB_OPTION_JOB_SHEETS, + opt->supported_values[i]); + m_ui.startBannerPageCombo->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(val)); + m_ui.endBannerPageCombo->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(val)); + } + + QByteArray defaultVal = opt->default_value; + QList defaultSheets = defaultVal.split(','); + if (defaultSheets.size() >= 2) { + QByteArray startSheet = defaultSheets[0], endSheet = defaultSheets[1]; + int startIndex = m_ui.startBannerPageCombo->findData(QVariant::fromValue(startSheet)); + int endIndex = m_ui.startBannerPageCombo->findData(QVariant::fromValue(endSheet)); + m_ui.startBannerPageCombo->setCurrentIndex(startIndex); + m_ui.endBannerPageCombo->setCurrentIndex(endIndex); + } + } else { + m_ui.startBannerPageCombo->setEnabled(false); + m_ui.endBannerPageCombo->setEnabled(false); + } +} + +QByteArray QCpdbJobWidget::jobHold() const +{ + return qvariant_cast(m_ui.jobHoldComboBox->itemData(m_ui.jobHoldComboBox->currentIndex())); +} + +QTime QCpdbJobWidget::jobHoldTime() const +{ + return m_ui.jobHoldTimeEdit->time(); +} + +QString QCpdbJobWidget::jobBilling() const +{ + return m_ui.jobBillingLineEdit->text(); +} + +int QCpdbJobWidget::jobPriority() const +{ + return m_ui.jobPrioritySpinBox->value(); +} + +QByteArray QCpdbJobWidget::startBannerPage() const +{ + return qvariant_cast(m_ui.startBannerPageCombo->itemData(m_ui.startBannerPageCombo->currentIndex())); +} + +QByteArray QCpdbJobWidget::endBannerPage() const +{ + return qvariant_cast(m_ui.endBannerPageCombo->itemData(m_ui.endBannerPageCombo->currentIndex())); +} + +void QCpdbJobWidget::setJobBilling(const QString &jobBilling) +{ + m_ui.jobBillingLineEdit->setText(jobBilling); +} + +void QCpdbJobWidget::setJobPriority(int jobPriority) +{ + m_ui.jobPrioritySpinBox->setValue(jobPriority); +} + +void QCpdbJobWidget::toggleJobHoldTime() +{ + if (jobHold() == "specific") + m_ui.jobHoldTimeEdit->setEnabled(true); + else + m_ui.jobHoldTimeEdit->setEnabled(false); +} + +QT_END_NAMESPACE + +#include "moc_qcpdbjobwidget_p.cpp" diff --git a/src/printsupport/widgets/qcpdbjobwidget_p.h b/src/printsupport/widgets/qcpdbjobwidget_p.h new file mode 100644 index 000000000000..8248a2420afe --- /dev/null +++ b/src/printsupport/widgets/qcpdbjobwidget_p.h @@ -0,0 +1,77 @@ +// 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 QCPDBJOBWIDGET_P_H +#define QCPDBJOBWIDGET_P_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 + +QT_REQUIRE_CONFIG(cpdbjobwidget); + +// Use the same UI as CUPS job widget +#include + +QT_BEGIN_NAMESPACE + +class QString; +class QTime; +class QPrinter; +class QPrintDevice; + +class QCpdbJobWidget : public QWidget +{ + Q_OBJECT + +public: + explicit QCpdbJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent = nullptr); + ~QCpdbJobWidget(); + void setupPrinter(); + + void updateSavedValues(); + void revertToSavedValues(); + + Q_DISABLE_COPY_MOVE(QCpdbJobWidget) + +private Q_SLOTS: + void toggleJobHoldTime(); + +private: + + QTime jobHoldTime() const; + QString jobBilling() const; + int jobPriority() const; + + void setJobBilling(const QString &jobBilling = QString()); + void setJobPriority(int priority = 50); + + QByteArray startBannerPage() const; + QByteArray endBannerPage() const; + QByteArray jobHold() const; + + void initJobHold(); + void initJobBilling(); + void initJobPriority(); + void initBannerPages(); + + QPrinter *m_printer; + Ui::QCupsJobWidget m_ui; + cpdb_printer_obj_t *m_printerObj; +}; + +QT_END_NAMESPACE + +#endif // QCPDBJOBWIDGET_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: From a4ff5018041876db63d36caa2c19c75a6072b064 Mon Sep 17 00:00:00 2001 From: Gaurav Guleria Date: Tue, 12 Mar 2024 13:36:56 +0530 Subject: [PATCH 02/10] Add support for dynamically loading print plugins Scraped out CUPS & CPDB specific code from print dialog frontend, and put it in their respective print plugin directories. This allows the print dialog to be able to dynamically select print backends at runtime instead of having to choose one at build time. Change-Id: I8ae53d19d91aa9689ec327fd8077558744e4768b --- src/plugins/printsupport/CMakeLists.txt | 3 +- src/plugins/printsupport/cpdb/CMakeLists.txt | 1 + src/plugins/printsupport/cpdb/cpdb.json | 3 +- .../printsupport/cpdb}/qcpdb.cpp | 0 .../printsupport/cpdb}/qcpdb_p.h | 33 +- .../printsupport/cpdb/qcpdbprintdevice.cpp | 378 +++++++++++++++- .../printsupport/cpdb/qcpdbprintdevice.h | 29 +- .../printsupport/cpdb/qcpdbprintengine.cpp | 6 +- .../printsupport/cpdb/qcpdbprintengine_p.h | 3 +- .../printsupport/cpdb/qcpdbprintersupport.cpp | 3 +- .../printsupport/cpdb/qcpdbprintersupport_p.h | 2 +- src/plugins/printsupport/cups/CMakeLists.txt | 1 + src/plugins/printsupport/cups/cups.json | 3 +- .../printsupport/cups}/qcups.cpp | 24 + .../printsupport/cups}/qcups_p.h | 7 +- .../printsupport/cups/qcupsprintengine.cpp | 2 +- .../printsupport/cups/qppdprintdevice.cpp | 419 +++++++++++++++++- .../printsupport/cups/qppdprintdevice.h | 4 + src/printsupport/CMakeLists.txt | 22 +- src/printsupport/configure.cmake | 20 +- .../dialogs/qpagesetupdialog_unix.cpp | 245 +++------- .../dialogs/qpagesetupdialog_unix_p.h | 28 +- .../dialogs/qprintdialog_unix.cpp | 347 +++++++++------ .../kernel/qplatformprintplugin.cpp | 49 +- src/printsupport/kernel/qprint_p.h | 27 ++ src/printsupport/kernel/qprintdevice_p.h | 18 +- src/printsupport/widgets/qcpdbjobwidget.cpp | 208 --------- src/printsupport/widgets/qcupsjobwidget.cpp | 229 ---------- src/printsupport/widgets/qcupsjobwidget_p.h | 85 ---- src/printsupport/widgets/qprintjobwidget.cpp | 235 ++++++++++ .../{qcupsjobwidget.ui => qprintjobwidget.ui} | 69 +-- ...qcpdbjobwidget_p.h => qprintjobwidget_p.h} | 39 +- 32 files changed, 1557 insertions(+), 985 deletions(-) rename src/{printsupport/kernel => plugins/printsupport/cpdb}/qcpdb.cpp (100%) rename src/{printsupport/kernel => plugins/printsupport/cpdb}/qcpdb_p.h (57%) rename src/{printsupport/kernel => plugins/printsupport/cups}/qcups.cpp (92%) rename src/{printsupport/kernel => plugins/printsupport/cups}/qcups_p.h (97%) delete mode 100644 src/printsupport/widgets/qcpdbjobwidget.cpp delete mode 100644 src/printsupport/widgets/qcupsjobwidget.cpp delete mode 100644 src/printsupport/widgets/qcupsjobwidget_p.h create mode 100644 src/printsupport/widgets/qprintjobwidget.cpp rename src/printsupport/widgets/{qcupsjobwidget.ui => qprintjobwidget.ui} (60%) rename src/printsupport/widgets/{qcpdbjobwidget_p.h => qprintjobwidget_p.h} (62%) diff --git a/src/plugins/printsupport/CMakeLists.txt b/src/plugins/printsupport/CMakeLists.txt index c12a6ce5c2c1..c0156b218ce7 100644 --- a/src/plugins/printsupport/CMakeLists.txt +++ b/src/plugins/printsupport/CMakeLists.txt @@ -5,6 +5,7 @@ if(QT_FEATURE_cpdb AND UNIX AND NOT APPLE) add_subdirectory(cpdb) -elseif(QT_FEATURE_cups AND UNIX AND NOT APPLE) +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 index a45468c372dd..c288d17ee7a9 100644 --- a/src/plugins/printsupport/cpdb/CMakeLists.txt +++ b/src/plugins/printsupport/cpdb/CMakeLists.txt @@ -7,6 +7,7 @@ qt_internal_add_plugin(QCpdbPrinterSupportPlugin 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 diff --git a/src/plugins/printsupport/cpdb/cpdb.json b/src/plugins/printsupport/cpdb/cpdb.json index c5e0fe9e9816..f017a99b62a4 100644 --- a/src/plugins/printsupport/cpdb/cpdb.json +++ b/src/plugins/printsupport/cpdb/cpdb.json @@ -1,3 +1,4 @@ { - "Keys": [ "cpdbprintersupport" ] + "Keys": [ "cpdbprintersupport" ], + "Priority": 80 } diff --git a/src/printsupport/kernel/qcpdb.cpp b/src/plugins/printsupport/cpdb/qcpdb.cpp similarity index 100% rename from src/printsupport/kernel/qcpdb.cpp rename to src/plugins/printsupport/cpdb/qcpdb.cpp diff --git a/src/printsupport/kernel/qcpdb_p.h b/src/plugins/printsupport/cpdb/qcpdb_p.h similarity index 57% rename from src/printsupport/kernel/qcpdb_p.h rename to src/plugins/printsupport/cpdb/qcpdb_p.h index e71a8a52ec15..e81a1bbd7b42 100644 --- a/src/printsupport/kernel/qcpdb_p.h +++ b/src/plugins/printsupport/cpdb/qcpdb_p.h @@ -18,6 +18,8 @@ #include #include +#include +#include #include @@ -29,7 +31,7 @@ class QPrintDevice; #define PDPK_CpdbPrinterObj QPrintDevice::PrintDevicePropertyKey(QPrintDevice::PDPK_CustomBase + 0x10) -class Q_PRINTSUPPORT_EXPORT QCPDBSupport +class QCPDBSupport { public: constexpr static qreal pointsMultiplier = 2.83464566929; // 1mm to points @@ -37,8 +39,37 @@ class Q_PRINTSUPPORT_EXPORT QCPDBSupport 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 index 48815e67dd13..f3c4e42560af 100644 --- a/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp +++ b/src/plugins/printsupport/cpdb/qcpdbprintdevice.cpp @@ -175,12 +175,8 @@ void QCpdbPrintDevice::loadDuplexModes() const m_duplexModes.reserve(opt->num_supported); for (int i = 0; i < opt->num_supported; i++) { const QByteArray value = opt->supported_values[i]; - if (value == CPDB_SIDES_ONE_SIDED) - m_duplexModes << QPrint::DuplexNone; - else if (value == CPDB_SIDES_TWO_SIDED_SHORT) - m_duplexModes << QPrint::DuplexShortSide; - else if (value == CPDB_SIDES_TWO_SIDED_LONG) - m_duplexModes << QPrint::DuplexLongSide; + if (QCPDBSupport::duplexMap.contains(value)) + m_duplexModes << QCPDBSupport::duplexMap[value]; } } } @@ -309,21 +305,381 @@ void QCpdbPrintDevice::loadMimeTypes() const bool QCpdbPrintDevice::isFeatureAvailable(QPrintDevice::PrintDevicePropertyKey key, const QVariant ¶ms) const { - Q_UNUSED(key); - Q_UNUSED(params); + 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); + } - return true; + 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 == 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 index e2213c7511f1..53e4cbc43eb2 100644 --- a/src/plugins/printsupport/cpdb/qcpdbprintdevice.h +++ b/src/plugins/printsupport/cpdb/qcpdbprintdevice.h @@ -15,10 +15,12 @@ // We mean it. // -#include +#include +#include #include +#include #include QT_BEGIN_NAMESPACE @@ -66,6 +68,31 @@ class QCpdbPrintDevice : public QPlatformPrintDevice 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 diff --git a/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp b/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp index 8fb82ecd04f7..b644d4f01391 100644 --- a/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp +++ b/src/plugins/printsupport/cpdb/qcpdbprintengine.cpp @@ -207,9 +207,9 @@ void QCpdbPrintEnginePrivate::changePrinter(const QString &newPrinter) duplexRequestedExplicitly = false; } - QPrint::ColorMode colorMode = grayscale ? QPrint::GrayScale : QPrint::Color; - if (!m_printDevice.supportedColorModes().contains(colorMode)) - grayscale = (m_printDevice.defaultColorMode() == QPrint::GrayScale); +// 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()) diff --git a/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h b/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h index 1e9921401b04..9191284e085c 100644 --- a/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h +++ b/src/plugins/printsupport/cpdb/qcpdbprintengine_p.h @@ -15,8 +15,7 @@ // We mean it. // -#include - +#include #include "QtPrintSupport/qprintengine.h" #include diff --git a/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp b/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp index 568b624fc1c8..102df3fd48db 100644 --- a/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp +++ b/src/plugins/printsupport/cpdb/qcpdbprintersupport.cpp @@ -38,8 +38,8 @@ QCpdbPrinterSupport::QCpdbPrinterSupport() QByteArray instanceName = "Qt"; frontendObj = cpdbGetNewFrontendObj(instanceName.constData(), printerCb); - cpdbConnectToDBus(frontendObj); cpdbIgnoreLastSavedSettings(frontendObj); + cpdbConnectToDBus(frontendObj); } QCpdbPrinterSupport::~QCpdbPrinterSupport() @@ -71,7 +71,6 @@ QPrintDevice QCpdbPrinterSupport::createPrintDevice(const QString &id) break; } } - return QPlatformPrinterSupport::createPrintDevice(new QCpdbPrintDevice(printerObj)); } diff --git a/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h b/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h index a1005edd9491..b5ef41938913 100644 --- a/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h +++ b/src/plugins/printsupport/cpdb/qcpdbprintersupport_p.h @@ -17,7 +17,7 @@ #include -#include +#include QT_BEGIN_NAMESPACE 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 927c4624667b..66ceae2f9087 100644 --- a/src/printsupport/CMakeLists.txt +++ b/src/printsupport/CMakeLists.txt @@ -84,12 +84,10 @@ 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 - SOURCES - kernel/qcpdb.cpp kernel/qcpdb_p.h - LIBRARIES - WrapCPDB::WrapCPDB -) +#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 @@ -124,6 +122,10 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cupsjobwidget AND UN 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 @@ -135,6 +137,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 @@ -210,11 +218,9 @@ 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/cpdb diff --git a/src/printsupport/configure.cmake b/src/printsupport/configure.cmake index 2c62238d726f..27f257edaca5 100644 --- a/src/printsupport/configure.cmake +++ b/src/printsupport/configure.cmake @@ -33,12 +33,6 @@ 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" @@ -48,15 +42,9 @@ 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 AND NOT QT_FEATURE_cups + CONDITION WrapCPDB_FOUND AND QT_FEATURE_printer AND QT_FEATURE_datestring ) qt_feature_definition("cpdb" "QT_NO_CPDB" NEGATE VALUE "1") -qt_feature("cpdbjobwidget" PUBLIC PRIVATE - SECTION "Widgets" - LABEL "CPDB job control widget" - CONDITION ( QT_FEATURE_buttongroup ) AND ( QT_FEATURE_calendarwidget ) AND ( QT_FEATURE_checkbox ) AND ( QT_FEATURE_combobox ) AND ( QT_FEATURE_cpdb ) AND ( QT_FEATURE_datetimeedit ) AND ( QT_FEATURE_groupbox ) AND ( QT_FEATURE_tablewidget ) -) -qt_feature_definition("cpdbjobwidget" "QT_NO_CPDBJOBWIDGET" NEGATE VALUE "1") qt_feature("printer" PUBLIC SECTION "Painting" LABEL "QPrinter" @@ -84,6 +72,12 @@ 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 "cpdb") diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp index 659757533021..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" @@ -123,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; @@ -201,12 +201,6 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent) m_pagePreview(nullptr), m_printer(nullptr), m_printDevice(nullptr), -#if QT_CONFIG(cpdb) - m_printerObj(nullptr), -#endif -#if QT_CONFIG(cups) - m_pageSizePpdOption(nullptr), -#endif m_outputFormat(QPrinter::PdfFormat), m_units(QPageLayout::Point), m_savedUnits(QPageLayout::Point), @@ -272,89 +266,29 @@ void QPageSetupWidget::initUnits() // Init the Pages Per Sheet (n-up) combo boxes if using CUPS void QPageSetupWidget::initPagesPerSheet() { -#if QT_CONFIG(cpdb) - bool showNumUp = false; - const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP); - if (opt && opt->num_supported > 1) { - showNumUp = true; + if (m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_NumberUp, QVariant())) { m_ui.pagesPerSheetCombo->clear(); - for (int i = 0; i < opt->num_supported; i++) { - QByteArray value = opt->supported_values[i]; - QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, - CPDB_OPTION_NUMBER_UP, - opt->supported_values[i]); - m_ui.pagesPerSheetCombo->addItem(QString::fromLocal8Bit(displayVal), - QVariant::fromValue(value)); + 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])); } - - QByteArray defaultVal = opt->default_value; - int idx = m_ui.pagesPerSheetCombo->findData(QVariant::fromValue(defaultVal)); - if (idx >= 0) - m_ui.pagesPerSheetCombo->setCurrentIndex(idx); + m_ui.pagesPerSheetCombo->setCurrentIndex(option.defaultChoice); + } else { + m_ui.pagesPerSheetCombo->setVisible(false); } - m_ui.pagesPerSheetCombo->setVisible(showNumUp); - bool showNumUpLayout = false; - opt = cpdbGetOption(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT); - if (opt && opt->num_supported > 1) { - showNumUpLayout = true; + if (m_printDevice->isFeatureAvailable(QPrintDevice::PDPK_NumberUpLayout, QVariant())) { m_ui.pagesPerSheetLayoutCombo->clear(); - for (int i = 0; i < opt->num_supported; i++) { - QByteArray value = opt->supported_values[i]; - QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, - CPDB_OPTION_NUMBER_UP_LAYOUT, - opt->supported_values[i]); - m_ui.pagesPerSheetLayoutCombo->addItem(QString::fromLocal8Bit(displayVal), - QVariant::fromValue(value)); + 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])); } - - QByteArray defaultVal = opt->default_value; - int idx = m_ui.pagesPerSheetLayoutCombo->findData(QVariant::fromValue(defaultVal)); - if (idx >= 0) - m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(idx); + m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(option.defaultChoice); + } else { + m_ui.pagesPerSheetLayoutCombo->setVisible(false); } - m_ui.pagesPerSheetLayoutCombo->setVisible(showNumUpLayout); - - m_ui.pagesPerSheetButtonGroup->setVisible(showNumUp || showNumUpLayout); -#elif 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 } void QPageSetupWidget::initPageSizes() @@ -411,17 +345,6 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, m_printer = printer; m_printDevice = printDevice; -#if QT_CONFIG(cpdb) - QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get(); - if (ps) { - QPrintDevice printDevice = ps->createPrintDevice(printerName); - m_printerObj = qvariant_cast(printDevice.property(PDPK_CpdbPrinterObj)); - } -#elif 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(); @@ -548,45 +471,25 @@ void QPageSetupWidget::setupPrinter() const { m_printer->setPageLayout(m_pageLayout); -#if QT_CONFIG(cpdb) - QSizeF size = m_pageLayout.pageSize().size(QPageSize::Millimeter); - QMarginsF margins = m_pageLayout.margins(QPageLayout::Millimeter); + m_printer->setPageOrientation(m_pageLayout.orientation()); - int width = size.width() * 100.0; - int height = size.height() * 100.0; - int left = margins.left() * 100.0; - int right = margins.right() * 100.0; - int top = margins.top() * 100.0; - int bottom = margins.bottom() * 100.0; - - char *borderless = cpdbGetSetting(m_printerObj, "borderless"); - if (qstrcmp(borderless, "true") == 0) { - left = right = top = bottom = 0; - cpdbClearSetting(m_printerObj->settings, "borderless"); + 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#"))); } - QString value = 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); + 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)); - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_MEDIA_COL, value.toLocal8Bit().constData()); -#endif + if (m_ui.pagesPerSheetCombo->isVisible()) + m_printDevice->setProperty(QPrintDevice::PDPK_NumberUp, m_ui.pagesPerSheetCombo->currentData()); - m_printer->setPageOrientation(m_pageLayout.orientation()); + if (m_ui.pagesPerSheetCombo->isVisible()) + m_printDevice->setProperty(QPrintDevice::PDPK_NumberUpLayout, m_ui.pagesPerSheetLayoutCombo->currentData()); -#if QT_CONFIG(cpdb) - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP, - qvariant_cast(m_ui.pagesPerSheetCombo->currentData())); - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_NUMBER_UP_LAYOUT, - qvariant_cast(m_ui.pagesPerSheetLayoutCombo->currentData())); -#endif -#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 #ifdef PSD_ENABLE_PAPERSOURCE m_printer->setPaperSource((QPrinter::PaperSource)m_ui.paperSource->currentIndex()); #endif @@ -612,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() @@ -637,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); - Q_EMIT ppdOptionChanged(); - break; - } - } - } -#endif + m_printDevice->setProperty(QPrintDevice::PDPK_PageSize, QVariant(pageSize.key().toLocal8Bit())); } else { QSizeF customSize; @@ -666,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); - Q_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 @@ -700,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 b39de1ce5de1..4332caf8dfe5 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h +++ b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h @@ -17,11 +17,6 @@ #include -#if QT_CONFIG(cpdb) -#include -#include -#endif - #include "qprinter.h" #include "kernel/qprint_p.h" @@ -48,12 +43,13 @@ 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; -Q_SIGNALS: - void ppdOptionChanged(); -#endif +//Q_SIGNALS: +// void ppdOptionChanged(); +//#endif private Q_SLOTS: void pageSizeChanged(); @@ -77,12 +73,12 @@ private Q_SLOTS: QPagePreview *m_pagePreview; QPrinter *m_printer; QPrintDevice *m_printDevice; -#if QT_CONFIG(cpdb) - cpdb_printer_obj_t *m_printerObj; -#endif -#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 9665fd1b06f9..638fa736add6 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -49,6 +49,7 @@ Q_DECLARE_METATYPE(const ppd_option_t *) #endif #endif +#include "qprintjobwidget_p.h" /* @@ -131,12 +132,20 @@ private Q_SLOTS: bool anyPpdOptionConflict() const; bool anyAdvancedOptionConflict() const; - QPrintDevice *m_currentPrintDevice; - QStringDecoder toUnicode; + 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; @@ -227,7 +236,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; }; @@ -252,8 +263,8 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * #endif , m_printer(printer) #endif + , m_currentPrintDevice(currentPrintDevice) , m_jobOptions(nullptr) -#endif { setWindowTitle(tr("Printer Properties")); QVBoxLayout *lay = new QVBoxLayout(this); @@ -296,6 +307,24 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * #else Q_UNUSED(currentPrintDevice); #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); + } + + widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); } QPrintPropertiesDialog::~QPrintPropertiesDialog() @@ -310,13 +339,19 @@ void QPrintPropertiesDialog::setupPrinter() const #endif widget.pageSetup->setupPrinter(); if (m_jobOptions) + m_currentPrintDevice->setProperty(QPrintDevice::PDPK_AdvancedOptions, QVariant(QByteArray("#clear#"))); + + widget.pageSetup->setupPrinter(); + + if (m_jobOptions) { m_jobOptions->setupPrinter(); -#endif + } // Set Color by default, that will change if the "ColorModel" property is available m_printer->setColorMode(QPrinter::Color); #endif + setPrinterAdvancedOptions(); } void QPrintPropertiesDialog::reject() @@ -325,16 +360,17 @@ void QPrintPropertiesDialog::reject() if (m_jobOptions) m_jobOptions->revertToSavedValues(); -#endif revertAdvancedOptionsToSavedValues(); -#endif + QDialog::reject(); } void QPrintPropertiesDialog::accept() { 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?"), @@ -357,6 +393,11 @@ void QPrintPropertiesDialog::accept() widget.pageSetup->updateSavedValues(); + if (m_jobOptions) + m_jobOptions->updateSavedValues(); + + advancedOptionsUpdateSavedValues(); + QDialog::accept(); } @@ -488,17 +529,23 @@ bool QPrintPropertiesDialog::createAdvancedOptionsWidget() // 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); +} + +// 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 { @@ -520,108 +567,73 @@ static bool isBlacklistedOption(const char *keyword) noexcept bool QPrintPropertiesDialog::createAdvancedOptionsWidget() { bool anyWidgetCreated = false; + auto *holdingWidget = new QWidget(); + auto vboxLayout = new QVBoxLayout(holdingWidget); + holdingWidget->setLayout(vboxLayout); - ppd_file_t *ppd = qvariant_cast(m_currentPrintDevice->property(PDPK_PpdFile)); + 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()) { 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; } { @@ -638,30 +650,37 @@ bool QPrintPropertiesDialog::createAdvancedOptionsWidget() m_printer->setColorMode(qstrcmp(selectedChoice, "Gray") == 0 ? QPrinter::GrayScale : QPrinter::Color); if (qstrcmp(option->defchoice, selectedChoice) != 0) +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; } @@ -673,9 +692,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)); @@ -687,8 +710,6 @@ bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const return anyConflicted; } -#endif - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -770,6 +791,9 @@ void QPrintDialogPrivate::init() 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 @@ -784,10 +808,16 @@ void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputForma options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide)); options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide)); - if (p->colorMode() == QPrinter::Color) - options.color->setChecked(true); - else - options.grayscale->setChecked(true); + // support feature PDPK_AdvancedColorMode if you want to display Color option separately + 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 @@ -818,7 +848,7 @@ void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputForma options.pageSetCombo->setEnabled(false); else - options.pageSetCombo->setEnabled(true); + options.pageSetCombo->setEnabled(top->d->m_currentPrintDevice.isFeatureAvailable(QPrintDevice::PDPK_PageSet, QVariant())); bool showPageSet = false; if (opt && opt->num_supported > 1) { @@ -836,9 +866,12 @@ void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputForma 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->setEnabled(showPageSet); - options.pageSetLabel->setEnabled(showPageSet); + options.pageSetCombo->setCurrentIndex(pageSetOption.defaultChoice); options.pagesRadioButton->setEnabled(showPageRanges); options.pagesLineEdit->setEnabled(showPageRanges); @@ -854,22 +887,25 @@ void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputForma void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio) + 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() @@ -965,6 +1001,28 @@ void QPrintDialogPrivate::setupPrinter() 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.colorMode->isEnabled()) { + p->setColorMode(options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale); + } // copies p->setCopyCount(options.copies->value()); @@ -1024,6 +1082,24 @@ void QPrintDialogPrivate::updateWidgets() 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) @@ -1149,6 +1225,7 @@ void QPrintDialog::accept() } 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 " @@ -1160,6 +1237,7 @@ void QPrintDialog::accept() #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); @@ -1391,10 +1469,12 @@ bool QUnixPrintWidgetPrivate::checkFields() 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; @@ -1441,6 +1521,9 @@ void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked() 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() 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/widgets/qcpdbjobwidget.cpp b/src/printsupport/widgets/qcpdbjobwidget.cpp deleted file mode 100644 index bbcadd998dd2..000000000000 --- a/src/printsupport/widgets/qcpdbjobwidget.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// 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 "qcpdbjobwidget_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -/*! - \internal - \class QCpdbJobWidget - - A widget to add to QPrintDialog to enable extra job options - such as Job Scheduling, Job Priority or Job Billing - \ingroup printing - \inmodule QtPrintSupport - */ - -QCpdbJobWidget::QCpdbJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent) - : QWidget(parent), - m_printer(printer) -{ - m_ui.setupUi(this); - m_printerObj = qvariant_cast(printDevice->property(PDPK_CpdbPrinterObj)); - - // set all the default values - initJobHold(); - initJobBilling(); - initJobPriority(); - initBannerPages(); -} - -QCpdbJobWidget::~QCpdbJobWidget() -{ -} - -void QCpdbJobWidget::setupPrinter() -{ - if (m_ui.startBannerPageCombo->isEnabled() && m_ui.endBannerPageCombo->isEnabled()) { - QByteArray jobSheets = startBannerPage() + "," + endBannerPage(); - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_SHEETS, jobSheets.constData()); - } - - 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(); - } - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL, jobHoldUntil.constData()); - } - - if (m_ui.jobPrioritySpinBox->isEnabled()) - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_JOB_PRIORITY, - QByteArray::number(jobPriority()).constData()); - - if (m_ui.jobBillingLineEdit->isEnabled()) - cpdbAddSettingToPrinter(m_printerObj, CPDB_OPTION_BILLING_INFO, - jobBilling().toLocal8Bit().constData()); -} - -void QCpdbJobWidget::initJobHold() -{ - const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_HOLD_UNTIL); - - if (opt && opt->num_supported > 0) { - for (int i = 0; i < opt->num_supported; i++) { - QByteArray value = opt->supported_values[i]; - QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, - CPDB_OPTION_JOB_HOLD_UNTIL, - opt->supported_values[i]); - m_ui.jobHoldComboBox->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(value)); - } - - QByteArray value = "specific"; - m_ui.jobHoldComboBox->addItem(tr("Specific Time"), QVariant::fromValue(value)); - - QByteArray defaultVal = opt->default_value; - int idx = m_ui.jobHoldComboBox->findData(QVariant::fromValue(defaultVal)); - if (idx >= 0) - m_ui.jobHoldComboBox->setCurrentIndex(idx); - - } else { - m_ui.jobHoldComboBox->setEnabled(false); - } - - toggleJobHoldTime(); - connect(m_ui.jobHoldComboBox, &QComboBox::currentIndexChanged, this, &QCpdbJobWidget::toggleJobHoldTime); -} - -void QCpdbJobWidget::initJobBilling() -{ - setJobBilling(); -} - -void QCpdbJobWidget::initJobPriority() -{ - const cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_PRIORITY); - if (opt) { - QByteArray defaultVal = opt->default_value; - bool ok; - int priority = defaultVal.toInt(&ok); - if (ok && priority > 0) - setJobPriority(priority); - else - setJobPriority(50); - } else { - m_ui.jobPrioritySpinBox->setEnabled(false); - } -} - -void QCpdbJobWidget::initBannerPages() -{ - cpdb_option_t *opt = cpdbGetOption(m_printerObj, CPDB_OPTION_JOB_SHEETS); - - if (opt && opt->num_supported > 1) { - for (int i = 0; i < opt->num_supported; i++) { - QByteArray val = opt->supported_values[i]; - QByteArray displayVal = QCPDBSupport::translateChoice(m_printerObj, - CPDB_OPTION_JOB_SHEETS, - opt->supported_values[i]); - m_ui.startBannerPageCombo->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(val)); - m_ui.endBannerPageCombo->addItem(QString::fromLocal8Bit(displayVal), QVariant::fromValue(val)); - } - - QByteArray defaultVal = opt->default_value; - QList defaultSheets = defaultVal.split(','); - if (defaultSheets.size() >= 2) { - QByteArray startSheet = defaultSheets[0], endSheet = defaultSheets[1]; - int startIndex = m_ui.startBannerPageCombo->findData(QVariant::fromValue(startSheet)); - int endIndex = m_ui.startBannerPageCombo->findData(QVariant::fromValue(endSheet)); - m_ui.startBannerPageCombo->setCurrentIndex(startIndex); - m_ui.endBannerPageCombo->setCurrentIndex(endIndex); - } - } else { - m_ui.startBannerPageCombo->setEnabled(false); - m_ui.endBannerPageCombo->setEnabled(false); - } -} - -QByteArray QCpdbJobWidget::jobHold() const -{ - return qvariant_cast(m_ui.jobHoldComboBox->itemData(m_ui.jobHoldComboBox->currentIndex())); -} - -QTime QCpdbJobWidget::jobHoldTime() const -{ - return m_ui.jobHoldTimeEdit->time(); -} - -QString QCpdbJobWidget::jobBilling() const -{ - return m_ui.jobBillingLineEdit->text(); -} - -int QCpdbJobWidget::jobPriority() const -{ - return m_ui.jobPrioritySpinBox->value(); -} - -QByteArray QCpdbJobWidget::startBannerPage() const -{ - return qvariant_cast(m_ui.startBannerPageCombo->itemData(m_ui.startBannerPageCombo->currentIndex())); -} - -QByteArray QCpdbJobWidget::endBannerPage() const -{ - return qvariant_cast(m_ui.endBannerPageCombo->itemData(m_ui.endBannerPageCombo->currentIndex())); -} - -void QCpdbJobWidget::setJobBilling(const QString &jobBilling) -{ - m_ui.jobBillingLineEdit->setText(jobBilling); -} - -void QCpdbJobWidget::setJobPriority(int jobPriority) -{ - m_ui.jobPrioritySpinBox->setValue(jobPriority); -} - -void QCpdbJobWidget::toggleJobHoldTime() -{ - if (jobHold() == "specific") - m_ui.jobHoldTimeEdit->setEnabled(true); - else - m_ui.jobHoldTimeEdit->setEnabled(false); -} - -QT_END_NAMESPACE - -#include "moc_qcpdbjobwidget_p.cpp" 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/qcupsjobwidget_p.h b/src/printsupport/widgets/qcupsjobwidget_p.h deleted file mode 100644 index 22d190edc8f9..000000000000 --- a/src/printsupport/widgets/qcupsjobwidget_p.h +++ /dev/null @@ -1,85 +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 - - -#ifndef QCUPSJOBWIDGET_P_H -#define QCUPSJOBWIDGET_P_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 - -QT_REQUIRE_CONFIG(cupsjobwidget); - -#include - -QT_BEGIN_NAMESPACE - -class QString; -class QTime; -class QPrinter; -class QPrintDevice; - -class QCupsJobWidget : public QWidget -{ - Q_OBJECT - -public: - explicit QCupsJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent = nullptr); - ~QCupsJobWidget(); - void setupPrinter(); - void updateSavedValues(); - void revertToSavedValues(); - -private Q_SLOTS: - void toggleJobHoldTime(); - -private: - - void setJobHold(QCUPSSupport::JobHoldUntil jobHold = QCUPSSupport::NoHold, QTime holdUntilTime = QTime()); - QCUPSSupport::JobHoldUntil jobHold() const; - QTime jobHoldTime() const; - - void setJobBilling(const QString &jobBilling = QString()); - QString jobBilling() const; - - void setJobPriority(int priority = 50); - int jobPriority() 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 initJobHold(); - void initJobBilling(); - void initJobPriority(); - void initBannerPages(); - - QPrinter *m_printer; - QPrintDevice *m_printDevice; - Ui::QCupsJobWidget m_ui; - - QCUPSSupport::JobHoldUntilWithTime m_savedJobHoldWithTime; - QString m_savedJobBilling; - int m_savedPriority; - QCUPSSupport::JobSheets m_savedJobSheets; - - Q_DISABLE_COPY_MOVE(QCupsJobWidget) -}; - -QT_END_NAMESPACE - -#endif // QCUPSJOBWIDGET_P_H 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/qcpdbjobwidget_p.h b/src/printsupport/widgets/qprintjobwidget_p.h similarity index 62% rename from src/printsupport/widgets/qcpdbjobwidget_p.h rename to src/printsupport/widgets/qprintjobwidget_p.h index 8248a2420afe..7efc405a263a 100644 --- a/src/printsupport/widgets/qcpdbjobwidget_p.h +++ b/src/printsupport/widgets/qprintjobwidget_p.h @@ -2,8 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#ifndef QCPDBJOBWIDGET_P_H -#define QCPDBJOBWIDGET_P_H +#ifndef QPRINTJOBWIDGET_P_H +#define QPRINTJOBWIDGET_P_H // // W A R N I N G @@ -18,12 +18,8 @@ // #include -#include -QT_REQUIRE_CONFIG(cpdbjobwidget); - -// Use the same UI as CUPS job widget -#include +#include QT_BEGIN_NAMESPACE @@ -32,35 +28,37 @@ class QTime; class QPrinter; class QPrintDevice; -class QCpdbJobWidget : public QWidget +class QPrintJobWidget : public QWidget { Q_OBJECT public: - explicit QCpdbJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent = nullptr); - ~QCpdbJobWidget(); + explicit QPrintJobWidget(QPrinter *printer, QPrintDevice *printDevice, QWidget *parent = nullptr); + ~QPrintJobWidget(); void setupPrinter(); void updateSavedValues(); void revertToSavedValues(); - Q_DISABLE_COPY_MOVE(QCpdbJobWidget) + Q_DISABLE_COPY_MOVE(QPrintJobWidget) private Q_SLOTS: void toggleJobHoldTime(); private: + QByteArray jobHold() const; QTime jobHoldTime() const; QString jobBilling() const; int jobPriority() const; + QByteArray startBannerPage() const; + QByteArray endBannerPage() const; + void setJobHold(const QByteArray &jobHold, const QTime &holdUntilTime); void setJobBilling(const QString &jobBilling = QString()); void setJobPriority(int priority = 50); - - QByteArray startBannerPage() const; - QByteArray endBannerPage() const; - QByteArray jobHold() const; + void setStartBannerPage(const QByteArray &bannerPage); + void setEndBannerPage(const QByteArray &bannerPage); void initJobHold(); void initJobBilling(); @@ -68,10 +66,15 @@ private Q_SLOTS: void initBannerPages(); QPrinter *m_printer; - Ui::QCupsJobWidget m_ui; - cpdb_printer_obj_t *m_printerObj; + QPrintDevice *m_printDevice; + Ui::QPrintJobWidget m_ui; + + QPair m_savedJobHoldWithTime; + QString m_savedJobBilling; + int m_savedPriority; + QPair m_savedJobSheets; }; QT_END_NAMESPACE -#endif // QCPDBJOBWIDGET_P_H +#endif // QPRINTJOBWIDGET_P_H From 4c07d3540dc81471fcf29e00b30a9602ced1b9bd Mon Sep 17 00:00:00 2001 From: Gaurav Guleria Date: Tue, 12 Mar 2024 13:36:56 +0530 Subject: [PATCH 03/10] Add support for dynamically loading print plugins Scraped out CUPS & CPDB specific code from print dialog frontend, and put it in their respective print plugin directories. This allows the print dialog to be able to dynamically select print backends at runtime instead of having to choose one at build time. Change-Id: I8ae53d19d91aa9689ec327fd8077558744e4768b --- .../dialogs/qprintdialog_unix.cpp | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index 638fa736add6..6568c8b008d4 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -133,6 +133,9 @@ private Q_SLOTS: bool anyAdvancedOptionConflict() const; + Ui::QPrintPropertiesWidget widget; + QDialogButtonBox *m_buttons; + Ui::QPrintPropertiesWidget widget; QDialogButtonBox *m_buttons; QPrintDevice *m_currentPrintDevice; @@ -324,6 +327,24 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * 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()); } @@ -341,6 +362,9 @@ void QPrintPropertiesDialog::setupPrinter() const 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) { @@ -533,6 +557,10 @@ static const char *ppdOptionProperty = "_q_ppd_option"; 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"; @@ -651,6 +679,9 @@ bool QPrintPropertiesDialog::createAdvancedOptionsWidget() if (qstrcmp(option->defchoice, selectedChoice) != 0) 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)); @@ -809,6 +840,7 @@ void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputForma 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 { @@ -891,6 +923,10 @@ void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio) && 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(); @@ -1020,6 +1056,25 @@ void QPrintDialogPrivate::setupPrinter() 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); } From 25958402ef9a20cb7de4b4267feda3ce35565aa5 Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:45:37 +0000 Subject: [PATCH 04/10] Fix CPDB feature definitions for cmake --- src/printsupport/configure.cmake | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/printsupport/configure.cmake b/src/printsupport/configure.cmake index 27f257edaca5..55f1ae5257fd 100644 --- a/src/printsupport/configure.cmake +++ b/src/printsupport/configure.cmake @@ -83,3 +83,16 @@ qt_configure_add_summary_section(NAME "Qt PrintSupport") qt_configure_add_summary_entry(ARGS "cpdb") 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" +) +qt_configure_feature_definition("printjobwidget" "QT_FEATURE_printjobwidget") +qt_configure_add_summary_entry(TYPE "bool" ARGS "cpdb") +qt_configure_add_summary_entry(TYPE "bool" ARGS "cpdbjobwidget") From c84c611a64c1f5a3912818b57efd8837e9470df6 Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:46:55 +0000 Subject: [PATCH 05/10] Remove invalid CMake commands from CPDB feature config --- src/printsupport/configure.cmake | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/printsupport/configure.cmake b/src/printsupport/configure.cmake index 55f1ae5257fd..80954567f9a4 100644 --- a/src/printsupport/configure.cmake +++ b/src/printsupport/configure.cmake @@ -80,8 +80,6 @@ qt_feature("printjobwidget" PUBLIC PRIVATE 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 "cpdb") -qt_configure_add_summary_entry(ARGS "cups") qt_configure_end_summary_section() # end of "Qt PrintSupport" section # CPDB features (backend-agnostic flags) @@ -93,6 +91,3 @@ qt_feature("cpdbjobwidget" PRIVATE CONDITION TRUE LABEL "CPDB print job options widget" ) -qt_configure_feature_definition("printjobwidget" "QT_FEATURE_printjobwidget") -qt_configure_add_summary_entry(TYPE "bool" ARGS "cpdb") -qt_configure_add_summary_entry(TYPE "bool" ARGS "cpdbjobwidget") From afad85f7feb73f80f8bfa4622d5aa0f2e6dd821c Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:48:35 +0000 Subject: [PATCH 06/10] Replace undefined cupsjobwidget with cpdbjobwidget in CMakeLists --- src/printsupport/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/printsupport/CMakeLists.txt b/src/printsupport/CMakeLists.txt index 66ceae2f9087..c64fcb387917 100644 --- a/src/printsupport/CMakeLists.txt +++ b/src/printsupport/CMakeLists.txt @@ -116,7 +116,7 @@ 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 From 0dfcc864b2e143220a18f24397c993011c0545b8 Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:50:41 +0000 Subject: [PATCH 07/10] Fix CPDB build issues: remove missing source file and add WrapCPDB target --- cmake/FindWrapCPDB.cmake | 30 ++++++------------------------ src/printsupport/CMakeLists.txt | 1 - 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/cmake/FindWrapCPDB.cmake b/cmake/FindWrapCPDB.cmake index 2e55fef9f3cc..c3cb46dc7e82 100644 --- a/cmake/FindWrapCPDB.cmake +++ b/cmake/FindWrapCPDB.cmake @@ -1,25 +1,7 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -if (TARGET WrapCPDB::WrapCPDB) - set(WrapCPDB_FOUND ON) - return() +find_package(PkgConfig REQUIRED) +pkg_check_modules(CPDB REQUIRED cpdb-libs-common) +if(CPDB_FOUND) + add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED) + target_include_directories(WrapCPDB::WrapCPDB INTERFACE ${CPDB_INCLUDE_DIRS}) + target_link_libraries(WrapCPDB::WrapCPDB INTERFACE ${CPDB_LIBRARIES}) endif() - -find_package(PkgConfig QUIET) -if (PKG_CONFIG_FOUND) - pkg_check_modules(CPDB QUIET cpdb-frontend) - if (CPDB_FOUND) - add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED) - target_compile_definitions(WrapCPDB::WrapCPDB INTERFACE -DQT_NO_KEYWORDS) - set_target_properties(WrapCPDB::WrapCPDB PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${CPDB_INCLUDE_DIRS}") - set_target_properties(WrapCPDB::WrapCPDB PROPERTIES - INTERFACE_LINK_LIBRARIES "${CPDB_LIBRARIES}") - endif() -endif() - -find_package_handle_standard_args(WrapCPDB - REQUIRED_VARS CPDB_INCLUDE_DIRS CPDB_LIBRARIES - VERSION_VAR CPDB_VERSION) - diff --git a/src/printsupport/CMakeLists.txt b/src/printsupport/CMakeLists.txt index c64fcb387917..b72b788dbfff 100644 --- a/src/printsupport/CMakeLists.txt +++ b/src/printsupport/CMakeLists.txt @@ -91,7 +91,6 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printpreviewwidget qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_cpdbjobwidget AND UNIX AND NOT APPLE SOURCES - widgets/qcpdbjobwidget.cpp widgets/qcupsjobwidget.ui widgets/qcpdbjobwidget_p.h LIBRARIES WrapCPDB::WrapCPDB ENABLE_AUTOGEN_TOOLS From aa66ba0d730b6a93c1f6b146ea56b98808527a7d Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:54:26 +0000 Subject: [PATCH 08/10] Make CPDB optional instead of required --- cmake/FindWrapCPDB.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindWrapCPDB.cmake b/cmake/FindWrapCPDB.cmake index c3cb46dc7e82..0a4c3714c90a 100644 --- a/cmake/FindWrapCPDB.cmake +++ b/cmake/FindWrapCPDB.cmake @@ -1,5 +1,5 @@ find_package(PkgConfig REQUIRED) -pkg_check_modules(CPDB REQUIRED cpdb-libs-common) +pkg_check_modules(CPDB cpdb-libs-common) if(CPDB_FOUND) add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED) target_include_directories(WrapCPDB::WrapCPDB INTERFACE ${CPDB_INCLUDE_DIRS}) From abb0b3efc675f205eb0fdefdcdf31096f1424bd7 Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:56:05 +0000 Subject: [PATCH 09/10] Remove references to missing widget source files --- src/printsupport/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/printsupport/CMakeLists.txt b/src/printsupport/CMakeLists.txt index b72b788dbfff..045c1f4c0911 100644 --- a/src/printsupport/CMakeLists.txt +++ b/src/printsupport/CMakeLists.txt @@ -117,7 +117,6 @@ endif() 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 ) From 9d2ed2f177e3934641db26c04f8f456f7d9ad2d3 Mon Sep 17 00:00:00 2001 From: Abrar Nasir Jaffari Date: Sat, 23 Aug 2025 08:59:14 +0000 Subject: [PATCH 10/10] Create proper WrapCPDB interface target --- cmake/FindWrapCPDB.cmake | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cmake/FindWrapCPDB.cmake b/cmake/FindWrapCPDB.cmake index 0a4c3714c90a..c5a5a14067fa 100644 --- a/cmake/FindWrapCPDB.cmake +++ b/cmake/FindWrapCPDB.cmake @@ -1,7 +1,3 @@ -find_package(PkgConfig REQUIRED) -pkg_check_modules(CPDB cpdb-libs-common) -if(CPDB_FOUND) - add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED) - target_include_directories(WrapCPDB::WrapCPDB INTERFACE ${CPDB_INCLUDE_DIRS}) - target_link_libraries(WrapCPDB::WrapCPDB INTERFACE ${CPDB_LIBRARIES}) -endif() +# Create an empty interface library for WrapCPDB when CPDB is not available +add_library(WrapCPDB::WrapCPDB INTERFACE IMPORTED GLOBAL) +set(WrapCPDB_FOUND TRUE)