File indexing completed on 2024-05-12 04:33:32
0001 /* 0002 SPDX-FileCopyrightText: 2008 Pino Toscano <pino@kde.org> 0003 SPDX-FileCopyrightText: 2008 Harri Porten <porten@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "js_field_p.h" 0009 0010 #include <QDebug> 0011 #include <QHash> 0012 #include <QJSEngine> 0013 #include <QTimer> 0014 0015 #include "../debug_p.h" 0016 #include "../document_p.h" 0017 #include "../form.h" 0018 #include "../page.h" 0019 #include "../page_p.h" 0020 #include "js_display_p.h" 0021 0022 using namespace Okular; 0023 0024 #define OKULAR_NAME QStringLiteral("okular_name") 0025 0026 typedef QHash<FormField *, Page *> FormCache; 0027 Q_GLOBAL_STATIC(FormCache, g_fieldCache) 0028 typedef QHash<QString, FormField *> ButtonCache; 0029 Q_GLOBAL_STATIC(ButtonCache, g_buttonCache) 0030 0031 // Helper for modified fields 0032 static void updateField(FormField *field) 0033 { 0034 Page *page = g_fieldCache->value(field); 0035 if (page) { 0036 Document *doc = PagePrivate::get(page)->m_doc->m_parent; 0037 const int pageNumber = page->number(); 0038 QTimer::singleShot(0, doc, [doc, pageNumber] { doc->refreshPixmaps(pageNumber); }); 0039 Q_EMIT doc->refreshFormWidget(field); 0040 } else { 0041 qWarning() << "Could not get page of field" << field; 0042 } 0043 } 0044 0045 // Field.doc 0046 QJSValue JSField::doc() const 0047 { 0048 return qjsEngine(this)->globalObject(); 0049 } 0050 0051 // Field.name 0052 QString JSField::name() const 0053 { 0054 return m_field->fullyQualifiedName(); 0055 } 0056 0057 // Field.readonly (getter) 0058 bool JSField::readonly() const 0059 { 0060 return m_field->isReadOnly(); 0061 } 0062 0063 // Field.readonly (setter) 0064 void JSField::setReadonly(bool readonly) 0065 { 0066 m_field->setReadOnly(readonly); 0067 0068 updateField(m_field); 0069 } 0070 0071 static QString fieldGetTypeHelper(const FormField *field) 0072 { 0073 switch (field->type()) { 0074 case FormField::FormButton: { 0075 const FormFieldButton *button = static_cast<const FormFieldButton *>(field); 0076 switch (button->buttonType()) { 0077 case FormFieldButton::Push: 0078 return QStringLiteral("button"); 0079 case FormFieldButton::CheckBox: 0080 return QStringLiteral("checkbox"); 0081 case FormFieldButton::Radio: 0082 return QStringLiteral("radiobutton"); 0083 } 0084 break; 0085 } 0086 case FormField::FormText: 0087 return QStringLiteral("text"); 0088 case FormField::FormChoice: { 0089 const FormFieldChoice *choice = static_cast<const FormFieldChoice *>(field); 0090 switch (choice->choiceType()) { 0091 case FormFieldChoice::ComboBox: 0092 return QStringLiteral("combobox"); 0093 case FormFieldChoice::ListBox: 0094 return QStringLiteral("listbox"); 0095 } 0096 break; 0097 } 0098 case FormField::FormSignature: 0099 return QStringLiteral("signature"); 0100 } 0101 return QString(); 0102 } 0103 0104 // Field.type 0105 QString JSField::type() const 0106 { 0107 return fieldGetTypeHelper(m_field); 0108 } 0109 0110 QJSValue JSField::fieldGetValueCore(bool asString) const 0111 { 0112 QJSValue result(QJSValue::UndefinedValue); 0113 0114 switch (m_field->type()) { 0115 case FormField::FormButton: { 0116 const FormFieldButton *button = static_cast<const FormFieldButton *>(m_field); 0117 if (button->state()) { 0118 result = QStringLiteral("Yes"); 0119 } else { 0120 result = QStringLiteral("Off"); 0121 } 0122 break; 0123 } 0124 case FormField::FormText: { 0125 const FormFieldText *text = static_cast<const FormFieldText *>(m_field); 0126 const QLocale locale; 0127 bool ok; 0128 const double textAsNumber = locale.toDouble(text->text(), &ok); 0129 if (ok && !asString) { 0130 result = textAsNumber; 0131 } else { 0132 result = text->text(); 0133 } 0134 break; 0135 } 0136 case FormField::FormChoice: { 0137 const FormFieldChoice *choice = static_cast<const FormFieldChoice *>(m_field); 0138 const QList<int> currentChoices = choice->currentChoices(); 0139 if (currentChoices.count() == 1) { 0140 result = choice->exportValueForChoice(choice->choices().at(currentChoices[0])); 0141 } 0142 break; 0143 } 0144 case FormField::FormSignature: { 0145 break; 0146 } 0147 } 0148 0149 qCDebug(OkularCoreDebug) << "fieldGetValueCore:" 0150 << " Field: " << m_field->fullyQualifiedName() << " Type: " << fieldGetTypeHelper(m_field) << " Value: " << result.toString() << (result.isString() ? "(as string)" : ""); 0151 return result; 0152 } 0153 // Field.value (getter) 0154 QJSValue JSField::value() const 0155 { 0156 return fieldGetValueCore(/*asString*/ false); 0157 } 0158 0159 // Field.value (setter) 0160 void JSField::setValue(const QJSValue &value) 0161 { 0162 qCDebug(OkularCoreDebug) << "fieldSetValue: Field: " << m_field->fullyQualifiedName() << " Type: " << fieldGetTypeHelper(m_field) << " Value: " << value.toString(); 0163 switch (m_field->type()) { 0164 case FormField::FormButton: { 0165 FormFieldButton *button = static_cast<FormFieldButton *>(m_field); 0166 const QString text = value.toString(); 0167 if (text == QStringLiteral("Yes")) { 0168 button->setState(true); 0169 updateField(m_field); 0170 } else if (text == QStringLiteral("Off")) { 0171 button->setState(false); 0172 updateField(m_field); 0173 } 0174 break; 0175 } 0176 case FormField::FormText: { 0177 FormFieldText *textField = static_cast<FormFieldText *>(m_field); 0178 const QString text = value.toString(); 0179 if (text != textField->text()) { 0180 textField->setText(text); 0181 updateField(m_field); 0182 } 0183 break; 0184 } 0185 case FormField::FormChoice: { 0186 FormFieldChoice *choice = static_cast<FormFieldChoice *>(m_field); 0187 Q_UNUSED(choice); // ### 0188 break; 0189 } 0190 case FormField::FormSignature: { 0191 break; 0192 } 0193 } 0194 } 0195 0196 // Field.valueAsString (getter) 0197 QJSValue JSField::valueAsString() const 0198 { 0199 return fieldGetValueCore(/*asString*/ true); 0200 } 0201 0202 // Field.hidden (getter) 0203 bool JSField::hidden() const 0204 { 0205 return !m_field->isVisible(); 0206 } 0207 0208 // Field.hidden (setter) 0209 void JSField::setHidden(bool hidden) 0210 { 0211 m_field->setVisible(!hidden); 0212 0213 updateField(m_field); 0214 } 0215 0216 // Field.display (getter) 0217 int JSField::display() const 0218 { 0219 bool visible = m_field->isVisible(); 0220 if (visible) { 0221 return m_field->isPrintable() ? FormDisplay::FormVisible : FormDisplay::FormNoPrint; 0222 } 0223 return m_field->isPrintable() ? FormDisplay::FormNoView : FormDisplay::FormHidden; 0224 } 0225 0226 // Field.display (setter) 0227 void JSField::setDisplay(int display) 0228 { 0229 switch (display) { 0230 case FormDisplay::FormVisible: 0231 m_field->setVisible(true); 0232 m_field->setPrintable(true); 0233 break; 0234 case FormDisplay::FormHidden: 0235 m_field->setVisible(false); 0236 m_field->setPrintable(false); 0237 break; 0238 case FormDisplay::FormNoPrint: 0239 m_field->setVisible(true); 0240 m_field->setPrintable(false); 0241 break; 0242 case FormDisplay::FormNoView: 0243 m_field->setVisible(false); 0244 m_field->setPrintable(true); 0245 break; 0246 } 0247 updateField(m_field); 0248 } 0249 0250 // Instead of getting the Icon, we pick the field. 0251 QJSValue JSField::buttonGetIcon([[maybe_unused]] int nFace) const 0252 { 0253 QJSValue fieldObject = qjsEngine(this)->newObject(); 0254 fieldObject.setProperty(OKULAR_NAME, m_field->fullyQualifiedName()); 0255 g_buttonCache->insert(m_field->fullyQualifiedName(), m_field); 0256 0257 return fieldObject; 0258 } 0259 0260 /* 0261 * Now we send to the button what Icon should be drawn on it 0262 */ 0263 void JSField::buttonSetIcon(const QJSValue &oIcon, [[maybe_unused]] int nFace) 0264 { 0265 const QString fieldName = oIcon.property(OKULAR_NAME).toString(); 0266 0267 if (m_field->type() == Okular::FormField::FormButton) { 0268 FormFieldButton *button = static_cast<FormFieldButton *>(m_field); 0269 const auto formField = g_buttonCache->value(fieldName); 0270 if (formField) { 0271 button->setIcon(formField); 0272 } 0273 } 0274 0275 updateField(m_field); 0276 } 0277 0278 JSField::JSField(FormField *field, QObject *parent) 0279 : QObject(parent) 0280 , m_field(field) 0281 { 0282 } 0283 0284 JSField::~JSField() = default; 0285 0286 QJSValue JSField::wrapField(QJSEngine *engine, FormField *field, Page *page) 0287 { 0288 // ### cache unique wrapper 0289 QJSValue f = engine->newQObject(new JSField(field)); 0290 f.setProperty(QStringLiteral("page"), page->number()); 0291 g_fieldCache->insert(field, page); 0292 return f; 0293 } 0294 0295 void JSField::clearCachedFields() 0296 { 0297 if (g_fieldCache.exists()) { 0298 g_fieldCache->clear(); 0299 } 0300 0301 if (g_buttonCache.exists()) { 0302 g_buttonCache->clear(); 0303 } 0304 }