diff --git a/core/script/kjs_app.cpp b/core/script/kjs_app.cpp index c17acd13f..3404356da 100644 --- a/core/script/kjs_app.cpp +++ b/core/script/kjs_app.cpp @@ -1,331 +1,441 @@ /*************************************************************************** * Copyright (C) 2008 by Pino Toscano * * Copyright (C) 2008 by Harri Porten * * * * 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 #include #include #include #include #include #include +#include +#include #include "../document_p.h" #include "../scripter.h" #include "kjs_fullscreen_p.h" using namespace Okular; #define OKULAR_TIMERID QStringLiteral( "okular_timerID" ) static KJSPrototype *g_appProto; typedef QHash< int, QTimer * > TimerCache; Q_GLOBAL_STATIC( TimerCache, g_timerCache ) // 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 * ) { QLocale locale; QString lang = QLocale::languageToString(locale.language()); QString country = QLocale::countryToString(locale.country()); QString acroLang = QStringLiteral( "ENU" ); if ( lang == QLatin1String( "da" ) ) acroLang = QStringLiteral( "DAN" ); // Danish else if ( lang == QLatin1String( "de" ) ) acroLang = QStringLiteral( "DEU" ); // German else if ( lang == QLatin1String( "en" ) ) acroLang = QStringLiteral( "ENU" ); // English else if ( lang == QLatin1String( "es" ) ) acroLang = QStringLiteral( "ESP" ); // Spanish else if ( lang == QLatin1String( "fr" ) ) acroLang = QStringLiteral( "FRA" ); // French else if ( lang == QLatin1String( "it" ) ) acroLang = QStringLiteral( "ITA" ); // Italian else if ( lang == QLatin1String( "ko" ) ) acroLang = QStringLiteral( "KOR" ); // Korean else if ( lang == QLatin1String( "ja" ) ) acroLang = QStringLiteral( "JPN" ); // Japanese else if ( lang == QLatin1String( "nl" ) ) acroLang = QStringLiteral( "NLD" ); // Dutch else if ( lang == QLatin1String( "pt" ) && country == QLatin1String( "BR" ) ) acroLang = QStringLiteral( "PTB" ); // Brazilian Portuguese else if ( lang == QLatin1String( "fi" ) ) acroLang = QStringLiteral( "SUO" ); // Finnish else if ( lang == QLatin1String( "sv" ) ) acroLang = QStringLiteral( "SVE" ); // Swedish else if ( lang == QLatin1String( "zh" ) && country == QLatin1String( "CN" ) ) acroLang = QStringLiteral( "CHS" ); // Chinese Simplified else if ( lang == QLatin1String( "zh" ) && country == QLatin1String( "TW" ) ) acroLang = QStringLiteral( "CHT" ); // Chinese Traditional 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 return KJSString( QStringLiteral( "UNIX" ) ); #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; 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 ); 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... return KJSString( QStringLiteral( "Reader" ) ); } static KJSObject appGetViewerVariation( KJSContext *, void * ) { // faking a bit... return KJSString( QStringLiteral( "Reader" ) ); } static KJSObject appGetViewerVersion( KJSContext *, void * ) { // faking a bit... return KJSNumber( fake_acroversion ); } +/* + Alert function defined in the reference, it shows a Dialog Box with options. + app.alert() +*/ +static KJSObject appAlert( KJSContext *context, void *, + const KJSArguments &arguments ) +{ + if ( arguments.count() < 1 ) + { + return context->throwException( i18n( "Missing alert type") ); + } + QString cMsg = arguments.at( 0 ).toString( context ); + int nIcon = 0; + int nType = 0; + QString cTitle = "Okular"; + + if( arguments.count() >= 2 ) + nIcon = arguments.at( 1 ).toInt32( context ); + if( arguments.count() >= 3 ) + nType = arguments.at( 2 ).toInt32( context ); + if( arguments.count() >= 4 ) + cTitle = arguments.at( 3 ).toString( context ); + + QMessageBox::Icon icon; + switch( nIcon ) + { + case 0: + icon = QMessageBox::Critical; + break; + case 1: + icon = QMessageBox::Warning; + break; + case 2: + icon = QMessageBox::Question; + break; + case 3: + icon = QMessageBox::Information; + break; + } + + QMessageBox box( icon, cTitle, cMsg ); + + switch( nType ) + { + case 0: + box.setStandardButtons( QMessageBox::Ok ); + break; + case 1: + box.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel ); + break; + case 2: + box.setStandardButtons( QMessageBox::Yes | QMessageBox::No ); + break; + case 3: + box.setStandardButtons( QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel ); + break; + } + + QCheckBox *checkBox = nullptr; + KJSObject oCheckbox; + if( arguments.count() >= 6 ) + { + oCheckbox = arguments.at( 5 ); + KJSObject oMsg = oCheckbox.property( context, "cMsg" ); + QString msg = i18n( "Do not show this message again" ); + + if( oMsg.isString() ) + msg = oMsg.toString( context ); + + bool bInitialValue = false; + KJSObject value = oCheckbox.property( context, "bInitialValue" ); + if( value.isBoolean() ) + bInitialValue = value.toBoolean( context ); + checkBox = new QCheckBox( msg ); + checkBox->setChecked( bInitialValue ); + box.setCheckBox( checkBox ); + + } + + int button = box.exec(); + + int ret; + + switch( button ) + { + case QMessageBox::Ok: + ret = 1; + break; + case QMessageBox::Cancel: + ret = 2; + break; + case QMessageBox::No: + ret = 3; + break; + case QMessageBox::Yes: + ret = 4; + break; + } + + if( arguments.count() >= 6 ) + oCheckbox.setProperty( context, QStringLiteral( "bAfterValue" ), checkBox->isChecked() ); + + delete checkBox; + + return KJSNumber( ret ); +} + static KJSObject appBeep( KJSContext *context, void *, const KJSArguments &arguments ) { if ( arguments.count() < 1 ) { return context->throwException( QStringLiteral("Missing beep type") ); } QApplication::beep(); return KJSUndefined(); } static KJSObject appGetNthPlugInName( KJSContext *context, void *, const KJSArguments &arguments ) { if ( arguments.count() < 1 ) { return context->throwException( QStringLiteral("Missing plugin index") ); } const int nIndex = arguments.at( 0 ).toInt32( context ); if ( nIndex < 0 || nIndex >= s_num_fake_plugins ) return context->throwException( QStringLiteral("PlugIn index out of bounds") ); 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(); } // app.setInterval() static KJSObject appSetInterval( KJSContext *ctx, void *object, const KJSArguments &arguments ) { DocumentPrivate *doc = reinterpret_cast< DocumentPrivate * >( object ); const QString function = arguments.at( 0 ).toString( ctx ) + ';'; const int interval = arguments.at( 1 ).toInt32( ctx ); QTimer *timer = new QTimer(); QObject::connect( timer, &QTimer::timeout, doc->m_parent, [=](){ doc->executeScript( function ); } ); timer->start( interval ); return JSApp::wrapTimer( ctx, timer ); } // app.clearInterval() static KJSObject appClearInterval( KJSContext *ctx, void *, const KJSArguments &arguments ) { KJSObject timerObject = arguments.at( 0 ); const int timerId = timerObject.property( ctx, OKULAR_TIMERID ).toInt32( ctx ); 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 ); const QString function = arguments.at( 0 ).toString( ctx ) + ';'; const int interval = arguments.at( 1 ).toInt32( ctx ); QTimer *timer = new QTimer(); timer->setSingleShot( true ); QObject::connect( timer, &QTimer::timeout, doc->m_parent, [=](){ doc->executeScript( function ); } ); timer->start( interval ); return JSApp::wrapTimer( ctx, timer ); } // app.clearTimeOut() static KJSObject appClearTimeOut( KJSContext *ctx, void *, const KJSArguments &arguments ) { KJSObject timerObject = arguments.at( 0 ); const int timerId = timerObject.property( ctx, OKULAR_TIMERID ).toInt32( ctx ); QTimer *timer = g_timerCache->value( timerId ); if( timer != nullptr ) { timer->stop(); g_timerCache->remove( timerId ); delete timer; } return KJSUndefined(); } void JSApp::initType( KJSContext *ctx ) { static bool initialized = false; if ( initialized ) return; initialized = true; g_appProto = new KJSPrototype(); 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("alert"), appAlert ); 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 ); 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 ); } KJSObject JSApp::object( KJSContext *ctx, DocumentPrivate *doc ) { return g_appProto->constructObject( ctx, doc ); } KJSObject JSApp::wrapTimer( KJSContext *ctx, QTimer *timer) { KJSObject timerObject = g_appProto->constructObject( ctx, timer ); timerObject.setProperty( ctx, OKULAR_TIMERID, timer->timerId() ); g_timerCache->insert( timer->timerId(), timer ); return timerObject; } void JSApp::clearCachedFields() { if ( g_timerCache ) { qDeleteAll( g_timerCache->begin(), g_timerCache->end() ); g_timerCache->clear(); } } diff --git a/core/script/kjs_util.cpp b/core/script/kjs_util.cpp index ba3c552e8..65c7e80db 100644 --- a/core/script/kjs_util.cpp +++ b/core/script/kjs_util.cpp @@ -1,74 +1,107 @@ /*************************************************************************** * Copyright (C) 2008 by Pino Toscano * * Copyright (C) 2008 by Harri Porten * * * * 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_util_p.h" #include #include #include #include +#include +#include +#include +#include using namespace Okular; static KJSPrototype *g_utilProto; static KJSObject crackURL( KJSContext *context, void *, const KJSArguments &arguments ) { if ( arguments.count() < 1 ) { return context->throwException( QStringLiteral("Missing URL argument") ); } QString cURL = arguments.at( 0 ).toString( context ); QUrl url(QUrl::fromLocalFile(cURL) ); if ( !url.isValid() ) { return context->throwException( QStringLiteral("Invalid URL") ); } if ( url.scheme() != QLatin1String( "file" ) || url.scheme() != QLatin1String( "http" ) || url.scheme() != QLatin1String( "https" ) ) { return context->throwException( QStringLiteral("Protocol not valid: '") + url.scheme() + QLatin1Char('\'') ); } KJSObject obj; obj.setProperty( context, QStringLiteral("cScheme"), url.scheme() ); if ( !url.userName().isEmpty() ) obj.setProperty( context, QStringLiteral("cUser"), url.userName() ); if ( !url.password().isEmpty() ) obj.setProperty( context, QStringLiteral("cPassword"), url.password() ); obj.setProperty( context, QStringLiteral("cHost"), url.host() ); obj.setProperty( context, QStringLiteral("nPort"), url.port( 80 ) ); // TODO cPath (Optional) The path portion of the URL. // TODO cParameters (Optional) The parameter string portion of the URL. if ( url.hasFragment() ) obj.setProperty( context, QStringLiteral("cFragments"), url.fragment(QUrl::FullyDecoded) ); return obj; } +static KJSObject printd( KJSContext *context, void *, + const KJSArguments &arguments ) +{ + if ( arguments.count() < 2 ) + { + return context->throwException( QStringLiteral("Invalid arguments") ); + } + + QLocale locale( "en_US" ); + QString format = arguments.at( 0 ).toString( context ).replace( "tt", "ap" ); + format.replace( "t", "a" ); + + QStringList str = arguments.at( 1 ).toString( context ).split( QRegularExpression( "\\W") ); + QString myStr = QStringLiteral( "%1/%2/%3 %4:%5:%6" ).arg( str[1] ). + arg( str[2] ).arg( str[3] ).arg( str[4] ).arg( str[5] ).arg( str[6] ); + QDateTime date = locale.toDateTime( myStr, QStringLiteral( "MMM/d/yyyy H:m:s" ) ); + + for( int i = 0 ; i < format.size() ; ++i ) + { + if( format[i] == 'M' ) + format[i] = 'm'; + else if( format[i] == 'm' ) + format[i] = 'M'; + } + + return KJSString( date.toString( format ) ); +} + void JSUtil::initType( KJSContext *ctx ) { static bool initialized = false; if ( initialized ) return; initialized = true; g_utilProto = new KJSPrototype(); g_utilProto->defineFunction( ctx, QStringLiteral("crackURL"), crackURL ); + g_utilProto->defineFunction( ctx, QStringLiteral("printd"), printd ); } KJSObject JSUtil::object( KJSContext *ctx ) { return g_utilProto->constructObject( ctx, nullptr ); }