Keystroke, format, validate, calculate events support for combo boxes.

Added keystroke, format, validate, calculate events for combo boxes. Also did some refactoring for recalculateForms method.
This commit is contained in:
Pratham Gandhi 2024-09-15 20:39:31 +00:00 committed by Albert Astals Cid
parent 1cad230102
commit 5b449e5fdf
10 changed files with 156 additions and 37 deletions

View file

@ -245,9 +245,9 @@ void FormatTest::testDateFormat()
QFETCH(QString, text);
QFETCH(QString, result);
Okular::FormFieldText *fft = reinterpret_cast<Okular::FormFieldText *>(m_fields[fieldName]);
fft->setText(text);
m_document->processFormatAction(fft->additionalAction(Okular::FormField::FormatField), fft);
Okular::FormField *ff = m_fields[fieldName];
ff->setValue(QVariant(text));
m_document->processFormatAction(ff->additionalAction(Okular::FormField::FormatField), ff);
QCOMPARE(m_formattedText, result);
}

View file

@ -423,11 +423,12 @@ void KeystrokeTest::testDateKeystrokeCommit()
QFETCH(QString, text);
QFETCH(QString, result);
Okular::FormFieldText *fft = reinterpret_cast<Okular::FormFieldText *>(m_AFMethodsTestsFields[fieldName]);
fft->setText(text);
m_AFMethodsTestsDocument->processKeystrokeCommitAction(fft->additionalAction(Okular::FormField::FieldModified), fft);
Okular::FormField *ff = m_AFMethodsTestsFields[fieldName];
ff->setValue(QVariant(text));
bool returnCode = true;
m_AFMethodsTestsDocument->processKeystrokeCommitAction(ff->additionalAction(Okular::FormField::FieldModified), ff, returnCode);
QCOMPARE(fft->text(), result);
QCOMPARE(ff->value().toString(), result);
}
void KeystrokeTest::testDateKeystrokeCommit_data()

View file

@ -1205,34 +1205,29 @@ void DocumentPrivate::recalculateForms()
if (form->id() == formId) {
const Action *action = form->additionalAction(FormField::CalculateField);
if (action) {
FormFieldText *fft = dynamic_cast<FormFieldText *>(form);
std::shared_ptr<Event> event;
QString oldVal;
if (fft) {
if (dynamic_cast<FormFieldText *>(form) || dynamic_cast<FormFieldChoice *>(form)) {
// Prepare text calculate event
event = Event::createFormCalculateEvent(fft, m_pagesVector[pageIdx]);
if (!m_scripter) {
m_scripter = new Scripter(this);
}
m_scripter->setEvent(event.get());
event = Event::createFormCalculateEvent(form, m_pagesVector[pageIdx]);
const ScriptAction *linkscript = static_cast<const ScriptAction *>(action);
executeScriptEvent(event, linkscript);
// The value maybe changed in javascript so save it first.
oldVal = fft->text();
}
oldVal = form->value().toString();
m_parent->processAction(action);
if (event && fft) {
// Update text field from calculate
m_scripter->setEvent(nullptr);
const QString newVal = event->value().toString();
if (newVal != oldVal) {
fft->setText(newVal);
fft->setAppearanceText(newVal);
if (const Okular::Action *action = fft->additionalAction(Okular::FormField::FormatField)) {
// The format action handles the refresh.
m_parent->processFormatAction(action, form);
} else {
Q_EMIT m_parent->refreshFormWidget(fft);
pageNeedsRefresh = true;
if (event) {
// Update text field from calculate
const QString newVal = event->value().toString();
if (newVal != oldVal) {
form->setValue(QVariant(newVal));
form->setAppearanceValue(QVariant(newVal));
if (const Okular::Action *action = form->additionalAction(Okular::FormField::FormatField)) {
// The format action handles the refresh.
m_parent->processFormatAction(action, form);
} else {
Q_EMIT m_parent->refreshFormWidget(form);
pageNeedsRefresh = true;
}
}
}
}

View file

@ -378,6 +378,45 @@ QString FormFieldChoice::exportValueForChoice(const QString &choice) const
return d->exportValues.value(choice, choice);
}
void FormFieldChoice::setValue(const QVariant &value)
{
if (choiceType() == ComboBox) {
const QStringList availableChoices = choices();
const QString valueToSet = value.toString();
for (int i = 0; i < availableChoices.size(); i++) {
if (valueToSet == availableChoices[i]) {
const QList oneChoiceList = {i};
setCurrentChoices(oneChoiceList);
return; // We expect to set only one element for a combo box
}
}
// If the value to be set is not present in the available choices
setEditChoice(valueToSet);
} else {
// TODO what to set for ListBox.
}
}
QVariant FormFieldChoice::value() const
{
if (choiceType() == ComboBox) {
if (currentChoices().isEmpty()) {
return QVariant(editChoice());
}
return QVariant(choices().at(currentChoices().constFirst()));
} else {
// TODO what to return for ListBox. Temporarily return empty string.
return QVariant(QString());
}
}
void FormFieldChoice::setAppearanceValue(const QVariant &value)
{
if (choiceType() == ComboBox) {
setAppearanceChoiceText(value.toString());
}
}
class Okular::FormFieldSignaturePrivate : public Okular::FormFieldPrivate
{
public:

View file

@ -502,6 +502,38 @@ public:
*/
QString exportValueForChoice(const QString &choice) const;
/**
* Sets the @p text which should be rendered by the PDF in the position of choice FormField.
*
* @since 24.12
*/
virtual void setAppearanceChoiceText(const QString &text) = 0;
/**
* Sets the @p value asssociated with the choice form field.
* It does not set anything for ListBox for now, only for the ComboBox.
*
* Expected type of @p value is QString.
* @since 24.12
*/
void setValue(const QVariant &value) override;
/**
* Returns the value associated with the choice form field.
* In case of ComboBox, if there is any selection, then the selected value is returned, else the value entered in editText of the comboBox.
* Returns empty string for ListBox for now.
*
* @since 24.12
*/
QVariant value() const override;
/**
* Sets the appearance @p value associated with the form field.
*
* @since 24.12
*/
void setAppearanceValue(const QVariant &value) override;
protected:
FormFieldChoice();

View file

@ -257,10 +257,7 @@ std::shared_ptr<Event> Event::createFormCalculateEvent(FormField *target, Page *
ret->setTargetPage(targetPage);
ret->setTargetName(targetName);
const FormFieldText *fft = dynamic_cast<FormFieldText *>(target);
if (fft) {
ret->setValue(QVariant(fft->text()));
}
ret->setValue(target->value());
return ret;
}

View file

@ -377,6 +377,15 @@ void PopplerFormFieldChoice::setEditChoice(const QString &text)
m_field->setEditChoice(text);
}
void PopplerFormFieldChoice::setAppearanceChoiceText(const QString &text)
{
#if POPPLER_VERSION_MACRO >= QT_VERSION_CHECK(24, 8, 0)
m_field->setAppearanceChoiceText(text);
#else
Q_UNUSED(text);
#endif
}
Qt::Alignment PopplerFormFieldChoice::textAlignment() const
{
return Qt::AlignTop | m_field->textAlignment();

View file

@ -114,6 +114,7 @@ public:
void setCurrentChoices(const QList<int> &choices) override;
QString editChoice() const override;
void setEditChoice(const QString &text) override;
void setAppearanceChoiceText(const QString &text) override;
Qt::Alignment textAlignment() const override;
bool canBeSpellChecked() const override;

View file

@ -85,7 +85,7 @@ void FormWidgetsController::signalMouseAction(Okular::Action *action, Okular::Fo
void FormWidgetsController::processScriptAction(Okular::Action *a, Okular::FormField *field, Okular::Annotation::AdditionalActionType type)
{
// If it's not a Action Script or if the field is not a FormText, handle it normally
if (a->actionType() != Okular::Action::Script || field->type() != Okular::FormField::FormText) {
if (a->actionType() != Okular::Action::Script || field->type() != Okular::FormField::FormText || field->type() != Okular::FormField::FormChoice) {
Q_EMIT action(a);
return;
}
@ -1065,6 +1065,7 @@ ComboEdit::ComboEdit(Okular::FormFieldChoice *choice, PageView *pageView)
connect(this, &QComboBox::editTextChanged, this, &ComboEdit::slotValueChanged);
connect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged);
m_editing = false;
setVisible(choice->isVisible());
setCursor(Qt::ArrowCursor);
m_prevCursorPos = lineEdit()->cursorPosition();
@ -1090,10 +1091,19 @@ void ComboEdit::slotValueChanged()
prevText = form->choices().at(form->currentChoices().constFirst());
}
int cursorPos = lineEdit()->cursorPosition();
int cursorPos;
if (text != prevText) {
Q_EMIT m_controller->formComboChangedByWidget(pageItem()->pageNumber(), form, currentText(), cursorPos, m_prevCursorPos, m_prevAnchorPos);
if (form->additionalAction(Okular::FormField::FieldModified) && m_editing && !form->isReadOnly()) {
m_controller->document()->processKeystrokeAction(form->additionalAction(Okular::FormField::FieldModified), form, lineEdit()->text(), m_prevCursorPos, m_prevAnchorPos);
}
cursorPos = lineEdit()->cursorPosition();
if (text == lineEdit()->text()) {
Q_EMIT m_controller->formComboChangedByWidget(pageItem()->pageNumber(), form, currentText(), cursorPos, m_prevCursorPos, m_prevAnchorPos);
}
} else {
cursorPos = lineEdit()->cursorPosition();
}
m_prevCursorPos = cursorPos;
m_prevAnchorPos = cursorPos;
if (lineEdit()->hasSelectedText()) {
@ -1176,6 +1186,40 @@ bool ComboEdit::event(QEvent *e)
Q_EMIT m_controller->requestRedo();
return true;
}
} else if (e->type() == QEvent::FocusIn) {
const auto ffc = static_cast<Okular::FormFieldChoice *>(m_ff);
QString prevText;
if (ffc->currentChoices().isEmpty()) {
prevText = ffc->editChoice();
} else {
prevText = ffc->choices().at(ffc->currentChoices().constFirst());
}
if (lineEdit()->text() != prevText) {
lineEdit()->setText(prevText);
}
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(e);
if (focusEvent->reason() != Qt::ActiveWindowFocusReason) {
if (const Okular::Action *action = m_ff->additionalAction(Okular::Annotation::FocusIn)) {
m_controller->document()->processFocusAction(action, m_ff);
}
}
setFocus();
m_editing = true;
} else if (e->type() == QEvent::FocusOut) {
m_editing = false;
// Don't worry about focus events from other sources than the user FocusEvent to edit the field
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(e);
if (focusEvent->reason() == Qt::OtherFocusReason || focusEvent->reason() == Qt::ActiveWindowFocusReason) {
return true;
}
m_controller->document()->processKVCFActions(m_ff);
if (const Okular::Action *action = m_ff->additionalAction(Okular::Annotation::FocusOut)) {
m_controller->document()->processFocusAction(action, m_ff);
}
}
return QComboBox::event(e);
}

View file

@ -317,6 +317,7 @@ private Q_SLOTS:
private:
int m_prevCursorPos;
int m_prevAnchorPos;
bool m_editing;
DECLARE_ADDITIONAL_ACTIONS
protected: