okular/core/script/js_field.cpp
2023-06-22 17:40:50 +02:00

302 lines
8 KiB
C++

/*
SPDX-FileCopyrightText: 2008 Pino Toscano <pino@kde.org>
SPDX-FileCopyrightText: 2008 Harri Porten <porten@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "js_field_p.h"
#include <QDebug>
#include <QHash>
#include <QJSEngine>
#include <QTimer>
#include "../debug_p.h"
#include "../document_p.h"
#include "../form.h"
#include "../page.h"
#include "../page_p.h"
#include "js_display_p.h"
using namespace Okular;
#define OKULAR_NAME QStringLiteral("okular_name")
typedef QHash<FormField *, Page *> FormCache;
Q_GLOBAL_STATIC(FormCache, g_fieldCache)
typedef QHash<QString, FormField *> ButtonCache;
Q_GLOBAL_STATIC(ButtonCache, g_buttonCache)
// Helper for modified fields
static void updateField(FormField *field)
{
Page *page = g_fieldCache->value(field);
if (page) {
Document *doc = PagePrivate::get(page)->m_doc->m_parent;
const int pageNumber = page->number();
QTimer::singleShot(0, doc, [doc, pageNumber] { doc->refreshPixmaps(pageNumber); });
Q_EMIT doc->refreshFormWidget(field);
} else {
qWarning() << "Could not get page of field" << field;
}
}
// Field.doc
QJSValue JSField::doc() const
{
return qjsEngine(this)->globalObject();
}
// Field.name
QString JSField::name() const
{
return m_field->fullyQualifiedName();
}
// Field.readonly (getter)
bool JSField::readonly() const
{
return m_field->isReadOnly();
}
// Field.readonly (setter)
void JSField::setReadonly(bool readonly)
{
m_field->setReadOnly(readonly);
updateField(m_field);
}
static QString fieldGetTypeHelper(const FormField *field)
{
switch (field->type()) {
case FormField::FormButton: {
const FormFieldButton *button = static_cast<const FormFieldButton *>(field);
switch (button->buttonType()) {
case FormFieldButton::Push:
return QStringLiteral("button");
case FormFieldButton::CheckBox:
return QStringLiteral("checkbox");
case FormFieldButton::Radio:
return QStringLiteral("radiobutton");
}
break;
}
case FormField::FormText:
return QStringLiteral("text");
case FormField::FormChoice: {
const FormFieldChoice *choice = static_cast<const FormFieldChoice *>(field);
switch (choice->choiceType()) {
case FormFieldChoice::ComboBox:
return QStringLiteral("combobox");
case FormFieldChoice::ListBox:
return QStringLiteral("listbox");
}
break;
}
case FormField::FormSignature:
return QStringLiteral("signature");
}
return QString();
}
// Field.type
QString JSField::type() const
{
return fieldGetTypeHelper(m_field);
}
QJSValue JSField::fieldGetValueCore(bool asString) const
{
QJSValue result(QJSValue::UndefinedValue);
switch (m_field->type()) {
case FormField::FormButton: {
const FormFieldButton *button = static_cast<const FormFieldButton *>(m_field);
if (button->state()) {
result = QStringLiteral("Yes");
} else {
result = QStringLiteral("Off");
}
break;
}
case FormField::FormText: {
const FormFieldText *text = static_cast<const FormFieldText *>(m_field);
const QLocale locale;
bool ok;
const double textAsNumber = locale.toDouble(text->text(), &ok);
if (ok && !asString) {
result = textAsNumber;
} else {
result = text->text();
}
break;
}
case FormField::FormChoice: {
const FormFieldChoice *choice = static_cast<const FormFieldChoice *>(m_field);
const QList<int> currentChoices = choice->currentChoices();
if (currentChoices.count() == 1) {
result = choice->exportValueForChoice(choice->choices().at(currentChoices[0]));
}
break;
}
case FormField::FormSignature: {
break;
}
}
qCDebug(OkularCoreDebug) << "fieldGetValueCore:"
<< " Field: " << m_field->fullyQualifiedName() << " Type: " << fieldGetTypeHelper(m_field) << " Value: " << result.toString() << (result.isString() ? "(as string)" : "");
return result;
}
// Field.value (getter)
QJSValue JSField::value() const
{
return fieldGetValueCore(/*asString*/ false);
}
// Field.value (setter)
void JSField::setValue(const QJSValue &value)
{
qCDebug(OkularCoreDebug) << "fieldSetValue: Field: " << m_field->fullyQualifiedName() << " Type: " << fieldGetTypeHelper(m_field) << " Value: " << value.toString();
switch (m_field->type()) {
case FormField::FormButton: {
FormFieldButton *button = static_cast<FormFieldButton *>(m_field);
const QString text = value.toString();
if (text == QStringLiteral("Yes")) {
button->setState(true);
updateField(m_field);
} else if (text == QStringLiteral("Off")) {
button->setState(false);
updateField(m_field);
}
break;
}
case FormField::FormText: {
FormFieldText *textField = static_cast<FormFieldText *>(m_field);
const QString text = value.toString();
if (text != textField->text()) {
textField->setText(text);
updateField(m_field);
}
break;
}
case FormField::FormChoice: {
FormFieldChoice *choice = static_cast<FormFieldChoice *>(m_field);
Q_UNUSED(choice); // ###
break;
}
case FormField::FormSignature: {
break;
}
}
}
// Field.valueAsString (getter)
QJSValue JSField::valueAsString() const
{
return fieldGetValueCore(/*asString*/ true);
}
// Field.hidden (getter)
bool JSField::hidden() const
{
return !m_field->isVisible();
}
// Field.hidden (setter)
void JSField::setHidden(bool hidden)
{
m_field->setVisible(!hidden);
updateField(m_field);
}
// Field.display (getter)
int JSField::display() const
{
bool visible = m_field->isVisible();
if (visible) {
return m_field->isPrintable() ? FormDisplay::FormVisible : FormDisplay::FormNoPrint;
}
return m_field->isPrintable() ? FormDisplay::FormNoView : FormDisplay::FormHidden;
}
// Field.display (setter)
void JSField::setDisplay(int display)
{
switch (display) {
case FormDisplay::FormVisible:
m_field->setVisible(true);
m_field->setPrintable(true);
break;
case FormDisplay::FormHidden:
m_field->setVisible(false);
m_field->setPrintable(false);
break;
case FormDisplay::FormNoPrint:
m_field->setVisible(true);
m_field->setPrintable(false);
break;
case FormDisplay::FormNoView:
m_field->setVisible(false);
m_field->setPrintable(true);
break;
}
updateField(m_field);
}
// Instead of getting the Icon, we pick the field.
QJSValue JSField::buttonGetIcon([[maybe_unused]] int nFace) const
{
QJSValue fieldObject;
fieldObject.setProperty(OKULAR_NAME, m_field->fullyQualifiedName());
g_buttonCache->insert(m_field->fullyQualifiedName(), m_field);
return fieldObject;
}
/*
* Now we send to the button what Icon should be drawn on it
*/
void JSField::buttonSetIcon(const QJSValue &oIcon, [[maybe_unused]] int nFace)
{
const QString fieldName = oIcon.property(OKULAR_NAME).toString();
if (m_field->type() == Okular::FormField::FormButton) {
FormFieldButton *button = static_cast<FormFieldButton *>(m_field);
button->setIcon(g_buttonCache->value(fieldName));
}
updateField(m_field);
}
JSField::JSField(FormField *field, QObject *parent)
: QObject(parent)
, m_field(field)
{
}
JSField::~JSField() = default;
QJSValue JSField::wrapField(QJSEngine *engine, FormField *field, Page *page)
{
// ### cache unique wrapper
QJSValue f = engine->newQObject(new JSField(field));
f.setProperty(QStringLiteral("page"), page->number());
g_fieldCache->insert(field, page);
return f;
}
void JSField::clearCachedFields()
{
if (g_fieldCache.exists()) {
g_fieldCache->clear();
}
if (g_buttonCache.exists()) {
g_buttonCache->clear();
}
}