diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index fd9872cee..47b350989 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -48,6 +48,11 @@ if(Poppler_Qt5_FOUND) LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore ) + ecm_add_test(keystroketest.cpp + TEST_NAME "keystroketest" + LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore + ) + ecm_add_test(signunsignedfieldtest TEST_NAME "signunsignedfieldtest" LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore diff --git a/autotests/data/keystroketest.pdf b/autotests/data/keystroketest.pdf new file mode 100644 index 000000000..ab65eb9af Binary files /dev/null and b/autotests/data/keystroketest.pdf differ diff --git a/autotests/keystroketest.cpp b/autotests/keystroketest.cpp new file mode 100644 index 000000000..9277b96e2 --- /dev/null +++ b/autotests/keystroketest.cpp @@ -0,0 +1,106 @@ +/* + SPDX-FileCopyrightText: 2019 João Netto + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include + +#include "../settings_core.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../generators/poppler/config-okular-poppler.h" + +class KeystrokeTest : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void testCommit(); + void testKeystroke(); + +private: + Okular::Document *m_document; + QMap m_fields; +}; + +void KeystrokeTest::initTestCase() +{ + Okular::SettingsCore::instance(QStringLiteral("keystroketest")); + m_document = new Okular::Document(nullptr); + + // Force consistent locale + QLocale locale(QStringLiteral("en_US")); + QLocale::setDefault(locale); + + const QString testFile = QStringLiteral(KDESRCDIR "data/keystroketest.pdf"); + QMimeDatabase db; + const QMimeType mime = db.mimeTypeForFile(testFile); + QCOMPARE(m_document->openDocument(testFile, QUrl(), mime), Okular::Document::OpenSuccess); + + const Okular::Page *page = m_document->page(0); + const QLinkedList pageFormFields = page->formFields(); + for (Okular::FormField *ff : pageFormFields) { + m_fields.insert(ff->name(), ff); + } +} + +void KeystrokeTest::testCommit() +{ + Okular::FormFieldText *fft = reinterpret_cast(m_fields[QStringLiteral("field2")]); + + // text that will be accepted + fft->setText(QStringLiteral("Lorem ipsum")); + m_document->processKeystrokeCommitAction(fft->additionalAction(Okular::FormField::FieldModified), fft); + QCOMPARE(fft->text(), QStringLiteral("Lorem ipsum")); + + // text that will be rejected + fft->setText(QStringLiteral("foo")); + m_document->processKeystrokeCommitAction(fft->additionalAction(Okular::FormField::FieldModified), fft); + QEXPECT_FAIL("", "reset to commited value not implemented", Continue); + QCOMPARE(fft->text(), QStringLiteral("Lorem ipsum")); +} + +void KeystrokeTest::testKeystroke() +{ + Okular::FormFieldText *fft = reinterpret_cast(m_fields[QStringLiteral("field3")]); + + // accept + m_document->processKeystrokeAction(fft->additionalAction(Okular::FormField::FieldModified), fft, QStringLiteral("hello")); + QCOMPARE(fft->text(), QStringLiteral("hello")); + + // accept + m_document->processKeystrokeAction(fft->additionalAction(Okular::FormField::FieldModified), fft, QStringLiteral("e")); + QCOMPARE(fft->text(), QStringLiteral("e")); + + // accept + m_document->processKeystrokeAction(fft->additionalAction(Okular::FormField::FieldModified), fft, QStringLiteral("ee")); + QCOMPARE(fft->text(), QStringLiteral("ee")); + + // accept + m_document->processKeystrokeAction(fft->additionalAction(Okular::FormField::FieldModified), fft, QStringLiteral("eee")); + QCOMPARE(fft->text(), QStringLiteral("eee")); + + // reject + m_document->processKeystrokeAction(fft->additionalAction(Okular::FormField::FieldModified), fft, QStringLiteral("eeef")); + QCOMPARE(fft->text(), QStringLiteral("eee")); +} + +void KeystrokeTest::cleanupTestCase() +{ + m_document->closeDocument(); + delete m_document; +} + +QTEST_MAIN(KeystrokeTest) +#include "keystroketest.moc" diff --git a/core/document.cpp b/core/document.cpp index ecb4b6c85..73f6a5344 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -4162,6 +4162,35 @@ void Document::processKeystrokeAction(const Action *action, Okular::FormFieldTex } } +void Document::processKeystrokeCommitAction(const Action *action, Okular::FormFieldText *fft) +{ + if (action->actionType() != Action::Script) { + qCDebug(OkularCoreDebug) << "Unsupported action type" << action->actionType() << "for keystroke."; + return; + } + // Lookup the page of the FormFieldText + int foundPage = d->findFieldPageNumber(fft); + + if (foundPage == -1) { + qCDebug(OkularCoreDebug) << "Could not find page for formfield!"; + return; + } + + std::shared_ptr event = Event::createKeystrokeEvent(fft, d->m_pagesVector[foundPage]); + event->setWillCommit(true); + + const ScriptAction *linkscript = static_cast(action); + + d->executeScriptEvent(event, linkscript); + + if (event->returnCode()) { + fft->setText(event->value().toString()); + // TODO commit value + } else { + // TODO reset to committed value + } +} + void Document::processFocusAction(const Action *action, Okular::FormField *field) { if (!action || action->actionType() != Action::Script) diff --git a/core/document.h b/core/document.h index 6cb2d7f8f..558d94ddd 100644 --- a/core/document.h +++ b/core/document.h @@ -688,6 +688,14 @@ public: */ void processKeystrokeAction(const Action *action, Okular::FormFieldText *fft, const QVariant &newValue); + /** + * Processes the given keystroke @p action on @p fft. + * This will set event.willCommit=true + * + * @since 22.04 + */ + void processKeystrokeCommitAction(const Action *action, Okular::FormFieldText *fft); + /** * Processes the given focus action on the field. * diff --git a/core/script/event.cpp b/core/script/event.cpp index 19b846e9d..ec0f93efb 100644 --- a/core/script/event.cpp +++ b/core/script/event.cpp @@ -22,6 +22,7 @@ public: , m_eventType(eventType) , m_returnCode(false) , m_shiftModifier(false) + , m_willCommit(false) { } @@ -34,6 +35,7 @@ public: QVariant m_value; bool m_returnCode; bool m_shiftModifier; + bool m_willCommit; }; Event::Event() @@ -169,6 +171,16 @@ void Event::setShiftModifier(bool shiftModifier) d->m_shiftModifier = shiftModifier; } +bool Event::willCommit() const +{ + return d->m_willCommit; +} + +void Event::setWillCommit(bool willCommit) +{ + d->m_willCommit = willCommit; +} + // static std::shared_ptr Event::createFormCalculateEvent(FormField *target, Page *targetPage, FormField *source, Page *sourcePage, const QString &targetName) { diff --git a/core/script/event_p.h b/core/script/event_p.h index 9e3a3890d..f3772722d 100644 --- a/core/script/event_p.h +++ b/core/script/event_p.h @@ -105,6 +105,9 @@ public: bool shiftModifier() const; void setShiftModifier(bool shiftModifier); + bool willCommit() const; + void setWillCommit(bool willCommit); + static std::shared_ptr createFormCalculateEvent(FormField *target, Page *targetPage, FormField *source = nullptr, Page *sourcePage = nullptr, const QString &targetName = QString()); static std::shared_ptr createFormatEvent(FormField *target, Page *targetPage, const QString &targetName = QString()); static std::shared_ptr createKeystrokeEvent(FormField *target, Page *targetPage); diff --git a/core/script/kjs_event.cpp b/core/script/kjs_event.cpp index 40af6f79d..108be68d5 100644 --- a/core/script/kjs_event.cpp +++ b/core/script/kjs_event.cpp @@ -115,10 +115,10 @@ static void eventSetReturnCode(KJSContext *ctx, void *object, KJSObject value) } // Event.willCommit (getter) -static KJSObject eventGetWillCommit(KJSContext *, void * /*object*/) +static KJSObject eventGetWillCommit(KJSContext *, void *object) { - // TODO Someone try to understand the defintion of willCommit better from js_api_reference.pdf - return KJSBoolean(true); + const Event *event = reinterpret_cast(object); + return KJSBoolean(event->willCommit()); } void JSEvent::initType(KJSContext *ctx) diff --git a/part/formwidgets.cpp b/part/formwidgets.cpp index c28bd3702..a6b570fb7 100644 --- a/part/formwidgets.cpp +++ b/part/formwidgets.cpp @@ -502,6 +502,11 @@ bool FormLineEdit::event(QEvent *e) if (focusEvent->reason() == Qt::OtherFocusReason || focusEvent->reason() == Qt::ActiveWindowFocusReason) return true; + if (m_ff->additionalAction(Okular::FormField::FieldModified) && !m_ff->isReadOnly()) { + Okular::FormFieldText *form = static_cast(m_ff); + m_controller->document()->processKeystrokeCommitAction(m_ff->additionalAction(Okular::FormField::FieldModified), form); + } + if (const Okular::Action *action = m_ff->additionalAction(Okular::Annotation::FocusOut)) { bool ok = false; m_controller->document()->processValidateAction(action, static_cast(m_ff), ok); @@ -637,6 +642,11 @@ bool TextAreaEdit::event(QEvent *e) m_editing = true; } else if (e->type() == QEvent::FocusOut) { m_editing = false; + + if (m_ff->additionalAction(Okular::FormField::FieldModified) && !m_ff->isReadOnly()) { + m_controller->document()->processKeystrokeCommitAction(m_ff->additionalAction(Okular::FormField::FieldModified), static_cast(m_ff)); + } + if (const Okular::Action *action = m_ff->additionalAction(Okular::FormField::FormatField)) { m_controller->document()->processFormatAction(action, static_cast(m_ff)); }