diff options
Diffstat (limited to 'src/printsupport')
-rw-r--r-- | src/printsupport/dialogs/qpagesetupdialog_mac.mm | 11 | ||||
-rw-r--r-- | src/printsupport/dialogs/qpagesetupdialog_unix.cpp | 69 | ||||
-rw-r--r-- | src/printsupport/dialogs/qpagesetupdialog_unix_p.h | 11 | ||||
-rw-r--r-- | src/printsupport/dialogs/qpagesetupwidget.ui | 3 | ||||
-rw-r--r-- | src/printsupport/dialogs/qprintdialog_mac.mm | 19 | ||||
-rw-r--r-- | src/printsupport/dialogs/qprintdialog_unix.cpp | 909 | ||||
-rw-r--r-- | src/printsupport/dialogs/qprintpreviewdialog.cpp | 5 | ||||
-rw-r--r-- | src/printsupport/dialogs/qprintpropertieswidget.ui | 106 | ||||
-rw-r--r-- | src/printsupport/kernel/qcups.cpp | 20 | ||||
-rw-r--r-- | src/printsupport/kernel/qcups_p.h | 5 | ||||
-rw-r--r-- | src/printsupport/kernel/qplatformprintdevice.cpp | 21 | ||||
-rw-r--r-- | src/printsupport/kernel/qplatformprintdevice.h | 14 | ||||
-rw-r--r-- | src/printsupport/kernel/qprintengine_pdf.cpp | 10 | ||||
-rw-r--r-- | src/printsupport/kernel/qprintengine_pdf_p.h | 1 | ||||
-rw-r--r-- | src/printsupport/kernel/qprintengine_win.cpp | 57 | ||||
-rw-r--r-- | src/printsupport/kernel/qprinter.cpp | 43 | ||||
-rw-r--r-- | src/printsupport/kernel/qprinter_p.h | 4 |
17 files changed, 580 insertions, 728 deletions
diff --git a/src/printsupport/dialogs/qpagesetupdialog_mac.mm b/src/printsupport/dialogs/qpagesetupdialog_mac.mm index 1e398452f7..a3511fe7b6 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_mac.mm +++ b/src/printsupport/dialogs/qpagesetupdialog_mac.mm @@ -52,16 +52,13 @@ QT_USE_NAMESPACE @class QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate); @interface QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) : NSObject -{ +@end + +@implementation QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) { NSPrintInfo *printInfo; } -- (id)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo; -- (void)pageLayoutDidEnd:(NSPageLayout *)pageLayout - returnCode:(int)returnCode contextInfo:(void *)contextInfo; -@end -@implementation QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) -- (id)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo +- (instancetype)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo { self = [super init]; if (self) { diff --git a/src/printsupport/dialogs/qpagesetupdialog_unix.cpp b/src/printsupport/dialogs/qpagesetupdialog_unix.cpp index 7e32f9aa57..d9b4a84aa9 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 <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(); @@ -415,6 +424,12 @@ void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice, initPageSizes(); updateWidget(); updateSavedValues(); + + if (m_ui.pageSizeCombo->currentIndex() == -1) { + // This can happen in raw printers that since they don't have a default + // page size none will get selected so just default to the first size (A4) + m_ui.pageSizeCombo->setCurrentIndex(0); + } } // Update the widget with the current settings @@ -547,15 +562,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 +611,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 <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; 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 @@ </property> </spacer> </item> + <item row="0" column="2"> + <widget class="QLabel" name="pageSizeWarningLabel"/> + </item> </layout> </widget> </item> diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm index 854779977c..ed2d0908c4 100644 --- a/src/printsupport/dialogs/qprintdialog_mac.mm +++ b/src/printsupport/dialogs/qprintdialog_mac.mm @@ -77,22 +77,20 @@ QT_USE_NAMESPACE @class QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate); @interface QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) : NSObject -{ +@end + +@implementation QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) { NSPrintInfo *printInfo; } -- (id)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo; -- (void)printPanelDidEnd:(NSPrintPanel *)printPanel - returnCode:(int)returnCode contextInfo:(void *)contextInfo; -@end -@implementation QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) -- (id)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo +- (instancetype)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo { - if (self = [super init]) { + if ((self = [self init])) { printInfo = nsPrintInfo; } return self; } + - (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(int)returnCode contextInfo:(void *)contextInfo { @@ -102,8 +100,8 @@ QT_USE_NAMESPACE QPrinter *printer = dialog->printer(); if (returnCode == NSModalResponseOK) { - PMPrintSession session = static_cast<PMPrintSession>([printInfo PMPrintSession]); - PMPrintSettings settings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]); + PMPrintSession session = static_cast<PMPrintSession>(printInfo.PMPrintSession); + PMPrintSettings settings = static_cast<PMPrintSettings>(printInfo.PMPrintSettings); UInt32 frompage, topage; PMGetFirstPage(settings, &frompage); @@ -192,6 +190,7 @@ QT_USE_NAMESPACE dialog->done((returnCode == NSModalResponseOK) ? QDialog::Accepted : QDialog::Rejected); } + @end QT_BEGIN_NAMESPACE diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index 86daea3b02..5390a8b2f2 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -50,12 +50,14 @@ #endif #include <QtCore/qdebug.h> #include <QtCore/qdir.h> +#include <QtCore/qglobal.h> #include <QtCore/qtextcodec.h> #include <QtGui/qevent.h> #if QT_CONFIG(filesystemmodel) #include <QtWidgets/qfilesystemmodel.h> #endif #include <QtWidgets/qstyleditemdelegate.h> +#include <QtWidgets/qformlayout.h> #include <QtPrintSupport/qprinter.h> #include <qpa/qplatformprintplugin.h> @@ -73,6 +75,7 @@ #include "ui_qprintwidget.h" #if QT_CONFIG(cups) +Q_DECLARE_METATYPE(const ppd_option_t *) #include <private/qcups_p.h> #if QT_CONFIG(cupsjobwidget) #include "qcupsjobwidget_p.h" @@ -110,11 +113,6 @@ Print dialog class declarations allow editing of Page and Advanced tabs. Layout in qprintpropertieswidget.ui - - QPPDOptionsModel: Holds the PPD Options for the printer. - - QPPDOptionsEditor: Edits the PPD Options for the printer. - */ static void initResources() @@ -124,9 +122,6 @@ static void initResources() QT_BEGIN_NAMESPACE -class QOptionTreeItem; -class QPPDOptionsModel; - class QPrintPropertiesDialog : public QDialog { Q_OBJECT @@ -138,13 +133,13 @@ public: void setupPrinter() const; - void showEvent(QShowEvent *event) override; - private slots: void reject() override; void accept() override; private: + void showEvent(QShowEvent *event) override; + friend class QUnixPrintWidgetPrivate; #if QT_CONFIG(cups) QPrinter *m_printer; @@ -156,9 +151,16 @@ private: #endif #if QT_CONFIG(cups) - void setCupsOptionsFromItems(QOptionTreeItem *parent) const; + bool createAdvancedOptionsWidget(); + void setPrinterAdvancedCupsOptions() const; + void revertAdvancedOptionsToSavedValues() const; + void advancedOptionsUpdateSavedValues() const; + bool anyPpdOptionConflict() const; + bool anyAdvancedOptionConflict() const; - QPPDOptionsModel *m_cupsOptionsModel; + QPrintDevice *m_currentPrintDevice; + QTextCodec *m_cupsCodec = nullptr; + QVector<QComboBox*> m_advancedOptionsCombos; #endif }; @@ -174,6 +176,7 @@ public: void updatePrinter(); private: + friend class QPrintDialog; friend class QPrintDialogPrivate; friend class QUnixPrintWidgetPrivate; QUnixPrintWidgetPrivate *d; @@ -206,6 +209,11 @@ public: void updateWidget(); +#if QT_CONFIG(cups) + void setPpdDuplex(QPrinter::DuplexMode mode); + ppd_option_t *m_duplexPpdOption; +#endif + private: QPrintDialogPrivate *optionsPane; bool filePrintersAdded; @@ -229,6 +237,9 @@ public: #endif void _q_collapseOrExpandDialog(); +#if QT_CONFIG(cups) + void updatePpdDuplexOption(QRadioButton *radio); +#endif void setupPrinter(); void updateWidgets(); @@ -240,103 +251,12 @@ public: QDialogButtonBox *buttons; QPushButton *collapseButton; QPrinter::OutputFormat printerOutputFormat; -}; - -#if QT_CONFIG(cups) -class QOptionTreeItem -{ -public: - enum ItemType { Root, Group, Option, Choice }; - - QOptionTreeItem(ItemType t, int i, const void *p, QOptionTreeItem *pi) - : type(t), - index(i), - ptr(p), - parentItem(pi) {} - - ~QOptionTreeItem() { - qDeleteAll(childItems); - } - - ItemType type; - int index; - const void *ptr; - QOptionTreeItem *parentItem; - QList<QOptionTreeItem*> childItems; -}; - -class QOptionTreeItemOption : public QOptionTreeItem -{ -public: - QOptionTreeItemOption (int i, const void *p, QOptionTreeItem *pi) - : QOptionTreeItem(Option, i, p, pi) - { - } - - // These indices are related to ppd_option_t::choices not to childItems - int selected; - int originallySelected; -}; - -class QPPDOptionsModel : public QAbstractItemModel -{ - Q_OBJECT - -public: - explicit QPPDOptionsModel(QPrintDevice *currentPrintDevice, QObject *parent); - - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &index) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - - void setCupsOptionsFromItems(QPrinter *printer) const; - void reject(); - void updateSavedValues(); - void revertToSavedValues(); - - QPrintDevice *currentPrintDevice() const; - QTextCodec *cupsCodec() const; - - void emitConflictsChanged(); - bool hasConflicts() const; - -signals: - void hasConflictsChanged(bool conflicts); - private: - void parseGroups(QOptionTreeItem *parent); - void parseOptions(QOptionTreeItem *parent); - void parseChoices(QOptionTreeItemOption *parent); - - void setCupsOptionsFromItems(QPrinter *printer, QOptionTreeItem *parent) const; - void reject(QOptionTreeItem *item); - void updateSavedValues(QOptionTreeItem *item); - void revertToSavedValues(QOptionTreeItem *item); - void emitDataChanged(QOptionTreeItem *item, const QModelIndex &itemIndex, bool *conflictsFound); - bool hasConflicts(QOptionTreeItem *item) const; - - QPrintDevice *m_currentPrintDevice; - QTextCodec *m_cupsCodec; - QOptionTreeItem *m_rootItem; + void setExplicitDuplexMode(QPrint::DuplexMode duplexMode); + // duplex mode explicitly set by user, QPrint::DuplexAuto otherwise + QPrint::DuplexMode explicitDuplexMode; }; -class QPPDOptionsEditor : public QStyledItemDelegate -{ - Q_OBJECT -public: - explicit QPPDOptionsEditor(QObject *parent) : QStyledItemDelegate(parent) {} - - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - void setEditorData(QWidget *editor, const QModelIndex &index) const override; - void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; -}; - -#endif - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -377,24 +297,15 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice * const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage); #if QT_CONFIG(cups) - m_cupsOptionsModel = new QPPDOptionsModel(currentPrintDevice, this); - - widget.treeView->setItemDelegate(new QPPDOptionsEditor(this)); + m_currentPrintDevice = currentPrintDevice; + const bool anyWidgetCreated = createAdvancedOptionsWidget(); - if (m_cupsOptionsModel->rowCount() > 0) { - widget.treeView->setModel(m_cupsOptionsModel); + widget.tabs->setTabEnabled(advancedTabIndex, anyWidgetCreated); - for (int i = 0; i < m_cupsOptionsModel->rowCount(); ++i) - widget.treeView->expand(m_cupsOptionsModel->index(i, 0)); + connect(widget.pageSetup, &QPageSetupWidget::ppdOptionChanged, this, [this] { + widget.conflictsLabel->setVisible(anyPpdOptionConflict()); + }); - widget.tabs->setTabEnabled(advancedTabIndex, true); - } else { - widget.treeView->setModel(nullptr); - widget.tabs->setTabEnabled(advancedTabIndex, false); - } - - widget.conflictsLabel->setVisible(m_cupsOptionsModel->hasConflicts()); - connect(m_cupsOptionsModel, &QPPDOptionsModel::hasConflictsChanged, widget.conflictsLabel, &QLabel::setVisible); #else Q_UNUSED(currentPrintDevice) widget.tabs->setTabEnabled(advancedTabIndex, false); @@ -420,16 +331,10 @@ void QPrintPropertiesDialog::setupPrinter() const // Set Color by default, that will change if the "ColorModel" property is available m_printer->setColorMode(QPrinter::Color); - m_cupsOptionsModel->setCupsOptionsFromItems(m_printer); + setPrinterAdvancedCupsOptions(); #endif } -void QPrintPropertiesDialog::showEvent(QShowEvent *event) -{ - widget.treeView->resizeColumnToContents(0); - QDialog::showEvent(event); -} - void QPrintPropertiesDialog::reject() { widget.pageSetup->revertToSavedValues(); @@ -439,7 +344,7 @@ void QPrintPropertiesDialog::reject() #endif #if QT_CONFIG(cups) - m_cupsOptionsModel->revertToSavedValues(); + revertAdvancedOptionsToSavedValues(); #endif QDialog::reject(); } @@ -447,7 +352,14 @@ void QPrintPropertiesDialog::reject() void QPrintPropertiesDialog::accept() { #if QT_CONFIG(cups) - if (m_cupsOptionsModel->hasConflicts()) { + 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?"), @@ -455,7 +367,7 @@ void QPrintPropertiesDialog::accept() if (answer != QMessageBox::No) return; } - m_cupsOptionsModel->updateSavedValues(); + advancedOptionsUpdateSavedValues(); #endif #if QT_CONFIG(cupsjobwidget) @@ -467,6 +379,224 @@ 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 +static const char *ppdOptionProperty = "_q_ppd_option"; + +// 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"; + +// 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) Q_DECL_NOTHROW +{ + return qstrcmp(group->name, "InstallableOptions") == 0; +}; + +static bool isBlacklistedOption(const char *keyword) Q_DECL_NOTHROW +{ + // 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)); +}; + +bool QPrintPropertiesDialog::createAdvancedOptionsWidget() +{ + bool anyWidgetCreated = false; + + ppd_file_t *ppd = m_currentPrintDevice->property(PDPK_PpdFile).value<ppd_file_t*>(); + + if (ppd) { + m_cupsCodec = QTextCodec::codecForName(ppd->lang_encoding); + + 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<int>(choice->marked) == 1) { + markedChoiceNotAvailable = true; + } else if (!choiceIsInstallableConflict) { + choicesCb->addItem(m_cupsCodec->toUnicode(choice->text), i); + if (static_cast<int>(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, QOverload<int>::of(&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(m_cupsCodec->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(m_cupsCodec->toUnicode(group->text)); + groupBox->setLayout(groupLayout); + layout->addWidget(groupBox); + } else { + delete groupLayout; + } + } + } + + layout->addStretch(); + widget.scrollArea->setWidget(holdingWidget); + } + + if (!m_cupsCodec) + m_cupsCodec = QTextCodec::codecForLocale(); + + return anyWidgetCreated; +} + +void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const +{ + for (const QComboBox *choicesCb : m_advancedOptionsCombos) { + const ppd_option_t *option = choicesCb->property(ppdOptionProperty).value<const ppd_option_t *>(); + + // 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 char *selectedChoice = option->choices[selectedChoiceIndex].choice; + + if (qstrcmp(option->keyword, "ColorModel") == 0) + m_printer->setColorMode(qstrcmp(selectedChoice, "Gray") == 0 ? QPrinter::GrayScale : QPrinter::Color); + + if (qstrcmp(option->defchoice, selectedChoice) != 0) + QCUPSSupport::setCupsOption(m_printer, QString::fromLatin1(option->keyword), QString::fromLatin1(selectedChoice)); + } +} + +void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const +{ + for (QComboBox *choicesCb : m_advancedOptionsCombos) { + const int originallySelectedChoice = choicesCb->property(ppdOriginallySelectedChoiceProperty).value<int>(); + const int newComboIndexToSelect = choicesCb->findData(originallySelectedChoice); + choicesCb->setCurrentIndex(newComboIndexToSelect); + // The currentIndexChanged lambda takes care of resetting the ppd option + } + widget.conflictsLabel->setVisible(anyPpdOptionConflict()); +} + +void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const +{ + for (QComboBox *choicesCb : m_advancedOptionsCombos) + 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); + + bool anyConflicted = false; + + for (const QComboBox *choicesCb : m_advancedOptionsCombos) { + const ppd_option_t *option = choicesCb->property(ppdOptionProperty).value<const ppd_option_t *>(); + QLabel *warningLabel = choicesCb->property(warningLabelProperty).value<QLabel *>(); + if (option->conflicted) { + anyConflicted = true; + const int pixmap_size = choicesCb->sizeHint().height() * .75; + warningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size)); + } else { + warningLabel->setPixmap(QPixmap()); + } + } + + return anyConflicted; +} + +#endif + + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -479,7 +609,8 @@ void QPrintPropertiesDialog::accept() */ QPrintDialogPrivate::QPrintDialogPrivate() - : top(nullptr), bottom(nullptr), buttons(nullptr), collapseButton(nullptr) + : top(nullptr), bottom(nullptr), buttons(nullptr), collapseButton(nullptr), + explicitDuplexMode(QPrint::DuplexAuto) { initResources(); } @@ -540,6 +671,16 @@ void QPrintDialogPrivate::init() q, SLOT(_q_togglePageSetCombo(bool))); QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog())); + + QObject::connect(options.noDuplex, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexNone); }); + QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexLongSide); }); + QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexShortSide); }); + +#if QT_CONFIG(cups) + QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); }); + QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); }); + QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); }); +#endif } // initialize printer options @@ -559,13 +700,20 @@ void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputForma else options.grayscale->setChecked(true); - switch (p->duplex()) { - case QPrinter::DuplexNone: + // keep duplex value explicitly set by user, if any, and selected printer supports it; + // use device default otherwise + QPrint::DuplexMode duplex; + if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode)) + duplex = explicitDuplexMode; + else + duplex = top->d->m_currentPrintDevice.defaultDuplexMode(); + switch (duplex) { + case QPrint::DuplexNone: options.noDuplex->setChecked(true); break; - case QPrinter::DuplexLongSide: - case QPrinter::DuplexAuto: + case QPrint::DuplexLongSide: + case QPrint::DuplexAuto: options.duplexLong->setChecked(true); break; - case QPrinter::DuplexShortSide: + case QPrint::DuplexShortSide: options.duplexShort->setChecked(true); break; } options.copies->setValue(p->copyCount()); @@ -665,8 +813,26 @@ 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::setExplicitDuplexMode(const QPrint::DuplexMode duplexMode) +{ + explicitDuplexMode = duplexMode; +} + void QPrintDialogPrivate::setupPrinter() { // First setup the requested OutputFormat, Printer and Page Size first @@ -931,6 +1097,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(); @@ -952,8 +1125,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) @@ -1043,6 +1219,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 @@ -1077,6 +1257,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) @@ -1172,11 +1356,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() @@ -1262,436 +1465,8 @@ void QUnixPrintWidget::updatePrinter() d->setupPrinter(); } -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/* - - QPPDOptionsModel - - Holds the PPD Options for the printer. - -*/ - #if QT_CONFIG(cups) -static bool isBlacklistedGroup(ppd_group_t *group) Q_DECL_NOTHROW -{ - return qstrcmp(group->name, "InstallableOptions") == 0; -}; - -QPPDOptionsModel::QPPDOptionsModel(QPrintDevice *currentPrintDevice, QObject *parent) - : QAbstractItemModel(parent) - , m_currentPrintDevice(currentPrintDevice) - , m_cupsCodec(nullptr) -{ - ppd_file_t *ppd = m_currentPrintDevice->property(PDPK_PpdFile).value<ppd_file_t*>(); - m_rootItem = new QOptionTreeItem(QOptionTreeItem::Root, 0, ppd, nullptr); - - if (ppd) { - m_cupsCodec = QTextCodec::codecForName(ppd->lang_encoding); - for (int i = 0; i < ppd->num_groups; ++i) { - if (!isBlacklistedGroup(&ppd->groups[i])) { - QOptionTreeItem *group = new QOptionTreeItem(QOptionTreeItem::Group, i, &ppd->groups[i], m_rootItem); - m_rootItem->childItems.append(group); - parseGroups(group); // parse possible subgroups - parseOptions(group); // parse options - } - } - } - - if (!m_cupsCodec) - m_cupsCodec = QTextCodec::codecForLocale(); -} - -int QPPDOptionsModel::columnCount(const QModelIndex &) const -{ - return 2; -} - -int QPPDOptionsModel::rowCount(const QModelIndex &parent) const -{ - QOptionTreeItem *itm; - if (!parent.isValid()) - itm = m_rootItem; - else - itm = static_cast<QOptionTreeItem*>(parent.internalPointer()); - - if (itm->type == QOptionTreeItem::Option) - return 0; - - return itm->childItems.count(); -} - -QVariant QPPDOptionsModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - QOptionTreeItem *itm = static_cast<QOptionTreeItem*>(index.internalPointer()); - - switch (role) { - case Qt::FontRole: { - if (itm->type == QOptionTreeItem::Group){ - QFont font; - font.setBold(true); - return QVariant(font); - } - return QVariant(); - } - break; - - case Qt::DisplayRole: { - if (index.column() == 0) { - if (itm->type == QOptionTreeItem::Option) { - const ppd_option_t *option = static_cast<const ppd_option_t*>(itm->ptr); - return m_cupsCodec->toUnicode(option->text); - } else if (itm->type == QOptionTreeItem::Group) { - const ppd_group_t *group = static_cast<const ppd_group_t*>(itm->ptr); - return m_cupsCodec->toUnicode(group->text); - } - } else if (itm->type == QOptionTreeItem::Option) { - QOptionTreeItemOption *itmOption = static_cast<QOptionTreeItemOption *>(itm); - const ppd_option_t *option = static_cast<const ppd_option_t*>(itm->ptr); - if (itmOption->selected > -1) - return m_cupsCodec->toUnicode(option->choices[itmOption->selected].text); - } - - return QVariant(); - } - break; - - case Qt::DecorationRole: { - if (itm->type == QOptionTreeItem::Option && index.column() == 1) { - const ppd_option_t *option = static_cast<const ppd_option_t*>(itm->ptr); - if (option->conflicted) { - const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr); - if (!warning.isNull()) - return warning; - - qWarning() << "Current application style returned a null icon for SP_MessageBoxWarning."; - return QColor(Qt::red); - } - } - return QVariant(); - } - break; - - } - - return QVariant(); -} - -QModelIndex QPPDOptionsModel::index(int row, int column, const QModelIndex &parent) const -{ - QOptionTreeItem *itm; - if (!parent.isValid()) - itm = m_rootItem; - else - itm = static_cast<QOptionTreeItem*>(parent.internalPointer()); - - return createIndex(row, column, itm->childItems.at(row)); -} - - -QModelIndex QPPDOptionsModel::parent(const QModelIndex &index) const -{ - if (!index.isValid()) - return QModelIndex(); - - QOptionTreeItem *itm = static_cast<QOptionTreeItem*>(index.internalPointer()); - - if (itm->parentItem && itm->parentItem != m_rootItem) - return createIndex(itm->parentItem->index, 0, itm->parentItem); - - return QModelIndex(); -} - -Qt::ItemFlags QPPDOptionsModel::flags(const QModelIndex &index) const -{ - if (!index.isValid() || static_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Group) - return Qt::ItemIsEnabled; - - if (index.column() == 1) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; - - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -QPrintDevice *QPPDOptionsModel::currentPrintDevice() const -{ - return m_currentPrintDevice; -} - -QTextCodec *QPPDOptionsModel::cupsCodec() const -{ - return m_cupsCodec; -} - -void QPPDOptionsModel::setCupsOptionsFromItems(QPrinter *printer) const -{ - setCupsOptionsFromItems(printer, m_rootItem); -} - -void QPPDOptionsModel::setCupsOptionsFromItems(QPrinter *printer, QOptionTreeItem *parent) const -{ - for (QOptionTreeItem *itm : qAsConst(parent->childItems)) { - if (itm->type == QOptionTreeItem::Option) { - QOptionTreeItemOption *itmOption = static_cast<QOptionTreeItemOption *>(itm); - const ppd_option_t *opt = static_cast<const ppd_option_t*>(itm->ptr); - - if (qstrcmp(opt->keyword, "ColorModel") == 0) - printer->setColorMode(qstrcmp(opt->choices[itmOption->selected].choice, "Gray") == 0 ? QPrinter::GrayScale : QPrinter::Color); - - if (qstrcmp(opt->defchoice, opt->choices[itmOption->selected].choice) != 0) { - QCUPSSupport::setCupsOption(printer, QString::fromLatin1(opt->keyword), QString::fromLatin1(opt->choices[itmOption->selected].choice)); - } - } else { - setCupsOptionsFromItems(printer, itm); - } - } -} - -void QPPDOptionsModel::parseGroups(QOptionTreeItem *parent) -{ - const ppd_group_t *group = static_cast<const ppd_group_t*>(parent->ptr); - - if (group) { - for (int i = 0; i < group->num_subgroups; ++i) { - if (!isBlacklistedGroup(&group->subgroups[i])) { - QOptionTreeItem *subgroup = new QOptionTreeItem(QOptionTreeItem::Group, i, &group->subgroups[i], parent); - parent->childItems.append(subgroup); - parseGroups(subgroup); // parse possible subgroups - parseOptions(subgroup); // parse options - } - } - } -} - -static bool isBlacklistedOption(const char *keyword) Q_DECL_NOTHROW -{ - // 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)); -}; - -void QPPDOptionsModel::parseOptions(QOptionTreeItem *parent) -{ - const ppd_group_t *group = static_cast<const ppd_group_t*>(parent->ptr); - for (int i = 0; i < group->num_options; ++i) { - if (!isBlacklistedOption(group->options[i].keyword)) { - QOptionTreeItemOption *opt = new QOptionTreeItemOption(i, &group->options[i], parent); - parseChoices(opt); - - // Don't show options that are actually not options at all - // because they don't give the user any choice - if (opt->childItems.count() > 1) - parent->childItems.append(opt); - else - delete opt; - } - } -} - -void QPPDOptionsModel::parseChoices(QOptionTreeItemOption *parent) -{ - const ppd_option_t *option = static_cast<const ppd_option_t*>(parent->ptr); - bool marked = false; - for (int i = 0; i < option->num_choices; ++i) { - const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(option->choices[i].choice); - if (!m_currentPrintDevice->isFeatureAvailable(PDPK_PpdChoiceIsInstallableConflict, values)) { - QOptionTreeItem *choice = new QOptionTreeItem(QOptionTreeItem::Choice, i, &option->choices[i], parent); - if (static_cast<int>(option->choices[i].marked) == 1) { - parent->selected = i; - marked = true; - } else if (!marked && qstrcmp(option->choices[i].choice, option->defchoice) == 0) { - parent->selected = i; - } - parent->originallySelected = parent->selected; - parent->childItems.append(choice); - } - } -} - -bool QPPDOptionsModel::hasConflicts() const -{ - return hasConflicts(m_rootItem); -} - -bool QPPDOptionsModel::hasConflicts(QOptionTreeItem *item) const -{ - if (item->type == QOptionTreeItem::Option) { - const ppd_option_t *option = static_cast<const ppd_option_t*>(item->ptr); - return option->conflicted; - } - - for (QOptionTreeItem *child : qAsConst(item->childItems)) { - if (hasConflicts(child)) - return true; - } - - return false; -} - -void QPPDOptionsModel::emitConflictsChanged() -{ - bool conflictsFound = false; - emitDataChanged(m_rootItem, QModelIndex(), &conflictsFound); - - emit hasConflictsChanged(conflictsFound); -} - -void QPPDOptionsModel::emitDataChanged(QOptionTreeItem *item, const QModelIndex &itemIndex, bool *conflictsFound) -{ - if (item->type == QOptionTreeItem::Option) { - // We just emit DecorationRole dataChanged for all the leaves - // and let the view requery the value - const QModelIndex secondColItem = index(itemIndex.row(), 1, itemIndex.parent()); - emit dataChanged(secondColItem, secondColItem, QVector<int>() << Qt::DecorationRole); - - if (conflictsFound && *conflictsFound == false) { - const ppd_option_t *option = static_cast<const ppd_option_t*>(item->ptr); - if (option->conflicted && conflictsFound) - *conflictsFound = true; - } - } - - for (int i = 0; i < item->childItems.count(); ++i) { - QOptionTreeItem *child = item->childItems.at(i); - emitDataChanged(child, index(i, 0, itemIndex), conflictsFound); - } -} - -QVariant QPPDOptionsModel::headerData(int section, Qt::Orientation, int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - switch (section) { - case 0: - return QVariant(tr("Name")); - case 1: - return QVariant(tr("Value")); - } - - return QVariant(); -} - -void QPPDOptionsModel::revertToSavedValues() -{ - revertToSavedValues(m_rootItem); - emitConflictsChanged(); -} - -void QPPDOptionsModel::revertToSavedValues(QOptionTreeItem *item) -{ - if (item->type == QOptionTreeItem::Option) { - QOptionTreeItemOption *itemOption = static_cast<QOptionTreeItemOption *>(item); - - const ppd_option_t *option = static_cast<const ppd_option_t*>(item->ptr); - const char *choice = itemOption->originallySelected != -1 ? option->choices[itemOption->originallySelected].choice - : option->defchoice; - const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(choice); - m_currentPrintDevice->setProperty(PDPK_PpdOption, values); - itemOption->selected = itemOption->originallySelected; - } - - for (QOptionTreeItem *child : qAsConst(item->childItems)) - revertToSavedValues(child); -} - -void QPPDOptionsModel::updateSavedValues() -{ - updateSavedValues(m_rootItem); -} - -void QPPDOptionsModel::updateSavedValues(QOptionTreeItem *item) -{ - if (item->type == QOptionTreeItem::Option) { - QOptionTreeItemOption *itemOption = static_cast<QOptionTreeItemOption *>(item); - itemOption->originallySelected = itemOption->selected; - } - - for (QOptionTreeItem *child : qAsConst(item->childItems)) - updateSavedValues(child); -} - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/* - - QPPDOptionsEditor - - Edits the PPD Options for the printer. - -*/ - -QWidget *QPPDOptionsEditor::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - Q_UNUSED(option) - - if (index.column() == 1 && static_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Option) - return new QComboBox(parent); - - return nullptr; -} - -void QPPDOptionsEditor::setEditorData(QWidget *editor, const QModelIndex &index) const -{ - if (index.column() != 1) - return; - - QComboBox *cb = static_cast<QComboBox*>(editor); - QOptionTreeItemOption *itm = static_cast<QOptionTreeItemOption*>(index.internalPointer()); - - if (itm->selected == -1) - cb->addItem(QString()); - - const QPPDOptionsModel *m = static_cast<const QPPDOptionsModel*>(index.model()); - for (auto *childItem : qAsConst(itm->childItems)) { - const ppd_choice_t *choice = static_cast<const ppd_choice_t*>(childItem->ptr); - cb->addItem(m->cupsCodec()->toUnicode(choice->text), childItem->index); - if (childItem->index == itm->selected) - cb->setCurrentIndex(cb->count() - 1); - } -} - -void QPPDOptionsEditor::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const -{ - QComboBox *cb = static_cast<QComboBox*>(editor); - QOptionTreeItemOption *itm = static_cast<QOptionTreeItemOption*>(index.internalPointer()); - - // We can't use cb->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 = cb->currentData().toInt(); - - if (itm->selected == selectedChoiceIndex || selectedChoiceIndex < 0) - return; - - const ppd_option_t *opt = static_cast<const ppd_option_t*>(itm->ptr); - QPPDOptionsModel *m = static_cast<QPPDOptionsModel*>(model); - - const auto values = QStringList{} << QString::fromLatin1(opt->keyword) << QString::fromLatin1(opt->choices[selectedChoiceIndex].choice); - m->currentPrintDevice()->setProperty(PDPK_PpdOption, values); - itm->selected = selectedChoiceIndex; - - m->emitConflictsChanged(); -} - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/src/printsupport/dialogs/qprintpreviewdialog.cpp b/src/printsupport/dialogs/qprintpreviewdialog.cpp index a4f721fbc8..418bc47a59 100644 --- a/src/printsupport/dialogs/qprintpreviewdialog.cpp +++ b/src/printsupport/dialogs/qprintpreviewdialog.cpp @@ -573,8 +573,11 @@ void QPrintPreviewDialogPrivate::_q_print() if (printer->outputFormat() != QPrinter::NativeFormat) { QString title = QCoreApplication::translate("QPrintPreviewDialog", "Export to PDF"); QString suffix = QLatin1String(".pdf"); - QString fileName = QFileDialog::getSaveFileName(q, title, printer->outputFileName(), + QString fileName; +#if QT_CONFIG(filedialog) + fileName = QFileDialog::getSaveFileName(q, title, printer->outputFileName(), QLatin1Char('*') + suffix); +#endif if (!fileName.isEmpty()) { if (QFileInfo(fileName).suffix().isEmpty()) fileName.append(suffix); diff --git a/src/printsupport/dialogs/qprintpropertieswidget.ui b/src/printsupport/dialogs/qprintpropertieswidget.ui index d8e526139b..c2b4836d26 100644 --- a/src/printsupport/dialogs/qprintpropertieswidget.ui +++ b/src/printsupport/dialogs/qprintpropertieswidget.ui @@ -47,60 +47,74 @@ </attribute> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QTreeView" name="treeView"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </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> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> </property> - <property name="text"> - <string>There are conflicts in some options. Please fix them.</string> + <property name="widgetResizable"> + <bool>true</bool> </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>376</width> + <height>217</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"/> + </widget> </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> 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<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) { 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 <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); diff --git a/src/printsupport/kernel/qplatformprintdevice.cpp b/src/printsupport/kernel/qplatformprintdevice.cpp index 8dba402a6e..23a92fc2a1 100644 --- a/src/printsupport/kernel/qplatformprintdevice.cpp +++ b/src/printsupport/kernel/qplatformprintdevice.cpp @@ -50,23 +50,6 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_PRINTER -QPlatformPrintDevice::QPlatformPrintDevice() - : m_isRemote(false), - m_supportsMultipleCopies(false), - m_supportsCollateCopies(false), - m_havePageSizes(false), - m_supportsCustomPageSizes(false), - m_haveResolutions(false), - m_haveInputSlots(false), - m_haveOutputBins(false), - m_haveDuplexModes(false), - m_haveColorModes(false) -#ifndef QT_NO_MIMETYPE - , m_haveMimeTypes(false) -#endif -{ -} - QPlatformPrintDevice::QPlatformPrintDevice(const QString &id) : m_id(id), m_isRemote(false), @@ -247,6 +230,10 @@ QPageSize QPlatformPrintDevice::supportedPageSize(const QSizeF &size, QPageSize: QPageSize QPlatformPrintDevice::supportedPageSizeMatch(const QPageSize &pageSize) const { + // If it's a known page size, just return itself + if (m_pageSizes.contains(pageSize)) + return pageSize; + // Try to find a supported page size based on point size for (const QPageSize &ps : m_pageSizes) { if (ps.sizePoints() == pageSize.sizePoints()) diff --git a/src/printsupport/kernel/qplatformprintdevice.h b/src/printsupport/kernel/qplatformprintdevice.h index a988518547..d95a5add9b 100644 --- a/src/printsupport/kernel/qplatformprintdevice.h +++ b/src/printsupport/kernel/qplatformprintdevice.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 John Layt <jlayt@kde.org> +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtPrintSupport module of the Qt Toolkit. @@ -69,8 +70,7 @@ class Q_PRINTSUPPORT_EXPORT QPlatformPrintDevice { Q_DISABLE_COPY(QPlatformPrintDevice) public: - QPlatformPrintDevice(); - explicit QPlatformPrintDevice(const QString &id); + explicit QPlatformPrintDevice(const QString &id = QString()); virtual ~QPlatformPrintDevice(); virtual QString id() const; @@ -152,16 +152,16 @@ protected: bool m_isRemote; - bool m_supportsMultipleCopies; - bool m_supportsCollateCopies; + mutable bool m_supportsMultipleCopies; + mutable bool m_supportsCollateCopies; mutable bool m_havePageSizes; mutable QList<QPageSize> m_pageSizes; - bool m_supportsCustomPageSizes; + mutable bool m_supportsCustomPageSizes; - QSize m_minimumPhysicalPageSize; - QSize m_maximumPhysicalPageSize; + mutable QSize m_minimumPhysicalPageSize; + mutable QSize m_maximumPhysicalPageSize; mutable bool m_haveResolutions; mutable QList<int> m_resolutions; diff --git a/src/printsupport/kernel/qprintengine_pdf.cpp b/src/printsupport/kernel/qprintengine_pdf.cpp index 0230ebddc8..3c24e5ac69 100644 --- a/src/printsupport/kernel/qprintengine_pdf.cpp +++ b/src/printsupport/kernel/qprintengine_pdf.cpp @@ -132,6 +132,8 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va // The following keys are settings that are unsupported by the PDF PrintEngine case PPK_CustomBase: break; + case PPK_Duplex: + break; // The following keys are properties and settings that are supported by the PDF PrintEngine case PPK_CollateCopies: @@ -203,9 +205,6 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va case PPK_FontEmbedding: d->embedFonts = value.toBool(); break; - case PPK_Duplex: - d->duplex = static_cast<QPrint::DuplexMode>(value.toInt()); - break; case PPK_CustomPaperSize: d->m_pageLayout.setPageSize(QPageSize(value.toSizeF(), QPageSize::Point)); break; @@ -249,6 +248,7 @@ QVariant QPdfPrintEngine::property(PrintEnginePropertyKey key) const // The following keys are settings that are unsupported by the PDF PrintEngine // Return sensible default values to ensure consistent behavior across platforms case PPK_CustomBase: + case PPK_Duplex: // Special case, leave null break; @@ -322,9 +322,6 @@ QVariant QPdfPrintEngine::property(PrintEnginePropertyKey key) const case PPK_FontEmbedding: ret = d->embedFonts; break; - case PPK_Duplex: - ret = d->duplex; - break; case PPK_CustomPaperSize: ret = d->m_pageLayout.fullRectPoints().size(); break; @@ -389,7 +386,6 @@ void QPdfPrintEnginePrivate::closePrintDevice() QPdfPrintEnginePrivate::QPdfPrintEnginePrivate(QPrinter::PrinterMode m) : QPdfEnginePrivate(), - duplex(QPrint::DuplexNone), collate(true), copies(1), pageOrder(QPrinter::FirstPageFirst), diff --git a/src/printsupport/kernel/qprintengine_pdf_p.h b/src/printsupport/kernel/qprintengine_pdf_p.h index bb01a2e9e1..e7ae21f260 100644 --- a/src/printsupport/kernel/qprintengine_pdf_p.h +++ b/src/printsupport/kernel/qprintengine_pdf_p.h @@ -130,7 +130,6 @@ private: QString printProgram; QString selectionOption; - QPrint::DuplexMode duplex; bool collate; int copies; QPrinter::PageOrder pageOrder; diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 6f263e5ea8..e3a5c3d2e8 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -1556,14 +1556,15 @@ HGLOBAL *QWin32PrintEngine::createGlobalDevNames() Q_D(QWin32PrintEngine); int size = sizeof(DEVNAMES) + d->m_printDevice.id().length() * 2 + 2; - HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size); - DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal); + auto hGlobal = reinterpret_cast<HGLOBAL *>(GlobalAlloc(GMEM_MOVEABLE, size)); + auto dn = reinterpret_cast<DEVNAMES*>(GlobalLock(hGlobal)); dn->wDriverOffset = 0; dn->wDeviceOffset = sizeof(DEVNAMES) / sizeof(wchar_t); dn->wOutputOffset = 0; - memcpy((ushort*)dn + dn->wDeviceOffset, d->m_printDevice.id().utf16(), d->m_printDevice.id().length() * 2 + 2); + memcpy(reinterpret_cast<ushort*>(dn) + dn->wDeviceOffset, + d->m_printDevice.id().utf16(), d->m_printDevice.id().length() * 2 + 2); dn->wDefault = 0; GlobalUnlock(hGlobal); @@ -1574,8 +1575,9 @@ void QWin32PrintEngine::setGlobalDevMode(HGLOBAL globalDevNames, HGLOBAL globalD { Q_D(QWin32PrintEngine); if (globalDevNames) { - DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevNames); - QString id = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset); + auto dn = reinterpret_cast<DEVNAMES*>(GlobalLock(globalDevNames)); + const QString id = + QString::fromWCharArray(reinterpret_cast<const wchar_t*>(dn) + dn->wDeviceOffset); QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get(); if (ps) d->m_printDevice = ps->createPrintDevice(id.isEmpty() ? ps->defaultPrintDeviceId() : id); @@ -1583,7 +1585,7 @@ void QWin32PrintEngine::setGlobalDevMode(HGLOBAL globalDevNames, HGLOBAL globalD } if (globalDevMode) { - DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevMode); + auto dm = reinterpret_cast<DEVMODE*>(GlobalLock(globalDevMode)); d->release(); d->globalDevMode = globalDevMode; if (d->ownsDevMode) { @@ -1779,39 +1781,26 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, _glyphs, positions); - if (_glyphs.size() == 0) { + if (_glyphs.isEmpty()) { SelectObject(hdc, old_font); return; } - bool outputEntireItem = _glyphs.size() > 0; - - if (outputEntireItem) { - options |= ETO_PDY; - QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2); - QVarLengthArray<wchar_t> g(_glyphs.size()); - for (int i=0; i<_glyphs.size() - 1; ++i) { - glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x); - glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y); - g[i] = _glyphs[i]; - } - glyphDistances[(_glyphs.size() - 1) * 2] = 0; - glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0; - g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1]; - ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0, - g.constData(), _glyphs.size(), - glyphDistances.data()); - } else { - int i = 0; - while(i < _glyphs.size()) { - wchar_t g = _glyphs[i]; - - ExtTextOut(hdc, qRound(positions[i].x), - qRound(positions[i].y), options, 0, - &g, 1, 0); - ++i; - } + options |= ETO_PDY; + QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2); + QVarLengthArray<wchar_t> g(_glyphs.size()); + const int lastGlyph = _glyphs.size() - 1; + for (int i = 0; i < lastGlyph; ++i) { + glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x); + glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y); + g[i] = _glyphs[i]; } + glyphDistances[lastGlyph * 2] = 0; + glyphDistances[lastGlyph * 2 + 1] = 0; + g[lastGlyph] = _glyphs[lastGlyph]; + ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, nullptr, + g.constData(), _glyphs.size(), + glyphDistances.data()); } win_xform.eM11 = win_xform.eM22 = 1.0; diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp index 8a2cdcb34f..ed4292ff3d 100644 --- a/src/printsupport/kernel/qprinter.cpp +++ b/src/printsupport/kernel/qprinter.cpp @@ -224,8 +224,8 @@ void QPrinterPrivate::setProperty(QPrintEngine::PrintEnginePropertyKey key, cons class QPrinterPagedPaintDevicePrivate : public QPagedPaintDevicePrivate { public: - QPrinterPagedPaintDevicePrivate(QPrinterPrivate *d) - : QPagedPaintDevicePrivate(), pd(d) + QPrinterPagedPaintDevicePrivate(QPrinter *p) + : QPagedPaintDevicePrivate(), m_printer(p) {} virtual ~QPrinterPagedPaintDevicePrivate() @@ -233,6 +233,8 @@ public: bool setPageLayout(const QPageLayout &newPageLayout) override { + QPrinterPrivate *pd = QPrinterPrivate::get(m_printer); + if (pd->paintEngine->type() != QPaintEngine::Pdf && pd->printEngine->printerState() == QPrinter::Active) { qWarning("QPrinter::setPageLayout: Cannot be changed while printer is active"); @@ -242,14 +244,13 @@ public: // Try to set the print engine page layout pd->setProperty(QPrintEngine::PPK_QPageLayout, QVariant::fromValue(newPageLayout)); - // Set QPagedPaintDevice layout to match the current print engine value - m_pageLayout = pageLayout(); - return pageLayout().isEquivalentTo(newPageLayout); } bool setPageSize(const QPageSize &pageSize) override { + QPrinterPrivate *pd = QPrinterPrivate::get(m_printer); + if (pd->paintEngine->type() != QPaintEngine::Pdf && pd->printEngine->printerState() == QPrinter::Active) { qWarning("QPrinter::setPageLayout: Cannot be changed while printer is active"); @@ -260,46 +261,38 @@ public: // Try to set the print engine page size pd->setProperty(QPrintEngine::PPK_QPageSize, QVariant::fromValue(pageSize)); - // Set QPagedPaintDevice layout to match the current print engine value - m_pageLayout = pageLayout(); - return pageLayout().pageSize().isEquivalentTo(pageSize); } bool setPageOrientation(QPageLayout::Orientation orientation) override { + QPrinterPrivate *pd = QPrinterPrivate::get(m_printer); + // Set the print engine value pd->setProperty(QPrintEngine::PPK_Orientation, orientation); - // Set QPagedPaintDevice layout to match the current print engine value - m_pageLayout = pageLayout(); - return pageLayout().orientation() == orientation; } - bool setPageMargins(const QMarginsF &margins) override - { - return setPageMargins(margins, pageLayout().units()); - } - bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override { + QPrinterPrivate *pd = QPrinterPrivate::get(m_printer); + // Try to set print engine margins QPair<QMarginsF, QPageLayout::Unit> pair = qMakePair(margins, units); pd->setProperty(QPrintEngine::PPK_QPageMargins, QVariant::fromValue(pair)); - // Set QPagedPaintDevice layout to match the current print engine value - m_pageLayout = pageLayout(); - return pageLayout().margins() == margins && pageLayout().units() == units; } QPageLayout pageLayout() const override { + QPrinterPrivate *pd = QPrinterPrivate::get(m_printer); + return pd->printEngine->property(QPrintEngine::PPK_QPageLayout).value<QPageLayout>(); } - QPrinterPrivate *pd; + QPrinter *m_printer; }; @@ -554,11 +547,9 @@ public: Creates a new printer object with the given \a mode. */ QPrinter::QPrinter(PrinterMode mode) - : QPagedPaintDevice(), + : QPagedPaintDevice(new QPrinterPagedPaintDevicePrivate(this)), d_ptr(new QPrinterPrivate(this)) { - delete d; - d = new QPrinterPagedPaintDevicePrivate(d_func()); d_ptr->init(QPrinterInfo(), mode); } @@ -568,11 +559,9 @@ QPrinter::QPrinter(PrinterMode mode) Creates a new printer object with the given \a printer and \a mode. */ QPrinter::QPrinter(const QPrinterInfo& printer, PrinterMode mode) - : QPagedPaintDevice(), + : QPagedPaintDevice(new QPrinterPagedPaintDevicePrivate(this)), d_ptr(new QPrinterPrivate(this)) { - delete d; - d = new QPrinterPagedPaintDevicePrivate(d_func()); d_ptr->init(printer, mode); } @@ -1469,8 +1458,6 @@ void QPrinter::setFullPage(bool fp) Q_D(QPrinter); // Set the print engine d->setProperty(QPrintEngine::PPK_FullPage, fp); - // Set QPagedPaintDevice layout to match the current print engine value - devicePageLayout() = pageLayout(); } diff --git a/src/printsupport/kernel/qprinter_p.h b/src/printsupport/kernel/qprinter_p.h index 6ced466236..37c9702c17 100644 --- a/src/printsupport/kernel/qprinter_p.h +++ b/src/printsupport/kernel/qprinter_p.h @@ -94,6 +94,10 @@ public: } + static QPrinterPrivate *get(QPrinter *printer) { + return printer->d_ptr.get(); + } + void init(const QPrinterInfo &printer, QPrinter::PrinterMode mode); QPrinterInfo findValidPrinter(const QPrinterInfo &printer = QPrinterInfo()); |