Form field manager (beginnings)

This commit is contained in:
Jakub Melka
2020-04-22 20:00:44 +02:00
parent b654ce463a
commit d16e2a2c02
15 changed files with 499 additions and 3 deletions

View File

@@ -25,6 +25,7 @@
#include "pdfpagecontentprocessor.h"
#include "pdfparser.h"
#include "pdfdrawwidget.h"
#include "pdfform.h"
#include <QDialog>
#include <QApplication>
@@ -897,6 +898,7 @@ PDFAnnotationManager::PDFAnnotationManager(PDFFontCache* fontCache,
m_fontCache(fontCache),
m_cmsManager(cmsManager),
m_optionalActivity(optionalActivity),
m_formManager(nullptr),
m_meshQualitySettings(meshQualitySettings),
m_features(features),
m_target(target)
@@ -1081,6 +1083,22 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
if (!oc.isValid() || !pdfPainter.isContentSuppressedByOC(oc))
{
pdfPainter.processForm(AA, formBoundingBox, resources, transparencyGroup, content);
// Is it a form field?
if (m_formManager && annotation.annotation->getType() == AnnotationType::Widget)
{
const PDFFormManager::FormAppearanceFlags flags = m_formManager->getAppearanceFlags();
if (flags.testFlag(PDFFormManager::HighlightFields) || flags.testFlag(PDFFormManager::HighlightRequiredFields))
{
const PDFFormField* formField = m_formManager->getFormFieldForWidget(annotation.annotation->getSelfReference());
if (!formField)
{
continue;
}
s
}
}
}
}
catch (PDFException exception)
@@ -1168,6 +1186,16 @@ bool PDFAnnotationManager::hasAnyPageAnnotation(const std::vector<PDFInteger>& p
return std::any_of(pageIndices.cbegin(), pageIndices.cend(), std::bind(&PDFAnnotationManager::hasAnnotation, this, std::placeholders::_1));
}
PDFFormManager* PDFAnnotationManager::getFormManager() const
{
return m_formManager;
}
void PDFAnnotationManager::setFormManager(PDFFormManager* formManager)
{
m_formManager = formManager;
}
PDFRenderer::Features PDFAnnotationManager::getFeatures() const
{
return m_features;
@@ -1336,7 +1364,8 @@ void PDFWidgetAnnotationManager::updateFromMouseEvent(QMouseEvent* event)
}
const PDFAction* linkAction = nullptr;
if (pageAnnotation.annotation->getType() == AnnotationType::Link)
const AnnotationType annotationType = pageAnnotation.annotation->getType();
if (annotationType == AnnotationType::Link)
{
const PDFLinkAnnotation* linkAnnotation = dynamic_cast<const PDFLinkAnnotation*>(pageAnnotation.annotation.data());
Q_ASSERT(linkAnnotation);
@@ -1350,6 +1379,10 @@ void PDFWidgetAnnotationManager::updateFromMouseEvent(QMouseEvent* event)
linkAction = linkAnnotation->getAction();
}
}
if (annotationType == AnnotationType::Widget)
{
m_cursor = QCursor(Qt::ArrowCursor);
}
// Generate popup window
if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton)

View File

@@ -43,6 +43,7 @@ class PDFWidget;
class PDFObjectStorage;
class PDFDrawWidgetProxy;
class PDFFontCache;
class PDFFormManager;
class PDFOptionalContentActivity;
using TextAlignment = Qt::Alignment;
@@ -1301,6 +1302,9 @@ public:
PDFRenderer::Features getFeatures() const;
void setFeatures(PDFRenderer::Features features);
PDFFormManager* getFormManager() const;
void setFormManager(PDFFormManager* formManager);
protected:
struct PageAnnotation
{
@@ -1368,6 +1372,7 @@ protected:
PDFFontCache* m_fontCache;
const PDFCMSManager* m_cmsManager;
const PDFOptionalContentActivity* m_optionalActivity;
PDFFormManager* m_formManager;
PDFMeshQualitySettings m_meshQualitySettings;
PDFRenderer::Features m_features;

View File

@@ -168,6 +168,8 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
catalogObject.m_baseURI = loader.readStringFromDictionary(URIDictionary, "Base");
}
catalogObject.m_formObject = catalogDictionary->get("AcroForm");
return catalogObject;
}

View File

@@ -235,6 +235,7 @@ public:
PageMode getPageMode() const { return m_pageMode; }
const QByteArray& getBaseURI() const { return m_baseURI; }
const std::map<QByteArray, PDFFileSpecification>& getEmbeddedFiles() const { return m_embeddedFiles; }
const PDFObject& getFormObject() const { return m_formObject; }
/// Returns destination using the key. If destination with the key is not found,
/// then nullptr is returned.
@@ -257,6 +258,7 @@ private:
PageLayout m_pageLayout = PageLayout::SinglePage;
PageMode m_pageMode = PageMode::UseNone;
QByteArray m_baseURI;
PDFObject m_formObject;
// Maps from Names dictionary
std::map<QByteArray, PDFDestination> m_destinations;

View File

@@ -17,6 +17,7 @@
#include "pdfform.h"
#include "pdfdocument.h"
#include "pdfdrawspacecontroller.h"
namespace pdf
{
@@ -55,6 +56,19 @@ PDFForm PDFForm::parse(const PDFObjectStorage* storage, PDFObject object)
return form;
}
void PDFFormField::fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping)
{
for (const auto& childField : m_childFields)
{
childField->fillWidgetToFormFieldMapping(mapping);
}
for (const PDFFormWidget& formWidget : m_widgets)
{
mapping[formWidget.getWidget()] = formWidget.getParent();
}
}
PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField)
{
PDFFormFieldPointer result;
@@ -253,4 +267,77 @@ PDFFormFieldButton::ButtonType PDFFormFieldButton::getButtonType() const
return ButtonType::CheckBox;
}
PDFFormManager::PDFFormManager(PDFDrawWidgetProxy* proxy, QObject* parent) :
BaseClass(parent),
m_proxy(proxy),
m_annotationManager(nullptr),
m_document(nullptr),
m_flags(getDefaultApperanceFlags())
{
Q_ASSERT(proxy);
}
PDFFormManager::~PDFFormManager()
{
}
PDFAnnotationManager* PDFFormManager::getAnnotationManager() const
{
return m_annotationManager;
}
void PDFFormManager::setAnnotationManager(PDFAnnotationManager* annotationManager)
{
m_annotationManager = annotationManager;
}
const PDFDocument* PDFFormManager::getDocument() const
{
return m_document;
}
void PDFFormManager::setDocument(const PDFDocument* document)
{
if (m_document != document)
{
m_document = document;
if (m_document)
{
m_form = PDFForm::parse(&m_document->getStorage(), m_document->getCatalog()->getFormObject());
}
else
{
// Clean the form
m_form = PDFForm();
}
updateWidgetToFormFieldMapping();
}
}
PDFFormManager::FormAppearanceFlags PDFFormManager::getAppearanceFlags() const
{
return m_flags;
}
void PDFFormManager::setAppearanceFlags(FormAppearanceFlags flags)
{
m_flags = flags;
}
void PDFFormManager::updateWidgetToFormFieldMapping()
{
m_widgetToFormField.clear();
if (hasAcroForm())
{
for (const PDFFormFieldPointer& formFieldPtr : m_form.getFormFields())
{
formFieldPtr->fillWidgetToFormFieldMapping(m_widgetToFormField);
}
}
}
} // namespace pdf

View File

@@ -31,6 +31,7 @@ class PDFFormField;
using PDFFormFieldPointer = QSharedPointer<PDFFormField>;
using PDFFormFields = std::vector<PDFFormFieldPointer>;
using PDFWidgetToFormFieldMapping = std::map<PDFObjectReference, PDFFormField*>;
/// A simple proxy to the widget annotation
class PDFFormWidget
@@ -182,6 +183,10 @@ public:
const PDFObject& getValue() const { return m_value; }
const PDFObject& getDefaultValue() const { return m_defaultValue; }
/// Fills widget to form field mapping
/// \param mapping Form field mapping
void fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping);
/// Parses form field from the object reference. If some error occurs
/// then null pointer is returned, no exception is thrown.
/// \param storage Storage
@@ -311,6 +316,7 @@ public:
};
Q_DECLARE_FLAGS(SignatureFlags, SignatureFlag)
FormType getFormType() const { return m_formType; }
const PDFFormFields& getFormFields() const { return m_formFields; }
bool isAppearanceUpdateNeeded() const { return m_needAppearances; }
SignatureFlags getSignatureFlags() const { return m_signatureFlags; }
@@ -338,6 +344,58 @@ private:
PDFObject m_xfa;
};
/// Form manager. Manages all form widgets functionality - triggers actions,
/// edits fields, updates annotation appearances, etc. Valid pointer to annotation
/// manager is requirement.
class PDFFORQTLIBSHARED_EXPORT PDFFormManager : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
explicit PDFFormManager(PDFDrawWidgetProxy* proxy, QObject* parent);
virtual ~PDFFormManager() override;
enum FormAppearanceFlag
{
None = 0x0000,
HighlightFields = 0x0001,
HighlightRequiredFields = 0x0002,
};
Q_DECLARE_FLAGS(FormAppearanceFlags, FormAppearanceFlag)
bool hasAcroForm() const { return m_form.getFormType() == PDFForm::FormType::AcroForm; }
/// Returns form field for widget. If widget doesn't have attached form field,
/// then nullptr is returned.
/// \param widget Widget annotation
const PDFFormField* getFormFieldForWidget(PDFObjectReference widget) const;
PDFAnnotationManager* getAnnotationManager() const;
void setAnnotationManager(PDFAnnotationManager* annotationManager);
const PDFDocument* getDocument() const;
void setDocument(const PDFDocument* document);
/// Returns default form apperance flags
static constexpr FormAppearanceFlags getDefaultApperanceFlags() { return HighlightFields | HighlightRequiredFields; }
FormAppearanceFlags getAppearanceFlags() const;
void setAppearanceFlags(FormAppearanceFlags flags);
private:
void updateWidgetToFormFieldMapping();
PDFDrawWidgetProxy* m_proxy;
PDFAnnotationManager* m_annotationManager;
const PDFDocument* m_document;
FormAppearanceFlags m_flags;
PDFForm m_form;
PDFWidgetToFormFieldMapping m_widgetToFormField;
};
} // namespace pdf
#endif // PDFFORM_H