Checkbox and radio form fields

This commit is contained in:
Jakub Melka
2020-05-02 18:04:25 +02:00
parent bfb26c4807
commit f604dd77b2
14 changed files with 584 additions and 23 deletions

View File

@@ -165,6 +165,23 @@ PDFObject PDFAppeareanceStreams::getAppearance(Appearance appearance, const QByt
return PDFObject();
}
QByteArrayList PDFAppeareanceStreams::getAppearanceStates(Appearance appearance)
{
QByteArrayList result;
for (const auto& item : m_appearanceStreams)
{
if (item.first.first != appearance)
{
continue;
}
result << item.first.second;
}
return result;
}
PDFAnnotation::PDFAnnotation() :
m_flags(),
m_structParent(0)

View File

@@ -209,6 +209,10 @@ public:
/// \param state State name
PDFObject getAppearance(Appearance appearance, const QByteArray& state) const;
/// Returns list of appearance states for given appearance
/// \param appearance Appearance
QByteArrayList getAppearanceStates(Appearance appearance);
private:
std::map<Key, PDFObject> m_appearanceStreams;
};

View File

@@ -45,6 +45,12 @@ QByteArray PDFObjectStorage::getDecodedStream(const PDFStream* stream) const
return PDFStreamFilterStorage::getDecodedStream(stream, std::bind(QOverload<const PDFObject&>::of(&PDFObjectStorage::getObject), this, std::placeholders::_1), getSecurityHandler());
}
bool PDFDocument::operator==(const PDFDocument& other) const
{
// Document is considered equal, if storage is equal
return m_pdfObjectStorage == other.m_pdfObjectStorage;
}
QByteArray PDFDocument::getDecodedStream(const PDFStream* stream) const
{
return m_pdfObjectStorage.getDecodedStream(stream);
@@ -215,6 +221,13 @@ void PDFDocument::initInfo()
}
}
bool PDFObjectStorage::operator==(const PDFObjectStorage& other) const
{
// We compare just content. Security handler just defines encryption behavior.
return m_objects == other.m_objects &&
m_trailerDictionary == other.m_trailerDictionary;
}
const PDFObject& PDFObjectStorage::getObject(PDFObjectReference reference) const
{
if (reference.objectNumber >= 0 &&

View File

@@ -48,11 +48,17 @@ public:
constexpr inline PDFObjectStorage& operator=(const PDFObjectStorage&) = default;
constexpr inline PDFObjectStorage& operator=(PDFObjectStorage&&) = default;
bool operator==(const PDFObjectStorage& other) const;
bool operator!=(const PDFObjectStorage& other) const { return !(*this == other); }
struct Entry
{
constexpr inline explicit Entry() = default;
inline explicit Entry(PDFInteger generation, PDFObject object) : generation(generation), object(std::move(object)) { }
inline bool operator==(const Entry& other) const { return generation == other.generation && object == other.object; }
inline bool operator!=(const Entry& other) const { return !(*this == other); }
PDFInteger generation = 0;
PDFObject object;
};
@@ -386,6 +392,9 @@ class PDFFORQTLIBSHARED_EXPORT PDFDocument
public:
explicit PDFDocument() = default;
bool operator==(const PDFDocument& other) const;
bool operator!=(const PDFDocument& other) const { return !(*this == other); }
const PDFObjectStorage& getStorage() const { return m_pdfObjectStorage; }
/// Info about the document. Title, Author, Keywords... It also stores "extra"

View File

@@ -1154,6 +1154,25 @@ PDFContentStreamBuilder::ContentStream PDFContentStreamBuilder::end(QPainter* pa
return result;
}
PDFDocumentModifier::PDFDocumentModifier(const PDFDocument* originalDocument) :
m_originalDocument(originalDocument),
m_builder(originalDocument)
{
}
bool PDFDocumentModifier::finalize()
{
PDFDocument document = m_builder.build();
if (document != *m_originalDocument)
{
m_modifiedDocument.reset(new PDFDocument(qMove(document)));
return true;
}
return false;
}
/* START GENERATED CODE */
PDFObjectReference PDFDocumentBuilder::appendPage(QRectF mediaBox)
@@ -2898,6 +2917,21 @@ PDFObject PDFDocumentBuilder::createTrailerDictionary(PDFObjectReference catalog
}
void PDFDocumentBuilder::setAnnotationAppearanceState(PDFObjectReference annotation,
QByteArray appearanceState)
{
PDFObjectFactory objectBuilder;
objectBuilder.beginDictionary();
objectBuilder.beginDictionaryItem("AS");
objectBuilder << WrapName(appearanceState);
objectBuilder.endDictionaryItem();
objectBuilder.endDictionary();
PDFObject annotationObject = objectBuilder.takeObject();
mergeTo(annotation, annotationObject);
}
void PDFDocumentBuilder::setAnnotationBorder(PDFObjectReference annotation,
PDFReal hRadius,
PDFReal vRadius,
@@ -3160,6 +3194,21 @@ void PDFDocumentBuilder::setDocumentTitle(QString title)
}
void PDFDocumentBuilder::setFormFieldValue(PDFObjectReference formField,
PDFObject value)
{
PDFObjectFactory objectBuilder;
objectBuilder.beginDictionary();
objectBuilder.beginDictionaryItem("V");
objectBuilder << value;
objectBuilder.endDictionaryItem();
objectBuilder.endDictionary();
PDFObject formFieldObject = objectBuilder.takeObject();
mergeTo(formField, formFieldObject);
}
void PDFDocumentBuilder::setLanguage(QLocale locale)
{
PDFObjectFactory objectBuilder;

View File

@@ -242,7 +242,7 @@ public:
/// Creates a new blank document (with no pages)
explicit PDFDocumentBuilder();
///
/// Creates a new document as modification of old document
explicit PDFDocumentBuilder(const PDFDocument* document);
/// Resets the object to the initial state.
@@ -800,6 +800,13 @@ public:
PDFObject createTrailerDictionary(PDFObjectReference catalog);
/// Sets annotation appearance state.
/// \param annotation Annotation
/// \param appearanceState Appearance state
void setAnnotationAppearanceState(PDFObjectReference annotation,
QByteArray appearanceState);
/// Sets annotation border.
/// \param annotation Annotation
/// \param hRadius Horizontal corner radius
@@ -913,6 +920,15 @@ public:
void setDocumentTitle(QString title);
/// Sets form field value. Value must be correct for this form field, no checking is performed. Also, if
/// you use this function, annotation widgets, which are attached to this form field, should also be
/// updated (for example, appearance state and sometimes appearance streams).
/// \param formField Form field
/// \param value Value
void setFormFieldValue(PDFObjectReference formField,
PDFObject value);
/// Set document language.
/// \param locale Locale, from which is language determined
void setLanguage(QLocale locale);
@@ -959,6 +975,38 @@ private:
PDFVersion m_version;
};
/// This class serves for document modification. While document is modified,
/// modification flags are gathered. At the end of the modification, it is checked,
/// if document was really changed.
class PDFFORQTLIBSHARED_EXPORT PDFDocumentModifier
{
public:
explicit PDFDocumentModifier(const PDFDocument* originalDocument);
/// Returns builder, which can modify document
PDFDocumentBuilder* getBuilder() { return &m_builder; }
/// Finalizes document modification and prepares new changed document.
/// If document content is equal to the original, then false is returned,
/// otherwise true is returned. If document was not modified,
/// then new document is not created and function \p getDocument
/// will return nullptr.
bool finalize();
PDFDocumentPointer getDocument() const { return m_modifiedDocument; }
PDFModifiedDocument::ModificationFlags getFlags() const { return m_modificationFlags; }
void markReset() { m_modificationFlags.setFlag(PDFModifiedDocument::Reset); }
void markAnnotationsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::Annotation); }
void markFormFieldChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::FormField); }
private:
const PDFDocument* m_originalDocument;
PDFDocumentBuilder m_builder;
PDFDocumentPointer m_modifiedDocument;
PDFModifiedDocument::ModificationFlags m_modificationFlags;
};
// Implementation
inline

View File

@@ -83,6 +83,7 @@ void PDFWidget::setDocument(const PDFModifiedDocument& document)
{
m_proxy->setDocument(document);
m_pageRenderingErrors.clear();
m_drawWidget->getWidget()->update();
}
void PDFWidget::updateRenderer(RendererEngine engine, int samplesCount)

View File

@@ -19,10 +19,12 @@
#include "pdfdocument.h"
#include "pdfdrawspacecontroller.h"
#include "pdfdrawwidget.h"
#include "pdfdocumentbuilder.h"
#include <QKeyEvent>
#include <QMouseEvent>
#include <QApplication>
#include <QByteArray>
namespace pdf
{
@@ -173,6 +175,16 @@ void PDFFormField::apply(const std::function<void (const PDFFormField*)>& functo
}
}
void PDFFormField::modify(const std::function<void (PDFFormField*)>& functor)
{
functor(this);
for (const PDFFormFieldPointer& childField : m_childFields)
{
childField->modify(functor);
}
}
PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField)
{
PDFFormFieldPointer result;
@@ -356,7 +368,16 @@ PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObje
return result;
}
PDFFormWidget::PDFFormWidget(PDFObjectReference widget, PDFFormField* parentField, PDFAnnotationAdditionalActions actions) :
bool PDFFormField::setValue(const SetValueParameters& parameters)
{
Q_UNUSED(parameters);
// Default behaviour: return false, value cannot be set
return false;
}
PDFFormWidget::PDFFormWidget(PDFObjectReference page, PDFObjectReference widget, PDFFormField* parentField, PDFAnnotationAdditionalActions actions) :
m_page(page),
m_widget(widget),
m_parentField(parentField),
m_actions(qMove(actions))
@@ -366,13 +387,16 @@ PDFFormWidget::PDFFormWidget(PDFObjectReference widget, PDFFormField* parentFiel
PDFFormWidget PDFFormWidget::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField)
{
PDFObjectReference pageReference;
PDFAnnotationAdditionalActions actions;
if (const PDFDictionary* annotationDictionary = storage->getDictionaryFromObject(storage->getObjectByReference(reference)))
{
PDFDocumentDataLoaderDecorator loader(storage);
pageReference = loader.readReferenceFromDictionary(annotationDictionary, "P");
actions = PDFAnnotationAdditionalActions::parse(storage, annotationDictionary->get("AA"), annotationDictionary->get("A"));
}
return PDFFormWidget(reference, parentField, qMove(actions));
return PDFFormWidget(pageReference, reference, parentField, qMove(actions));
}
PDFFormFieldButton::ButtonType PDFFormFieldButton::getButtonType() const
@@ -389,6 +413,105 @@ PDFFormFieldButton::ButtonType PDFFormFieldButton::getButtonType() const
return ButtonType::CheckBox;
}
QByteArray PDFFormFieldButton::getOnAppearanceState(const PDFFormManager* formManager, const PDFFormWidget* widget)
{
Q_ASSERT(formManager);
Q_ASSERT(widget);
const PDFDocument* document = formManager->getDocument();
Q_ASSERT(document);
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(document->getObjectByReference(widget->getWidget())))
{
PDFAppeareanceStreams streams = PDFAppeareanceStreams::parse(&document->getStorage(), dictionary->get("AP"));
QByteArrayList states = streams.getAppearanceStates(PDFAppeareanceStreams::Appearance::Normal);
for (const QByteArray& state : states)
{
if (!state.isEmpty() && state != "Off")
{
return state;
}
}
}
return QByteArray();
}
QByteArray PDFFormFieldButton::getOffAppearanceState(const PDFFormManager* formManager, const PDFFormWidget* widget)
{
Q_UNUSED(formManager);
Q_UNUSED(widget);
// 'Off' value is specified by PDF 1.7 specification. It has always value 'Off'.
// 'On' values can have different appearance states.
return "Off";
}
bool PDFFormFieldButton::setValue(const SetValueParameters& parameters)
{
// Do not allow to set value to push buttons
if (getFlags().testFlag(PushButton))
{
return false;
}
// If form field is readonly, and scope is user (form field is changed by user,
// not by calculated value), then we must not allow value change.
if (getFlags().testFlag(ReadOnly) && parameters.scope == SetValueParameters::Scope::User)
{
return false;
}
Q_ASSERT(parameters.formManager);
Q_ASSERT(parameters.modifier);
Q_ASSERT(parameters.value.isName());
PDFDocumentBuilder* builder = parameters.modifier->getBuilder();
QByteArray state = parameters.value.getString();
parameters.modifier->markFormFieldChanged();
builder->setFormFieldValue(getSelfReference(), parameters.value);
// Change widget appearance states
const bool isRadio = getFlags().testFlag(Radio);
const bool isRadioInUnison = getFlags().testFlag(RadiosInUnison);
const bool isSameValueForAllWidgets = !isRadio || isRadioInUnison;
const bool isAllowedToCheckAllOff = !getFlags().testFlag(NoToggleToOff);
bool hasWidgets = !m_widgets.empty();
bool isAnyWidgetToggledOn = false;
for (const PDFFormWidget& formWidget : getWidgets())
{
QByteArray onState = PDFFormFieldButton::getOnAppearanceState(parameters.formManager, &formWidget);
// We set appearance to 'On' if following two conditions both hold:
// 1) State equals to widget's "On" state
// 2) Either we are setting value to invoking widget, or setting of same
// value to other widgets is allowed (it is a checkbox, or radio in unison)
if (state == onState && (isSameValueForAllWidgets || formWidget.getWidget() == parameters.invokingWidget))
{
isAnyWidgetToggledOn = true;
builder->setAnnotationAppearanceState(formWidget.getWidget(), onState);
}
else
{
QByteArray offState = PDFFormFieldButton::getOffAppearanceState(parameters.formManager, &formWidget);
builder->setAnnotationAppearanceState(formWidget.getWidget(), offState);
}
parameters.modifier->markAnnotationsChanged();
}
// We must check, if correct value has been set. If form field has no widgets,
// but has same qualified name, then no check is performed (just form field value is set
// to same value in all form fields with same qualified name, according to the PDF specification.
if (hasWidgets && !isAnyWidgetToggledOn && !isAllowedToCheckAllOff)
{
return false;
}
return true;
}
PDFFormManager::PDFFormManager(PDFDrawWidgetProxy* proxy, QObject* parent) :
BaseClass(parent),
m_proxy(proxy),
@@ -503,6 +626,14 @@ void PDFFormManager::apply(const std::function<void (const PDFFormField*)>& func
}
}
void PDFFormManager::modify(const std::function<void (PDFFormField*)>& functor) const
{
for (const PDFFormFieldPointer& childField : m_form.getFormFields())
{
childField->modify(functor);
}
}
void PDFFormManager::setFocusToEditor(PDFFormFieldWidgetEditor* editor)
{
if (m_focusedEditor != editor)
@@ -603,6 +734,47 @@ const PDFAction* PDFFormManager::getAction(PDFAnnotationAdditionalActions::Actio
return nullptr;
}
void PDFFormManager::setFormFieldValue(PDFFormField::SetValueParameters parameters)
{
Q_ASSERT(parameters.invokingFormField);
Q_ASSERT(parameters.invokingWidget.isValid());
parameters.formManager = this;
parameters.scope = PDFFormField::SetValueParameters::Scope::User;
PDFDocumentModifier modifier(m_document);
parameters.modifier = &modifier;
if (parameters.invokingFormField->setValue(parameters))
{
// We must also set dependent fields with same name
QString qualifiedFormFieldName = parameters.invokingFormField->getName(PDFFormField::NameType::FullyQualified);
if (!qualifiedFormFieldName.isEmpty())
{
parameters.scope = PDFFormField::SetValueParameters::Scope::Internal;
auto updateDependentField = [&parameters, &qualifiedFormFieldName](PDFFormField* formField)
{
if (parameters.invokingFormField == formField)
{
// Do not update self
return;
}
if (qualifiedFormFieldName == formField->getName(PDFFormField::NameType::FullyQualified))
{
formField->setValue(parameters);
}
};
modify(updateDependentField);
}
if (modifier.finalize())
{
emit documentModified(modifier.getDocument(), modifier.getFlags());
}
}
}
void PDFFormManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
{
if (m_focusedEditor)
@@ -966,7 +1138,6 @@ void PDFFormFieldWidgetEditor::performKeypadNavigation(QWidget* widget, QKeyEven
const bool isLeft = key == Qt::Key_Left;
const bool isRight = key == Qt::Key_Right;
const bool isUp = key == Qt::Key_Up;
const bool isDown = key == Qt::Key_Down;
const bool isHorizontal = isLeft || isRight;
@@ -1032,7 +1203,13 @@ PDFFormFieldPushButtonEditor::PDFFormFieldPushButtonEditor(PDFFormManager* formM
}
void PDFFormFieldPushButtonEditor::keyPressEvent(QWidget* widget, QKeyEvent* event)
PDFFormFieldAbstractButtonEditor::PDFFormFieldAbstractButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent) :
BaseClass(formManager, formWidget, parent)
{
}
void PDFFormFieldAbstractButtonEditor::keyPressEvent(QWidget* widget, QKeyEvent* event)
{
switch (event->key())
{
@@ -1058,7 +1235,7 @@ void PDFFormFieldPushButtonEditor::keyPressEvent(QWidget* widget, QKeyEvent* eve
}
}
void PDFFormFieldPushButtonEditor::keyReleaseEvent(QWidget* widget, QKeyEvent* event)
void PDFFormFieldAbstractButtonEditor::keyReleaseEvent(QWidget* widget, QKeyEvent* event)
{
Q_UNUSED(widget);
@@ -1077,7 +1254,7 @@ void PDFFormFieldPushButtonEditor::keyReleaseEvent(QWidget* widget, QKeyEvent* e
}
}
void PDFFormFieldPushButtonEditor::mousePressEvent(QWidget* widget, QMouseEvent* event)
void PDFFormFieldAbstractButtonEditor::mousePressEvent(QWidget* widget, QMouseEvent* event)
{
Q_UNUSED(widget);
@@ -1106,6 +1283,33 @@ PDFFormFieldCheckableButtonEditor::PDFFormFieldCheckableButtonEditor(PDFFormMana
}
void PDFFormFieldCheckableButtonEditor::click()
{
QByteArray newState;
// First, check current state of form field
PDFDocumentDataLoaderDecorator loader(m_formManager->getDocument());
QByteArray state = loader.readName(m_formWidget.getParent()->getValue());
QByteArray onState = PDFFormFieldButton::getOnAppearanceState(m_formManager, &m_formWidget);
if (state != onState)
{
newState = onState;
}
else
{
newState = PDFFormFieldButton::getOffAppearanceState(m_formManager, &m_formWidget);
}
// We have a new state, try to apply it to form field
PDFFormField::SetValueParameters parameters;
parameters.formManager = m_formManager;
parameters.invokingWidget = m_formWidget.getWidget();
parameters.invokingFormField = m_formWidget.getParent();
parameters.scope = PDFFormField::SetValueParameters::Scope::User;
parameters.value = PDFObject::createName(std::make_shared<PDFString>(qMove(newState)));
m_formManager->setFormFieldValue(parameters);
}
PDFFormFieldComboBoxEditor::PDFFormFieldComboBoxEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent) :
BaseClass(formManager, formWidget, parent)
{

View File

@@ -19,6 +19,7 @@
#define PDFFORM_H
#include "pdfobject.h"
#include "pdfdocument.h"
#include "pdfannotation.h"
#include "pdfdocumentdrawinterface.h"
@@ -30,6 +31,7 @@ class PDFFormField;
class PDFFormManager;
class PDFObjectStorage;
class PDFModifiedDocument;
class PDFDocumentModifier;
using PDFFormFieldPointer = QSharedPointer<PDFFormField>;
using PDFFormFields = std::vector<PDFFormFieldPointer>;
@@ -40,8 +42,9 @@ class PDFFormWidget
{
public:
explicit inline PDFFormWidget() = default;
explicit inline PDFFormWidget(PDFObjectReference widget, PDFFormField* parentField, PDFAnnotationAdditionalActions actions);
explicit inline PDFFormWidget(PDFObjectReference page, PDFObjectReference widget, PDFFormField* parentField, PDFAnnotationAdditionalActions actions);
PDFObjectReference getPage() const { return m_page; }
PDFObjectReference getWidget() const { return m_widget; }
PDFFormField* getParent() const { return m_parentField; }
const PDFAction* getAction(PDFAnnotationAdditionalActions::Action action) const { return m_actions.getAction(action); }
@@ -54,6 +57,7 @@ public:
static PDFFormWidget parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField);
private:
PDFObjectReference m_page;
PDFObjectReference m_widget;
PDFFormField* m_parentField;
PDFAnnotationAdditionalActions m_actions;
@@ -200,6 +204,12 @@ public:
/// \param functor Functor to apply
void apply(const std::function<void(const PDFFormField*)>& functor) const;
/// Applies function to this form field and all its descendants,
/// in pre-order (first application is to the parent, following
/// calls to apply for children).
/// \param functor Functor to apply
void modify(const std::function<void(PDFFormField*)>& functor);
/// Returns action by type. If action is not found, nullptr is returned
/// \param action Action type
const PDFAction* getAction(PDFAnnotationAdditionalActions::Action action) const { return m_additionalActions.getAction(action); }
@@ -211,6 +221,29 @@ public:
/// \param parentField Parent field (or nullptr, if it is root field)
static PDFFormFieldPointer parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField);
struct SetValueParameters
{
enum class Scope
{
User, ///< Changed value comes from user input
Internal ///< Value is changed by some program operation (for example, calculation)
};
PDFObject value;
PDFObjectReference invokingWidget;
PDFFormField* invokingFormField = nullptr;
PDFDocumentModifier* modifier = nullptr;
PDFFormManager* formManager = nullptr;
Scope scope = Scope::User;
};
/// Sets value to the form field. If value has been correctly
/// set, then true is returned, otherwise false is returned.
/// This function also verifies, if value can be set (i.e. form field
/// is editable, and value is valid).
/// \param parameters Parameters
virtual bool setValue(const SetValueParameters& parameters);
protected:
PDFObjectReference m_selfReference;
FieldType m_fieldType = FieldType::Invalid;
@@ -243,10 +276,26 @@ public:
const QStringList& getOptions() const { return m_options; }
/// Returns appearance state, which corresponds to the checked
/// state of checkbox or radio button. If error occurs, then
/// empty byte array is returned.
/// \param formManager Form manager
/// \param widget Widget
static QByteArray getOnAppearanceState(const PDFFormManager* formManager, const PDFFormWidget* widget);
/// Returns appearance state, which corresponds to the unchecked
/// state of checkbox or radio button. If error occurs, then
/// empty byte array is returned.
/// \param formManager Form manager
/// \param widget Widget
static QByteArray getOffAppearanceState(const PDFFormManager* formManager, const PDFFormWidget* widget);
virtual bool setValue(const SetValueParameters& parameters) override;
private:
friend static PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField);
/// List of names of 'On' state for radio buttons. In widget annotation's appearance
/// List of export names of 'On' state for radio buttons. In widget annotation's appearance
/// dictionaries, state names are computer generated numbers (for example /1, /3, ...),
/// which are indices to this string list. This allows to distinguish between
/// different widget annotations, even if they have same value in m_options array.
@@ -410,8 +459,8 @@ protected:
bool m_hasFocus;
};
/// Editor for push buttons
class PDFFormFieldPushButtonEditor : public PDFFormFieldWidgetEditor
/// Editor for button-like editors
class PDFFormFieldAbstractButtonEditor : public PDFFormFieldWidgetEditor
{
Q_OBJECT
@@ -419,28 +468,47 @@ private:
using BaseClass = PDFFormFieldWidgetEditor;
public:
explicit PDFFormFieldPushButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent);
virtual ~PDFFormFieldPushButtonEditor() = default;
explicit PDFFormFieldAbstractButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent);
virtual ~PDFFormFieldAbstractButtonEditor() = default;
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
private:
void click();
protected:
virtual void click() = 0;
};
/// Editor for check boxes or radio buttons
class PDFFormFieldCheckableButtonEditor : public PDFFormFieldWidgetEditor
/// Editor for push buttons
class PDFFormFieldPushButtonEditor : public PDFFormFieldAbstractButtonEditor
{
Q_OBJECT
private:
using BaseClass = PDFFormFieldWidgetEditor;
using BaseClass = PDFFormFieldAbstractButtonEditor;
public:
explicit PDFFormFieldPushButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent);
virtual ~PDFFormFieldPushButtonEditor() = default;
protected:
virtual void click() override;
};
/// Editor for check boxes or radio buttons
class PDFFormFieldCheckableButtonEditor : public PDFFormFieldAbstractButtonEditor
{
Q_OBJECT
private:
using BaseClass = PDFFormFieldAbstractButtonEditor;
public:
explicit PDFFormFieldCheckableButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent);
virtual ~PDFFormFieldCheckableButtonEditor() = default;
protected:
virtual void click() override;
};
/// Editor for text fields
@@ -542,6 +610,12 @@ public:
/// \param functor Functor to apply
void apply(const std::function<void(const PDFFormField*)>& functor) const;
/// Applies function to all form fields present in the form,
/// in pre-order (first application is to the parent, following
/// calls to apply for children).
/// \param functor Functor to apply
void modify(const std::function<void(PDFFormField*)>& functor) const;
/// Sets focus to the editor. Is is allowed to pass nullptr to this
/// function, it means that no editor is focused.
/// \param editor Editor to be focused
@@ -586,6 +660,9 @@ public:
bool isValid() const { return editor != nullptr; }
};
/// Tries to set value to the form field
void setFormFieldValue(PDFFormField::SetValueParameters parameters);
// interface IDrawWidgetInputInterface
/// Handles key press event from widget
@@ -628,6 +705,7 @@ public:
signals:
void actionTriggered(const PDFAction* action);
void documentModified(PDFDocumentPointer document, PDFModifiedDocument::ModificationFlags flags);
private:
void updateFormWidgetEditors();