mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Form field manager (beginnings)
This commit is contained in:
@@ -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)
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user