• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

qscript.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2007 Richard J. Moore <rich@kde.org>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License version 2 as
00006  *   published by the Free Software Foundation
00007  *
00008  *   This program is distributed in the hope that it will be useful,
00009  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *   GNU General Public License for more details
00012  *
00013  *   You should have received a copy of the GNU Library General Public
00014  *   License along with this program; if not, write to the
00015  *   Free Software Foundation, Inc.,
00016  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00017  */
00018 
00019 #include "qscript.h"
00020 
00021 #include <QScriptEngine>
00022 #include <QFile>
00023 #include <QUiLoader>
00024 
00025 #include <KDebug>
00026 #include <KLocale>
00027 #include <KStandardDirs>
00028 
00029 #include <plasma/applet.h>
00030 #include <plasma/svg.h>
00031 #include <plasma/uiloader.h>
00032 
00033 using namespace Plasma;
00034 
00035 #include "bind_dataengine.h"
00036 
00037 Q_DECLARE_METATYPE(QPainter*)
00038 Q_DECLARE_METATYPE(QStyleOptionGraphicsItem*)
00039 Q_DECLARE_METATYPE(QScriptApplet*)
00040 Q_DECLARE_METATYPE(Layout*)
00041 Q_DECLARE_METATYPE(Applet*)
00042 
00043 QScriptValue constructPainterClass(QScriptEngine *engine);
00044 QScriptValue constructGraphicsItemClass(QScriptEngine *engine);
00045 QScriptValue constructTimerClass(QScriptEngine *engine);
00046 QScriptValue constructFontClass(QScriptEngine *engine);
00047 QScriptValue constructQRectFClass(QScriptEngine *engine);
00048 QScriptValue constructQPointClass(QScriptEngine *engine);
00049 QScriptValue constructQSizeFClass(QScriptEngine *engine);
00050 
00051 /*
00052  * Workaround the fact that QtScripts handling of variants seems a bit broken.
00053  */
00054 QScriptValue variant2ScriptValue( QScriptEngine *engine, QVariant var )
00055 {
00056     if( var.isNull() )
00057     return engine->nullValue();
00058 
00059     switch( var.type() )
00060     {
00061         case QVariant::Invalid:
00062         return engine->nullValue();
00063         case QVariant::Bool:
00064         return QScriptValue( engine, var.toBool() );
00065         case QVariant::Date:
00066         return engine->newDate( var.toDateTime() );
00067         case QVariant::DateTime:
00068         return engine->newDate( var.toDateTime() );
00069         case QVariant::Double:
00070         return QScriptValue( engine, var.toDouble() );
00071         case QVariant::Int:
00072         case QVariant::LongLong:
00073         return QScriptValue( engine, var.toInt() );
00074         case QVariant::String:
00075         return QScriptValue( engine, var.toString() );
00076         case QVariant::Time:
00077         return engine->newDate( var.toDateTime() );
00078         case QVariant::UInt:
00079         return QScriptValue( engine, var.toUInt() );
00080     default:
00081         break;
00082     }
00083 
00084     return qScriptValueFromValue(engine, var);
00085 }
00086 
00087 QScriptValue qScriptValueFromData( QScriptEngine *engine, const DataEngine::Data &data )
00088 {
00089     DataEngine::Data::const_iterator begin = data.begin();
00090     DataEngine::Data::const_iterator end = data.end();
00091     DataEngine::Data::const_iterator it;
00092 
00093     QScriptValue obj = engine->newObject();
00094 
00095     for ( it = begin; it != end; ++it ) {
00096     obj.setProperty( it.key(), variant2ScriptValue( engine, it.value() ) );
00097     }
00098 
00099     return obj;
00100 }
00101 
00102 
00103 QScriptApplet::QScriptApplet( QObject *parent, const QVariantList &args )
00104     : Plasma::AppletScript( parent )
00105 {
00106     kDebug() << "Script applet launched, args" << args;
00107 
00108     m_engine = new QScriptEngine( this );
00109     importExtensions();
00110     setupObjects();
00111 }
00112 
00113 QScriptApplet::~QScriptApplet()
00114 {
00115 }
00116 
00117 void QScriptApplet::reportError()
00118 {
00119     kDebug() << "Error: " << m_engine->uncaughtException().toString()
00120          << " at line " << m_engine->uncaughtExceptionLineNumber() << endl;
00121     kDebug() << m_engine->uncaughtExceptionBacktrace();
00122 }
00123 
00124 void QScriptApplet::showConfigurationInterface()
00125 {
00126     kDebug() << "Script: showConfigurationInterface";
00127 
00128     // Here we'll load a ui file...
00129     QScriptValue global = m_engine->globalObject();
00130 
00131     QScriptValue fun = m_self.property("showConfigurationInterface");
00132     if ( !fun.isFunction() ) {
00133     kDebug() << "Script: ShowConfiguratioInterface is not a function, " << fun.toString();
00134     return;
00135     }
00136 
00137     QScriptContext *ctx = m_engine->pushContext();
00138     ctx->setActivationObject( m_self );
00139     fun.call( m_self );
00140     m_engine->popContext();
00141 
00142     if ( m_engine->hasUncaughtException() ) {
00143     reportError();
00144     }
00145 }
00146 
00147 void QScriptApplet::configAccepted()
00148 {
00149     QScriptValue fun = m_self.property("configAccepted");
00150     if ( !fun.isFunction() ) {
00151     kDebug() << "Script: configAccepted is not a function, " << fun.toString();
00152     return;
00153     }
00154 
00155     QScriptContext *ctx = m_engine->pushContext();
00156     ctx->setActivationObject( m_self );
00157     fun.call( m_self );
00158     m_engine->popContext();
00159 
00160     if ( m_engine->hasUncaughtException() ) {
00161     reportError();
00162     }
00163 }
00164 
00165 void QScriptApplet::dataUpdated( const QString &name, const DataEngine::Data &data )
00166 {
00167     QScriptValue fun = m_self.property("dataUpdated");
00168     if ( !fun.isFunction() ) {
00169     kDebug() << "Script: dataUpdated is not a function, " << fun.toString();
00170     return;
00171     }
00172 
00173     QScriptValueList args;
00174     args << m_engine->toScriptValue( name ) << m_engine->toScriptValue( data );
00175 
00176     QScriptContext *ctx = m_engine->pushContext();
00177     ctx->setActivationObject( m_self );
00178     fun.call( m_self, args );
00179     m_engine->popContext();
00180 
00181     if ( m_engine->hasUncaughtException() ) {
00182     reportError();
00183     }
00184 }
00185 
00186 void QScriptApplet::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
00187 {
00188     Q_UNUSED(option)
00189     Q_UNUSED(contentsRect)
00190 
00191 //    kDebug() << "paintInterface() (c++)";
00192     QScriptValue fun = m_self.property( "paintInterface" );
00193     if ( !fun.isFunction() ) {
00194     kDebug() << "Script: paintInterface is not a function, " << fun.toString();
00195     return;
00196     }
00197 
00198     QScriptValueList args;
00199     args << m_engine->toScriptValue( p );
00200     args << m_engine->toScriptValue( const_cast<QStyleOptionGraphicsItem*>(option) );
00201     args << m_engine->toScriptValue( contentsRect );
00202 
00203     QScriptContext *ctx = m_engine->pushContext();
00204     ctx->setActivationObject( m_self );
00205     fun.call( m_self, args );
00206     m_engine->popContext();
00207 
00208     if ( m_engine->hasUncaughtException() ) {
00209     reportError();
00210     }
00211 }
00212 
00213 bool QScriptApplet::init()
00214 {
00215     kDebug() << "ScriptName:" << applet()->name();
00216     kDebug() << "ScriptCategory:" << applet()->category();
00217 
00218     applet()->resize(200, 200);
00219     QFile file(mainScript());
00220     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
00221         kWarning() << "Unable to load script file";
00222         return false;
00223     }
00224 
00225     QString script = file.readAll();
00226     kDebug() << "Script says" << script;
00227 
00228     m_engine->evaluate( script );
00229     if ( m_engine->hasUncaughtException() ) {
00230         reportError();
00231         return false;
00232     }
00233 
00234     return true;
00235 }
00236 
00237 void QScriptApplet::importExtensions()
00238 {
00239     QStringList extensions;
00240     extensions << "qt.core" << "qt.gui" << "qt.svg" << "qt.xml" << "qt.plasma";
00241     for (int i = 0; i < extensions.size(); ++i) {
00242         QString ext = extensions.at(i);
00243         kDebug() << "importing " << ext << "...";
00244         QScriptValue ret = m_engine->importExtension(ext);
00245         if (ret.isError())
00246             kDebug() << "failed to import extension" << ext << ":" << ret.toString();
00247     }
00248     kDebug() << "done importing extensions.";
00249 }
00250 
00251 void QScriptApplet::setupObjects()
00252 {
00253     QScriptValue global = m_engine->globalObject();
00254 
00255     // Expose an applet
00256     m_self = m_engine->newQObject( this );
00257     m_self.setScope( global );    
00258 
00259     global.setProperty("applet", m_self);
00260     // Add a global loadui method for ui files
00261     QScriptValue fun = m_engine->newFunction( QScriptApplet::loadui );
00262     global.setProperty("loadui", fun);
00263 
00264     // Work around bug in 4.3.0
00265     qMetaTypeId<QVariant>();
00266 
00267     // Add constructors
00268     global.setProperty("PlasmaSvg", m_engine->newFunction( QScriptApplet::newPlasmaSvg ) );
00269 
00270     // Add stuff from 4.4
00271     global.setProperty("QPainter", constructPainterClass(m_engine));
00272     global.setProperty("QGraphicsItem", constructGraphicsItemClass(m_engine));
00273     global.setProperty("QTimer", constructTimerClass(m_engine));
00274     global.setProperty("QFont", constructFontClass(m_engine));
00275     global.setProperty("QRectF", constructQRectFClass(m_engine));
00276     global.setProperty("QSizeF", constructQSizeFClass(m_engine));
00277     global.setProperty("QPoint", constructQPointClass(m_engine));
00278 
00279     // Bindings for data engine
00280     m_engine->setDefaultPrototype( qMetaTypeId<DataEngine*>(), m_engine->newQObject( new DataEngine() ) );
00281 #if 0
00282     fun = m_engine->newFunction( QScriptApplet::dataEngine );
00283     m_self.setProperty("dataEngine", fun);
00284 #endif
00285     
00286     qScriptRegisterMapMetaType<DataEngine::Dict>(m_engine);
00287 //    qScriptRegisterMapMetaType<DataEngine::Data>(m_engine);
00288     qScriptRegisterMetaType<DataEngine::Data>( m_engine, qScriptValueFromData, 0, QScriptValue() );
00289 }
00290 
00291 QString QScriptApplet::findDataResource( const QString &filename )
00292 {
00293     QString path("plasma-script/%1");
00294     return KGlobal::dirs()->findResource("data", path.arg(filename) );
00295 }
00296 
00297 void QScriptApplet::debug( const QString &msg )
00298 {
00299     kDebug() << msg;
00300 }
00301 
00302 #if 0
00303 QScriptValue QScriptApplet::dataEngine(QScriptContext *context, QScriptEngine *engine)
00304 {
00305     if ( context->argumentCount() != 1 )
00306     return context->throwError("dataEngine takes one argument");
00307 
00308     QString dataEngine = context->argument(0).toString();
00309 
00310     Script *self = engine->fromScriptValue<Script*>( context->thisObject() );
00311 
00312     DataEngine *data = self->dataEngine( dataEngine );
00313     return engine->newQObject( data );
00314 }
00315 #endif
00316 
00317 QScriptValue QScriptApplet::loadui(QScriptContext *context, QScriptEngine *engine)
00318 {
00319     if ( context->argumentCount() != 1 )
00320     return context->throwError("loadui takes one argument");
00321 
00322     QUiLoader loader;
00323     QString filename = context->argument(0).toString();
00324     QFile f( filename );
00325     if ( !f.open(QIODevice::ReadOnly) )
00326     return context->throwError(QString("Unable to open '%1'").arg(filename) );
00327 
00328     QWidget *w = loader.load( &f );
00329     f.close();
00330 
00331     return engine->newQObject( w );
00332 }
00333 
00334 QScriptValue QScriptApplet::newPlasmaSvg(QScriptContext *context, QScriptEngine *engine)
00335 {
00336     if ( context->argumentCount() == 0 )
00337     return context->throwError("Constructor takes at least 1 argument");
00338 
00339     QString filename = context->argument(0).toString();
00340     QObject *parent = 0;
00341 
00342     if ( context->argumentCount() == 2 )
00343     parent = qscriptvalue_cast<QObject *>(context->argument(1));
00344 
00345     Svg *svg = new Svg( parent );
00346     svg->setImagePath(filename);
00347     return engine->newQObject( svg );
00348 }
00349 
00350 void QScriptApplet::installWidgets( QScriptEngine *engine )
00351 {
00352     QScriptValue globalObject = engine->globalObject();
00353     UiLoader loader;
00354 
00355     QStringList widgets = loader.availableWidgets();
00356     for ( int i=0; i < widgets.size(); ++i ) {
00357     QScriptValue fun = engine->newFunction( createWidget );
00358     QScriptValue name = engine->toScriptValue(widgets[i]);
00359     fun.setProperty( QString("functionName"), name,
00360              QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration );
00361     fun.setProperty( QString("prototype"), createPrototype( engine, name.toString() ) );
00362 
00363     globalObject.setProperty(widgets[i], fun);
00364     }
00365 
00366 }
00367 
00368 QScriptValue QScriptApplet::createWidget(QScriptContext *context, QScriptEngine *engine)
00369 {
00370 #if 0 // FIXME: Broken by WoC
00371     if ( context->argumentCount() > 1 )
00372     return context->throwError("Create widget takes one argument");
00373 
00374     Applet *parent = 0;
00375     if ( context->argumentCount() ) {
00376     parent = qscriptvalue_cast<Applet*>(context->argument(0));
00377 
00378     if ( !parent )
00379         return context->throwError("The parent must be a Widget");
00380     }
00381 
00382     QString self = context->callee().property( "functionName" ).toString();
00383     UiLoader loader;
00384     Applet *w = loader.createWidget( self, parent );
00385 
00386     if (!w)
00387     return QScriptValue();
00388 
00389     QScriptValue fun = engine->newQObject( w );
00390     fun.setPrototype( context->callee().property("prototype") );
00391 
00392     return fun;
00393 #endif
00394     return QScriptValue();
00395 }
00396 
00397 QScriptValue QScriptApplet::createPrototype( QScriptEngine *engine, const QString &name )
00398 {
00399     Q_UNUSED(name)
00400     QScriptValue proto = engine->newObject();
00401 
00402     // Hook for adding extra properties/methods
00403 
00404     return proto;
00405 }
00406 
00407 #include "qscript.moc"
00408 
00409 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal