KParts
scriptableextension.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2010 Maksim Orlovich <maksim@kde.org> 00003 Copyright (C) 2002, 2004 Koos Vriezen <koos.vriezen@gmail.com> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 #include "scriptableextension.h" 00021 #include "scriptableextension_p.h" 00022 #include <kglobal.h> 00023 #include <kdebug.h> 00024 00025 namespace KParts { 00026 00027 struct ScriptableExtensionPrivate { 00028 ScriptableExtension* hostContext; 00029 00030 ScriptableExtensionPrivate(): hostContext(0) 00031 {} 00032 }; 00033 00034 ScriptableExtension::ScriptableExtension(QObject* parent): 00035 QObject(parent), d(new ScriptableExtensionPrivate) 00036 {} 00037 00038 ScriptableExtension::~ScriptableExtension() 00039 { 00040 delete d; 00041 } 00042 00043 ScriptableExtension* ScriptableExtension::childObject(QObject* obj) 00044 { 00045 return KGlobal::findDirectChild<KParts::ScriptableExtension*>(obj); 00046 } 00047 00048 ScriptableExtension* ScriptableExtension::adapterFromLiveConnect(QObject* parentObj, 00049 LiveConnectExtension* oldApi) 00050 { 00051 return new ScriptableLiveConnectExtension(parentObj, oldApi); 00052 } 00053 00054 void ScriptableExtension::setHost(ScriptableExtension* host) 00055 { 00056 d->hostContext = host; 00057 } 00058 00059 ScriptableExtension* ScriptableExtension::host() const 00060 { 00061 return d->hostContext; 00062 } 00063 00064 QVariant ScriptableExtension::rootObject() 00065 { 00066 return QVariant::fromValue(Null()); 00067 } 00068 00069 QVariant ScriptableExtension::enclosingObject() 00070 { 00071 if (d->hostContext) 00072 return d->hostContext->encloserForKid(this); 00073 else 00074 return QVariant::fromValue(Null()); 00075 } 00076 00077 QVariant ScriptableExtension::encloserForKid(KParts::ScriptableExtension* kid) 00078 { 00079 Q_UNUSED(kid); 00080 return QVariant::fromValue(Null()); 00081 } 00082 00083 static QVariant unimplemented() 00084 { 00085 ScriptableExtension::Exception except(QString::fromLatin1("[unimplemented]")); 00086 return QVariant::fromValue(except); 00087 } 00088 00089 QVariant ScriptableExtension::callAsFunction(ScriptableExtension* callerPrincipal, 00090 quint64 objId, const ArgList& args) 00091 { 00092 Q_UNUSED(callerPrincipal); 00093 Q_UNUSED(objId); 00094 Q_UNUSED(args); 00095 return unimplemented(); 00096 } 00097 00098 QVariant ScriptableExtension::callFunctionReference(ScriptableExtension* callerPrincipal, 00099 quint64 objId, const QString& f, 00100 const ArgList& args) 00101 { 00102 Q_UNUSED(callerPrincipal); 00103 Q_UNUSED(objId); 00104 Q_UNUSED(args); 00105 Q_UNUSED(f); 00106 return unimplemented(); 00107 } 00108 00109 QVariant ScriptableExtension::callAsConstructor(ScriptableExtension* callerPrincipal, 00110 quint64 objId, const ArgList& args) 00111 { 00112 Q_UNUSED(callerPrincipal); 00113 Q_UNUSED(objId); 00114 Q_UNUSED(args); 00115 return unimplemented(); 00116 } 00117 00118 bool ScriptableExtension::hasProperty(ScriptableExtension* callerPrincipal, 00119 quint64 objId, const QString& propName) 00120 { 00121 Q_UNUSED(callerPrincipal); 00122 Q_UNUSED(objId); 00123 Q_UNUSED(propName); 00124 return false; 00125 } 00126 00127 QVariant ScriptableExtension::get(ScriptableExtension* callerPrincipal, 00128 quint64 objId, const QString& propName) 00129 { 00130 Q_UNUSED(callerPrincipal); 00131 Q_UNUSED(objId); 00132 Q_UNUSED(propName); 00133 return unimplemented(); 00134 } 00135 00136 bool ScriptableExtension::put(ScriptableExtension* callerPrincipal, quint64 objId, 00137 const QString& propName, const QVariant& value) 00138 { 00139 Q_UNUSED(callerPrincipal); 00140 Q_UNUSED(objId); 00141 Q_UNUSED(propName); 00142 Q_UNUSED(value); 00143 return false; 00144 } 00145 00146 bool ScriptableExtension::removeProperty(ScriptableExtension* callerPrincipal, 00147 quint64 objId, const QString& propName) 00148 { 00149 Q_UNUSED(callerPrincipal); 00150 Q_UNUSED(objId); 00151 Q_UNUSED(propName); 00152 return false; 00153 } 00154 00155 bool ScriptableExtension::enumerateProperties(ScriptableExtension* callerPrincipal, 00156 quint64 objId, QStringList* result) 00157 { 00158 Q_UNUSED(callerPrincipal); 00159 Q_UNUSED(objId); 00160 Q_UNUSED(result); 00161 return false; 00162 } 00163 00164 bool ScriptableExtension::setException(ScriptableExtension* callerPrincipal, 00165 const QString& message) 00166 { 00167 Q_UNUSED(callerPrincipal); 00168 Q_UNUSED(message); 00169 return false; 00170 } 00171 00172 QVariant ScriptableExtension::evaluateScript(ScriptableExtension* callerPrincipal, 00173 quint64 contextObjectId, 00174 const QString& code, 00175 ScriptLanguage language) 00176 { 00177 Q_UNUSED(callerPrincipal); 00178 Q_UNUSED(contextObjectId); 00179 Q_UNUSED(code); 00180 Q_UNUSED(language); 00181 return unimplemented(); 00182 } 00183 00184 bool ScriptableExtension::isScriptLanguageSupported(ScriptLanguage lang) const 00185 { 00186 Q_UNUSED(lang); 00187 return false; 00188 } 00189 00190 void ScriptableExtension::acquire(quint64 objId) 00191 { 00192 Q_UNUSED(objId); 00193 } 00194 00195 QVariant ScriptableExtension::acquireValue(const QVariant& v) 00196 { 00197 if (v.canConvert<Object>()) { 00198 Object o = v.value<Object>(); 00199 o.owner->acquire(o.objId); 00200 } else if (v.canConvert<FunctionRef>()) { 00201 FunctionRef fr = v.value<FunctionRef>(); 00202 fr.base.owner->acquire(fr.base.objId); 00203 } 00204 return v; 00205 } 00206 00207 void ScriptableExtension::release(quint64 objId) 00208 { 00209 Q_UNUSED(objId); 00210 } 00211 00212 QVariant ScriptableExtension::releaseValue(const QVariant& v) 00213 { 00214 if (v.canConvert<Object>()) { 00215 Object o = v.value<Object>(); 00216 o.owner->release(o.objId); 00217 } else if (v.canConvert<FunctionRef>()) { 00218 FunctionRef fr = v.value<FunctionRef>(); 00219 fr.base.owner->release(fr.base.objId); 00220 } 00221 return v; 00222 } 00223 00224 // LiveConnectExtension -> ScriptableExtension adapter. We use 00225 // lc object IDs as our own object IDs. 00226 // ---------------------------------------------------------------------------- 00227 ScriptableLiveConnectExtension::ScriptableLiveConnectExtension(QObject* p, LiveConnectExtension* old): 00228 ScriptableExtension(p), wrapee(old) 00229 { 00230 connect(wrapee, 00231 SIGNAL(partEvent(const unsigned long, const QString &, const KParts::LiveConnectExtension::ArgList &)), 00232 this, 00233 SLOT(liveConnectEvent(const unsigned long, const QString&, const KParts::LiveConnectExtension::ArgList &))); 00234 } 00235 00236 QVariant ScriptableLiveConnectExtension::rootObject() 00237 { 00238 // Plugin root is always LC object #0. 00239 return acquireValue(QVariant::fromValue(ScriptableExtension::Object(this, 0))); 00240 } 00241 00242 bool ScriptableLiveConnectExtension::hasProperty(ScriptableExtension*, quint64 objId, const QString& propName) 00243 { 00244 QVariant val = get(0, objId, propName); 00245 bool ok = !val.canConvert<ScriptableExtension::Exception>(); 00246 releaseValue(val); 00247 return ok; 00248 } 00249 00250 // Note that since we wrap around a plugin, and do not implement the browser, 00251 // we do not perform XSS checks ourselves. 00252 QVariant ScriptableLiveConnectExtension::callFunctionReference(ScriptableExtension*, 00253 quint64 o, const QString& f, const ScriptableExtension::ArgList& a) 00254 { 00255 QStringList qargs; 00256 // Convert args to strings for LC use. 00257 for (int i = 0; i < a.size(); ++i) { 00258 bool ok; 00259 qargs.append(toLC(a[i], &ok)); 00260 if (!ok) 00261 return unimplemented(); 00262 } 00263 00264 LiveConnectExtension::Type retType; 00265 unsigned long retObjId; 00266 QString retVal; 00267 if (wrapee->call((unsigned long)o, f, qargs, retType, retObjId, retVal)) { 00268 return acquireValue(fromLC(QString(), retType, retObjId, retVal)); 00269 } else { 00270 return unimplemented(); 00271 } 00272 } 00273 00274 QVariant ScriptableLiveConnectExtension::get(ScriptableExtension*, 00275 quint64 objId, const QString& propName) 00276 { 00277 LiveConnectExtension::Type retType; 00278 unsigned long retObjId; 00279 QString retVal; 00280 if (wrapee->get((unsigned long)objId, propName, retType, retObjId, retVal)) { 00281 return acquireValue(fromLC(propName, retType, retObjId, retVal)); 00282 } else { 00283 // exception signals failure. ### inellegant 00284 return unimplemented(); 00285 } 00286 } 00287 00288 bool ScriptableLiveConnectExtension::put(ScriptableExtension*, quint64 objId, 00289 const QString& propName, const QVariant& value) 00290 { 00291 bool ok; 00292 QString val = toLC(value, &ok); 00293 if (!ok) 00294 return false; 00295 00296 return wrapee->put((unsigned long)objId, propName, val); 00297 } 00298 00299 QVariant ScriptableLiveConnectExtension::fromLC(const QString& name, 00300 LiveConnectExtension::Type type, 00301 unsigned long objId, 00302 const QString& value) 00303 { 00304 switch (type) { 00305 case KParts::LiveConnectExtension::TypeBool: { 00306 bool ok; 00307 int i = value.toInt(&ok); 00308 if (ok) 00309 return QVariant(bool(i)); 00310 return QVariant(value.toLower() == QLatin1String("true")); 00311 } 00312 case KParts::LiveConnectExtension::TypeObject: 00313 case KParts::LiveConnectExtension::TypeFunction: { 00314 if (!refCounts.contains(objId)) 00315 refCounts[objId] = 0; 00316 00317 Object o = ScriptableExtension::Object(this, objId); 00318 if (type == KParts::LiveConnectExtension::TypeObject) 00319 return QVariant::fromValue(o); 00320 else 00321 return QVariant::fromValue(FunctionRef(o, name)); 00322 } 00323 00324 case KParts::LiveConnectExtension::TypeNumber: 00325 return QVariant(value.toDouble()); 00326 00327 case KParts::LiveConnectExtension::TypeString: 00328 return QVariant(value); 00329 00330 case KParts::LiveConnectExtension::TypeVoid: 00331 default: 00332 return QVariant::fromValue(ScriptableExtension::Undefined()); 00333 } 00334 } 00335 00336 QString ScriptableLiveConnectExtension::toLC(const QVariant& in, bool* ok) 00337 { 00338 *ok = true; // most of the time. 00339 00340 // Objects (or exceptions) can't be converted 00341 if (in.canConvert<ScriptableExtension::Object>() || 00342 in.canConvert<ScriptableExtension::Exception>() || 00343 in.canConvert<ScriptableExtension::FunctionRef>()) { 00344 00345 *ok = false; 00346 return QString(); 00347 } 00348 00349 // Convert null and undefined to appropriate strings 00350 // ### this matches old KHTML behavior, but is this sensible? 00351 if (in.canConvert<ScriptableExtension::Null>()) 00352 return QString::fromLatin1("null"); 00353 00354 if (in.canConvert<ScriptableExtension::Undefined>()) 00355 return QString::fromLatin1("undefined"); 00356 00357 if (in.type() == QVariant::Bool) 00358 return in.toBool() ? QString::fromLatin1("true") : QString::fromLatin1("false"); 00359 00360 // Just stringify everything else, makes sense for nums as well. 00361 if (in.canConvert<QString>()) 00362 return in.toString(); 00363 00364 // something really icky... 00365 *ok = false; 00366 return QString(); 00367 } 00368 00369 void ScriptableLiveConnectExtension::acquire(quint64 objId) 00370 { 00371 ++refCounts[objId]; 00372 } 00373 00374 void ScriptableLiveConnectExtension::release(quint64 objId) 00375 { 00376 int newRC = --refCounts[objId]; 00377 if (!newRC) { 00378 if (objId != 0) 00379 wrapee->unregister((unsigned long)objId); 00380 refCounts.remove(objId); 00381 } 00382 } 00383 00384 void ScriptableLiveConnectExtension::liveConnectEvent(const unsigned long, const QString& event, 00385 const LiveConnectExtension::ArgList& args) 00386 { 00387 // We want to evaluate in the enclosure's context. 00388 QVariant enclosure = enclosingObject(); 00389 if (!enclosure.canConvert<Object>()) { 00390 releaseValue(enclosure); 00391 kDebug(1000) << "No enclosure, can't evaluate"; 00392 return; 00393 } 00394 00395 Object enclosureObj = enclosure.value<Object>(); 00396 00397 if (!host()->isScriptLanguageSupported(ECMAScript)) { 00398 releaseValue(enclosure); 00399 kDebug(1000) << "Host can't evaluate ECMAScript"; 00400 } 00401 00402 // Compute a string to evaluate. We ned to escape a lot of stuff 00403 // since we're composing a bunch of strings into one. 00404 QString script; 00405 script.sprintf("%s(", event.toLatin1().constData()); 00406 00407 LiveConnectExtension::ArgList::const_iterator i = args.begin(); 00408 const LiveConnectExtension::ArgList::const_iterator argsBegin = i; 00409 const LiveConnectExtension::ArgList::const_iterator argsEnd = args.end(); 00410 00411 for ( ; i != argsEnd; ++i) { 00412 if (i != argsBegin) 00413 script += ","; 00414 if ((*i).first == KParts::LiveConnectExtension::TypeString) { 00415 script += "\""; 00416 script += QString((*i).second).replace('\\', "\\\\").replace('"', "\\\""); 00417 script += "\""; 00418 } else 00419 script += (*i).second; 00420 } 00421 script += ")"; 00422 00423 kDebug(1000) << script; 00424 00425 // Ask host to evaluate.. (unfortunately, we can't do anything with the result, 00426 // but anything that uses this interface isn't expective one in the first place) 00427 QVariant result = host()->evaluateScript(this, enclosureObj.objId, script); 00428 00429 releaseValue(result); 00430 releaseValue(enclosure); 00431 } 00432 00433 // hash functions 00434 // ---------------------------------------------------------------------------- 00435 00436 unsigned int qHash(const KParts::ScriptableExtension::Object& o) 00437 { 00438 return qHash(qMakePair(o.owner, o.objId)); 00439 } 00440 00441 unsigned int qHash(const KParts::ScriptableExtension::FunctionRef& f) 00442 { 00443 return qHash(qMakePair(f.base, f.field)); 00444 } 00445 00446 } // namespace KParts 00447 00448 00449 00450 #include "scriptableextension.moc" 00451 #include "scriptableextension_p.moc" 00452 // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; 00453
KDE 4.6 API Reference