File indexing completed on 2024-03-24 15:37:26
0001 /*************************************************************************** 0002 * plugin.cpp 0003 * This file is part of the KDE project 0004 * copyright (C)2007 by Sebastian Sauer (mail@dipe.org) 0005 * 0006 * This program is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this program; see the file COPYING. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 ***************************************************************************/ 0019 0020 #include "plugin.h" 0021 #include "kross_qts_plugin_debug.h" 0022 0023 #include "../core/manager.h" 0024 #include "../core/object.h" 0025 0026 #include <QByteArray> 0027 #include <QUrl> 0028 #include <QColor> 0029 #include <QRect> 0030 #include <QPoint> 0031 #include <QSize> 0032 #include <QWidget> 0033 #include <QLayout> 0034 #include <QVBoxLayout> 0035 #include <QtUiTools/QUiLoader> 0036 #include <QAbstractItemView> 0037 #include <QAbstractItemModel> 0038 #include <QStringListModel> 0039 #include <QScriptClass> 0040 #include <QScriptContext> 0041 #include <QScriptValueIterator> 0042 #include <QDebug> 0043 0044 #include <klocalizedstring.h> 0045 0046 using namespace Kross; 0047 0048 namespace Kross 0049 { 0050 0051 /** 0052 * The EcmaObject implements QScriptClass and Kross::Object to provide 0053 * custom behavior to QtScript objects. 0054 */ 0055 class EcmaObject : public QScriptClass, public Kross::Object 0056 { 0057 public: 0058 explicit EcmaObject(QScriptEngine *engine, const QScriptValue &object = QScriptValue()) 0059 : QScriptClass(engine), Kross::Object(), m_object(object) {} 0060 ~EcmaObject() override {} 0061 QString name() const override 0062 { 0063 return "KrossObject"; 0064 } 0065 QScriptValue prototype() const override 0066 { 0067 return m_object; 0068 } 0069 0070 QVariant callMethod(const QString &name, const QVariantList &args = QVariantList()) override 0071 { 0072 QScriptValue function = m_object.property(name); 0073 if (! function.isFunction()) { 0074 qCWarning(KROSS_QTS_PLUGIN_LOG) << "EcmaScript::callFunction No such function " << name; 0075 if (QScriptContext *context = engine()->currentContext()) { 0076 context->throwError(QScriptContext::ReferenceError, i18n("No such function \"%1\"", name)); 0077 } 0078 return QVariant(); 0079 } 0080 QScriptValueList arguments; 0081 foreach (const QVariant &v, args) { 0082 arguments << engine()->toScriptValue(v); 0083 } 0084 QScriptValue result = function.call(m_object, arguments); 0085 return result.toVariant(); 0086 } 0087 0088 QStringList methodNames() override 0089 { 0090 QStringList methods; 0091 QScriptValueIterator it(m_object); 0092 while (it.hasNext()) { 0093 it.next(); 0094 if (it.value().isFunction()) { 0095 methods << it.name(); 0096 } 0097 } 0098 return methods; 0099 } 0100 0101 private: 0102 QScriptValue m_object; 0103 }; 0104 0105 QScriptValue toByteArray(QScriptEngine *e, const QByteArray &ba) 0106 { 0107 return ba.isNull() ? e->nullValue() : e->newVariant(ba); 0108 } 0109 void fromByteArray(const QScriptValue &v, QByteArray &ba) 0110 { 0111 ba = v.isNull() ? QByteArray() : v.toString().toUtf8(); 0112 } 0113 0114 QScriptValue toUrl(QScriptEngine *e, const QUrl &url) 0115 { 0116 return e->newVariant(url.toString()); 0117 } 0118 void fromUrl(const QScriptValue &v, QUrl &url) 0119 { 0120 url.setUrl(v.toString()); 0121 } 0122 0123 QScriptValue toColor(QScriptEngine *e, const QColor &c) 0124 { 0125 return c.isValid() ? e->newVariant(c.name()) : e->nullValue(); 0126 } 0127 void fromColor(const QScriptValue &v, QColor &c) 0128 { 0129 c.setNamedColor(v.isNull() ? QString() : v.toString()); 0130 } 0131 0132 QScriptValue toRect(QScriptEngine *e, const QRect &r) 0133 { 0134 return e->toScriptValue(QVariantList() << r.x() << r.y() << r.width() << r.height()); 0135 } 0136 void fromRect(const QScriptValue &v, QRect &r) 0137 { 0138 r = v.isArray() ? QRect(v.property(0).toInt32(), v.property(1).toInt32(), v.property(2).toInt32(), v.property(3).toInt32()) : QRect(); 0139 } 0140 QScriptValue toRectF(QScriptEngine *e, const QRectF &r) 0141 { 0142 return e->toScriptValue(QVariantList() << r.x() << r.y() << r.width() << r.height()); 0143 } 0144 void fromRectF(const QScriptValue &v, QRectF &r) 0145 { 0146 r = v.isArray() ? QRectF(v.property(0).toNumber(), v.property(1).toNumber(), v.property(2).toNumber(), v.property(3).toNumber()) : QRectF(); 0147 } 0148 0149 QScriptValue toPoint(QScriptEngine *e, const QPoint &p) 0150 { 0151 return e->toScriptValue(QVariantList() << p.x() << p.y()); 0152 } 0153 void fromPoint(const QScriptValue &v, QPoint &p) 0154 { 0155 p = v.isArray() ? QPoint(v.property(0).toInt32(), v.property(1).toInt32()) : QPoint(); 0156 } 0157 QScriptValue toPointF(QScriptEngine *e, const QPointF &p) 0158 { 0159 return e->toScriptValue(QVariantList() << p.x() << p.y()); 0160 } 0161 void fromPointF(const QScriptValue &v, QPointF &p) 0162 { 0163 p = v.isArray() ? QPointF(v.property(0).toNumber(), v.property(1).toNumber()) : QPointF(); 0164 } 0165 0166 QScriptValue toSize(QScriptEngine *e, const QSize &s) 0167 { 0168 return e->toScriptValue(QVariantList() << s.width() << s.height()); 0169 } 0170 void fromSize(const QScriptValue &v, QSize &s) 0171 { 0172 s = v.isArray() ? QSize(v.property(0).toInt32(), v.property(1).toInt32()) : QSize(); 0173 } 0174 QScriptValue toSizeF(QScriptEngine *e, const QSizeF &s) 0175 { 0176 return e->toScriptValue(QVariantList() << s.width() << s.height()); 0177 } 0178 void fromSizeF(const QScriptValue &v, QSizeF &s) 0179 { 0180 s = v.isArray() ? QSizeF(v.property(0).toNumber(), v.property(1).toNumber()) : QSizeF(); 0181 } 0182 0183 /* 0184 QScriptValue toVariantList(QScriptEngine *e, const QVariantList &l) { 0185 const int len = l.size(); 0186 QScriptValue a = e->newArray(len); 0187 for(int i = 0; i < len; ++i) 0188 a.setProperty(i, e->toScriptValue(l[i])); 0189 return a; 0190 } 0191 void fromVariantList(const QScriptValue &v, QVariantList &l) { 0192 l.clear(); 0193 const int len = v.isArray() ? v.property("length").toInt32() : 0; 0194 for(int i = 0; i < len; ++i) 0195 l << v.property(i).toVariant(); 0196 } 0197 */ 0198 0199 QScriptValue toObjPtr(QScriptEngine *e, const Kross::Object::Ptr &ptr) 0200 { 0201 const EcmaObject *obj = dynamic_cast<const EcmaObject *>(ptr.data()); 0202 return obj ? obj->prototype() : e->nullValue(); 0203 } 0204 void fromObjPtr(const QScriptValue &v, Kross::Object::Ptr &ptr) 0205 { 0206 ptr = new EcmaObject(v.engine(), v); 0207 } 0208 0209 QScriptValue createWidget(QScriptContext *context, QScriptEngine *engine) 0210 { 0211 const QString widgetname = context->callee().prototype().property("className").toString(); 0212 Q_ASSERT(! widgetname.isEmpty()); 0213 QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0)); 0214 QUiLoader loader; 0215 QWidget *widget = loader.createWidget(widgetname, parent); 0216 if (! widget) { 0217 return context->throwError(QScriptContext::TypeError, QString("No such QWidget \"%1\"").arg(widgetname)); 0218 } 0219 if (parent && parent->layout()) { 0220 parent->layout()->addWidget(widget); 0221 } 0222 QScriptEngine::ValueOwnership owner = parent ? QScriptEngine::QtOwnership : QScriptEngine::ScriptOwnership; 0223 QScriptValue result = engine->newQObject(widget, owner); 0224 //result.setPrototype(context->callee().prototype()); 0225 return result; 0226 } 0227 0228 QScriptValue addWidgetLayout(QScriptContext *c, QScriptEngine *engine) 0229 { 0230 if (QLayout *layout = dynamic_cast<QLayout *>(qscriptvalue_cast<QObject *>(c->thisObject()))) { 0231 QGridLayout *gridLayout = dynamic_cast<QGridLayout *>(layout); 0232 QObject *obj = qscriptvalue_cast<QObject *>(c->argument(0)); 0233 if (QWidget *w = dynamic_cast<QWidget *>(obj)) { 0234 if (gridLayout) { 0235 gridLayout->addWidget(w, c->argument(1).toInt32(), c->argument(2).toInt32(), (Qt::Alignment)c->argument(3).toInt32()); 0236 } else { 0237 layout->addWidget(w); 0238 } 0239 } else if (QLayout *l = dynamic_cast<QLayout *>(qscriptvalue_cast<QObject *>(c->argument(0)))) { 0240 if (gridLayout) { 0241 gridLayout->addLayout(l, c->argument(1).toInt32(), c->argument(2).toInt32(), (Qt::Alignment)c->argument(3).toInt32()); 0242 } else if (QBoxLayout *bl = dynamic_cast<QBoxLayout *>(layout)) { 0243 bl->addLayout(l); 0244 } 0245 } 0246 } 0247 return engine->nullValue(); 0248 } 0249 QScriptValue createLayout(QScriptContext *context, QScriptEngine *engine, QLayout *layout) 0250 { 0251 QObject *parent = qscriptvalue_cast<QObject *>(context->argument(0)); 0252 if (QWidget *parentWidget = dynamic_cast<QWidget *>(parent)) { 0253 parentWidget->setLayout(layout); 0254 } else if (QBoxLayout *parentLayout = dynamic_cast<QBoxLayout *>(parent)) { 0255 parentLayout->addLayout(layout); 0256 } 0257 QScriptValue obj = engine->newQObject(layout); 0258 obj.setProperty("addWidget", engine->newFunction(addWidgetLayout)); 0259 obj.setProperty("addLayout", engine->newFunction(addWidgetLayout)); 0260 return obj; 0261 } 0262 QScriptValue createVBoxLayout(QScriptContext *context, QScriptEngine *engine) 0263 { 0264 return createLayout(context, engine, new QVBoxLayout()); 0265 } 0266 QScriptValue createHBoxLayout(QScriptContext *context, QScriptEngine *engine) 0267 { 0268 return createLayout(context, engine, new QHBoxLayout()); 0269 } 0270 QScriptValue createGridLayout(QScriptContext *context, QScriptEngine *engine) 0271 { 0272 return createLayout(context, engine, new QGridLayout()); 0273 } 0274 QScriptValue includeFunction(QScriptContext *context, QScriptEngine *engine) 0275 { 0276 if (context->argumentCount() < 1) { 0277 return engine->nullValue(); 0278 } 0279 return engine->importExtension(context->argument(0).toString()); 0280 } 0281 0282 /** 0283 * Initialize some core functionality like common used types we like 0284 * to use within scripts. 0285 */ 0286 void initializeCore(QScriptEngine *engine) 0287 { 0288 QScriptValue global = engine->globalObject(); 0289 0290 // compatibility to kjs/kjsembed 0291 if (! global.property("println").isValid()) { 0292 global.setProperty("println", global.property("print")); 0293 } 0294 0295 // register common used types 0296 qScriptRegisterMetaType< QByteArray >(engine, toByteArray, fromByteArray); 0297 qScriptRegisterMetaType< QUrl >(engine, toUrl, fromUrl); 0298 qScriptRegisterMetaType< QColor >(engine, toColor, fromColor); 0299 qScriptRegisterMetaType< QRect >(engine, toRect, fromRect); 0300 qScriptRegisterMetaType< QRectF >(engine, toRectF, fromRectF); 0301 qScriptRegisterMetaType< QPoint >(engine, toPoint, fromPoint); 0302 qScriptRegisterMetaType< QPointF >(engine, toPointF, fromPointF); 0303 qScriptRegisterMetaType< QSize >(engine, toSize, fromSize); 0304 qScriptRegisterMetaType< QSizeF >(engine, toSizeF, fromSizeF); 0305 0306 // we should probably go with an own wrapper for QVariant/QObject... 0307 //qScriptRegisterMetaType< QVariant >(engine, toVariant, fromVariant); 0308 //qScriptRegisterMetaType< QVariantList >(engine, toVariantList, fromVariantList); 0309 0310 // register the Kross::Object::Ptr wrapper 0311 qScriptRegisterMetaType< Kross::Object::Ptr >(engine, toObjPtr, fromObjPtr); 0312 0313 // register the include function that allows to importExtension 0314 global.setProperty("include", engine->newFunction(includeFunction)); 0315 } 0316 0317 /** 0318 * Initialize GUI functionality like widgets the QUiLoader provides 0319 * and some layout-managers. 0320 */ 0321 void initializeGui(QScriptEngine *engine) 0322 { 0323 QScriptValue global = engine->globalObject(); 0324 0325 // register UI widgets 0326 QUiLoader loader; 0327 foreach (const QString &widgetname, loader.availableWidgets()) { 0328 QScriptValue proto = engine->newObject(); 0329 proto.setProperty("className", QScriptValue(engine, widgetname)); 0330 QScriptValue func = engine->newFunction(createWidget); 0331 func.setPrototype(proto); 0332 global.setProperty(widgetname, func); 0333 } 0334 0335 // register layouts 0336 global.setProperty("QVBoxLayout", engine->newFunction(createVBoxLayout)); 0337 global.setProperty("QHBoxLayout", engine->newFunction(createHBoxLayout)); 0338 global.setProperty("QGridLayout", engine->newFunction(createGridLayout)); 0339 } 0340 0341 }