summaryrefslogtreecommitdiffstats
path: root/src/printsupport
diff options
context:
space:
mode:
Diffstat (limited to 'src/printsupport')
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_mac.mm11
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_unix.cpp69
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_unix_p.h11
-rw-r--r--src/printsupport/dialogs/qpagesetupwidget.ui3
-rw-r--r--src/printsupport/dialogs/qprintdialog_mac.mm19
-rw-r--r--src/printsupport/dialogs/qprintdialog_unix.cpp907
-rw-r--r--src/printsupport/dialogs/qprintpropertieswidget.ui106
-rw-r--r--src/printsupport/kernel/qcups.cpp20
-rw-r--r--src/printsupport/kernel/qcups_p.h5
-rw-r--r--src/printsupport/kernel/qplatformprintdevice.cpp21
-rw-r--r--src/printsupport/kernel/qplatformprintdevice.h3
-rw-r--r--src/printsupport/kernel/qprintengine_pdf.cpp10
-rw-r--r--src/printsupport/kernel/qprintengine_pdf_p.h1
-rw-r--r--src/printsupport/kernel/qprinter.cpp43
-rw-r--r--src/printsupport/kernel/qprinter_p.h4
15 files changed, 546 insertions, 687 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..9e89277c43 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 QPrint::DuplexLongSide:
case QPrinter::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/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..14701271c3 100644
--- a/src/printsupport/kernel/qplatformprintdevice.h
+++ b/src/printsupport/kernel/qplatformprintdevice.h
@@ -69,8 +69,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;
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/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());