Commit d3a549ca authored by Andre Heinecke's avatar Andre Heinecke Committed by Albert Astals Cid

Add JavaScript Event Object handling

Summary:
This adds a new data object "Event" that can be used
to carry information in and out of JavaScript execution
contexts. The Event Object is defined in the Adobe JavaScript
scripting reference.

The implementation now adds handling for the FieldCalculate
Event. It should be extensible enough so that in the future
more events could be supported.

Reviewers: #okular

Subscribers: aacid

Tags: #okular

Maniphest Tasks: T7805

Differential Revision: https://phabricator.kde.org/D10073
parent 879f40e3
......@@ -160,11 +160,13 @@ set(okularcore_SRCS
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
......
/***************************************************************************
* Copyright (C) 2018 by Intevation GmbH <intevation@intevation.de> *
* *
* 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> Event::createFormCalculateEvent( FormField *target,
Page *targetPage,
FormField *source,
Page *sourcePage,
const QString &targetName )
{
std::shared_ptr<Event> 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;
}
/***************************************************************************
* Copyright (C) 2018 by Intevation GmbH <intevation@intevation.de> *
* *
* 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 <QString>
#include <QVariant>
#include <memory>
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<Event> createFormCalculateEvent( FormField *target,
Page *targetPage,
FormField *source = nullptr,
Page *sourcePage = nullptr,
const QString &targetName = QString() );
private:
class Private;
std::shared_ptr<Private> d;
Q_DISABLE_COPY( Event )
};
} // namespace Okular
#endif //OKULAR_SCRIPT_EVENT_P_H
......@@ -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 @@ void ExecutorKJSPrivate::initTypes()
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 @@ ExecutorKJS::~ExecutorKJS()
delete d;
}
void ExecutorKJS::execute( const QString &script )
void ExecutorKJS::execute( const QString &script, Event *event )
{
#if 0
QString script2;
......@@ -97,9 +100,12 @@ void ExecutorKJS::execute( const QString &script )
}
#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();
......@@ -107,6 +113,12 @@ void ExecutorKJS::execute( const QString &script )
else
{
qCDebug(OkularCoreDebug) << "result:" << result.value().toString( ctx );
if (event)
{
qCDebug(OkularCoreDebug) << "Event Result:" << event->name()
<< event->type() << "value:" << event->value();
}
}
JSField::clearCachedFields();
}
......@@ -16,6 +16,7 @@ namespace Okular {
class DocumentPrivate;
class ExecutorKJSPrivate;
class Event;
class ExecutorKJS
{
......@@ -23,7 +24,7 @@ class ExecutorKJS
ExecutorKJS( DocumentPrivate *doc );
~ExecutorKJS();
void execute( const QString &script );
void execute( const QString &script, Event *event );
private:
friend class ExecutorKJSPrivate;
......
/***************************************************************************
* Copyright (C) 2018 by Intevation GmbH <intevation@intevation.de> *
* *
* 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 <kjs/kjsinterpreter.h>
#include <kjs/kjsobject.h>
#include <kjs/kjsprototype.h>
#include <kjs/kjsarguments.h>
#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 );
}
/***************************************************************************
* Copyright (C) 2018 by Intevation GmbH <intevation@intevation.de> *
* *
* 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_KJS_EVENT_P_H
#define OKULAR_SCRIPT_KJS_EVENT_P_H
class KJSContext;
class KJSObject;
namespace Okular {
class Event;
class JSEvent
{
public:
static void initType( KJSContext *ctx );
static KJSObject wrapEvent( KJSContext *ctx, Event *event );
static void clearCachedFields();
};
}
#endif
......@@ -20,7 +20,7 @@ class Okular::ScripterPrivate
{
public:
ScripterPrivate( DocumentPrivate *doc )
: m_doc( doc ), m_kjs( nullptr )
: m_doc( doc ), m_kjs( nullptr ), m_event( nullptr )
{
}
......@@ -31,6 +31,7 @@ class Okular::ScripterPrivate
DocumentPrivate *m_doc;
ExecutorKJS *m_kjs;
Event *m_event;
};
Scripter::Scripter( DocumentPrivate *doc )
......@@ -59,8 +60,18 @@ QString Scripter::execute( ScriptType type, const QString &script )
{
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;
}
......@@ -19,6 +19,7 @@ namespace Okular {
class Document;
class DocumentPrivate;
class Event;
class ScripterPrivate;
class Scripter
......@@ -31,6 +32,9 @@ class Scripter
QString execute( ScriptType type, const QString &script );
void setEvent( Event *event );
Event *event() const;
private:
friend class ScripterPrivate;
ScripterPrivate* d;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment