Commit 7555212d authored by Joao Oliveira's avatar Joao Oliveira Committed by Albert Astals Cid

Implemented the getOCGs and OCGs methods to support layer changing by JavaScript.

Implemented more unit tests to cover the OCGs
parent cc10164d
......@@ -312,6 +312,7 @@ if (KF5JS_FOUND)
core/script/kjs_spell.cpp
core/script/kjs_util.cpp
core/script/kjs_event.cpp
core/script/kjs_ocg.cpp
)
target_link_libraries(okularcore PRIVATE KF5::JS KF5::JSApi)
endif()
......
......@@ -9,6 +9,7 @@
#include <QtTest>
#include <QAbstractItemModel>
#include <QMap>
#include <QMimeType>
#include <QMimeDatabase>
......@@ -33,6 +34,8 @@ private slots:
void testDisplay();
void testSetClearInterval();
void testSetClearTimeOut();
void testGetOCGs();
void testOCGSetState();
void cleanupTestCase();
private:
......@@ -60,7 +63,7 @@ void KJSFunctionsTest::initTestCase()
void KJSFunctionsTest::testNumFields()
{
QString result = m_document->executeScript( "Doc.numFields" );
QCOMPARE( "22", result );
QCOMPARE( "31", result );
}
void KJSFunctionsTest::testNthFieldName()
......@@ -89,7 +92,6 @@ void KJSFunctionsTest::testDisplay()
QCOMPARE( false, m_fields["0.15"]->isVisible() );
QCOMPARE( true, m_fields["0.20"]->isVisible() );
m_document->executeScript( "field = Doc.getField(\"0.20\");field.display=display.hidden;\
field = Doc.getField(\"0.0\");field.display=display.visible;" );
QCOMPARE( false, m_fields["0.20"]->isVisible() );
......@@ -110,6 +112,7 @@ void KJSFunctionsTest::testSetClearInterval()
intv = app.setInterval('obj.inc()', 450);obj.idx;" );
QCOMPARE( "0", result );
delay();
result = m_document->executeScript( "app.clearInterval(intv);obj.idx;");
QCOMPARE( "4", result );
}
......@@ -119,16 +122,82 @@ void KJSFunctionsTest::testSetClearTimeOut()
QString result = m_document->executeScript( "intv = app.setTimeOut('obj.inc()', 1);obj.idx;" );
QCOMPARE( "4", result );
delay();
result = m_document->executeScript( "obj.idx;" );
QCOMPARE( "5", result );
result = m_document->executeScript( "intv = app.setTimeOut('obj.inc()', 2000);obj.idx;" );
QCOMPARE( "5", result );
result = m_document->executeScript( "app.clearTimeOut(intv);obj.idx;" );
QCOMPARE( "5", result );
delay();
QCOMPARE( "5", result );
}
void KJSFunctionsTest::testGetOCGs()
{
QAbstractItemModel *model = m_document->layersModel();
QString result = m_document->executeScript( "var ocg = this.getOCGs(this.pageNum);\
ocgName = ocg[0].name;" );
QCOMPARE( model->data( model->index( 0, 0 ), Qt::DisplayRole ).toString() , result );
result = m_document->executeScript( "ocgName = ocg[1].name;" );
QCOMPARE( model->data( model->index( 1, 0 ), Qt::DisplayRole ).toString() , result );
result = m_document->executeScript( "ocgName = ocg[2].name;" );
QCOMPARE( model->data( model->index( 2, 0 ), Qt::DisplayRole ).toString() , result );
result = m_document->executeScript( "ocgName = ocg[3].name;" );
QCOMPARE( model->data( model->index( 3, 0 ), Qt::DisplayRole ).toString() , result );
result = m_document->executeScript( "ocgName = ocg[0].initState;" );
QCOMPARE( model->data( model->index( 0, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false"
, result );
result = m_document->executeScript( "ocgName = ocg[1].initState;" );
QCOMPARE( model->data( model->index( 1, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false"
, result );
result = m_document->executeScript( "ocgName = ocg[2].initState;" );
QCOMPARE( model->data( model->index( 2, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false"
, result );
result = m_document->executeScript( "ocgName = ocg[3].initState;" );
QCOMPARE( model->data( model->index( 3, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false"
, result );
}
void KJSFunctionsTest::testOCGSetState()
{
QAbstractItemModel *model = m_document->layersModel();
QString result = m_document->executeScript( "ocgName = ocg[0].state;" );
QCOMPARE( model->data( model->index( 0, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocg[0].state = false;ocgName = ocg[0].state;");
QCOMPARE( model->data( model->index( 0, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocgName = ocg[1].state;" );
QCOMPARE( model->data( model->index( 1, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocg[1].state = false;ocgName = ocg[1].state;");
QCOMPARE( model->data( model->index( 1, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocgName = ocg[2].state;" );
QCOMPARE( model->data( model->index( 2, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocg[2].state = true;ocgName = ocg[2].state;");
QCOMPARE( model->data( model->index( 2, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocgName = ocg[3].state;" );
QCOMPARE( model->data( model->index( 3, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
result = m_document->executeScript( "ocg[3].state = true;ocgName = ocg[3].state;");
QCOMPARE( model->data( model->index( 3, 0 ), Qt::CheckStateRole ).toBool() ? "true" : "false", result );
}
void KJSFunctionsTest::cleanupTestCase()
{
m_document->closeDocument();
......
......@@ -5117,7 +5117,6 @@ QByteArray Document::requestSignedRevisionData( const Okular::SignatureInfo &inf
QString Document::executeScript( QString function )
{
qDebug() << function;
if( !d->m_scripter )
d->m_scripter = new Scripter( d );
return d->m_scripter->execute( JavaScript, function );
......
......@@ -29,6 +29,7 @@
#include "kjs_event_p.h"
#include "kjs_field_p.h"
#include "kjs_fullscreen_p.h"
#include "kjs_ocg_p.h"
#include "kjs_spell_p.h"
#include "kjs_util_p.h"
......@@ -69,13 +70,15 @@ void ExecutorKJSPrivate::initTypes()
JSDocument::initType( ctx );
JSEvent::initType( ctx );
JSField::initType( ctx );
JSOCG::initType( ctx );
JSSpell::initType( ctx );
JSUtil::initType( ctx );
m_docObject.setProperty( ctx, QStringLiteral("app"), JSApp::object( ctx, m_doc ) );
m_docObject.setProperty( ctx, QStringLiteral("console"), JSConsole::object( ctx ) );
m_docObject.setProperty( ctx, QStringLiteral("Doc"), m_docObject );
m_docObject.setProperty( ctx, QStringLiteral("display"), JSDisplay::object( ctx ));
m_docObject.setProperty( ctx, QStringLiteral("display"), JSDisplay::object( ctx ) );
m_docObject.setProperty( ctx, QStringLiteral("OCG"), JSOCG::object( ctx ) );
m_docObject.setProperty( ctx, QStringLiteral("spell"), JSSpell::object( ctx ) );
m_docObject.setProperty( ctx, QStringLiteral("util"), JSUtil::object( ctx ) );
}
......@@ -89,6 +92,7 @@ ExecutorKJS::~ExecutorKJS()
{
JSField::clearCachedFields();
JSApp::clearCachedFields();
JSOCG::clearCachedFields();
delete d;
}
......
......@@ -24,6 +24,7 @@
#include "../form.h"
#include "kjs_data_p.h"
#include "kjs_field_p.h"
#include "kjs_ocg_p.h"
using namespace Okular;
......@@ -289,6 +290,30 @@ static KJSObject docGetNthFieldName( KJSContext *ctx, void *object,
return KJSUndefined();
}
static KJSObject docGetOCGs( KJSContext *ctx, void *object,
const KJSArguments &arguments )
{
DocumentPrivate *doc = reinterpret_cast< DocumentPrivate* >( object );
QAbstractItemModel * model = doc->m_parent->layersModel();
KJSArray array( ctx, model->rowCount() );
for(int i = 0;i < model->rowCount();++i){
for(int j = 0;j < model->columnCount();++j){
QModelIndex index = model->index( i, j );
KJSObject item = JSOCG::wrapOCGObject( ctx, model, i, j );
item.setProperty( ctx, QStringLiteral("name"), model->data( index , Qt::DisplayRole ).toString() );
item.setProperty( ctx, QStringLiteral("initState"), model->data( index , Qt::CheckStateRole ).toBool() );
array.setProperty( ctx, QString::number( i ), item );
}
}
return array;
}
void JSDocument::initType( KJSContext *ctx )
{
assert( g_docProto );
......@@ -324,6 +349,7 @@ void JSDocument::initType( KJSContext *ctx )
g_docProto->defineFunction( ctx, QStringLiteral("gotoNamedDest"), docGotoNamedDest );
g_docProto->defineFunction( ctx, QStringLiteral("syncAnnotScan"), docSyncAnnotScan );
g_docProto->defineFunction( ctx, QStringLiteral("getNthFieldName"), docGetNthFieldName );
g_docProto->defineFunction( ctx, QStringLiteral("getOCGs"), docGetOCGs );
}
KJSGlobalObject JSDocument::wrapDocument( DocumentPrivate *doc )
......
/***************************************************************************
* Copyright (C) 2019 by João Netto <joaonetto901@gmail.com> *
* *
* 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_ocg_p.h"
#include <kjs/kjsobject.h>
#include <kjs/kjsprototype.h>
#include <kjs/kjsinterpreter.h>
#include <QString>
#include <QAbstractItemModel>
#include <QDebug>
#include <QPair>
#include <memory>
using namespace Okular;
std::unique_ptr < KJSPrototype > g_OCGProto;
typedef QHash< QPair< int, int > *, QAbstractItemModel* > OCGCache;
Q_GLOBAL_STATIC( OCGCache, g_OCGCache )
// OCG.state (getter)
static KJSObject OCGGetState( KJSContext *, void *object )
{
QPair< int, int > *pair = reinterpret_cast< QPair< int, int >* > ( object );
QAbstractItemModel *model = g_OCGCache->value( pair );
QModelIndex index = model->index( pair->first, pair->second );
bool state = model->data( index, Qt::CheckStateRole ).toBool();
return KJSBoolean( state );
}
// OCG.state (setter)
static void OCGSetState( KJSContext* ctx, void* object,
KJSObject value )
{
QPair< int, int > *pair = reinterpret_cast< QPair< int, int >* > ( object );
QAbstractItemModel *model = g_OCGCache->value( pair );
QModelIndex index = model->index( pair->first, pair->second );
bool state = value.toBoolean( ctx );
model->setData( index, QVariant( state ? Qt::Checked : Qt::Unchecked ), Qt::CheckStateRole );
}
void JSOCG::initType( KJSContext *ctx )
{
if ( g_OCGProto )
return;
g_OCGProto.reset(new KJSPrototype);
g_OCGProto->defineProperty( ctx, QStringLiteral("state"), OCGGetState, OCGSetState );
}
KJSObject JSOCG::object( KJSContext *ctx )
{
return g_OCGProto->constructObject( ctx, nullptr );
}
KJSObject JSOCG::wrapOCGObject( KJSContext *ctx, QAbstractItemModel *model, int i, int j )
{
QPair< int, int > *pair = new QPair< int ,int >( i, j );
g_OCGCache->insert( pair, model );
return g_OCGProto->constructObject( ctx, pair );
}
void JSOCG::clearCachedFields()
{
if ( g_OCGCache.exists() )
{
g_OCGCache->clear();
}
}
\ No newline at end of file
/***************************************************************************
* Copyright (C) 2019 by João Netto <joaonetto901@gmail.com> *
* *
* 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_OCG_P_H
#define OKULAR_SCRIPT_KJS_OCG_P_H
class KJSContext;
class KJSObject;
class QAbstractItemModel;
namespace Okular {
class JSOCG
{
public:
static void initType( KJSContext *ctx );
static KJSObject object( KJSContext *ctx );
static KJSObject wrapOCGObject( KJSContext *ctx, QAbstractItemModel *model, int i, int j );
static void clearCachedFields();
};
}
#endif
\ No newline at end of file
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