Reintroduce the Advanced tab in the QPrintPropertiesDialog

This is mostly a revert of 69de617761 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>
bb10
Albert Astals Cid 2017-12-05 09:40:59 +01:00
parent 27f70d7826
commit b4330bc391
2 changed files with 409 additions and 6 deletions

View File

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

View File

@ -32,6 +32,20 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="cupsPropertiesPage" >
<attribute name="title" >
<string>Advanced</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2" >
<item>
<widget class="QTreeView" name="treeView" >
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>