Implement keystroke commit events

When a form field loses focus a special keystroke event with
willCommit=true is sent.

This is based on work by Joao Netto <joaonetto901@gmail.com>
remotes/origin/work/fhek/foreground_background_text
Nicolas Fella 4 years ago committed by Albert Astals Cid
parent 1aa175cf3f
commit d1ecad897c
  1. 5
      autotests/CMakeLists.txt
  2. BIN
      autotests/data/keystroketest.pdf
  3. 106
      autotests/keystroketest.cpp
  4. 29
      core/document.cpp
  5. 8
      core/document.h
  6. 12
      core/script/event.cpp
  7. 3
      core/script/event_p.h
  8. 6
      core/script/kjs_event.cpp
  9. 10
      part/formwidgets.cpp

@ -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

Binary file not shown.

@ -0,0 +1,106 @@
/*
SPDX-FileCopyrightText: 2019 João Netto <joaonetto901@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QtTest>
#include "../settings_core.h"
#include <QLocale>
#include <QMap>
#include <QMimeDatabase>
#include <QMimeType>
#include <core/document.h>
#include <core/form.h>
#include <core/page.h>
#include <qtestcase.h>
#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<QString, Okular::FormField *> 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<Okular::FormField *> pageFormFields = page->formFields();
for (Okular::FormField *ff : pageFormFields) {
m_fields.insert(ff->name(), ff);
}
}
void KeystrokeTest::testCommit()
{
Okular::FormFieldText *fft = reinterpret_cast<Okular::FormFieldText *>(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<Okular::FormFieldText *>(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"

@ -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 = Event::createKeystrokeEvent(fft, d->m_pagesVector[foundPage]);
event->setWillCommit(true);
const ScriptAction *linkscript = static_cast<const ScriptAction *>(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)

@ -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.
*

@ -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> Event::createFormCalculateEvent(FormField *target, Page *targetPage, FormField *source, Page *sourcePage, const QString &targetName)
{

@ -105,6 +105,9 @@ public:
bool shiftModifier() const;
void setShiftModifier(bool shiftModifier);
bool willCommit() const;
void setWillCommit(bool willCommit);
static std::shared_ptr<Event> createFormCalculateEvent(FormField *target, Page *targetPage, FormField *source = nullptr, Page *sourcePage = nullptr, const QString &targetName = QString());
static std::shared_ptr<Event> createFormatEvent(FormField *target, Page *targetPage, const QString &targetName = QString());
static std::shared_ptr<Event> createKeystrokeEvent(FormField *target, Page *targetPage);

@ -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<Event *>(object);
return KJSBoolean(event->willCommit());
}
void JSEvent::initType(KJSContext *ctx)

@ -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<Okular::FormFieldText *>(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<Okular::FormFieldText *>(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<Okular::FormFieldText *>(m_ff));
}
if (const Okular::Action *action = m_ff->additionalAction(Okular::FormField::FormatField)) {
m_controller->document()->processFormatAction(action, static_cast<Okular::FormFieldText *>(m_ff));
}

Loading…
Cancel
Save