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 <andy.shaw@qt.io>
This commit is contained in:
Albert Astals Cid 2018-02-14 09:56:21 +01:00
parent 3d5fd088c3
commit 0fb3d21778
7 changed files with 244 additions and 53 deletions

View File

@ -49,6 +49,7 @@
#include "qpainter.h"
#include "qprintdialog.h"
#include "qtextcodec.h"
#include "qdialogbuttonbox.h"
#include <ui_qpagesetupwidget.h>
@ -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<QPageSize>();
#if QT_CONFIG(cups)
if (m_pageSizePpdOption) {
ppd_file_t *ppd = m_printDevice->property(PDPK_PpdFile).value<ppd_file_t*>();
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()));

View File

@ -54,6 +54,7 @@
#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
#include "qprinter.h"
#include "kernel/qprint_p.h"
#include <QtGui/qpagelayout.h>
@ -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;

View File

@ -99,6 +99,9 @@
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QLabel" name="pageSizeWarningLabel"/>
</item>
</layout>
</widget>
</item>

View File

@ -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()

View File

@ -67,54 +67,54 @@
</widget>
</widget>
</item>
<item>
<widget class="QLabel" name="conflictsLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>165</red>
<green>167</green>
<blue>169</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="text">
<string>There are conflicts in some options. Please fix them.</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QLabel" name="conflictsLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>165</red>
<green>167</green>
<blue>169</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="text">
<string>There are conflicts in some options. Please fix them.</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -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<ppd_file_t*>();
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)
{

View File

@ -52,6 +52,7 @@
//
#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
#include <QtPrintSupport/private/qprint_p.h>
#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);