diff --git a/Pdf4QtLib/sources/pdfdocument.h b/Pdf4QtLib/sources/pdfdocument.h index 26edce1..4572c5a 100644 --- a/Pdf4QtLib/sources/pdfdocument.h +++ b/Pdf4QtLib/sources/pdfdocument.h @@ -38,7 +38,7 @@ class PDFDocumentBuilder; /// Storage for objects. This class is not thread safe for writing (calling non-const functions). Caller must ensure /// locking, if this object is used from multiple threads. Calling const functions should be thread safe. -class PDFObjectStorage +class Pdf4QtLIBSHARED_EXPORT PDFObjectStorage { public: inline PDFObjectStorage() = default; diff --git a/Pdf4QtLib/sources/pdfitemmodels.h b/Pdf4QtLib/sources/pdfitemmodels.h index 73f62c0..4e06a3e 100644 --- a/Pdf4QtLib/sources/pdfitemmodels.h +++ b/Pdf4QtLib/sources/pdfitemmodels.h @@ -36,7 +36,7 @@ class PDFOptionalContentActivity; class PDFDrawWidgetProxy; /// Represents tree item in the GUI tree -class PDFTreeItem +class Pdf4QtLIBSHARED_EXPORT PDFTreeItem { public: inline explicit PDFTreeItem() = default; @@ -60,6 +60,7 @@ public: int getRow() const { return m_parent->m_children.indexOf(const_cast(this)); } int getChildCount() const { return m_children.size(); } const PDFTreeItem* getChild(int index) const { return m_children.at(index); } + PDFTreeItem* getChild(int index) { return m_children.at(index); } const PDFTreeItem* getParent() const { return m_parent; } private: diff --git a/Pdf4QtLib/sources/pdfobject.h b/Pdf4QtLib/sources/pdfobject.h index 7b031e5..13cb377 100644 --- a/Pdf4QtLib/sources/pdfobject.h +++ b/Pdf4QtLib/sources/pdfobject.h @@ -307,7 +307,7 @@ private: }; /// Represents an array of objects in the PDF file. -class PDFArray : public PDFObjectContent +class Pdf4QtLIBSHARED_EXPORT PDFArray : public PDFObjectContent { public: inline PDFArray() = default; @@ -460,7 +460,7 @@ private: /// Represents a stream object in the PDF file. Stream consists of dictionary /// and stream content - byte array. -class PDFStream : public PDFObjectContent +class Pdf4QtLIBSHARED_EXPORT PDFStream : public PDFObjectContent { public: inline explicit PDFStream() = default; diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/ObjectInspectorPlugin.json b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/ObjectInspectorPlugin.json new file mode 100644 index 0000000..efe00cb --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/ObjectInspectorPlugin.json @@ -0,0 +1,7 @@ +{ + "Name" : "ObjectInspector", + "Author" : "Jakub Melka", + "Version" : "1.0.0", + "License" : "LGPL v3", + "Description" : "Explore internal structure of a document. View decompressed streams and images. Modify objects directly." +} diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/ObjectInspectorPlugin.pro b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/ObjectInspectorPlugin.pro new file mode 100644 index 0000000..9b5f225 --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/ObjectInspectorPlugin.pro @@ -0,0 +1,54 @@ +# Copyright (C) 2021 Jakub Melka +# +# This file is part of Pdf4Qt. +# +# Pdf4Qt 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 +# with the written consent of the copyright owner, any later version. +# +# Pdf4Qt 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 Pdf4Qt. If not, see . + +TEMPLATE = lib +DEFINES += OBJECTINSPECTORPLUGIN_LIBRARY + +QT += gui widgets + +LIBS += -L$$OUT_PWD/../.. + +LIBS += -lPdf4QtLib + +QMAKE_CXXFLAGS += /std:c++latest /utf-8 + +INCLUDEPATH += $$PWD/../../Pdf4QtLib/Sources + +DESTDIR = $$OUT_PWD/../../pdfplugins + +CONFIG += c++11 + +SOURCES += \ + objectinspectordialog.cpp \ + objectinspectorplugin.cpp \ + pdfobjectinspectortreeitemmodel.cpp + +HEADERS += \ + objectinspectordialog.h \ + objectinspectorplugin.h \ + pdfobjectinspectortreeitemmodel.h + +CONFIG += force_debug_info + +DISTFILES += \ + ObjectInspectorPlugin.json + +RESOURCES += \ + icons.qrc + +FORMS += \ + objectinspectordialog.ui diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/icons.qrc b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/icons.qrc new file mode 100644 index 0000000..84b825c --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/icons.qrc @@ -0,0 +1,5 @@ + + + object-inspector.svg + + diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/object-inspector.svg b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/object-inspector.svg new file mode 100644 index 0000000..9285e7d --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/object-inspector.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + image/svg+xml + + + + + + Jakub Melka + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.cpp b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.cpp new file mode 100644 index 0000000..4746e42 --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2021 Jakub Melka +// +// This file is part of Pdf4Qt. +// +// Pdf4Qt 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 +// with the written consent of the copyright owner, any later version. +// +// Pdf4Qt 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 Pdf4Qt. If not, see . + +#include "objectinspectordialog.h" +#include "ui_objectinspectordialog.h" + +#include "pdfwidgetutils.h" +#include "pdfobjectinspectortreeitemmodel.h" + +#include + +namespace pdfplugin +{ + +ObjectInspectorDialog::ObjectInspectorDialog(const pdf::PDFDocument* document, QWidget* parent) : + QDialog(parent, Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint), + ui(new Ui::ObjectInspectorDialog), + m_document(document), + m_model(nullptr) +{ + ui->setupUi(this); + + ui->modeComboBox->addItem(tr("Document"), int(PDFObjectInspectorTreeItemModel::Document)); + ui->modeComboBox->addItem(tr("Pages"), int(PDFObjectInspectorTreeItemModel::Page)); + ui->modeComboBox->addItem(tr("Images"), int(PDFObjectInspectorTreeItemModel::Image)); + ui->modeComboBox->addItem(tr("Object List"), int(PDFObjectInspectorTreeItemModel::List)); + + ui->modeComboBox->setCurrentIndex(ui->modeComboBox->findData(int(PDFObjectInspectorTreeItemModel::Document))); + connect(ui->modeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &ObjectInspectorDialog::onModeChanged); + + m_model = new PDFObjectInspectorTreeItemModel(this); + onModeChanged(); + m_model->setDocument(pdf::PDFModifiedDocument(const_cast(document), nullptr, pdf::PDFModifiedDocument::Reset)); + + ui->objectTreeView->setRootIsDecorated(true); + ui->objectTreeView->setModel(m_model); + + QSplitter* splitter = new QSplitter(this); + splitter->addWidget(ui->objectTreeView); + splitter->addWidget(ui->tabWidget); + + ui->objectTreeView->setMinimumWidth(pdf::PDFWidgetUtils::scaleDPI_x(this, 200)); + setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600))); +} + +ObjectInspectorDialog::~ObjectInspectorDialog() +{ + delete ui; +} + +void ObjectInspectorDialog::onModeChanged() +{ + const PDFObjectInspectorTreeItemModel::Mode mode = static_cast(ui->modeComboBox->currentData().toInt()); + m_model->setMode(mode); +} + +} // namespace pdfplugin diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.h b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.h new file mode 100644 index 0000000..46d15cb --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.h @@ -0,0 +1,52 @@ +// Copyright (C) 2021 Jakub Melka +// +// This file is part of Pdf4Qt. +// +// Pdf4Qt 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 +// with the written consent of the copyright owner, any later version. +// +// Pdf4Qt 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 Pdf4Qt. If not, see . + +#ifndef OBJECTINSPECTORDIALOG_H +#define OBJECTINSPECTORDIALOG_H + +#include "pdfdocument.h" + +#include + +namespace Ui +{ +class ObjectInspectorDialog; +} + +namespace pdfplugin +{ +class PDFObjectInspectorTreeItemModel; + +class ObjectInspectorDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ObjectInspectorDialog(const pdf::PDFDocument* document, QWidget* parent); + virtual ~ObjectInspectorDialog() override; + +private: + void onModeChanged(); + + Ui::ObjectInspectorDialog* ui; + const pdf::PDFDocument* m_document; + PDFObjectInspectorTreeItemModel* m_model; +}; + +} // namespace pdfplugin + +#endif // OBJECTINSPECTORDIALOG_H diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.ui b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.ui new file mode 100644 index 0000000..a37e907 --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectordialog.ui @@ -0,0 +1,88 @@ + + + ObjectInspectorDialog + + + + 0 + 0 + 742 + 666 + + + + Object Inspector + + + + + + false + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + Tab 1 + + + + + Tab 2 + + + + + + + + + + buttonBox + accepted() + ObjectInspectorDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ObjectInspectorDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectorplugin.cpp b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectorplugin.cpp new file mode 100644 index 0000000..5f9c120 --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectorplugin.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2021 Jakub Melka +// +// This file is part of Pdf4Qt. +// +// Pdf4Qt 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 +// with the written consent of the copyright owner, any later version. +// +// Pdf4Qt 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 Pdf4Qt. If not, see . + +#include "objectinspectorplugin.h" + +#include "pdfcms.h" +#include "pdfutils.h" +#include "pdfdrawwidget.h" + +#include "objectinspectordialog.h" + +#include + +namespace pdfplugin +{ + +ObjectInspectorPlugin::ObjectInspectorPlugin() : + pdf::PDFPlugin(nullptr), + m_objectInspectorAction(nullptr) +{ + +} + +void ObjectInspectorPlugin::setWidget(pdf::PDFWidget* widget) +{ + Q_ASSERT(!m_widget); + + BaseClass::setWidget(widget); + + m_objectInspectorAction = new QAction(QIcon(":/pdfplugins/objectinspector/object-inspector.svg"), tr("Object Inspector"), this); + m_objectInspectorAction->setCheckable(false); + m_objectInspectorAction->setObjectName("actionObjectInspector_ObjectInspector"); + + connect(m_objectInspectorAction, &QAction::triggered, this, &ObjectInspectorPlugin::onObjectInspectorTriggered); + + updateActions(); +} + +void ObjectInspectorPlugin::setCMSManager(pdf::PDFCMSManager* manager) +{ + BaseClass::setCMSManager(manager); +} + +void ObjectInspectorPlugin::setDocument(const pdf::PDFModifiedDocument& document) +{ + BaseClass::setDocument(document); + + if (document.hasReset()) + { + updateActions(); + } +} + +std::vector ObjectInspectorPlugin::getActions() const +{ + return { m_objectInspectorAction }; +} + +void ObjectInspectorPlugin::onObjectInspectorTriggered() +{ + ObjectInspectorDialog dialog(m_document, m_widget); + dialog.exec(); +} + +void ObjectInspectorPlugin::updateActions() +{ + m_objectInspectorAction->setEnabled(m_widget && m_document); +} + +} diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectorplugin.h b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectorplugin.h new file mode 100644 index 0000000..da60da9 --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/objectinspectorplugin.h @@ -0,0 +1,54 @@ +// Copyright (C) 2021 Jakub Melka +// +// This file is part of Pdf4Qt. +// +// Pdf4Qt 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 +// with the written consent of the copyright owner, any later version. +// +// Pdf4Qt 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 Pdf4Qt. If not, see . + +#ifndef OBJECTINSPECTORPLUGIN_H +#define OBJECTINSPECTORPLUGIN_H + +#include "pdfplugin.h" + +#include + +namespace pdfplugin +{ + +class ObjectInspectorPlugin : public pdf::PDFPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "Pdf4Qt.ObjectInspectorPlugin" FILE "ObjectInspectorPlugin.json") + +private: + using BaseClass = pdf::PDFPlugin; + +public: + ObjectInspectorPlugin(); + + virtual void setWidget(pdf::PDFWidget* widget) override; + virtual void setCMSManager(pdf::PDFCMSManager* manager) override; + virtual void setDocument(const pdf::PDFModifiedDocument& document) override; + virtual std::vector getActions() const override; + +private: + void onObjectInspectorTriggered(); + + void updateActions(); + + QAction* m_objectInspectorAction; +}; + +} // namespace pdfplugin + +#endif // OBJECTINSPECTORPLUGIN_H diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/pdfobjectinspectortreeitemmodel.cpp b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/pdfobjectinspectortreeitemmodel.cpp new file mode 100644 index 0000000..c3429da --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/pdfobjectinspectortreeitemmodel.cpp @@ -0,0 +1,425 @@ +// Copyright (C) 2021 Jakub Melka +// +// This file is part of Pdf4Qt. +// +// Pdf4Qt 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 +// with the written consent of the copyright owner, any later version. +// +// Pdf4Qt 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 Pdf4Qt. If not, see . + +#include "pdfobjectinspectortreeitemmodel.h" +#include "pdfdocument.h" +#include "pdfvisitor.h" + +#include + +#include + +namespace pdfplugin +{ + +class PDFObjectInspectorTreeItem : public pdf::PDFTreeItem +{ +public: + + inline explicit PDFObjectInspectorTreeItem() = default; + inline explicit PDFObjectInspectorTreeItem(PDFObjectInspectorTreeItem* parent) : pdf::PDFTreeItem(parent) { } + inline explicit PDFObjectInspectorTreeItem(pdf::PDFObject object, PDFObjectInspectorTreeItem* parent) : pdf::PDFTreeItem(parent), m_object(std::move(object)) { } + inline explicit PDFObjectInspectorTreeItem(QByteArray dictionaryKey, pdf::PDFObject object, PDFObjectInspectorTreeItem* parent) : pdf::PDFTreeItem(parent), m_dictionaryKey(std::move(dictionaryKey)), m_object(std::move(object)) { } + inline explicit PDFObjectInspectorTreeItem(pdf::PDFObjectReference reference, pdf::PDFObject object, PDFObjectInspectorTreeItem* parent) : pdf::PDFTreeItem(parent), m_reference(std::move(reference)), m_object(std::move(object)) { } + + virtual ~PDFObjectInspectorTreeItem() override { } + + + QByteArray getDictionaryKey() const; + void setDictionaryKey(const QByteArray& dictionaryKey); + + pdf::PDFObjectReference getReference() const; + void setReference(const pdf::PDFObjectReference& reference); + + const pdf::PDFObject& getObject() const; + void setObject(const pdf::PDFObject& object); + +private: + QByteArray m_dictionaryKey; + pdf::PDFObjectReference m_reference; + pdf::PDFObject m_object; +}; + +QByteArray PDFObjectInspectorTreeItem::getDictionaryKey() const +{ + return m_dictionaryKey; +} + +void PDFObjectInspectorTreeItem::setDictionaryKey(const QByteArray& dictionaryKey) +{ + m_dictionaryKey = dictionaryKey; +} + +pdf::PDFObjectReference PDFObjectInspectorTreeItem::getReference() const +{ + return m_reference; +} + +void PDFObjectInspectorTreeItem::setReference(const pdf::PDFObjectReference& reference) +{ + m_reference = reference; +} + +const pdf::PDFObject& PDFObjectInspectorTreeItem::getObject() const +{ + return m_object; +} + +void PDFObjectInspectorTreeItem::setObject(const pdf::PDFObject& object) +{ + m_object = object; +} + +PDFObjectInspectorTreeItemModel::PDFObjectInspectorTreeItemModel(QObject* parent) : + pdf::PDFTreeItemModel(parent) +{ +} + +QVariant PDFObjectInspectorTreeItemModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + Q_UNUSED(section); + Q_UNUSED(orientation); + Q_UNUSED(role); + + return QVariant(); +} + +int PDFObjectInspectorTreeItemModel::columnCount(const QModelIndex& parent) const +{ + return 1; +} + +QVariant PDFObjectInspectorTreeItemModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + if (role != Qt::DisplayRole) + { + return QVariant(); + } + + const PDFObjectInspectorTreeItem* item = static_cast(index.internalPointer()); + const PDFObjectInspectorTreeItem* parent = static_cast(index.parent().internalPointer()); + + QStringList data; + if (item->getReference().isValid() && parent && !parent->getReference().isValid()) + { + data << QString("%1 %2 R").arg(item->getReference().objectNumber).arg(item->getReference().generation); + } + + QByteArray dictionaryKey = item->getDictionaryKey(); + if (!dictionaryKey.isEmpty()) + { + data << QString("/%1").arg(QString::fromLatin1(dictionaryKey.toPercentEncoding())); + } + + QLocale locale; + + const pdf::PDFObject& object = item->getObject(); + switch (object.getType()) + { + case pdf::PDFObject::Type::Null: + data << tr("null"); + break; + + case pdf::PDFObject::Type::Bool: + data << (object.getBool() ? tr("true") : tr("false")); + break; + + case pdf::PDFObject::Type::Int: + data << locale.toString(object.getInteger()); + break; + + case pdf::PDFObject::Type::Real: + data << locale.toString(object.getReal()); + break; + + case pdf::PDFObject::Type::String: + data << QString("\"%1\"").arg(QString::fromLatin1(object.getString().toPercentEncoding())); + break; + + case pdf::PDFObject::Type::Name: + data << QString("/%1").arg(QString::fromLatin1(object.getString().toPercentEncoding())); + break; + + case pdf::PDFObject::Type::Array: + data << tr("Array [%1 items]").arg(locale.toString(object.getArray()->getCount())); + break; + + case pdf::PDFObject::Type::Dictionary: + data << tr("Dictionary [%1 items]").arg(locale.toString(object.getDictionary()->getCount())); + break; + + case pdf::PDFObject::Type::Stream: + data << tr("Stream [%1 items, %2 data bytes]").arg(locale.toString(object.getStream()->getDictionary()->getCount())).arg(locale.toString(object.getStream()->getContent()->size())); + break; + + case pdf::PDFObject::Type::Reference: + data << QString("%1 %2 R").arg(object.getReference().objectNumber).arg(object.getReference().generation); + break; + + default: + Q_ASSERT(false); + break; + } + + return data.join(" "); +} + +void PDFObjectInspectorTreeItemModel::update() +{ + beginResetModel(); + + m_rootItem.reset(); + + if (m_document) + { + std::set usedReferences; + + switch (m_mode) + { + case pdfplugin::PDFObjectInspectorTreeItemModel::Document: + { + m_rootItem.reset(new PDFObjectInspectorTreeItem()); + const pdf::PDFObjectStorage& storage = m_document->getStorage(); + createObjectItem(getRootItem(), pdf::PDFObjectReference(), storage.getTrailerDictionary(), true, usedReferences); + break; + } + + case pdfplugin::PDFObjectInspectorTreeItemModel::Page: + { + m_rootItem.reset(new PDFObjectInspectorTreeItem()); + + const size_t pageCount = m_document->getCatalog()->getPageCount(); + for (size_t i = 0; i < pageCount; ++i) + { + if (const pdf::PDFPage* page = m_document->getCatalog()->getPage(i)) + { + pdf::PDFObjectReference reference = page->getPageReference(); + pdf::PDFObject object = m_document->getStorage().getObjectByReference(reference); + createObjectItem(getRootItem(), reference, object, true, usedReferences); + } + } + + break; + } + + case pdfplugin::PDFObjectInspectorTreeItemModel::Image: + break; + + case pdfplugin::PDFObjectInspectorTreeItemModel::List: + { + m_rootItem.reset(new PDFObjectInspectorTreeItem()); + + const pdf::PDFObjectStorage& storage = m_document->getStorage(); + createObjectItem(getRootItem(), pdf::PDFObjectReference(), storage.getTrailerDictionary(), false, usedReferences); + const pdf::PDFObjectStorage::PDFObjects& objects = storage.getObjects(); + for (size_t i = 0; i < objects.size(); ++i) + { + pdf::PDFObjectReference reference(i, objects[i].generation); + pdf::PDFObject object = objects[i].object; + + if (object.isNull()) + { + // We skip null objects + continue; + } + + createObjectItem(getRootItem(), reference, object, false, usedReferences); + } + + break; + } + + default: + Q_ASSERT(false); + break; + } + } + + endResetModel(); +} + +void PDFObjectInspectorTreeItemModel::setMode(Mode mode) +{ + if (m_mode != mode) + { + m_mode = mode; + update(); + } +} + +class PDFCreateObjectInspectorTreeItemFromObjectVisitor : public pdf::PDFAbstractVisitor +{ +public: + explicit PDFCreateObjectInspectorTreeItemFromObjectVisitor(std::set* usedReferences, + const pdf::PDFDocument* document, + bool followReferences, + pdf::PDFObjectReference reference, + PDFObjectInspectorTreeItem* parent) : + m_usedReferences(usedReferences), + m_document(document), + m_followReferences(followReferences), + m_reference(reference) + { + m_parents.push(parent); + } + + virtual ~PDFCreateObjectInspectorTreeItemFromObjectVisitor() override + { + m_parents.pop(); + Q_ASSERT(m_parents.empty()); + } + + virtual void visitNull() override; + virtual void visitBool(bool value) override; + virtual void visitInt(pdf::PDFInteger value) override; + virtual void visitReal(pdf::PDFReal value) override; + virtual void visitString(pdf::PDFStringRef string) override; + virtual void visitName(pdf::PDFStringRef name) override; + virtual void visitArray(const pdf::PDFArray* array) override; + virtual void visitDictionary(const pdf::PDFDictionary* dictionary) override; + virtual void visitStream(const pdf::PDFStream* stream) override; + virtual void visitReference(const pdf::PDFObjectReference reference) override; + +private: + std::set* m_usedReferences; + const pdf::PDFDocument* m_document; + bool m_followReferences; + pdf::PDFObjectReference m_reference; + std::stack m_parents; +}; + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitNull() +{ + m_parents.top()->addCreatedChild(new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createNull(), m_parents.top())); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitBool(bool value) +{ + m_parents.top()->addCreatedChild(new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createBool(value), m_parents.top())); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitInt(pdf::PDFInteger value) +{ + m_parents.top()->addCreatedChild(new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createInteger(value), m_parents.top())); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitReal(pdf::PDFReal value) +{ + m_parents.top()->addCreatedChild(new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createReal(value), m_parents.top())); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitString(pdf::PDFStringRef string) +{ + m_parents.top()->addCreatedChild(new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createString(string.getString()), m_parents.top())); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitName(pdf::PDFStringRef name) +{ + m_parents.top()->addCreatedChild(new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createName(name), m_parents.top())); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitArray(const pdf::PDFArray* array) +{ + PDFObjectInspectorTreeItem* arrayRoot = new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createArray(std::make_shared(*array)), m_parents.top()); + m_parents.top()->addCreatedChild(arrayRoot); + m_parents.push(arrayRoot); + acceptArray(array); + m_parents.pop(); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitDictionary(const pdf::PDFDictionary* dictionary) +{ + PDFObjectInspectorTreeItem* dictionaryRoot = new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createDictionary(std::make_shared(*dictionary)), m_parents.top()); + m_parents.top()->addCreatedChild(dictionaryRoot); + m_parents.push(dictionaryRoot); + + acceptDictionary(dictionary); + + Q_ASSERT(dictionaryRoot->getChildCount() == dictionary->getCount()); + for (size_t i = 0, count = dictionary->getCount(); i < count; ++i) + { + PDFObjectInspectorTreeItem* child = static_cast(dictionaryRoot->getChild(int(i))); + child->setDictionaryKey(dictionary->getKey(i).getString()); + } + + m_parents.pop(); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitStream(const pdf::PDFStream* stream) +{ + PDFObjectInspectorTreeItem* streamRoot = new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createStream(std::make_shared(*stream)), m_parents.top()); + m_parents.top()->addCreatedChild(streamRoot); + m_parents.push(streamRoot); + + const pdf::PDFDictionary* dictionary = stream->getDictionary(); + acceptDictionary(dictionary); + + Q_ASSERT(streamRoot->getChildCount() == dictionary->getCount()); + for (size_t i = 0, count = dictionary->getCount(); i < count; ++i) + { + PDFObjectInspectorTreeItem* child = static_cast(streamRoot->getChild(int(i))); + child->setDictionaryKey(dictionary->getKey(i).getString()); + } + + m_parents.pop(); +} + +void PDFCreateObjectInspectorTreeItemFromObjectVisitor::visitReference(const pdf::PDFObjectReference reference) +{ + PDFObjectInspectorTreeItem* referenceRoot = new PDFObjectInspectorTreeItem(m_reference, pdf::PDFObject::createReference(reference), m_parents.top()); + m_parents.top()->addCreatedChild(referenceRoot); + + if (m_followReferences && reference.isValid()) + { + Q_ASSERT(m_usedReferences); + + if (!m_usedReferences->count(reference)) + { + // Reference already followed + return; + } + + m_usedReferences->insert(reference); + + m_parents.push(referenceRoot); + const pdf::PDFObject& object = m_document->getObjectByReference(reference); + object.accept(this); + m_parents.pop(); + } +} + +void PDFObjectInspectorTreeItemModel::createObjectItem(PDFObjectInspectorTreeItem* parent, + pdf::PDFObjectReference reference, + pdf::PDFObject object, + bool followRef, + std::set& usedReferences) const +{ + PDFCreateObjectInspectorTreeItemFromObjectVisitor visitor(&usedReferences, m_document, followRef, reference, parent); + object.accept(&visitor); +} + +PDFObjectInspectorTreeItem* PDFObjectInspectorTreeItemModel::getRootItem() +{ + return static_cast(m_rootItem.get()); +} + +} // namespace pdfplugin diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/pdfobjectinspectortreeitemmodel.h b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/pdfobjectinspectortreeitemmodel.h new file mode 100644 index 0000000..383d6d1 --- /dev/null +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/pdfobjectinspectortreeitemmodel.h @@ -0,0 +1,67 @@ +// Copyright (C) 2021 Jakub Melka +// +// This file is part of Pdf4Qt. +// +// Pdf4Qt 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 +// with the written consent of the copyright owner, any later version. +// +// Pdf4Qt 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 Pdf4Qt. If not, see . + +#ifndef PDFOBJECTINSPECTORTREEITEMMODEL_H +#define PDFOBJECTINSPECTORTREEITEMMODEL_H + +#include "pdfitemmodels.h" + +#include + +namespace pdfplugin +{ + +class PDFObjectInspectorTreeItem; + +class PDFObjectInspectorTreeItemModel : public pdf::PDFTreeItemModel +{ + Q_OBJECT + +public: + + enum Mode + { + Document, + Page, + Image, + List + }; + + explicit PDFObjectInspectorTreeItemModel(QObject* parent); + + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant data(const QModelIndex& index, int role) const override; + virtual void update() override; + + void setMode(Mode mode); + +private: + void createObjectItem(PDFObjectInspectorTreeItem* parent, + pdf::PDFObjectReference reference, + pdf::PDFObject object, + bool followRef, + std::set& usedReferences) const; + + PDFObjectInspectorTreeItem* getRootItem(); + + Mode m_mode = List; +}; + +} // namespace pdfplugin + +#endif // PDFOBJECTINSPECTORTREEITEMMODEL_H diff --git a/Pdf4QtViewerPlugins/Pdf4QtViewerPlugins.pro b/Pdf4QtViewerPlugins/Pdf4QtViewerPlugins.pro index 30d37f6..2a14a5c 100644 --- a/Pdf4QtViewerPlugins/Pdf4QtViewerPlugins.pro +++ b/Pdf4QtViewerPlugins/Pdf4QtViewerPlugins.pro @@ -22,6 +22,7 @@ SUBDIRS += \ DimensionsPlugin \ SoftProofingPlugin \ RedactPlugin \ - OutputPreviewPlugin + OutputPreviewPlugin \ + ObjectInspectorPlugin