00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
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
00256 m_self = m_engine->newQObject( this );
00257 m_self.setScope( global );
00258
00259 global.setProperty("applet", m_self);
00260
00261 QScriptValue fun = m_engine->newFunction( QScriptApplet::loadui );
00262 global.setProperty("loadui", fun);
00263
00264
00265 qMetaTypeId<QVariant>();
00266
00267
00268 global.setProperty("PlasmaSvg", m_engine->newFunction( QScriptApplet::newPlasmaSvg ) );
00269
00270
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
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
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
00403
00404 return proto;
00405 }
00406
00407 #include "qscript.moc"
00408
00409