mirror of https://github.com/JakubMelka/PDF4QT.git
Refactoring - prepare for undo/redo and document modification
This commit is contained in:
parent
76af397b07
commit
57b3711210
|
@ -1185,13 +1185,17 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
|
|||
}
|
||||
}
|
||||
|
||||
void PDFAnnotationManager::setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity)
|
||||
void PDFAnnotationManager::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
m_document = document;
|
||||
m_optionalActivity = optionalContentActivity;
|
||||
m_pageAnnotations.clear();
|
||||
m_optionalActivity = document.getOptionalContentActivity();
|
||||
|
||||
if (document.hasReset() || document.hasFlag(PDFModifiedDocument::Annotation))
|
||||
{
|
||||
m_pageAnnotations.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ class PDFObjectStorage;
|
|||
class PDFDrawWidgetProxy;
|
||||
class PDFFontCache;
|
||||
class PDFFormManager;
|
||||
class PDFModifiedDocument;
|
||||
class PDFOptionalContentActivity;
|
||||
|
||||
using TextAlignment = Qt::Alignment;
|
||||
|
@ -1287,7 +1288,9 @@ public:
|
|||
const QMatrix& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
void setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity);
|
||||
/// Set document
|
||||
/// \param document New document
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
Target getTarget() const;
|
||||
void setTarget(Target target);
|
||||
|
|
|
@ -57,7 +57,7 @@ void PDFAsynchronousPageCompiler::start()
|
|||
}
|
||||
}
|
||||
|
||||
void PDFAsynchronousPageCompiler::stop()
|
||||
void PDFAsynchronousPageCompiler::stop(bool clearCache)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
|
@ -75,7 +75,11 @@ void PDFAsynchronousPageCompiler::stop()
|
|||
taskItem.second.taskWatcher->waitForFinished();
|
||||
}
|
||||
m_tasks.clear();
|
||||
m_cache.clear();
|
||||
|
||||
if (clearCache)
|
||||
{
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
m_state = State::Inactive;
|
||||
break;
|
||||
|
@ -92,7 +96,7 @@ void PDFAsynchronousPageCompiler::stop()
|
|||
|
||||
void PDFAsynchronousPageCompiler::reset()
|
||||
{
|
||||
stop();
|
||||
stop(true);
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -291,7 +295,7 @@ void PDFAsynchronousTextLayoutCompiler::start()
|
|||
}
|
||||
}
|
||||
|
||||
void PDFAsynchronousTextLayoutCompiler::stop()
|
||||
void PDFAsynchronousTextLayoutCompiler::stop(bool clearCache)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
|
@ -303,7 +307,12 @@ void PDFAsynchronousTextLayoutCompiler::stop()
|
|||
// Stop the engine
|
||||
m_state = State::Stopping;
|
||||
m_textLayoutCompileFutureWatcher.waitForFinished();
|
||||
m_textLayouts = std::nullopt;
|
||||
|
||||
if (clearCache)
|
||||
{
|
||||
m_textLayouts = std::nullopt;
|
||||
}
|
||||
|
||||
m_state = State::Inactive;
|
||||
break;
|
||||
}
|
||||
|
@ -319,7 +328,7 @@ void PDFAsynchronousTextLayoutCompiler::stop()
|
|||
|
||||
void PDFAsynchronousTextLayoutCompiler::reset()
|
||||
{
|
||||
stop();
|
||||
stop(true);
|
||||
start();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,13 @@ public:
|
|||
void start();
|
||||
|
||||
/// Stops the engine and all underlying asynchronous tasks. Also
|
||||
/// clears the cache. Call this function only if engine is active.
|
||||
void stop();
|
||||
/// clears the cache if needed. Call this function only if engine is active.
|
||||
/// Cache is cleared only, if \p clearCache parameter is being set to true.
|
||||
/// Set it to false, if "soft" document update occurs (this means change
|
||||
/// to the document, which doesn't modify page content in precompiled
|
||||
/// pages (graphic content / number of pages change).
|
||||
/// \param clearCache Clear cache
|
||||
void stop(bool clearCache);
|
||||
|
||||
/// Resets the engine - calls stop and then calls start.
|
||||
void reset();
|
||||
|
@ -107,8 +112,12 @@ public:
|
|||
void start();
|
||||
|
||||
/// Stops the engine and all underlying asynchronous tasks. Also
|
||||
/// clears the cache. Call this function only if engine is active.
|
||||
void stop();
|
||||
/// clears the cache if parameter \p clearCache. Call this function
|
||||
/// only if engine is active. Clear cache should be set to false,
|
||||
/// only if "soft" document update appears (no text on page is being
|
||||
/// changed).
|
||||
/// \param clearCache Clear cache
|
||||
void stop(bool clearCache);
|
||||
|
||||
/// Resets the engine - calls stop and then calls start.
|
||||
void reset();
|
||||
|
|
|
@ -479,6 +479,59 @@ private:
|
|||
PDFCatalog m_catalog;
|
||||
};
|
||||
|
||||
/// Helper class for document updates (for example, add/delete annotations,
|
||||
/// fill form fields, do some other minor operations) and also for major
|
||||
/// updates (document reset). It also contains modification flags, which are
|
||||
/// hints for update operations (for example, if only annotations are changed,
|
||||
/// then rebuilding outline tree is not needed). At least one of the flags
|
||||
/// must be set. Reset flag is conservative, so it should be set, when document
|
||||
/// changes are not known.
|
||||
class PDFModifiedDocument
|
||||
{
|
||||
public:
|
||||
|
||||
enum ModificationFlag
|
||||
{
|
||||
None = 0x0000, ///< No flag
|
||||
Reset = 0x0001, ///< Whole document content is changed (for example, new document is being set)
|
||||
Annotation = 0x0002, ///< Annotations changed
|
||||
FormField = 0x0004, ///< Form field content changed
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(ModificationFlags, ModificationFlag)
|
||||
|
||||
explicit inline PDFModifiedDocument() = default;
|
||||
explicit inline PDFModifiedDocument(PDFDocument* document, PDFOptionalContentActivity* optionalContentActivity) :
|
||||
m_document(document),
|
||||
m_optionalContentActivity(optionalContentActivity),
|
||||
m_flags(Reset)
|
||||
{
|
||||
Q_ASSERT(document);
|
||||
}
|
||||
|
||||
explicit inline PDFModifiedDocument(PDFDocument* document, PDFOptionalContentActivity* optionalContentActivity, ModificationFlags flags) :
|
||||
m_document(document),
|
||||
m_optionalContentActivity(optionalContentActivity),
|
||||
m_flags(flags)
|
||||
{
|
||||
Q_ASSERT(document);
|
||||
}
|
||||
|
||||
PDFDocument* getDocument() const { return m_document; }
|
||||
PDFOptionalContentActivity* getOptionalContentActivity() const { return m_optionalContentActivity; }
|
||||
void setOptionalContentActivity(PDFOptionalContentActivity* optionalContentActivity) { m_optionalContentActivity = optionalContentActivity; }
|
||||
|
||||
bool hasReset() const { return m_flags.testFlag(Reset); }
|
||||
bool hasFlag(ModificationFlag flag) const { return m_flags.testFlag(flag); }
|
||||
|
||||
operator PDFDocument*() const { return m_document; }
|
||||
|
||||
private:
|
||||
PDFDocument* m_document = nullptr;
|
||||
PDFOptionalContentActivity* m_optionalContentActivity = nullptr;
|
||||
ModificationFlags m_flags = Reset;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
|
||||
inline
|
||||
|
|
|
@ -49,14 +49,20 @@ PDFDrawSpaceController::~PDFDrawSpaceController()
|
|||
|
||||
}
|
||||
|
||||
void PDFDrawSpaceController::setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity)
|
||||
void PDFDrawSpaceController::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
if (document != m_document)
|
||||
{
|
||||
m_document = document;
|
||||
m_fontCache.setDocument(document);
|
||||
m_optionalContentActivity = optionalContentActivity;
|
||||
recalculate();
|
||||
m_optionalContentActivity = document.getOptionalContentActivity();
|
||||
|
||||
// If document is not being reset, then recalculation is not needed,
|
||||
// pages should remain the same.
|
||||
if (document.hasReset())
|
||||
{
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,14 +417,22 @@ PDFDrawWidgetProxy::~PDFDrawWidgetProxy()
|
|||
|
||||
}
|
||||
|
||||
void PDFDrawWidgetProxy::setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity)
|
||||
void PDFDrawWidgetProxy::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
m_compiler->stop();
|
||||
m_textLayoutCompiler->stop();
|
||||
m_controller->setDocument(document, optionalContentActivity);
|
||||
connect(optionalContentActivity, &PDFOptionalContentActivity::optionalContentGroupStateChanged, this, &PDFDrawWidgetProxy::onOptionalContentGroupStateChanged);
|
||||
m_compiler->start();
|
||||
m_textLayoutCompiler->start();
|
||||
if (getDocument() != document)
|
||||
{
|
||||
m_compiler->stop(document.hasReset());
|
||||
m_textLayoutCompiler->stop(document.hasReset());
|
||||
m_controller->setDocument(document);
|
||||
|
||||
if (PDFOptionalContentActivity* optionalContentActivity = document.getOptionalContentActivity())
|
||||
{
|
||||
connect(optionalContentActivity, &PDFOptionalContentActivity::optionalContentGroupStateChanged, this, &PDFDrawWidgetProxy::onOptionalContentGroupStateChanged, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
m_compiler->start();
|
||||
m_textLayoutCompiler->start();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDrawWidgetProxy::init(PDFWidget* widget)
|
||||
|
@ -1312,8 +1326,8 @@ void PDFDrawWidgetProxy::setFeatures(PDFRenderer::Features features)
|
|||
{
|
||||
if (m_features != features)
|
||||
{
|
||||
m_compiler->stop();
|
||||
m_textLayoutCompiler->stop();
|
||||
m_compiler->stop(true);
|
||||
m_textLayoutCompiler->stop(true);
|
||||
m_features = features;
|
||||
m_compiler->start();
|
||||
m_textLayoutCompiler->start();
|
||||
|
@ -1325,7 +1339,7 @@ void PDFDrawWidgetProxy::setPreferredMeshResolutionRatio(PDFReal ratio)
|
|||
{
|
||||
if (m_meshQualitySettings.preferredMeshResolutionRatio != ratio)
|
||||
{
|
||||
m_compiler->stop();
|
||||
m_compiler->stop(true);
|
||||
m_meshQualitySettings.preferredMeshResolutionRatio = ratio;
|
||||
m_compiler->start();
|
||||
emit pageImageChanged(true, { });
|
||||
|
@ -1336,7 +1350,7 @@ void PDFDrawWidgetProxy::setMinimalMeshResolutionRatio(PDFReal ratio)
|
|||
{
|
||||
if (m_meshQualitySettings.minimalMeshResolutionRatio != ratio)
|
||||
{
|
||||
m_compiler->stop();
|
||||
m_compiler->stop(true);
|
||||
m_meshQualitySettings.minimalMeshResolutionRatio = ratio;
|
||||
m_compiler->start();
|
||||
emit pageImageChanged(true, { });
|
||||
|
@ -1347,7 +1361,7 @@ void PDFDrawWidgetProxy::setColorTolerance(PDFReal colorTolerance)
|
|||
{
|
||||
if (m_meshQualitySettings.tolerance != colorTolerance)
|
||||
{
|
||||
m_compiler->stop();
|
||||
m_compiler->stop(true);
|
||||
m_meshQualitySettings.tolerance = colorTolerance;
|
||||
m_compiler->start();
|
||||
emit pageImageChanged(true, { });
|
||||
|
|
|
@ -56,8 +56,7 @@ public:
|
|||
/// in that case, draw space is cleared. Optional content activity can be nullptr,
|
||||
/// in that case, no content is suppressed.
|
||||
/// \param document Document
|
||||
/// \param optionalContentActivity Optional content activity
|
||||
void setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Sets the page layout. Page layout can be one of the PDF's page layouts.
|
||||
/// \param pageLayout Page layout
|
||||
|
@ -193,8 +192,7 @@ public:
|
|||
/// in that case, draw space is cleared. Optional content activity can be nullptr,
|
||||
/// in that case, no content is suppressed.
|
||||
/// \param document Document
|
||||
/// \param optionalContentActivity Optional content activity
|
||||
void setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
void init(PDFWidget* widget);
|
||||
|
||||
|
|
|
@ -66,9 +66,9 @@ PDFWidget::~PDFWidget()
|
|||
|
||||
}
|
||||
|
||||
void PDFWidget::setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity)
|
||||
void PDFWidget::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
m_proxy->setDocument(document, optionalContentActivity);
|
||||
m_proxy->setDocument(document);
|
||||
m_pageRenderingErrors.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ class PDFCMSManager;
|
|||
class PDFToolManager;
|
||||
class PDFDrawWidget;
|
||||
class PDFDrawWidgetProxy;
|
||||
class PDFModifiedDocument;
|
||||
class PDFWidgetAnnotationManager;
|
||||
class IDrawWidgetInputInterface;
|
||||
|
||||
|
@ -64,8 +65,7 @@ public:
|
|||
/// in that case, widget contents are cleared. Optional content activity can be nullptr,
|
||||
/// if this occurs, no content is suppressed.
|
||||
/// \param document Document
|
||||
/// \param optionalContentActivity Optional content activity
|
||||
void setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Update rendering engine according the settings
|
||||
/// \param engine Engine type
|
||||
|
|
|
@ -1591,14 +1591,20 @@ FontType PDFTrueTypeFont::getFontType() const
|
|||
return FontType::TrueType;
|
||||
}
|
||||
|
||||
void PDFFontCache::setDocument(const PDFDocument* document)
|
||||
void PDFFontCache::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
if (m_document != document)
|
||||
{
|
||||
m_document = document;
|
||||
m_fontCache.clear();
|
||||
m_realizedFontCache.clear();
|
||||
|
||||
// Jakub Melka: If document has not reset flag, then fonts of the
|
||||
// document remains the same. So it is not needed to clear font cache.
|
||||
if (document.hasReset())
|
||||
{
|
||||
m_fontCache.clear();
|
||||
m_realizedFontCache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ class QPainterPath;
|
|||
namespace pdf
|
||||
{
|
||||
class PDFDocument;
|
||||
class PDFModifiedDocument;
|
||||
class PDFRenderErrorReporter;
|
||||
|
||||
using CID = unsigned int;
|
||||
|
@ -396,9 +397,10 @@ public:
|
|||
|
||||
}
|
||||
|
||||
/// Sets the document to the cache. Whole cache is cleared.
|
||||
/// Sets the document to the cache. Whole cache is cleared,
|
||||
/// if it is needed.
|
||||
/// \param document Document to be setted
|
||||
void setDocument(const PDFDocument* document);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Retrieves font from the cache. If font can't be accessed or created,
|
||||
/// then exception is thrown.
|
||||
|
|
|
@ -69,6 +69,21 @@ void PDFFormField::fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& map
|
|||
}
|
||||
}
|
||||
|
||||
void PDFFormField::reloadValue(const PDFObjectStorage* storage, PDFObject parentValue)
|
||||
{
|
||||
Q_ASSERT(storage);
|
||||
|
||||
if (const PDFDictionary* fieldDictionary = storage->getDictionaryFromObject(storage->getObjectByReference(getSelfReference())))
|
||||
{
|
||||
m_value = fieldDictionary->hasKey("V") ? fieldDictionary->get("V") : parentValue;
|
||||
}
|
||||
|
||||
for (const PDFFormFieldPointer& childField : m_childFields)
|
||||
{
|
||||
childField->reloadValue(storage, m_value);
|
||||
}
|
||||
}
|
||||
|
||||
PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField)
|
||||
{
|
||||
PDFFormFieldPointer result;
|
||||
|
@ -308,23 +323,31 @@ const PDFDocument* PDFFormManager::getDocument() const
|
|||
return m_document;
|
||||
}
|
||||
|
||||
void PDFFormManager::setDocument(const PDFDocument* document)
|
||||
void PDFFormManager::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
m_document = document;
|
||||
|
||||
if (m_document)
|
||||
if (document.hasReset())
|
||||
{
|
||||
m_form = PDFForm::parse(&m_document->getStorage(), m_document->getCatalog()->getFormObject());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clean the form
|
||||
m_form = PDFForm();
|
||||
}
|
||||
if (m_document)
|
||||
{
|
||||
m_form = PDFForm::parse(&m_document->getStorage(), m_document->getCatalog()->getFormObject());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clean the form
|
||||
m_form = PDFForm();
|
||||
}
|
||||
|
||||
updateWidgetToFormFieldMapping();
|
||||
updateWidgetToFormFieldMapping();
|
||||
}
|
||||
else if (document.hasFlag(PDFModifiedDocument::FormField))
|
||||
{
|
||||
// Just update field values
|
||||
updateFieldValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,6 +361,17 @@ void PDFFormManager::setAppearanceFlags(FormAppearanceFlags flags)
|
|||
m_flags = flags;
|
||||
}
|
||||
|
||||
void PDFFormManager::updateFieldValues()
|
||||
{
|
||||
if (m_document)
|
||||
{
|
||||
for (const PDFFormFieldPointer& childField : m_form.getFormFields())
|
||||
{
|
||||
childField->reloadValue(&m_document->getStorage(), PDFObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFFormManager::updateWidgetToFormFieldMapping()
|
||||
{
|
||||
m_widgetToFormField.clear();
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDFObjectStorage;
|
||||
class PDFFormField;
|
||||
class PDFObjectStorage;
|
||||
class PDFModifiedDocument;
|
||||
|
||||
using PDFFormFieldPointer = QSharedPointer<PDFFormField>;
|
||||
using PDFFormFields = std::vector<PDFFormFieldPointer>;
|
||||
|
@ -187,6 +187,9 @@ public:
|
|||
/// \param mapping Form field mapping
|
||||
void fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping);
|
||||
|
||||
/// Reloads value from object storage. Actually stored value is lost.
|
||||
void reloadValue(const PDFObjectStorage* storage, PDFObject parentValue);
|
||||
|
||||
/// Parses form field from the object reference. If some error occurs
|
||||
/// then null pointer is returned, no exception is thrown.
|
||||
/// \param storage Storage
|
||||
|
@ -378,7 +381,7 @@ public:
|
|||
void setAnnotationManager(PDFAnnotationManager* annotationManager);
|
||||
|
||||
const PDFDocument* getDocument() const;
|
||||
void setDocument(const PDFDocument* document);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Returns default form apperance flags
|
||||
static constexpr FormAppearanceFlags getDefaultApperanceFlags() { return HighlightFields | HighlightRequiredFields; }
|
||||
|
@ -387,6 +390,7 @@ public:
|
|||
void setAppearanceFlags(FormAppearanceFlags flags);
|
||||
|
||||
private:
|
||||
void updateFieldValues();
|
||||
void updateWidgetToFormFieldMapping();
|
||||
|
||||
PDFDrawWidgetProxy* m_proxy;
|
||||
|
|
|
@ -40,12 +40,18 @@ PDFTreeItemModel::PDFTreeItemModel(QObject* parent) :
|
|||
|
||||
}
|
||||
|
||||
void PDFTreeItemModel::setDocument(const PDFDocument* document)
|
||||
void PDFTreeItemModel::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
m_document = document;
|
||||
update();
|
||||
|
||||
// We must only update only, when document has been reset, i.e.
|
||||
// all document content has been changed.
|
||||
if (document.hasReset())
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,20 +733,29 @@ void PDFThumbnailsItemModel::setThumbnailsSize(int size)
|
|||
}
|
||||
}
|
||||
|
||||
void PDFThumbnailsItemModel::setDocument(const PDFDocument* document)
|
||||
void PDFThumbnailsItemModel::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
beginResetModel();
|
||||
m_thumbnailCache.clear();
|
||||
m_document = document;
|
||||
|
||||
m_pageCount = 0;
|
||||
if (m_document)
|
||||
if (document.hasReset() || document.hasFlag(PDFModifiedDocument::Annotation))
|
||||
{
|
||||
m_pageCount = static_cast<int>(m_document->getCatalog()->getPageCount());
|
||||
beginResetModel();
|
||||
m_thumbnailCache.clear();
|
||||
m_document = document;
|
||||
|
||||
m_pageCount = 0;
|
||||
if (m_document)
|
||||
{
|
||||
m_pageCount = static_cast<int>(m_document->getCatalog()->getPageCount());
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Soft reset
|
||||
m_document = document;
|
||||
Q_ASSERT(!m_document || m_pageCount == static_cast<int>(m_document->getCatalog()->getPageCount()));
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -778,4 +793,19 @@ QString PDFThumbnailsItemModel::getKey(int pageIndex) const
|
|||
return QString("PDF_THUMBNAIL_%1").arg(pageIndex);
|
||||
}
|
||||
|
||||
PDFAttachmentsTreeItem::PDFAttachmentsTreeItem(PDFAttachmentsTreeItem* parent, QIcon icon, QString title, QString description, const PDFFileSpecification* fileSpecification) :
|
||||
PDFTreeItem(parent),
|
||||
m_icon(qMove(icon)),
|
||||
m_title(qMove(title)),
|
||||
m_description(qMove(description)),
|
||||
m_fileSpecification(std::make_unique<PDFFileSpecification>(*fileSpecification))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFAttachmentsTreeItem::~PDFAttachmentsTreeItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace pdf
|
|||
class PDFAction;
|
||||
class PDFDocument;
|
||||
class PDFOutlineItem;
|
||||
class PDFModifiedDocument;
|
||||
class PDFFileSpecification;
|
||||
class PDFOptionalContentActivity;
|
||||
class PDFDrawWidgetProxy;
|
||||
|
@ -66,13 +67,15 @@ private:
|
|||
QList<PDFTreeItem*> m_children;
|
||||
};
|
||||
|
||||
/// Root of all tree item models
|
||||
/// Root of all tree item models. Reimplementations of this model
|
||||
/// must handle "soft" document updates, such as only annotations changed etc.
|
||||
/// Model should be rebuilded only, if it is neccessary.
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFTreeItemModel : public QAbstractItemModel
|
||||
{
|
||||
public:
|
||||
explicit PDFTreeItemModel(QObject* parent);
|
||||
|
||||
void setDocument(const pdf::PDFDocument* document);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
|
@ -172,26 +175,19 @@ private:
|
|||
class PDFAttachmentsTreeItem : public PDFTreeItem
|
||||
{
|
||||
public:
|
||||
explicit PDFAttachmentsTreeItem(PDFAttachmentsTreeItem* parent, QIcon icon, QString title, QString description, const PDFFileSpecification* fileSpecification) :
|
||||
PDFTreeItem(parent),
|
||||
m_icon(qMove(icon)),
|
||||
m_title(qMove(title)),
|
||||
m_description(qMove(description)),
|
||||
m_fileSpecification(fileSpecification)
|
||||
{
|
||||
|
||||
}
|
||||
explicit PDFAttachmentsTreeItem(PDFAttachmentsTreeItem* parent, QIcon icon, QString title, QString description, const PDFFileSpecification* fileSpecification);
|
||||
virtual ~PDFAttachmentsTreeItem() override;
|
||||
|
||||
const QIcon& getIcon() const { return m_icon; }
|
||||
const QString& getTitle() const { return m_title; }
|
||||
const QString& getDescription() const { return m_description; }
|
||||
const PDFFileSpecification* getFileSpecification() const { return m_fileSpecification; }
|
||||
const PDFFileSpecification* getFileSpecification() const { return m_fileSpecification.get(); }
|
||||
|
||||
private:
|
||||
QIcon m_icon;
|
||||
QString m_title;
|
||||
QString m_description;
|
||||
const PDFFileSpecification* m_fileSpecification;
|
||||
std::unique_ptr<PDFFileSpecification> m_fileSpecification;
|
||||
};
|
||||
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFAttachmentsTreeItemModel : public PDFTreeItemModel
|
||||
|
@ -235,7 +231,7 @@ public:
|
|||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
|
||||
void setThumbnailsSize(int size);
|
||||
void setDocument(const PDFDocument* document);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Sets the extra item width/height for size hint. This space will be added to the size hint (pixmap size)
|
||||
void setExtraItemSizeHint(int width, int height) { m_extraItemWidthHint = width; m_extraItemHeighHint = height; }
|
||||
|
|
|
@ -343,6 +343,16 @@ OCState PDFOptionalContentActivity::getState(PDFObjectReference ocg) const
|
|||
return OCState::Unknown;
|
||||
}
|
||||
|
||||
void PDFOptionalContentActivity::setDocument(const PDFDocument* document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
Q_ASSERT(document);
|
||||
m_document = document;
|
||||
m_properties = document->getCatalog()->getOptionalContentProperties();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFOptionalContentActivity::setState(PDFObjectReference ocg, OCState state, bool preserveRadioButtons)
|
||||
{
|
||||
auto it = m_states.find(ocg);
|
||||
|
|
|
@ -167,6 +167,11 @@ public:
|
|||
/// \param ocg Optional content group
|
||||
OCState getState(PDFObjectReference ocg) const;
|
||||
|
||||
/// Sets document to this object. Optional content settings
|
||||
/// must be compatible and applicable to new document.
|
||||
/// \param document Document
|
||||
void setDocument(const PDFDocument* document);
|
||||
|
||||
/// Sets the state of optional content group. If optional content group doesn't exist,
|
||||
/// then nothing happens. If optional content group is contained in radio button group, then
|
||||
/// all other optional content groups in the group are switched off, if we are
|
||||
|
|
|
@ -434,9 +434,13 @@ void PDFRasterizerPool::render(const std::vector<PDFInteger>& pageIndices,
|
|||
emit renderError(PDFRenderError(error.type, PDFTranslationContext::tr("Page %1: %2").arg(pageIndex + 1).arg(error.message)));
|
||||
}
|
||||
|
||||
// We can const-cast here, because we do not modify the document in annotation manager.
|
||||
// Annotations are just rendered to the target picture.
|
||||
PDFModifiedDocument modifiedDocument(const_cast<PDFDocument*>(m_document), const_cast<PDFOptionalContentActivity*>(m_optionalContentActivity));
|
||||
|
||||
// Annotation manager
|
||||
PDFAnnotationManager annotationManager(m_fontCache, m_cmsManager, m_optionalContentActivity, m_meshQualitySettings, m_features, PDFAnnotationManager::Target::Print, nullptr);
|
||||
annotationManager.setDocument(m_document, m_optionalContentActivity);
|
||||
annotationManager.setDocument(modifiedDocument);
|
||||
|
||||
// Render page to image
|
||||
PDFRasterizer* rasterizer = acquire();
|
||||
|
|
|
@ -60,12 +60,17 @@ PDFWidgetTool::~PDFWidgetTool()
|
|||
|
||||
}
|
||||
|
||||
void PDFWidgetTool::setDocument(const PDFDocument* document)
|
||||
void PDFWidgetTool::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
// We must turn off the tool, if we are changing the document
|
||||
setActive(false);
|
||||
// We must turn off the tool, if we are changing the document. We turn off tool,
|
||||
// only if whole document is being reset.
|
||||
if (document.hasReset())
|
||||
{
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
m_document = document;
|
||||
|
||||
for (PDFWidgetTool* tool : m_toolStack)
|
||||
|
@ -728,7 +733,7 @@ PDFToolManager::PDFToolManager(PDFDrawWidgetProxy* proxy, Actions actions, QObje
|
|||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::setDocument(const PDFDocument* document)
|
||||
void PDFToolManager::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
for (PDFWidgetTool* tool : m_tools)
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
/// Sets document, shuts down the tool, if it is active, and document
|
||||
/// is changing.
|
||||
/// \param document Document
|
||||
void setDocument(const PDFDocument* document);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Sets tool as active or inactive. If tool is active, then it is processed
|
||||
/// in draw widget proxy events (such as drawing etc.).
|
||||
|
@ -416,7 +416,7 @@ public:
|
|||
|
||||
/// Sets document
|
||||
/// \param document Document
|
||||
void setDocument(const PDFDocument* document);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
enum PredefinedTools
|
||||
{
|
||||
|
|
|
@ -49,14 +49,20 @@ PDFAdvancedFindWidget::~PDFAdvancedFindWidget()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void PDFAdvancedFindWidget::setDocument(const pdf::PDFDocument* document)
|
||||
void PDFAdvancedFindWidget::setDocument(const pdf::PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
m_document = document;
|
||||
m_findResults.clear();
|
||||
updateUI();
|
||||
updateResultsUI();
|
||||
|
||||
// If document is not being reset, then page text should remain the same,
|
||||
// so, there is no need to clear the results.
|
||||
if (document.hasReset())
|
||||
{
|
||||
m_findResults.clear();
|
||||
updateUI();
|
||||
updateResultsUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
const QMatrix& pagePointToDevicePointMatrix,
|
||||
QList<pdf::PDFRenderError>& errors) const override;
|
||||
|
||||
void setDocument(const pdf::PDFDocument* document);
|
||||
void setDocument(const pdf::PDFModifiedDocument& document);
|
||||
|
||||
protected:
|
||||
virtual void showEvent(QShowEvent* event) override;
|
||||
|
|
|
@ -121,10 +121,10 @@ PDFSidebarWidget::~PDFSidebarWidget()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void PDFSidebarWidget::setDocument(const pdf::PDFDocument* document, pdf::PDFOptionalContentActivity* optionalContentActivity)
|
||||
void PDFSidebarWidget::setDocument(const pdf::PDFModifiedDocument& document)
|
||||
{
|
||||
m_document = document;
|
||||
m_optionalContentActivity = optionalContentActivity;
|
||||
m_optionalContentActivity = document.getOptionalContentActivity();
|
||||
|
||||
// Update outline
|
||||
m_outlineTreeModel->setDocument(document);
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace pdf
|
|||
class PDFAction;
|
||||
class PDFDocument;
|
||||
class PDFDrawWidgetProxy;
|
||||
class PDFModifiedDocument;
|
||||
class PDFOutlineTreeItemModel;
|
||||
class PDFThumbnailsItemModel;
|
||||
class PDFAttachmentsTreeItemModel;
|
||||
|
@ -69,7 +70,7 @@ public:
|
|||
_END
|
||||
};
|
||||
|
||||
void setDocument(const pdf::PDFDocument* document, pdf::PDFOptionalContentActivity* optionalContentActivity);
|
||||
void setDocument(const pdf::PDFModifiedDocument& document);
|
||||
|
||||
/// Returns true, if all items in sidebar are empty
|
||||
bool isEmpty() const;
|
||||
|
|
|
@ -61,7 +61,7 @@ bool PDFTextToSpeech::isValid() const
|
|||
return m_document != nullptr;
|
||||
}
|
||||
|
||||
void PDFTextToSpeech::setDocument(const pdf::PDFDocument* document)
|
||||
void PDFTextToSpeech::setDocument(const pdf::PDFModifiedDocument& document)
|
||||
{
|
||||
if (m_document != document)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace pdf
|
|||
{
|
||||
class PDFDocument;
|
||||
class PDFDrawWidgetProxy;
|
||||
class PDFModifiedDocument;
|
||||
}
|
||||
|
||||
namespace pdfviewer
|
||||
|
@ -66,7 +67,7 @@ public:
|
|||
bool isValid() const;
|
||||
|
||||
/// Sets active document to text to speech engine
|
||||
void setDocument(const pdf::PDFDocument* document);
|
||||
void setDocument(const pdf::PDFModifiedDocument& document);
|
||||
|
||||
/// Apply settings to the reader
|
||||
void setSettings(const PDFViewerSettings* viewerSettings);
|
||||
|
|
|
@ -959,7 +959,8 @@ void PDFViewerMainWindow::onDocumentReadingFinished()
|
|||
m_recentFileManager->addRecentFile(m_fileInfo.originalFileName);
|
||||
|
||||
m_pdfDocument = result.document;
|
||||
setDocument(m_pdfDocument.data());
|
||||
pdf::PDFModifiedDocument document(m_pdfDocument.data(), m_optionalContentActivity);
|
||||
setDocument(document);
|
||||
|
||||
statusBar()->showMessage(tr("Document '%1' was successfully loaded!").arg(m_fileInfo.fileName), 4000);
|
||||
break;
|
||||
|
@ -977,27 +978,36 @@ void PDFViewerMainWindow::onDocumentReadingFinished()
|
|||
updateActionsAvailability();
|
||||
}
|
||||
|
||||
void PDFViewerMainWindow::setDocument(const pdf::PDFDocument* document)
|
||||
void PDFViewerMainWindow::setDocument(pdf::PDFModifiedDocument document)
|
||||
{
|
||||
if (m_optionalContentActivity)
|
||||
if (document.hasReset())
|
||||
{
|
||||
// We use deleteLater, because we want to avoid consistency problem with model
|
||||
// (we set document to the model before activity).
|
||||
m_optionalContentActivity->deleteLater();
|
||||
m_optionalContentActivity = nullptr;
|
||||
if (m_optionalContentActivity)
|
||||
{
|
||||
// We use deleteLater, because we want to avoid consistency problem with model
|
||||
// (we set document to the model before activity).
|
||||
m_optionalContentActivity->deleteLater();
|
||||
m_optionalContentActivity = nullptr;
|
||||
}
|
||||
|
||||
if (document)
|
||||
{
|
||||
m_optionalContentActivity = new pdf::PDFOptionalContentActivity(document, pdf::OCUsage::View, this);
|
||||
}
|
||||
}
|
||||
else if (m_optionalContentActivity)
|
||||
{
|
||||
Q_ASSERT(document);
|
||||
m_optionalContentActivity->setDocument(document);
|
||||
}
|
||||
|
||||
if (document)
|
||||
{
|
||||
m_optionalContentActivity = new pdf::PDFOptionalContentActivity(document, pdf::OCUsage::View, this);
|
||||
}
|
||||
|
||||
m_annotationManager->setDocument(document, m_optionalContentActivity);
|
||||
document.setOptionalContentActivity(m_optionalContentActivity);
|
||||
m_annotationManager->setDocument(document);
|
||||
m_formManager->setDocument(document);
|
||||
m_toolManager->setDocument(document);
|
||||
m_textToSpeech->setDocument(document);
|
||||
m_pdfWidget->setDocument(document, m_optionalContentActivity);
|
||||
m_sidebarWidget->setDocument(document, m_optionalContentActivity);
|
||||
m_pdfWidget->setDocument(document);
|
||||
m_sidebarWidget->setDocument(document);
|
||||
m_advancedFindWidget->setDocument(document);
|
||||
|
||||
if (m_sidebarWidget->isEmpty())
|
||||
|
@ -1034,7 +1044,7 @@ void PDFViewerMainWindow::setDocument(const pdf::PDFDocument* document)
|
|||
|
||||
void PDFViewerMainWindow::closeDocument()
|
||||
{
|
||||
setDocument(nullptr);
|
||||
setDocument(pdf::PDFModifiedDocument());
|
||||
m_pdfDocument.reset();
|
||||
updateActionsAvailability();
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ private:
|
|||
void onRenderingOptionTriggered(bool checked);
|
||||
|
||||
void openDocument(const QString& fileName);
|
||||
void setDocument(const pdf::PDFDocument* document);
|
||||
void setDocument(pdf::PDFModifiedDocument document);
|
||||
void closeDocument();
|
||||
|
||||
void setPageLayout(pdf::PageLayout pageLayout);
|
||||
|
|
Loading…
Reference in New Issue