Mapper (continuation)

This commit is contained in:
Jakub Melka 2020-11-28 17:50:14 +01:00
parent 41ec260793
commit 112ba7beb9
5 changed files with 509 additions and 22 deletions

View File

@ -122,6 +122,7 @@ HEADERS += \
sources/pdfobject.h \
sources/pdfobjecteditormodel.h \
sources/pdfobjecteditorwidget.h \
sources/pdfobjecteditorwidget_impl.h \
sources/pdfobjectutils.h \
sources/pdfoptimizer.h \
sources/pdfoptionalcontent.h \

View File

@ -40,6 +40,11 @@ size_t PDFObjectEditorAbstractModel::getAttributeCount() const
return m_attributes.size();
}
ObjectEditorAttributeType PDFObjectEditorAbstractModel::getAttributeType(size_t index) const
{
return m_attributes.at(index).type;
}
const QString& PDFObjectEditorAbstractModel::getAttributeCategory(size_t index) const
{
return m_attributes.at(index).category;
@ -55,6 +60,11 @@ const QString& PDFObjectEditorAbstractModel::getAttributeName(size_t index) cons
return m_attributes.at(index).name;
}
const PDFObjectEditorModelAttributeEnumItems& PDFObjectEditorAbstractModel::getAttributeEnumItems(size_t index) const
{
return m_attributes.at(index).enumItems;
}
bool PDFObjectEditorAbstractModel::queryAttribute(size_t index, Question question) const
{
const PDFObjectEditorModelAttribute& attribute = m_attributes.at(index);
@ -87,7 +97,9 @@ bool PDFObjectEditorAbstractModel::queryAttribute(size_t index, Question questio
return true;
}
s
case Question::IsAttributeEditable:
return queryAttribute(index, Question::HasAttribute) && !attribute.attributeFlags.testFlag(PDFObjectEditorModelAttribute::Readonly);
default:
break;
@ -96,6 +108,11 @@ bool PDFObjectEditorAbstractModel::queryAttribute(size_t index, Question questio
return false;
}
bool PDFObjectEditorAbstractModel::getSelectorValue(size_t index) const
{
return m_attributes.at(index).selectorAttributeValue;
}
PDFObject PDFObjectEditorAbstractModel::getValue(size_t index) const
{
const QByteArrayList& dictionaryAttribute = m_attributes.at(index).dictionaryAttribute;
@ -112,7 +129,7 @@ PDFObject PDFObjectEditorAbstractModel::getValue(size_t index) const
for (int i = 0; i < pathDepth; ++i)
{
dictionary = m_storage->getDictionaryFromObject(dictionaryAttribute[i]);
dictionary = m_storage->getDictionaryFromObject(dictionary->get(dictionaryAttribute[i]));
if (!dictionary)
{
return PDFObject();
@ -141,9 +158,11 @@ size_t PDFObjectEditorAbstractModel::createAttribute(ObjectEditorAttributeType t
{
size_t index = m_attributes.size();
QByteArrayList attributes;
attributes.push_back(attributeName);
PDFObjectEditorModelAttribute attribute;
attribute.type = type;
attribute.dictionaryAttribute = QByteArrayList(qMove(attributeName));
attribute.dictionaryAttribute = attributes;
attribute.category = qMove(category);
attribute.subcategory = qMove(subcategory);
attribute.name = qMove(name);
@ -162,14 +181,14 @@ size_t PDFObjectEditorAbstractModel::createAttribute(ObjectEditorAttributeType t
size_t PDFObjectEditorAbstractModel::createSelectorAttribute(QString category, QString subcategory, QString name)
{
return createAttribute(ObjectEditorAttributeType::Selector, QString(), qMove(category), qMove(subcategory), qMove(name));
return createAttribute(ObjectEditorAttributeType::Selector, QByteArray(), qMove(category), qMove(subcategory), qMove(name));
}
uint32_t PDFObjectEditorAbstractModel::getCurrentTypeFlags() const
{
PDFObject value = getValue(m_typeAttribute);
for (const PDFObjectEditorModelAttributeEnumItem& item : m_attributes.at(index).enumItems)
for (const PDFObjectEditorModelAttributeEnumItem& item : m_attributes.at(m_typeAttribute).enumItems)
{
if (item.value == value)
{

View File

@ -103,6 +103,9 @@ struct PDFObjectEditorModelAttribute
/// Enum items
PDFObjectEditorModelAttributeEnumItems enumItems;
/// Value for selector attribute
bool selectorAttributeValue = false;
};
class PDFFORQTLIBSHARED_EXPORT PDFObjectEditorAbstractModel : public QObject
@ -117,9 +120,11 @@ public:
virtual ~PDFObjectEditorAbstractModel();
size_t getAttributeCount() const;
ObjectEditorAttributeType getAttributeType(size_t index) const;
const QString& getAttributeCategory(size_t index) const;
const QString& getAttributeSubcategory(size_t index) const;
const QString& getAttributeName(size_t index) const;
const PDFObjectEditorModelAttributeEnumItems& getAttributeEnumItems(size_t index) const;
enum class Question
{
@ -134,6 +139,8 @@ public:
PDFObject getValue(size_t index) const;
PDFObject getDefaultValue(size_t index) const;
const PDFObjectStorage* getStorage() const { return m_storage; }
protected:
size_t createAttribute(ObjectEditorAttributeType type,
QByteArray attributeName,

View File

@ -16,30 +16,23 @@
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#include "pdfobjecteditorwidget.h"
#include "pdfobjecteditorwidget_impl.h"
#include "pdfdocumentbuilder.h"
#include <QTabWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QSpacerItem>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QTextBrowser>
#include <QPushButton>
namespace pdf
{
class PDFObjectEditorWidgetMapper : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
explicit PDFObjectEditorWidgetMapper(PDFObjectEditorAbstractModel* model, QObject* parent);
void initialize();
private:
PDFObjectEditorAbstractModel* m_model;
};
PDFObjectEditorWidget::PDFObjectEditorWidget(PDFObjectEditorAbstractModel* model, QWidget* parent) :
BaseClass(parent),
m_mapper(nullptr),
@ -50,6 +43,7 @@ PDFObjectEditorWidget::PDFObjectEditorWidget(PDFObjectEditorAbstractModel* model
layout->addWidget(m_tabWidget);
m_mapper = new PDFObjectEditorWidgetMapper(model, this);
m_mapper->initialize(m_tabWidget);
}
PDFObjectEditorWidgetMapper::PDFObjectEditorWidgetMapper(PDFObjectEditorAbstractModel* model, QObject* parent) :
@ -59,10 +53,303 @@ PDFObjectEditorWidgetMapper::PDFObjectEditorWidgetMapper(PDFObjectEditorAbstract
}
void PDFObjectEditorWidgetMapper::initialize()
void PDFObjectEditorWidgetMapper::initialize(QTabWidget* tabWidget)
{
size_t attributeCount = m_model->getAttributeCount();
for (size_t i = 0; i < attributeCount; ++i)
{
// Unmapped attributes are ignored
if (!m_model->queryAttribute(i, PDFObjectEditorAbstractModel::Question::IsMapped))
{
continue;
}
QString categoryName = m_model->getAttributeCategory(i);
QString subcategoryName = m_model->getAttributeSubcategory(i);
Category* category = getOrCreateCategory(categoryName);
Subcategory* subcategory = category->getOrCreateSubcategory(subcategoryName);
subcategory->attributes.push_back(i);
}
// Create GUI
for (Category& category : m_categories)
{
category.page = new QWidget(tabWidget);
tabWidget->addTab(category.page, category.name);
category.page->setLayout(new QVBoxLayout());
// Create subcategory GUI
for (Subcategory& subcategory : category.subcategories)
{
QGroupBox* groupBox = new QGroupBox(category.page);
category.page->layout()->addWidget(groupBox);
QGridLayout* layout = new QGridLayout();
groupBox->setLayout(layout);
for (size_t attribute : subcategory.attributes)
{
createMappedAdapter(groupBox, layout, attribute);
}
}
category.page->layout()->addItem(new QSpacerItem(0, 0));
}
}
void PDFObjectEditorWidgetMapper::createMappedAdapter(QGroupBox* groupBox, QGridLayout* layout, size_t attribute)
{
auto setAdapter = [this, attribute](PDFObjectEditorMappedWidgetAdapter* adapter)
{
Q_ASSERT(!m_adapters.count(attribute));
m_adapters[attribute] = adapter;
};
ObjectEditorAttributeType type = m_model->getAttributeType(attribute);
switch (type)
{
case ObjectEditorAttributeType::Type:
case ObjectEditorAttributeType::ComboBox:
{
int row = layout->rowCount();
QLabel* label = new QLabel(groupBox);
QComboBox* comboBox = new QComboBox(groupBox);
layout->addWidget(label, row, 0);
layout->addWidget(comboBox, row, 1);
setAdapter(new PDFObjectEditorMappedComboBoxAdapter(label, comboBox, m_model, attribute, this));
break;
}
case ObjectEditorAttributeType::TextLine:
{
int row = layout->rowCount();
QLabel* label = new QLabel(groupBox);
QLineEdit* lineEdit = new QLineEdit(groupBox);
layout->addWidget(label, row, 0);
layout->addWidget(lineEdit, row, 1);
setAdapter(new PDFObjectEditorMappedLineEditAdapter(label, lineEdit, m_model, attribute, this));
break;
}
case ObjectEditorAttributeType::TextBrowser:
{
int row = layout->rowCount();
QLabel* label = new QLabel(groupBox);
QTextBrowser* textBrowser = new QTextBrowser(groupBox);
layout->addWidget(label, row, 0, 1, -1);
layout->addWidget(textBrowser, row + 1, 0, 1, -1);
setAdapter(new PDFObjectEditorMappedTextBrowserAdapter(label, textBrowser, m_model, attribute, this));
break;
}
case ObjectEditorAttributeType::Rectangle:
{
int row = layout->rowCount();
QLabel* label = new QLabel(groupBox);
QPushButton* pushButton = new QPushButton(groupBox);
pushButton->setFlat(true);
layout->addWidget(label, row, 0);
layout->addWidget(pushButton, row, 1);
setAdapter(new PDFObjectEditorMappedRectangleAdapter(label, pushButton, m_model, attribute, this));
break;
}
default:
Q_ASSERT(false);
}
x
/*
DateTime, ///< Date/time
Flags, ///< Flags
Selector, ///< Selector attribute, it is not persisted
Color, ///< Color
Boolean, ///< Check box*/
}
PDFObjectEditorWidgetMapper::Category* PDFObjectEditorWidgetMapper::getOrCreateCategory(QString categoryName)
{
auto categoryIt = std::find_if(m_categories.begin(), m_categories.end(), [&categoryName](const auto& category) { return category.name == categoryName; });
if (categoryIt != m_categories.end())
{
return &*categoryIt;
}
Category category;
category.name = qMove(categoryName);
m_categories.emplace_back(qMove(category));
return &m_categories.back();
}
PDFObjectEditorWidgetMapper::Subcategory* PDFObjectEditorWidgetMapper::Category::getOrCreateSubcategory(QString subcategoryName)
{
auto subcategoryIt = std::find_if(subcategories.begin(), subcategories.end(), [&subcategoryName](const auto& subcategory) { return subcategory.name == subcategoryName; });
if (subcategoryIt != subcategories.end())
{
return &*subcategoryIt;
}
Subcategory subcategory;
subcategory.name = qMove(subcategoryName);
subcategories.emplace_back(qMove(subcategory));
return &subcategories.back();
}
PDFObjectEditorMappedWidgetAdapter::PDFObjectEditorMappedWidgetAdapter(PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent) :
BaseClass(parent),
m_model(model),
m_attribute(attribute)
{
}
void PDFObjectEditorMappedWidgetAdapter::initLabel(QLabel* label)
{
label->setText(m_model->getAttributeName(m_attribute));
}
PDFObjectEditorMappedComboBoxAdapter::PDFObjectEditorMappedComboBoxAdapter(QLabel* label,
QComboBox* comboBox,
PDFObjectEditorAbstractModel* model,
size_t attribute,
QObject* parent) :
BaseClass(model, attribute, parent),
m_label(label),
m_comboBox(comboBox)
{
initLabel(label);
comboBox->clear();
for (const PDFObjectEditorModelAttributeEnumItem& item : m_model->getAttributeEnumItems(attribute))
{
comboBox->addItem(item.name, item.flags);
}
connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this, attribute](){ emit commitRequested(attribute); });
}
PDFObject PDFObjectEditorMappedComboBoxAdapter::getValue() const
{
QVariant currentData = m_comboBox->currentData();
if (!currentData.isValid())
{
return PDFObject();
}
const uint32_t flags = currentData.toUInt();
for (const PDFObjectEditorModelAttributeEnumItem& item : m_model->getAttributeEnumItems(m_attribute))
{
if (item.flags == flags)
{
return item.value;
}
}
return PDFObject();
}
void PDFObjectEditorMappedComboBoxAdapter::setValue(PDFObject object)
{
for (const PDFObjectEditorModelAttributeEnumItem& item : m_model->getAttributeEnumItems(m_attribute))
{
if (item.value == object)
{
m_comboBox->setCurrentIndex(m_comboBox->findData(int(item.flags)));
return;
}
}
m_comboBox->setCurrentIndex(-1);
}
PDFObjectEditorMappedLineEditAdapter::PDFObjectEditorMappedLineEditAdapter(QLabel* label,
QLineEdit* lineEdit,
PDFObjectEditorAbstractModel* model,
size_t attribute,
QObject* parent) :
BaseClass(model, attribute, parent),
m_label(label),
m_lineEdit(lineEdit)
{
initLabel(label);
lineEdit->setClearButtonEnabled(true);
connect(lineEdit, &QLineEdit::editingFinished, this, [this, attribute](){ emit commitRequested(attribute); });
}
PDFObject PDFObjectEditorMappedLineEditAdapter::getValue() const
{
PDFObjectFactory factory;
factory << m_lineEdit->text();
return factory.takeObject();
}
void PDFObjectEditorMappedLineEditAdapter::setValue(PDFObject object)
{
PDFDocumentDataLoaderDecorator loader(m_model->getStorage());
m_lineEdit->setText(loader.readTextString(object, QString()));
}
PDFObjectEditorMappedTextBrowserAdapter::PDFObjectEditorMappedTextBrowserAdapter(QLabel* label,
QTextBrowser* textBrowser,
PDFObjectEditorAbstractModel* model,
size_t attribute,
QObject* parent) :
BaseClass(model, attribute, parent),
m_label(label),
m_textBrowser(textBrowser)
{
initLabel(label);
textBrowser->setUndoRedoEnabled(true);
textBrowser->setTextInteractionFlags(Qt::TextEditorInteraction);
connect(textBrowser, &QTextBrowser::textChanged, this, [this, attribute](){ emit commitRequested(attribute); });
}
PDFObject PDFObjectEditorMappedTextBrowserAdapter::getValue() const
{
PDFObjectFactory factory;
factory << m_textBrowser->toPlainText();
return factory.takeObject();
}
void PDFObjectEditorMappedTextBrowserAdapter::setValue(PDFObject object)
{
PDFDocumentDataLoaderDecorator loader(m_model->getStorage());
m_textBrowser->setText(loader.readTextString(object, QString()));
}
PDFObjectEditorMappedRectangleAdapter::PDFObjectEditorMappedRectangleAdapter(QLabel* label,
QPushButton* pushButton,
PDFObjectEditorAbstractModel* model,
size_t attribute,
QObject* parent):
BaseClass(model, attribute, parent),
m_label(label),
m_pushButton(pushButton)
{
initLabel(label);
}
PDFObject PDFObjectEditorMappedRectangleAdapter::getValue() const
{
return m_rectangle;
}
void PDFObjectEditorMappedRectangleAdapter::setValue(PDFObject object)
{
m_rectangle = qMove(object);
}
} // namespace pdf

View File

@ -0,0 +1,173 @@
// Copyright (C) 2020 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PdfForQt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFOBJECTEDITORWIDGET_IMPL_H
#define PDFOBJECTEDITORWIDGET_IMPL_H
#include "pdfobjecteditormodel.h"
class QLabel;
class QGroupBox;
class QComboBox;
class QTabWidget;
class QGridLayout;
class QLineEdit;
class QTextBrowser;
class QPushButton;
namespace pdf
{
class PDFObjectEditorMappedWidgetAdapter : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
explicit PDFObjectEditorMappedWidgetAdapter(PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
/// Returns PDFObject value currently present in the widget
virtual PDFObject getValue() const = 0;
/// Sets PDFObject value to the widget. If data are incompatible,
/// then no data are set to the widget.
virtual void setValue(PDFObject object) = 0;
signals:
void commitRequested(size_t attribute);
protected:
// Initializes label text with attributes name
void initLabel(QLabel* label);
PDFObjectEditorAbstractModel* m_model;
size_t m_attribute;
};
class PDFObjectEditorMappedComboBoxAdapter : public PDFObjectEditorMappedWidgetAdapter
{
Q_OBJECT
private:
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
public:
explicit PDFObjectEditorMappedComboBoxAdapter(QLabel* label, QComboBox* comboBox, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
virtual PDFObject getValue() const override;
virtual void setValue(PDFObject object) override;
private:
QLabel* m_label;
QComboBox* m_comboBox;
};
class PDFObjectEditorMappedLineEditAdapter : public PDFObjectEditorMappedWidgetAdapter
{
Q_OBJECT
private:
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
public:
explicit PDFObjectEditorMappedLineEditAdapter(QLabel* label, QLineEdit* lineEdit, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
virtual PDFObject getValue() const override;
virtual void setValue(PDFObject object) override;
private:
QLabel* m_label;
QLineEdit* m_lineEdit;
};
class PDFObjectEditorMappedTextBrowserAdapter : public PDFObjectEditorMappedWidgetAdapter
{
Q_OBJECT
private:
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
public:
explicit PDFObjectEditorMappedTextBrowserAdapter(QLabel* label, QTextBrowser* textBrowser, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
virtual PDFObject getValue() const override;
virtual void setValue(PDFObject object) override;
private:
QLabel* m_label;
QTextBrowser* m_textBrowser;
};
class PDFObjectEditorWidgetMapper : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
explicit PDFObjectEditorWidgetMapper(PDFObjectEditorAbstractModel* model, QObject* parent);
void initialize(QTabWidget* tabWidget);
private:
struct Subcategory
{
QString name;
std::vector<size_t> attributes;
};
struct Category
{
QString name;
std::vector<Subcategory> subcategories;
QWidget* page = nullptr;
Subcategory* getOrCreateSubcategory(QString name);
};
void createMappedAdapter(QGroupBox* groupBox, QGridLayout* layout, size_t attribute);
Category* getOrCreateCategory(QString categoryName);
PDFObjectEditorAbstractModel* m_model;
std::vector<Category> m_categories;
std::map<size_t, PDFObjectEditorMappedWidgetAdapter*> m_adapters;
};
class PDFObjectEditorMappedRectangleAdapter : public PDFObjectEditorMappedWidgetAdapter
{
Q_OBJECT
private:
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
public:
explicit PDFObjectEditorMappedRectangleAdapter(QLabel* label, QPushButton* pushButton, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
virtual PDFObject getValue() const override;
virtual void setValue(PDFObject object) override;
private:
QLabel* m_label;
QPushButton* m_pushButton;
PDFObject m_rectangle;
};
} // namespace pdf
#endif // PDFOBJECTEDITORWIDGET_IMPL_H