kjs_app.cpp 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/***************************************************************************
 *   Copyright (C) 2008 by Pino Toscano <pino@kde.org>                     *
 *   Copyright (C) 2008 by Harri Porten <porten@kde.org>                   *
 *                                                                         *
 *   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_app_p.h"

#include <kjs/kjsarguments.h>
#include <kjs/kjsobject.h>
#include <kjs/kjsprototype.h>

#include <qapplication.h>

Alex Richardson's avatar
Alex Richardson committed
19 20 21
#include <QLocale>

#include <KLocalizedString>
22 23

#include "../document_p.h"
24
#include "../scripter.h"
25 26 27 28 29
#include "kjs_fullscreen_p.h"

using namespace Okular;

static KJSPrototype *g_appProto;
30 31
typedef QHash< int, QTimer * > TimerCache;
Q_GLOBAL_STATIC( TimerCache, g_timerCache )
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

// the acrobat version we fake
static const double fake_acroversion = 8.00;

static const struct FakePluginInfo {
    const char *name;
    bool certified;
    bool loaded;
    const char *path;
} s_fake_plugins[] = {
    { "Annots", true, true, "" },
    { "EFS", true, true, "" },
    { "EScript", true, true, "" },
    { "Forms", true, true, "" },
    { "ReadOutLoud", true, true, "" },
    { "WebLink", true, true, "" }
};
static const int s_num_fake_plugins = sizeof( s_fake_plugins ) / sizeof( s_fake_plugins[0] );


static KJSObject appGetFormsVersion( KJSContext *, void * )
{
    // faking a bit...
    return KJSNumber( fake_acroversion );
}

static KJSObject appGetLanguage( KJSContext *, void * )
{
Alex Richardson's avatar
Alex Richardson committed
60 61 62
    QLocale locale;
    QString lang = QLocale::languageToString(locale.language());
    QString country = QLocale::countryToString(locale.country());
Laurent Montel's avatar
Laurent Montel committed
63
    QString acroLang = QStringLiteral( "ENU" );
64
    if ( lang == QLatin1String( "da" ) )
Laurent Montel's avatar
Laurent Montel committed
65
        acroLang = QStringLiteral( "DAN" ); // Danish
66
    else if ( lang == QLatin1String( "de" ) )
Laurent Montel's avatar
Laurent Montel committed
67
        acroLang = QStringLiteral( "DEU" ); // German
68
    else if ( lang == QLatin1String( "en" ) )
Laurent Montel's avatar
Laurent Montel committed
69
        acroLang = QStringLiteral( "ENU" ); // English
70
    else if ( lang == QLatin1String( "es" ) )
Laurent Montel's avatar
Laurent Montel committed
71
        acroLang = QStringLiteral( "ESP" ); // Spanish
72
    else if ( lang == QLatin1String( "fr" ) )
Laurent Montel's avatar
Laurent Montel committed
73
        acroLang = QStringLiteral( "FRA" ); // French
74
    else if ( lang == QLatin1String( "it" ) )
Laurent Montel's avatar
Laurent Montel committed
75
        acroLang = QStringLiteral( "ITA" ); // Italian
76
    else if ( lang == QLatin1String( "ko" ) )
Laurent Montel's avatar
Laurent Montel committed
77
        acroLang = QStringLiteral( "KOR" ); // Korean
78
    else if ( lang == QLatin1String( "ja" ) )
Laurent Montel's avatar
Laurent Montel committed
79
        acroLang = QStringLiteral( "JPN" ); // Japanese
80
    else if ( lang == QLatin1String( "nl" ) )
Laurent Montel's avatar
Laurent Montel committed
81
        acroLang = QStringLiteral( "NLD" ); // Dutch
82
    else if ( lang == QLatin1String( "pt" ) && country == QLatin1String( "BR" ) )
Laurent Montel's avatar
Laurent Montel committed
83
        acroLang = QStringLiteral( "PTB" ); // Brazilian Portuguese
84
    else if ( lang == QLatin1String( "fi" ) )
Laurent Montel's avatar
Laurent Montel committed
85
        acroLang = QStringLiteral( "SUO" ); // Finnish
86
    else if ( lang == QLatin1String( "sv" ) )
Laurent Montel's avatar
Laurent Montel committed
87
        acroLang = QStringLiteral( "SVE" ); // Swedish
88
    else if ( lang == QLatin1String( "zh" ) && country == QLatin1String( "CN" ) )
Laurent Montel's avatar
Laurent Montel committed
89
        acroLang = QStringLiteral( "CHS" ); // Chinese Simplified
90
    else if ( lang == QLatin1String( "zh" ) && country == QLatin1String( "TW" ) )
Laurent Montel's avatar
Laurent Montel committed
91
        acroLang = QStringLiteral( "CHT" ); // Chinese Traditional
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    return KJSString( acroLang );
}

static KJSObject appGetNumPlugins( KJSContext *, void * )
{
    return KJSNumber( s_num_fake_plugins );
}

static KJSObject appGetPlatform( KJSContext *, void * )
{
#if defined(Q_OS_WIN)
    return KJSString( QString::fromLatin1( "WIN" ) );
#elif defined(Q_OS_MAC)
    return KJSString( QString::fromLatin1( "MAC" ) );
#else
Laurent Montel's avatar
Laurent Montel committed
107
    return KJSString( QStringLiteral( "UNIX" ) );
108 109 110 111 112 113 114 115 116 117
#endif
}

static KJSObject appGetPlugIns( KJSContext *context, void * )
{
    KJSArray plugins( context, s_num_fake_plugins );
    for ( int i = 0; i < s_num_fake_plugins; ++i )
    {
        const FakePluginInfo &info = s_fake_plugins[i];
        KJSObject plugin;
Laurent Montel's avatar
Laurent Montel committed
118 119 120 121 122
        plugin.setProperty( context, QStringLiteral("certified"), info.certified );
        plugin.setProperty( context, QStringLiteral("loaded"), info.loaded );
        plugin.setProperty( context, QStringLiteral("name"), info.name );
        plugin.setProperty( context, QStringLiteral("path"), info.path );
        plugin.setProperty( context, QStringLiteral("version"), fake_acroversion );
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
        plugins.setProperty( context, QString::number( i ), plugin );
    }
    return plugins;
}

static KJSObject appGetPrintColorProfiles( KJSContext *context, void * )
{
    return KJSArray( context, 0 );
}

static KJSObject appGetPrinterNames( KJSContext *context, void * )
{
    return KJSArray( context, 0 );
}

static KJSObject appGetViewerType( KJSContext *, void * )
{
    // faking a bit...
Laurent Montel's avatar
Laurent Montel committed
141
    return KJSString( QStringLiteral( "Reader" ) );
142 143 144 145 146
}

static KJSObject appGetViewerVariation( KJSContext *, void * )
{
    // faking a bit...
Laurent Montel's avatar
Laurent Montel committed
147
    return KJSString( QStringLiteral( "Reader" ) );
148 149 150 151 152 153 154 155 156 157 158 159 160
}

static KJSObject appGetViewerVersion( KJSContext *, void * )
{
    // faking a bit...
    return KJSNumber( fake_acroversion );
}

static KJSObject appBeep( KJSContext *context, void *,
                          const KJSArguments &arguments )
{
    if ( arguments.count() < 1 )
    {
Laurent Montel's avatar
Laurent Montel committed
161
        return context->throwException( QStringLiteral("Missing beep type") );
162 163 164 165 166 167 168 169 170 171
    }
    QApplication::beep();
    return KJSUndefined();
}

static KJSObject appGetNthPlugInName( KJSContext *context, void *,
                                      const KJSArguments &arguments )
{
    if ( arguments.count() < 1 )
    {
Laurent Montel's avatar
Laurent Montel committed
172
        return context->throwException( QStringLiteral("Missing plugin index") );
173 174 175 176
    }
    const int nIndex = arguments.at( 0 ).toInt32( context );

    if ( nIndex < 0 || nIndex >= s_num_fake_plugins )
Laurent Montel's avatar
Laurent Montel committed
177
        return context->throwException( QStringLiteral("PlugIn index out of bounds") );
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

    const FakePluginInfo &info = s_fake_plugins[nIndex];
    return KJSString( info.name );
}

static KJSObject appGoBack( KJSContext *, void *object,
                            const KJSArguments & )
{
    const DocumentPrivate *doc = reinterpret_cast< DocumentPrivate * >( object );
    if ( doc->m_parent->historyAtBegin() )
        return KJSUndefined();

    doc->m_parent->setPrevViewport();
    return KJSUndefined();
}

static KJSObject appGoForward( KJSContext *, void *object,
                               const KJSArguments & )
{
    const DocumentPrivate *doc = reinterpret_cast< DocumentPrivate * >( object );
    if ( doc->m_parent->historyAtEnd() )
        return KJSUndefined();

    doc->m_parent->setNextViewport();
    return KJSUndefined();
}

205 206 207 208 209
// app.setInterval()
static KJSObject appSetInterval( KJSContext *ctx, void *object,
                                      const KJSArguments &arguments )
{
    DocumentPrivate *doc = reinterpret_cast< DocumentPrivate * >( object );
210 211
    const QString function = arguments.at( 0 ).toString( ctx ) + ';';
    const int interval = arguments.at( 1 ).toInt32( ctx );
212 213 214

    QTimer *timer = new QTimer();

215
    QObject::connect( timer, &QTimer::timeout, [=](){ doc->executeScript( function ); } );
216 217 218 219 220 221 222

    timer->start( interval );

    return JSApp::wrapTimer( ctx, timer );
}

// app.clearInterval()
223
static KJSObject appClearInterval( KJSContext *ctx, void *,
224 225 226
                                      const KJSArguments &arguments )
{
    KJSObject timerObject = arguments.at( 0 );
227
    const int timerId = timerObject.property( ctx, QStringLiteral("okular_timerID") ).toInt32( ctx );
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
    QTimer *timer = g_timerCache->value( timerId );
    if( timer != nullptr )
    {
        timer->stop();
        g_timerCache->remove( timerId );
        delete timer;
    }

    return KJSUndefined();
}

// app.setTimeOut()
static KJSObject appSetTimeOut( KJSContext *ctx, void *object,
                                      const KJSArguments &arguments )
{
    DocumentPrivate *doc = reinterpret_cast< DocumentPrivate * >( object );
244 245
    const QString function = arguments.at( 0 ).toString( ctx ) + ';';
    const int interval = arguments.at( 1 ).toInt32( ctx );
246 247 248 249

    QTimer *timer = new QTimer();
    timer->setSingleShot( true );

250
    QObject::connect( timer, &QTimer::timeout, [=](){ doc->executeScript( function ); } );
251 252 253 254 255 256 257

    timer->start( interval );

    return JSApp::wrapTimer( ctx, timer );
}

// app.clearTimeOut()
258
static KJSObject appClearTimeOut( KJSContext *ctx, void *,
259 260 261
                                      const KJSArguments &arguments )
{
    KJSObject timerObject = arguments.at( 0 );
262
    const int timerId = timerObject.property( ctx, QStringLiteral("okular_timerID") ).toInt32( ctx );
263 264 265 266 267 268 269 270 271 272 273 274 275
    QTimer *timer = g_timerCache->value( timerId );

    if( timer != nullptr )
    {
        timer->stop();
        g_timerCache->remove( timerId );
        delete timer;
    }

    return KJSUndefined();
}


276 277 278 279 280 281 282 283 284
void JSApp::initType( KJSContext *ctx )
{
    static bool initialized = false;
    if ( initialized )
        return;
    initialized = true;

    g_appProto = new KJSPrototype();

Laurent Montel's avatar
Laurent Montel committed
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    g_appProto->defineProperty( ctx, QStringLiteral("formsVersion"), appGetFormsVersion );
    g_appProto->defineProperty( ctx, QStringLiteral("language"), appGetLanguage );
    g_appProto->defineProperty( ctx, QStringLiteral("numPlugIns"), appGetNumPlugins );
    g_appProto->defineProperty( ctx, QStringLiteral("platform"), appGetPlatform );
    g_appProto->defineProperty( ctx, QStringLiteral("plugIns"), appGetPlugIns );
    g_appProto->defineProperty( ctx, QStringLiteral("printColorProfiles"), appGetPrintColorProfiles );
    g_appProto->defineProperty( ctx, QStringLiteral("printerNames"), appGetPrinterNames );
    g_appProto->defineProperty( ctx, QStringLiteral("viewerType"), appGetViewerType );
    g_appProto->defineProperty( ctx, QStringLiteral("viewerVariation"), appGetViewerVariation );
    g_appProto->defineProperty( ctx, QStringLiteral("viewerVersion"), appGetViewerVersion );

    g_appProto->defineFunction( ctx, QStringLiteral("beep"), appBeep );
    g_appProto->defineFunction( ctx, QStringLiteral("getNthPlugInName"), appGetNthPlugInName );
    g_appProto->defineFunction( ctx, QStringLiteral("goBack"), appGoBack );
    g_appProto->defineFunction( ctx, QStringLiteral("goForward"), appGoForward );
300 301 302 303
    g_appProto->defineFunction( ctx, QStringLiteral("setInterval"), appSetInterval );
    g_appProto->defineFunction( ctx, QStringLiteral("clearInterval"), appClearInterval );
    g_appProto->defineFunction( ctx, QStringLiteral("setTimeOut"), appSetTimeOut );
    g_appProto->defineFunction( ctx, QStringLiteral("clearTimeOut"), appClearTimeOut );
304 305 306 307 308 309
}

KJSObject JSApp::object( KJSContext *ctx, DocumentPrivate *doc )
{
    return g_appProto->constructObject( ctx, doc );
}
310 311 312 313

KJSObject JSApp::wrapTimer( KJSContext *ctx, QTimer *timer)
{
    KJSObject timerObject = g_appProto->constructObject( ctx, timer );
314
    timerObject.setProperty( ctx, QStringLiteral("okular_timerID"), timer->timerId() );
315 316 317 318 319 320 321 322 323 324

    g_timerCache->insert( timer->timerId(), timer );

    return timerObject;
}

void JSApp::clearCachedFields()
{
    if ( g_timerCache )
    {
325
        qDeleteAll( g_timerCache->begin(), g_timerCache->end() );
326 327 328
        g_timerCache->clear();
    }
}