summaryrefslogtreecommitdiffstats
path: root/src/printsupport/dialogs/qprintdialog_unix.cpp
diff options
context:
space:
mode:
authorAlbert Astals Cid <albert.astals.cid@kdab.com>2017-12-05 09:40:59 +0100
committerAlbert Astals Cid <albert.astals.cid@kdab.com>2017-12-15 13:25:21 +0000
commitb4330bc391bbb08898f192ea3469b73aed09134c (patch)
tree28be7d5721ed2e641fc328f838ccefdbe9d2e232 /src/printsupport/dialogs/qprintdialog_unix.cpp
parent27f70d7826d739fe8705cb23b1a26cfb6e0bc16c (diff)
Reintroduce the Advanced tab in the QPrintPropertiesDialog
This is mostly a revert of 69de6177615de3c4c31dea529172389e92f490b0 adapted to the new code. The commit that removed this code said: a) there's duplicate settings in the advanced tabs and in the rest of the ui: this easily solved with a blacklist b) you can set these options in the system settings: probably true, but it is very cumbersome to go to the printer settings every time i print to select from which tray the paper should be used Task Number: QTBUG-54464 Change-Id: I7b1cacf51006dadb10aa6e00fe6dd2ff748fe576 Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Diffstat (limited to 'src/printsupport/dialogs/qprintdialog_unix.cpp')
-rw-r--r--src/printsupport/dialogs/qprintdialog_unix.cpp401
1 files changed, 395 insertions, 6 deletions
diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp
index f87630f1a0..d5ad90e85e 100644
--- a/src/printsupport/dialogs/qprintdialog_unix.cpp
+++ b/src/printsupport/dialogs/qprintdialog_unix.cpp
@@ -108,6 +108,11 @@ 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,19 +129,29 @@ class QPrintPropertiesDialog : public QDialog
{
Q_OBJECT
public:
- QPrintPropertiesDialog(QPrinter *printer, QPrinter::OutputFormat outputFormat,
- const QString &printerName, QAbstractPrintDialog *parent = nullptr);
+ QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice,
+ QPrinter::OutputFormat outputFormat, const QString &printerName,
+ QAbstractPrintDialog *parent);
~QPrintPropertiesDialog();
void setupPrinter() const;
+ void showEvent(QShowEvent *event) override;
+
private:
friend class QUnixPrintWidgetPrivate;
+ QPrinter *m_printer;
Ui::QPrintPropertiesWidget widget;
QDialogButtonBox *m_buttons;
#if QT_CONFIG(cupsjobwidget)
QCupsJobWidget *m_jobOptions;
#endif
+
+#if QT_CONFIG(cups)
+ void setCupsOptionsFromItems(QOptionTreeItem *parent) const;
+
+ QPPDOptionsModel *m_cupsOptionsModel;
+#endif
};
class QUnixPrintWidgetPrivate;
@@ -220,6 +235,70 @@ public:
QPrinter::OutputFormat printerOutputFormat;
};
+#if QT_CONFIG(cups)
+class QOptionTreeItem
+{
+public:
+ enum ItemType { Root, Group, Option, Choice };
+
+ QOptionTreeItem(ItemType t, int i, const void *p, const char *desc, QOptionTreeItem *pi)
+ : type(t),
+ index(i),
+ ptr(p),
+ description(desc),
+ selected(-1),
+ selDescription(nullptr),
+ parentItem(pi) {}
+
+ ~QOptionTreeItem() {
+ qDeleteAll(childItems);
+ }
+
+ ItemType type;
+ int index;
+ const void *ptr;
+ const char *description;
+ int selected;
+ const char *selDescription;
+ QOptionTreeItem *parentItem;
+ QList<QOptionTreeItem*> childItems;
+};
+
+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;
+
+ QPrintDevice *m_currentPrintDevice;
+ QTextCodec *cupsCodec;
+ QOptionTreeItem *rootItem;
+ void parseGroups(QOptionTreeItem *parent);
+ void parseOptions(QOptionTreeItem *parent);
+ void parseChoices(QOptionTreeItem *parent);
+};
+
+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
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -233,9 +312,11 @@ public:
*/
-QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrinter::OutputFormat outputFormat,
- const QString &printerName, QAbstractPrintDialog *parent)
+QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice,
+ QPrinter::OutputFormat outputFormat, const QString &printerName,
+ QAbstractPrintDialog *parent)
: QDialog(parent)
+ , m_printer(printer)
{
setWindowTitle(tr("Printer Properties"));
QVBoxLayout *lay = new QVBoxLayout(this);
@@ -252,7 +333,29 @@ QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrinter::Outp
#if QT_CONFIG(cupsjobwidget)
m_jobOptions = new QCupsJobWidget(printer);
- widget.tabs->addTab(m_jobOptions, tr("Job Options"));
+ widget.tabs->insertTab(1, m_jobOptions, tr("Job Options"));
+#endif
+
+ const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage);
+#if QT_CONFIG(cups)
+ m_cupsOptionsModel = new QPPDOptionsModel(currentPrintDevice, this);
+
+ widget.treeView->setItemDelegate(new QPPDOptionsEditor(this));
+
+ if (m_cupsOptionsModel->rowCount() > 0) {
+ widget.treeView->setModel(m_cupsOptionsModel);
+
+ for (int i = 0; i < m_cupsOptionsModel->rowCount(); ++i)
+ widget.treeView->expand(m_cupsOptionsModel->index(i, 0));
+
+ widget.tabs->setTabEnabled(advancedTabIndex, true);
+ } else {
+ widget.treeView->setModel(nullptr);
+ widget.tabs->setTabEnabled(advancedTabIndex, false);
+ }
+#else
+ Q_UNUSED(currentPrintDevice)
+ widget.tabs->setTabEnabled(advancedTabIndex, false);
#endif
}
@@ -266,8 +369,36 @@ void QPrintPropertiesDialog::setupPrinter() const
#if QT_CONFIG(cupsjobwidget)
m_jobOptions->setupPrinter();
#endif
+
+#if QT_CONFIG(cups)
+ setCupsOptionsFromItems(m_cupsOptionsModel->rootItem);
+#endif
}
+void QPrintPropertiesDialog::showEvent(QShowEvent *event)
+{
+ widget.treeView->resizeColumnToContents(0);
+ QDialog::showEvent(event);
+}
+
+#if QT_CONFIG(cups)
+void QPrintPropertiesDialog::setCupsOptionsFromItems(QOptionTreeItem *parent) const
+{
+ for (QOptionTreeItem *itm : qAsConst(parent->childItems)) {
+ if (itm->type == QOptionTreeItem::Option) {
+ const ppd_option_t *opt = static_cast<const ppd_option_t*>(itm->ptr);
+ if (qstrcmp(opt->defchoice, opt->choices[itm->selected].choice) != 0) {
+ QStringList cupsOptions = QCUPSSupport::cupsOptionsList(m_printer);
+ QCUPSSupport::setCupsOption(cupsOptions, QString::fromLatin1(opt->keyword), QString::fromLatin1(opt->choices[itm->selected].choice));
+ QCUPSSupport::setCupsOptions(m_printer, cupsOptions);
+ }
+ } else {
+ setCupsOptionsFromItems(itm);
+ }
+ }
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -844,7 +975,7 @@ void QUnixPrintWidgetPrivate::setupPrinterProperties()
printerName = widget.printers->currentText();
}
- propertiesDialog = new QPrintPropertiesDialog(q->printer(), outputFormat, printerName, q);
+ propertiesDialog = new QPrintPropertiesDialog(q->printer(), &m_currentPrintDevice, outputFormat, printerName, q);
propertiesDialog->setResult(QDialog::Rejected);
propertiesDialogShown = false;
}
@@ -952,6 +1083,264 @@ void QUnixPrintWidget::updatePrinter()
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
+/*
+
+ QPPDOptionsModel
+
+ Holds the PPD Options for the printer.
+
+*/
+
+#if QT_CONFIG(cups)
+
+QPPDOptionsModel::QPPDOptionsModel(QPrintDevice *currentPrintDevice, QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_currentPrintDevice(currentPrintDevice)
+{
+ ppd_file_t *ppd = m_currentPrintDevice->property(PDPK_PpdFile).value<ppd_file_t*>();
+ rootItem = new QOptionTreeItem(QOptionTreeItem::Root, 0, ppd, "Root Item", 0);
+
+ if (ppd) {
+ cupsCodec = QTextCodec::codecForName(ppd->lang_encoding);
+ for (int i = 0; i < ppd->num_groups; ++i) {
+ QOptionTreeItem *group = new QOptionTreeItem(QOptionTreeItem::Group, i, &ppd->groups[i], ppd->groups[i].text, rootItem);
+ rootItem->childItems.append(group);
+ parseGroups(group); // parse possible subgroups
+ parseOptions(group); // parse options
+ }
+ }
+
+ if (!cupsCodec)
+ cupsCodec = QTextCodec::codecForLocale();
+}
+
+int QPPDOptionsModel::columnCount(const QModelIndex &) const
+{
+ return 2;
+}
+
+int QPPDOptionsModel::rowCount(const QModelIndex &parent) const
+{
+ QOptionTreeItem *itm;
+ if (!parent.isValid())
+ itm = 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)
+ return cupsCodec->toUnicode(itm->description);
+ else if (itm->type == QOptionTreeItem::Option && itm->selected > -1)
+ return cupsCodec->toUnicode(itm->selDescription);
+ else
+ return QVariant();
+ }
+ break;
+
+ }
+
+ return QVariant();
+}
+
+QModelIndex QPPDOptionsModel::index(int row, int column, const QModelIndex &parent) const
+{
+ QOptionTreeItem *itm;
+ if (!parent.isValid())
+ itm = 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 != 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;
+}
+
+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) {
+ QOptionTreeItem *subgroup = new QOptionTreeItem(QOptionTreeItem::Group, i, &group->subgroups[i], group->subgroups[i].text, 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"
+ };
+ 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)) {
+ QOptionTreeItem *opt = new QOptionTreeItem(QOptionTreeItem::Option, i, &group->options[i], group->options[i].text, parent);
+ parent->childItems.append(opt);
+ parseChoices(opt);
+ }
+ }
+}
+
+void QPPDOptionsModel::parseChoices(QOptionTreeItem *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) {
+ QOptionTreeItem *choice = new QOptionTreeItem(QOptionTreeItem::Choice, i, &option->choices[i], option->choices[i].text, parent);
+ if (static_cast<int>(option->choices[i].marked) == 1) {
+ parent->selected = i;
+ parent->selDescription = option->choices[i].text;
+ marked = true;
+ } else if (!marked && qstrcmp(option->choices[i].choice, option->defchoice) == 0) {
+ parent->selected = i;
+ parent->selDescription = option->choices[i].text;
+ }
+ parent->childItems.append(choice);
+ }
+}
+
+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();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+
+ 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);
+ QOptionTreeItem *itm = static_cast<QOptionTreeItem*>(index.internalPointer());
+
+ if (itm->selected == -1)
+ cb->addItem(QString());
+
+ const QPPDOptionsModel *m = static_cast<const QPPDOptionsModel*>(index.model());
+ for (auto *childItem : qAsConst(itm->childItems))
+ cb->addItem(m->cupsCodec->toUnicode(childItem->description));
+
+ if (itm->selected > -1)
+ cb->setCurrentIndex(itm->selected);
+}
+
+void QPPDOptionsEditor::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+ QComboBox *cb = static_cast<QComboBox*>(editor);
+ QOptionTreeItem *itm = static_cast<QOptionTreeItem*>(index.internalPointer());
+
+ if (itm->selected == cb->currentIndex())
+ 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[cb->currentIndex()].choice);
+ if (m->m_currentPrintDevice->setProperty(PDPK_PpdOption, values)) {
+ itm->selected = cb->currentIndex();
+ itm->selDescription = static_cast<const ppd_option_t*>(itm->ptr)->choices[itm->selected].text;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+#endif // QT_CONFIG(cups)
#endif // defined (Q_OS_UNIX)
QT_END_NAMESPACE