diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,11 +160,13 @@ core/utils.cpp core/view.cpp core/fileprinter.cpp + core/script/event.cpp core/script/executor_kjs.cpp core/script/kjs_app.cpp core/script/kjs_console.cpp core/script/kjs_data.cpp core/script/kjs_document.cpp + core/script/kjs_event.cpp core/script/kjs_fullscreen.cpp core/script/kjs_field.cpp core/script/kjs_spell.cpp diff --git a/core/script/event.cpp b/core/script/event.cpp new file mode 100644 --- /dev/null +++ b/core/script/event.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** + * Copyright (C) 2018 by Intevation GmbH * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "event_p.h" + +#include "../form.h" + +using namespace Okular; + +class Event::Private +{ + public: + Private( EventType eventType ): m_target( nullptr ), + m_targetPage( nullptr ), + m_source( nullptr ), + m_sourcePage( nullptr ), + m_eventType( eventType ) + { + } + + void *m_target; + Page *m_targetPage; + FormField *m_source; + Page *m_sourcePage; + EventType m_eventType; + QString m_targetName; + QVariant m_value; +}; + +Event::Event(): d( new Private( UnknownEvent ) ) +{ +} + +Event::Event( EventType eventType ): d( new Private( eventType ) ) +{ + +} + +Event::EventType Event::eventType() const +{ + return d->m_eventType; +} + +QString Event::name() const +{ + switch ( d->m_eventType ) + { + case ( FieldCalculate ): + return QStringLiteral( "Calculate" ); + case ( UnknownEvent ): + default: + return QStringLiteral( "Unknown" ); + } +} + +QString Event::type() const +{ + switch ( d->m_eventType ) + { + case ( FieldCalculate ): + return QStringLiteral( "Field" ); + case ( UnknownEvent ): + default: + return QStringLiteral( "Unknown" ); + } +} + +QString Event::targetName() const +{ + if ( !d->m_targetName.isNull() ) + { + return d->m_targetName; + } + + return QStringLiteral( "JavaScript for: " ) + type() + name(); +} + +void Event::setTargetName( const QString &val ) +{ + d->m_targetName = val; +} + +FormField *Event::source() const +{ + return d->m_source; +} + +void Event::setSource( FormField *val ) +{ + d->m_source = val; +} + +Page *Event::sourcePage() const +{ + return d->m_sourcePage; +} + +void Event::setSourcePage( Page *val ) +{ + d->m_sourcePage = val; +} + +void *Event::target() const +{ + return d->m_target; +} + +void Event::setTarget( void *target ) +{ + d->m_target = target; +} + +Page *Event::targetPage() const +{ + return d->m_sourcePage; +} + +void Event::setTargetPage( Page *val ) +{ + d->m_targetPage = val; +} + +QVariant Event::value() const +{ + return d->m_value; +} + +void Event::setValue( const QVariant &val ) +{ + d->m_value = val; +} + +// static +std::shared_ptr Event::createFormCalculateEvent( FormField *target, + Page *targetPage, + FormField *source, + Page *sourcePage, + const QString &targetName ) +{ + std::shared_ptr ret( new Event( Event::FieldCalculate ) ); + ret->setSource( source ); + ret->setSourcePage( sourcePage ); + ret->setTarget( target ); + ret->setTargetPage( targetPage ); + ret->setTargetName( targetName ); + + FormFieldText *fft = dynamic_cast< FormFieldText * >(target); + if ( fft ) + { + ret->setValue( QVariant( fft->text() ) ); + } + return ret; +} diff --git a/core/script/event_p.h b/core/script/event_p.h new file mode 100644 --- /dev/null +++ b/core/script/event_p.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2018 by Intevation GmbH * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OKULAR_SCRIPT_EVENT_P_H +#define OKULAR_SCRIPT_EVENT_P_H + +#include +#include + +#include + +namespace Okular { + +class FormField; +class Page; + +/** + * @short A JavaScript Event Object data container. + * + * Object to represet a JavaScript Event Object as described in the + * Acrobat JavaScript Scripting Reference. + * + * The implementation is currently limited. To implement support + * for a new event create the according data fields / getters + * and setters and update the handling in kjs_event + * accordingly. + * + * See Acrobat JavaScript Scripting Reference for the meaning + * the fields and add getter / setter according for the + * event you wish to implement. + */ +class Event +{ + private: + Event(); + + public: + enum EventType { + UnknownEvent, /// < Unknown + AppInit, /// < Not implemented. + BatchExec, /// < Not implemented. + BookmarkMouseUp, /// < Not implemented. + ConsoleExec, /// < Not implemented. + DocDidPrint, /// < Not implemented. + DocDidSave, /// < Not implemented. + DocOpen, /// < Not implemented. + DocWillClose, /// < Not implemented. + DocWillPrint, /// < Not implemented. + DocWillSave, /// < Not implemented. + ExternalExec, /// < Not implemented. + FieldBlur, /// < Not implemented. + FieldCalculate, /// < This event is defined in a field re-calculation. + FieldFocus, /// < Not implemented. + FieldFormat, /// < Not implemented. + FieldKeystroke, /// < Not implemented. + FieldMouseDown, /// < Not implemented. + FieldMouseEnter, /// < Not implemented. + FieldMouseExit, /// < Not implemented. + FieldMouseUp, /// < Not implemented. + FieldValidate, /// < Not implemented. + LinkMouseUp, /// < Not implemented. + MenuExec, /// < Not implemented. + PageOpen, /// < Not implemented. + PageClose, /// < Not implemented. + }; + + Event(EventType type); + + /** One of the defined EventTypes */ + EventType eventType() const; + + QString name() const; + + QString type() const; + + QString targetName() const; + void setTargetName( const QString &val ); + + Page *targetPage() const; + void setTargetPage( Page *val ); + + FormField *source() const; + void setSource( FormField *val ); + + Page *sourcePage() const; + void setSourcePage( Page *val ); + + void *target() const; + void setTarget( void *target ); + + QVariant value() const; + void setValue(const QVariant &val); + + static std::shared_ptr createFormCalculateEvent( FormField *target, + Page *targetPage, + FormField *source = nullptr, + Page *sourcePage = nullptr, + const QString &targetName = QString() ); + private: + class Private; + std::shared_ptr d; + Q_DISABLE_COPY( Event ) +}; + +} // namespace Okular +#endif //OKULAR_SCRIPT_EVENT_P_H diff --git a/core/script/executor_kjs.cpp b/core/script/executor_kjs.cpp --- a/core/script/executor_kjs.cpp +++ b/core/script/executor_kjs.cpp @@ -20,10 +20,12 @@ #include "../debug_p.h" #include "../document_p.h" +#include "event_p.h" #include "kjs_app_p.h" #include "kjs_console_p.h" #include "kjs_data_p.h" #include "kjs_document_p.h" +#include "kjs_event_p.h" #include "kjs_field_p.h" #include "kjs_fullscreen_p.h" #include "kjs_spell_p.h" @@ -63,6 +65,7 @@ JSConsole::initType( ctx ); JSData::initType( ctx ); JSDocument::initType( ctx ); + JSEvent::initType( ctx ); JSField::initType( ctx ); JSSpell::initType( ctx ); JSUtil::initType( ctx ); @@ -84,7 +87,7 @@ delete d; } -void ExecutorKJS::execute( const QString &script ) +void ExecutorKJS::execute( const QString &script, Event *event ) { #if 0 QString script2; @@ -97,16 +100,25 @@ } #endif + KJSContext* ctx = d->m_interpreter->globalContext(); + + d->m_docObject.setProperty( ctx, QStringLiteral("event"), event ? JSEvent::wrapEvent( ctx, event ) : KJSUndefined() ); + KJSResult result = d->m_interpreter->evaluate( QStringLiteral("okular.js"), 1, script, &d->m_docObject ); - KJSContext* ctx = d->m_interpreter->globalContext(); if ( result.isException() || ctx->hasException() ) { qCDebug(OkularCoreDebug) << "JS exception" << result.errorMessage(); } else { qCDebug(OkularCoreDebug) << "result:" << result.value().toString( ctx ); + + if (event) + { + qCDebug(OkularCoreDebug) << "Event Result:" << event->name() + << event->type() << "value:" << event->value(); + } } JSField::clearCachedFields(); } diff --git a/core/script/executor_kjs_p.h b/core/script/executor_kjs_p.h --- a/core/script/executor_kjs_p.h +++ b/core/script/executor_kjs_p.h @@ -16,14 +16,15 @@ class DocumentPrivate; class ExecutorKJSPrivate; +class Event; class ExecutorKJS { public: ExecutorKJS( DocumentPrivate *doc ); ~ExecutorKJS(); - void execute( const QString &script ); + void execute( const QString &script, Event *event ); private: friend class ExecutorKJSPrivate; diff --git a/core/script/kjs_event.cpp b/core/script/kjs_event.cpp new file mode 100644 --- /dev/null +++ b/core/script/kjs_event.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2018 by Intevation GmbH * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "kjs_event_p.h" + +#include +#include +#include +#include + +#include "kjs_field_p.h" +#include "event_p.h" + +using namespace Okular; + +static KJSPrototype *g_eventProto; + +// Event.name +static KJSObject eventGetName( KJSContext *, void *object ) +{ + const Event *event = reinterpret_cast< Event * >( object ); + return KJSString( event->name() ); +} + +// Event.type +static KJSObject eventGetType( KJSContext *, void *object ) +{ + const Event *event = reinterpret_cast< Event * >( object ); + return KJSString( event->type() ); +} + +// Event.targetName (getter) +static KJSObject eventGetTargetName( KJSContext *, void *object ) +{ + const Event *event = reinterpret_cast< Event * >( object ); + return KJSString( event->targetName() ); +} + +// Event.targetName (setter) +static void eventSetTargetName( KJSContext *ctx, void *object, KJSObject value ) +{ + Event *event = reinterpret_cast< Event * >( object ); + event->setTargetName ( value.toString ( ctx ) ); +} + +// Event.source +static KJSObject eventGetSource( KJSContext *ctx, void *object ) +{ + const Event *event = reinterpret_cast< Event * >( object ); + if ( event->eventType() == Event::FieldCalculate ) + { + FormField *src = event->source(); + if ( src ) + return JSField::wrapField( ctx, src, event->sourcePage() ); + } + return KJSUndefined(); +} + +// Event.target +static KJSObject eventGetTarget( KJSContext *ctx, void *object ) +{ + const Event *event = reinterpret_cast< Event * >( object ); + if ( event->eventType() == Event::FieldCalculate ) + { + FormField *target = static_cast< FormField * >( event->target() ); + if ( target ) + return JSField::wrapField( ctx, target, event->targetPage() ); + } + return KJSUndefined(); +} + +// Event.value (getter) +static KJSObject eventGetValue( KJSContext *, void *object ) +{ + const Event *event = reinterpret_cast< Event * >( object ); + return KJSString( event->value().toString() ); +} + +// Event.value (setter) +static void eventSetValue( KJSContext *ctx, void *object, KJSObject value ) +{ + Event *event = reinterpret_cast< Event * >( object ); + event->setValue ( QVariant( value.toString ( ctx ) ) ); +} + +void JSEvent::initType( KJSContext *ctx ) +{ + static bool initialized = false; + if ( initialized ) + return; + initialized = true; + + if ( !g_eventProto ) + g_eventProto = new KJSPrototype(); + + g_eventProto->defineProperty( ctx, QStringLiteral( "name" ), eventGetName ); + g_eventProto->defineProperty( ctx, QStringLiteral( "type" ), eventGetType ); + g_eventProto->defineProperty( ctx, QStringLiteral( "targetName" ), eventGetTargetName, + eventSetTargetName ); + g_eventProto->defineProperty( ctx, QStringLiteral( "source" ), eventGetSource ); + g_eventProto->defineProperty( ctx, QStringLiteral( "target" ), eventGetTarget ); + g_eventProto->defineProperty( ctx, QStringLiteral( "value" ), eventGetValue, eventSetValue ); +} + +KJSObject JSEvent::wrapEvent( KJSContext *ctx, Event *event ) +{ + return g_eventProto->constructObject( ctx, event ); +} + + diff --git a/core/script/executor_kjs_p.h b/core/script/kjs_event_p.h copy from core/script/executor_kjs_p.h copy to core/script/kjs_event_p.h --- a/core/script/executor_kjs_p.h +++ b/core/script/kjs_event_p.h @@ -1,33 +1,28 @@ /*************************************************************************** - * Copyright (C) 2008 by Pino Toscano * + * Copyright (C) 2018 by Intevation GmbH * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ -#ifndef OKULAR_SCRIPT_EXECUTOR_KJS_P_H -#define OKULAR_SCRIPT_EXECUTOR_KJS_P_H +#ifndef OKULAR_SCRIPT_KJS_EVENT_P_H +#define OKULAR_SCRIPT_KJS_EVENT_P_H -class QString; +class KJSContext; +class KJSObject; namespace Okular { -class DocumentPrivate; -class ExecutorKJSPrivate; +class Event; -class ExecutorKJS +class JSEvent { public: - ExecutorKJS( DocumentPrivate *doc ); - ~ExecutorKJS(); - - void execute( const QString &script ); - - private: - friend class ExecutorKJSPrivate; - ExecutorKJSPrivate* d; + static void initType( KJSContext *ctx ); + static KJSObject wrapEvent( KJSContext *ctx, Event *event ); + static void clearCachedFields(); }; } diff --git a/core/scripter.h b/core/scripter.h --- a/core/scripter.h +++ b/core/scripter.h @@ -19,6 +19,7 @@ class Document; class DocumentPrivate; +class Event; class ScripterPrivate; class Scripter @@ -31,6 +32,9 @@ QString execute( ScriptType type, const QString &script ); + void setEvent( Event *event ); + Event *event() const; + private: friend class ScripterPrivate; ScripterPrivate* d; diff --git a/core/scripter.cpp b/core/scripter.cpp --- a/core/scripter.cpp +++ b/core/scripter.cpp @@ -20,7 +20,7 @@ { public: ScripterPrivate( DocumentPrivate *doc ) - : m_doc( doc ), m_kjs( nullptr ) + : m_doc( doc ), m_kjs( nullptr ), m_event( nullptr ) { } @@ -31,6 +31,7 @@ DocumentPrivate *m_doc; ExecutorKJS *m_kjs; + Event *m_event; }; Scripter::Scripter( DocumentPrivate *doc ) @@ -59,8 +60,18 @@ { d->m_kjs = new ExecutorKJS( d->m_doc ); } - d->m_kjs->execute( script ); + d->m_kjs->execute( script, d->m_event ); break; } return QString(); } + +void Scripter::setEvent( Event *event ) +{ + d->m_event = event; +} + +Event *Scripter::event() const +{ + return d->m_event; +}