From 0fb3d2177867524310eb744dd97fc5e370b0fd11 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 14 Feb 2018 09:56:21 +0100 Subject: cups: Take conflicts for duplex and page size into account Duplex and Page Size are not shown in the "Advanced" options tag since they are more important options, this means we were not taking them into account for ppd conflicts since we never set their values in the ppd, we do use the new-style cups options for them when printing With this patch we add m_pageSizePpdOption and m_duplexPpdOption to set the values to the ppd struct behind the scenes. Change-Id: I48bd9fe93d0c08b7b8dd9620a07c56fc79cce13b Reviewed-by: Andy Shaw --- src/printsupport/dialogs/qpagesetupdialog_unix.cpp | 63 +++++++++++- src/printsupport/dialogs/qpagesetupdialog_unix_p.h | 11 +++ src/printsupport/dialogs/qpagesetupwidget.ui | 3 + src/printsupport/dialogs/qprintdialog_unix.cpp | 107 +++++++++++++++++++-- src/printsupport/dialogs/qprintpropertieswidget.ui | 88 ++++++++--------- src/printsupport/kernel/qcups.cpp | 20 ++++ src/printsupport/kernel/qcups_p.h | 5 + 7 files changed, 244 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp index 7e32f9aa57..177e220c89 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp +++ b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp @@ -49,6 +49,7 @@ #include "qpainter.h" #include "qprintdialog.h" +#include "qtextcodec.h" #include "qdialogbuttonbox.h" #include @@ -235,6 +236,9 @@ QPageSetupWidget::QPageSetupWidget(QWidget *parent) m_pagePreview(nullptr), m_printer(nullptr), m_printDevice(nullptr), +#if QT_CONFIG(cups) + m_pageSizePpdOption(nullptr), +#endif m_outputFormat(QPrinter::PdfFormat), m_units(QPageLayout::Point), m_savedUnits(QPageLayout::Point), @@ -391,6 +395,11 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, m_printer = printer; m_printDevice = printDevice; +#if QT_CONFIG(cups) + // find the PageSize cups option + m_pageSizePpdOption = m_printDevice ? QCUPSSupport::findPpdOption("PageSize", m_printDevice) : nullptr; +#endif + // Initialize the layout to the current QPrinter layout m_pageLayout = m_printer->pageLayout(); @@ -547,15 +556,48 @@ void QPageSetupWidget::revertToSavedValues() m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(m_savedPagesPerSheetLayout); } +#if QT_CONFIG(cups) +bool QPageSetupWidget::hasPpdConflict() 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; + } + + return false; +} +#endif + // Updates size/preview after the combobox has been changed. void QPageSetupWidget::pageSizeChanged() { - if (m_blockSignals) - return; - QPageSize pageSize; if (m_ui.pageSizeCombo->currentIndex() != m_realCustomPageSizeIndex) { pageSize = m_ui.pageSizeCombo->currentData().value(); + +#if QT_CONFIG(cups) + if (m_pageSizePpdOption) { + ppd_file_t *ppd = m_printDevice->property(PDPK_PpdFile).value(); + QTextCodec *cupsCodec = QTextCodec::codecForName(ppd->lang_encoding); + for (int i = 0; i < m_pageSizePpdOption->num_choices; ++i) { + const ppd_choice_t *choice = &m_pageSizePpdOption->choices[i]; + if (cupsCodec->toUnicode(choice->text) == m_ui.pageSizeCombo->currentText()) { + const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword) + << QString::fromLatin1(choice->choice); + m_printDevice->setProperty(PDPK_PpdOption, values); + emit ppdOptionChanged(); + break; + } + } + } +#endif + } else { QSizeF customSize; if (m_pageLayout.orientation() == QPageLayout::Landscape) @@ -563,7 +605,22 @@ void QPageSetupWidget::pageSizeChanged() else customSize = QSizeF(m_ui.pageWidth->value(), m_ui.pageHeight->value()); pageSize = QPageSize(customSize, QPageSize::Unit(m_units)); + +#if QT_CONFIG(cups) + if (m_pageSizePpdOption) { + const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword) + << QStringLiteral("Custom"); + m_printDevice->setProperty(PDPK_PpdOption, values); + emit ppdOptionChanged(); + } +#endif } + + // We always need to update the m_pageSizePpdOption when the page size changes + // even if it's from inside updateWidget, so do not move up + if (m_blockSignals) + return; + const QMarginsF printable = m_printDevice ? m_printDevice->printableMargins(pageSize, m_pageLayout.orientation(), m_printer->resolution()) : QMarginsF(); m_pageLayout.setPageSize(pageSize, qt_convertMargins(printable, QPageLayout::Point, m_pageLayout.units())); diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h index bb33a0f587..7bfdaed740 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_unix_p.h +++ b/src/printsupport/dialogs/qpagesetupdialog_unix_p.h @@ -54,6 +54,7 @@ #include #include "qprinter.h" +#include "kernel/qprint_p.h" #include @@ -78,6 +79,13 @@ public: void updateSavedValues(); void revertToSavedValues(); +#if QT_CONFIG(cups) + bool hasPpdConflict() const; + +signals: + void ppdOptionChanged(); +#endif + private slots: void pageSizeChanged(); void pageOrientationChanged(); @@ -100,6 +108,9 @@ private: QPagePreview *m_pagePreview; QPrinter *m_printer; QPrintDevice *m_printDevice; +#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/qpagesetupwidget.ui b/src/printsupport/dialogs/qpagesetupwidget.ui index 960a9dac17..3f24553c76 100644 --- a/src/printsupport/dialogs/qpagesetupwidget.ui +++ b/src/printsupport/dialogs/qpagesetupwidget.ui @@ -99,6 +99,9 @@ + + + diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index 6a8aa0541a..ebf63ea568 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -138,6 +138,8 @@ private slots: void accept() override; private: + void showEvent(QShowEvent *event) override; + friend class QUnixPrintWidgetPrivate; QPrinter *m_printer; Ui::QPrintPropertiesWidget widget; @@ -151,6 +153,7 @@ private: void setPrinterAdvancedCupsOptions() const; void revertAdvancedOptionsToSavedValues() const; void advancedOptionsUpdateSavedValues() const; + bool anyPpdOptionConflict() const; bool anyAdvancedOptionConflict() const; QPrintDevice *m_currentPrintDevice; @@ -171,6 +174,7 @@ public: void updatePrinter(); private: + friend class QPrintDialog; friend class QPrintDialogPrivate; friend class QUnixPrintWidgetPrivate; QUnixPrintWidgetPrivate *d; @@ -203,6 +207,11 @@ public: void updateWidget(); +#if QT_CONFIG(cups) + void setPpdDuplex(QPrinter::DuplexMode mode); + ppd_option_t *m_duplexPpdOption; +#endif + private: QPrintDialogPrivate *optionsPane; bool filePrintersAdded; @@ -226,6 +235,9 @@ public: #endif void _q_collapseOrExpandDialog(); +#if QT_CONFIG(cups) + void updatePpdDuplexOption(QRadioButton *radio); +#endif void setupPrinter(); void updateWidgets(); @@ -281,7 +293,11 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * const bool anyWidgetCreated = createAdvancedOptionsWidget(); widget.tabs->setTabEnabled(advancedTabIndex, anyWidgetCreated); - widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); + + connect(widget.pageSetup, &QPageSetupWidget::ppdOptionChanged, this, [this] { + widget.conflictsLabel->setVisible(anyPpdOptionConflict()); + }); + #else Q_UNUSED(currentPrintDevice) widget.tabs->setTabEnabled(advancedTabIndex, false); @@ -328,7 +344,14 @@ void QPrintPropertiesDialog::reject() void QPrintPropertiesDialog::accept() { #if QT_CONFIG(cups) - if (anyAdvancedOptionConflict()) { + if (widget.pageSetup->hasPpdConflict()) { + 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?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + 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?"), @@ -348,6 +371,14 @@ void QPrintPropertiesDialog::accept() QDialog::accept(); } +void QPrintPropertiesDialog::showEvent(QShowEvent *event) +{ +#if QT_CONFIG(cups) + widget.conflictsLabel->setVisible(anyPpdOptionConflict()); +#endif + QDialog::showEvent(event); +} + #if QT_CONFIG(cups) // Used to store the ppd_option_t for each QComboBox that represents an advanced option @@ -434,7 +465,7 @@ bool QPrintPropertiesDialog::createAdvancedOptionsWidget() const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(option->choices[selectedChoiceIndex].choice); m_currentPrintDevice->setProperty(PDPK_PpdOption, values); - widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); + widget.conflictsLabel->setVisible(anyPpdOptionConflict()); }); // We need an extra label at the end to show the conflict warning @@ -504,7 +535,7 @@ void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const choicesCb->setCurrentIndex(newComboIndexToSelect); // The currentIndexChanged lambda takes care of resetting the ppd option } - widget.conflictsLabel->setVisible(anyAdvancedOptionConflict()); + widget.conflictsLabel->setVisible(anyPpdOptionConflict()); } void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const @@ -513,6 +544,14 @@ void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, choicesCb->currentData()); } +bool QPrintPropertiesDialog::anyPpdOptionConflict() const +{ + // we need to execute both since besides returning true/false they update the warning icons + const bool pageSetupConflicts = widget.pageSetup->hasPpdConflict(); + const bool advancedOptionConflicts = anyAdvancedOptionConflict(); + return pageSetupConflicts || advancedOptionConflicts; +} + bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const { const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr); @@ -610,6 +649,12 @@ void QPrintDialogPrivate::init() q, SLOT(_q_togglePageSetCombo(bool))); QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog())); + +#if QT_CONFIG(cups) + QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); }); + QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); }); + QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); }); +#endif } // initialize printer options @@ -735,6 +780,19 @@ static bool isValidPagesString(const QString &pagesString) Q_DECL_NOTHROW auto pagesRanges = pageRangesFromString(pagesString); return !pagesRanges.empty(); } + +void QPrintDialogPrivate::updatePpdDuplexOption(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); + } + 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::setupPrinter() @@ -1001,6 +1059,13 @@ void QPrintDialog::accept() QMessageBox::Ok, QMessageBox::Ok); return; } + 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?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + if (answer != QMessageBox::No) + return; + } #endif d->setupPrinter(); QDialog::accept(); @@ -1022,8 +1087,11 @@ void QPrintDialog::accept() /*! \internal */ QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn) - : parent(p), propertiesDialog(nullptr), printer(prn), optionsPane(0), - filePrintersAdded(false) + : parent(p), propertiesDialog(nullptr), printer(prn), +#if QT_CONFIG(cups) + m_duplexPpdOption(nullptr), +#endif + optionsPane(nullptr), filePrintersAdded(false) { q = nullptr; if (parent) @@ -1113,6 +1181,10 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) propertiesDialog = nullptr; } +#if QT_CONFIG(cups) + m_duplexPpdOption = nullptr; +#endif + if (filePrintersAdded) { Q_ASSERT(index != printerCount - 2); // separator if (index == printerCount - 1) { // PDF @@ -1147,6 +1219,10 @@ void QUnixPrintWidgetPrivate::_q_printerChanged(int index) if (optionsPane) optionsPane->selectPrinter(QPrinter::NativeFormat); } + +#if QT_CONFIG(cups) + m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice); +#endif } void QUnixPrintWidgetPrivate::setOptionsPane(QPrintDialogPrivate *pane) @@ -1242,11 +1318,30 @@ 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"); + if (mode == QPrinter::DuplexNone) values << QStringLiteral("None"); + else if (mode == QPrinter::DuplexLongSide) values << QStringLiteral("DuplexNoTumble"); + else if (mode == QPrinter::DuplexShortSide) values << QStringLiteral("DuplexTumble"); + + m_currentPrintDevice.setProperty(PDPK_PpdOption, values); +} +#endif + void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked() { if (!propertiesDialog) setupPrinterProperties(); propertiesDialog->exec(); + +#if QT_CONFIG(cups) + // update the warning icon on the duplex options if needed + optionsPane->updatePpdDuplexOption(optionsPane->options.noDuplex); + optionsPane->updatePpdDuplexOption(optionsPane->options.duplexLong); + optionsPane->updatePpdDuplexOption(optionsPane->options.duplexShort); +#endif } void QUnixPrintWidgetPrivate::setupPrinter() diff --git a/src/printsupport/dialogs/qprintpropertieswidget.ui b/src/printsupport/dialogs/qprintpropertieswidget.ui index b9d457a507..c2b4836d26 100644 --- a/src/printsupport/dialogs/qprintpropertieswidget.ui +++ b/src/printsupport/dialogs/qprintpropertieswidget.ui @@ -67,54 +67,54 @@ - - - - - - - - - 255 - 0 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - - - 165 - 167 - 169 - - - - - - - - There are conflicts in some options. Please fix them. - - - + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 165 + 167 + 169 + + + + + + + + There are conflicts in some options. Please fix them. + + + diff --git a/src/printsupport/kernel/qcups.cpp b/src/printsupport/kernel/qcups.cpp index 7e8e1707b2..8505e8356c 100644 --- a/src/printsupport/kernel/qcups.cpp +++ b/src/printsupport/kernel/qcups.cpp @@ -39,6 +39,7 @@ #include "qcups_p.h" +#include "qprintdevice_p.h" #include "qprintengine.h" QT_BEGIN_NAMESPACE @@ -146,6 +147,25 @@ QCUPSSupport::JobHoldUntilWithTime QCUPSSupport::parseJobHoldUntil(const QString return { QCUPSSupport::NoHold, QTime() }; } +ppd_option_t *QCUPSSupport::findPpdOption(const char *optionName, QPrintDevice *printDevice) +{ + ppd_file_t *ppd = printDevice->property(PDPK_PpdFile).value(); + + if (ppd) { + for (int i = 0; i < ppd->num_groups; ++i) { + ppd_group_t *group = &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; +} void QCUPSSupport::setJobHold(QPrinter *printer, const JobHoldUntil jobHold, const QTime &holdUntilTime) { diff --git a/src/printsupport/kernel/qcups_p.h b/src/printsupport/kernel/qcups_p.h index 9a71483bb9..57ec281383 100644 --- a/src/printsupport/kernel/qcups_p.h +++ b/src/printsupport/kernel/qcups_p.h @@ -52,6 +52,7 @@ // #include +#include #include "QtCore/qstring.h" #include "QtCore/qstringlist.h" #include "QtPrintSupport/qprinter.h" @@ -61,6 +62,8 @@ QT_REQUIRE_CONFIG(cups); QT_BEGIN_NAMESPACE +class QPrintDevice; + // HACK! Define these here temporarily so they can be used in the dialogs // without a circular reference to QCupsPrintEngine in the plugin. // Move back to qcupsprintengine_p.h in the plugin once all usage @@ -163,6 +166,8 @@ public: QTime time; }; static JobHoldUntilWithTime parseJobHoldUntil(const QString &jobHoldUntil); + + static ppd_option_t *findPpdOption(const char *optionName, QPrintDevice *printDevice); }; Q_DECLARE_TYPEINFO(QCUPSSupport::JobHoldUntil, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QCUPSSupport::BannerPage, Q_PRIMITIVE_TYPE); -- cgit v1.2.3