From 0f4eeeacb711ae17edc082bafb163fd6fe1c97ab Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Mon, 11 May 2020 19:34:17 +0200 Subject: [PATCH] Text form field bugfixing --- PdfForQtLib/sources/pdfdocumentbuilder.cpp | 12 ++- PdfForQtLib/sources/pdfdocumentbuilder.h | 5 ++ PdfForQtLib/sources/pdfform.cpp | 87 ++++++++++++++++++++++ PdfForQtLib/sources/pdfform.h | 7 +- 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/PdfForQtLib/sources/pdfdocumentbuilder.cpp b/PdfForQtLib/sources/pdfdocumentbuilder.cpp index 5180663..c2f8866 100644 --- a/PdfForQtLib/sources/pdfdocumentbuilder.cpp +++ b/PdfForQtLib/sources/pdfdocumentbuilder.cpp @@ -541,7 +541,7 @@ PDFObjectFactory& PDFObjectFactory::operator<<(WrapEmptyArray) return *this; } -PDFObjectFactory& PDFObjectFactory::operator<<(QString textString) +PDFObject PDFObjectFactory::createTextString(QString textString) { if (!PDFEncoding::canConvertToEncoding(textString, PDFEncoding::Encoding::PDFDoc)) { @@ -555,14 +555,18 @@ PDFObjectFactory& PDFObjectFactory::operator<<(QString textString) textStream << textString; } - addObject(PDFObject::createString(std::make_shared(qMove(ba)))); + return PDFObject::createString(std::make_shared(qMove(ba))); } else { // Use PDF document encoding - addObject(PDFObject::createString(std::make_shared(PDFEncoding::convertToEncoding(textString, PDFEncoding::Encoding::PDFDoc)))); + return PDFObject::createString(std::make_shared(PDFEncoding::convertToEncoding(textString, PDFEncoding::Encoding::PDFDoc))); } +} +PDFObjectFactory& PDFObjectFactory::operator<<(QString textString) +{ + addObject(createTextString(textString)); return *this; } @@ -764,8 +768,10 @@ void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference an PDFContentStreamBuilder builder(mediaBox.size(), PDFContentStreamBuilder::CoordinateSystem::PDF); AnnotationDrawParameters parameters; + parameters.annotation = annotation.data(); parameters.key = key; parameters.painter = builder.begin(); + parameters.formManager = m_formManager; annotation->draw(parameters); PDFContentStreamBuilder::ContentStream contentStream = builder.end(parameters.painter); diff --git a/PdfForQtLib/sources/pdfdocumentbuilder.h b/PdfForQtLib/sources/pdfdocumentbuilder.h index 9f540d6..7497840 100644 --- a/PdfForQtLib/sources/pdfdocumentbuilder.h +++ b/PdfForQtLib/sources/pdfdocumentbuilder.h @@ -134,6 +134,11 @@ public: PDFObject takeObject(); + /// Creates text string object from QString, using PDFDocEncoding, if possible, + /// if not, then UTF-16 BE encoding is used + /// \param textString Text to be converted + static PDFObject createTextString(QString textString); + private: void addObject(PDFObject object); diff --git a/PdfForQtLib/sources/pdfform.cpp b/PdfForQtLib/sources/pdfform.cpp index dc4d687..2634d87 100644 --- a/PdfForQtLib/sources/pdfform.cpp +++ b/PdfForQtLib/sources/pdfform.cpp @@ -773,6 +773,12 @@ const PDFAction* PDFFormManager::getAction(PDFAnnotationAdditionalActions::Actio void PDFFormManager::setFormFieldValue(PDFFormField::SetValueParameters parameters) { + if (!m_document) + { + // This can happen, when we are closing the document and some editor is opened + return; + } + Q_ASSERT(parameters.invokingFormField); Q_ASSERT(parameters.invokingWidget.isValid()); @@ -1154,6 +1160,11 @@ void PDFFormManager::updateFieldValues() { childField->reloadValue(&m_document->getStorage(), PDFObject()); } + + for (PDFFormFieldWidgetEditor* editor : m_widgetEditors) + { + editor->reloadValue(); + } } } @@ -1496,6 +1507,22 @@ void PDFFormFieldTextBoxEditor::setFocusImpl(bool focused) m_textEdit.setCursorPosition(m_textEdit.getPositionEnd(), false); m_textEdit.performSelectAll(); } + else if (!m_textEdit.isPassword()) // Passwords are not saved in the document + { + // If text has been changed, then commit it + PDFObject object = PDFObjectFactory::createTextString(m_textEdit.getText()); + + if (object != m_formWidget.getParent()->getValue()) + { + 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 = qMove(object); + m_formManager->setFormFieldValue(parameters); + } + } } PDFFormFieldTextBoxEditor::PDFFormFieldTextBoxEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent) : @@ -1514,6 +1541,23 @@ void PDFFormFieldTextBoxEditor::shortcutOverrideEvent(QWidget* widget, QKeyEvent void PDFFormFieldTextBoxEditor::keyPressEvent(QWidget* widget, QKeyEvent* event) { + if (!m_textEdit.isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) + { + // Commit the editor + m_formManager->setFocusToEditor(nullptr); + event->accept(); + return; + } + + if (event->key() == Qt::Key_Escape) + { + // Cancel the editor + reloadValue(); + m_formManager->setFocusToEditor(nullptr); + event->accept(); + return; + } + m_textEdit.keyPressEvent(widget, event); if (event->isAccepted()) @@ -1562,6 +1606,12 @@ void PDFFormFieldTextBoxEditor::mouseMoveEvent(QWidget* widget, QMouseEvent* eve } } +void PDFFormFieldTextBoxEditor::reloadValue() +{ + PDFDocumentDataLoaderDecorator loader(m_formManager->getDocument()); + m_textEdit.setText(loader.readTextString(m_formWidget.getParent()->getValue(), QString())); +} + void PDFFormFieldTextBoxEditor::draw(AnnotationDrawParameters& parameters) const { m_textEdit.draw(parameters, true); @@ -1846,6 +1896,10 @@ void PDFTextEditPseudowidget::keyPressEvent(QWidget* widget, QKeyEvent* event) const int position = (event->modifiers().testFlag(Qt::ControlModifier)) ? getCursorWordForward() : getCursorCharacterForward(); setCursorPosition(position, event->modifiers().testFlag(Qt::ShiftModifier)); } + else if (isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) + { + performInsertText(QString::fromUtf16(u"\u2028")); + } else { QString text = event->text(); @@ -2442,4 +2496,37 @@ int PDFTextEditPseudowidget::getCursorLineDown() const return m_positionCursor; } +bool PDFFormFieldText::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); + + PDFDocumentBuilder* builder = parameters.modifier->getBuilder(); + parameters.modifier->markFormFieldChanged(); + builder->setFormFieldValue(getSelfReference(), parameters.value); + m_value = parameters.value; + + // Change widget appearance states + for (const PDFFormWidget& formWidget : getWidgets()) + { + builder->updateAnnotationAppearanceStreams(formWidget.getWidget()); + parameters.modifier->markAnnotationsChanged(); + } + + return true; +} + } // namespace pdf diff --git a/PdfForQtLib/sources/pdfform.h b/PdfForQtLib/sources/pdfform.h index e4e9dc8..f355b88 100644 --- a/PdfForQtLib/sources/pdfform.h +++ b/PdfForQtLib/sources/pdfform.h @@ -316,6 +316,8 @@ public: const QString& getRichTextDefaultStyle() const { return m_defaultStyle; } const QString& getRichTextValue() const { return m_richTextValue; } + virtual bool setValue(const SetValueParameters& parameters) override; + private: friend static PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField); @@ -473,6 +475,7 @@ public: inline void clearSelection() { m_selectionStart = m_selectionEnd = 0; } + inline const QString& getText() const { return m_editText; } inline QString getSelectedText() const { return m_editText.mid(m_selectionStart, getSelectionLength()); } /// Sets (updates) text selection @@ -628,7 +631,7 @@ public: virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition); virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition); virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition); - + virtual void reloadValue() { } virtual bool isEditorDrawEnabled() const { return false; } const PDFFormWidget* getFormWidget() const { return &m_formWidget; } @@ -723,7 +726,7 @@ public: virtual void mousePressEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition); virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition); virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition); - + virtual void reloadValue() override; virtual bool isEditorDrawEnabled() const override { return m_hasFocus; } virtual void draw(AnnotationDrawParameters& parameters) const override;