summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-09-03 00:14:54 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-09-03 00:14:54 (GMT)
commitb9c834048d6dc6e04567c1c73212ecb1b9c96664 (patch)
tree223b1d3d101883dabadadbf68b020808de56399e
parentdc26066be54bed3d508b460db1cc8d8b4b68cc1f (diff)
downloadQt-b9c834048d6dc6e04567c1c73212ecb1b9c96664.zip
Qt-b9c834048d6dc6e04567c1c73212ecb1b9c96664.tar.gz
Qt-b9c834048d6dc6e04567c1c73212ecb1b9c96664.tar.bz2
Add QML enum support
Enums are accessed as <Type Name>.<Enum value name> Currently this is highly unoptimal - enum assignments are not detected in the compiler, nor are they cached in the script engine.
-rw-r--r--src/declarative/qml/qmlcompiler.cpp2
-rw-r--r--src/declarative/qml/qmlcompiler_p.h1
-rw-r--r--src/declarative/qml/qmlcomponent.cpp1
-rw-r--r--src/declarative/qml/qmlcontext_p.h2
-rw-r--r--src/declarative/qml/qmlengine.cpp135
-rw-r--r--src/declarative/qml/qmlengine_p.h33
-rw-r--r--tests/auto/declarative/qmlbindengine/enums.1.qml20
-rw-r--r--tests/auto/declarative/qmlbindengine/testtypes.h19
-rw-r--r--tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp19
9 files changed, 213 insertions, 19 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index c0f7bfd..6519dff 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -642,6 +642,8 @@ void QmlCompiler::compileTree(Object *tree)
def.type = QmlInstruction::SetDefault;
output->bytecode << def;
+ output->imports = unit->imports;
+
if (tree->metatype)
static_cast<QMetaObject &>(output->root) = *tree->metaObject();
else
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index c42c2d9..83c415c 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -76,6 +76,7 @@ public:
QByteArray name;
QUrl url;
+ QmlEnginePrivate::Imports imports;
struct TypeReference
{
diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp
index c844a32..e897cce 100644
--- a/src/declarative/qml/qmlcomponent.cpp
+++ b/src/declarative/qml/qmlcomponent.cpp
@@ -488,6 +488,7 @@ QObject *QmlComponent::beginCreate(QmlContext *context)
static_cast<QmlContextPrivate *>(QObjectPrivate::get(context));
QmlContext *ctxt = new QmlContext(context, 0, true);
static_cast<QmlContextPrivate*>(ctxt->d_func())->url = d->cc->url;
+ static_cast<QmlContextPrivate*>(ctxt->d_func())->imports = d->cc->imports;
QmlVME vme;
QObject *rv = vme.run(ctxt, d->cc, d->start, d->count);
diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h
index 84d990c..b305408 100644
--- a/src/declarative/qml/qmlcontext_p.h
+++ b/src/declarative/qml/qmlcontext_p.h
@@ -60,6 +60,7 @@
#include <QtScript/qscriptvalue.h>
#include <QtCore/qset.h>
#include <private/qguard_p.h>
+#include <private/qmlengine_p.h>
QT_BEGIN_NAMESPACE
@@ -91,6 +92,7 @@ public:
QScriptValueList scopeChain;
QUrl url;
+ QmlEnginePrivate::Imports imports;
void init();
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index 0d6e281..3d8b2c4 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -181,6 +181,7 @@ void QmlEnginePrivate::init()
contextClass = new QmlContextScriptClass(q);
objectClass = new QmlObjectScriptClass(q);
valueTypeClass = new QmlValueTypeScriptClass(q);
+ typeNameClass = new QmlTypeNameScriptClass(q);
rootContext = new QmlContext(q,true);
#ifdef QT_SCRIPTTOOLS_LIB
if (qmlDebugger()){
@@ -211,10 +212,22 @@ QmlEnginePrivate::CapturedProperty::CapturedProperty(const QmlMetaProperty &p)
{
}
-////////////////////////////////////////////////////////////////////
-typedef QHash<QPair<const QMetaObject *, QString>, bool> FunctionCache;
-Q_GLOBAL_STATIC(FunctionCache, functionCache);
+struct QmlTypeNameBridge
+{
+ QObject *object;
+ QmlType *type;
+ QmlEnginePrivate::ImportedNamespace *ns;
+};
+Q_DECLARE_METATYPE(QmlTypeNameBridge);
+
+struct QmlValueTypeReference {
+ QmlValueType *type;
+ QGuard<QObject> object;
+ int property;
+};
+Q_DECLARE_METATYPE(QmlValueTypeReference);
+////////////////////////////////////////////////////////////////////
QScriptClass::QueryFlags
QmlEnginePrivate::queryContext(const QString &propName, uint *id,
QmlContext *bindContext)
@@ -223,19 +236,32 @@ QmlEnginePrivate::queryContext(const QString &propName, uint *id,
*id = resolveData.safetyCheckId;
resolveData.clear();
- QScriptClass::QueryFlags rv = 0;
QHash<QString, int>::Iterator contextProperty =
bindContext->d_func()->propertyNames.find(propName);
if (contextProperty != bindContext->d_func()->propertyNames.end()) {
- rv |= QScriptClass::HandlesReadAccess;
resolveData.context = bindContext;
resolveData.contextIndex = *contextProperty;
- return rv;
+ return QScriptClass::HandlesReadAccess;
}
+ QmlType *type = 0; ImportedNamespace *ns = 0;
+ if (currentExpression && bindContext == currentExpression->context() &&
+ propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) {
+
+ if (type || ns) {
+ // Must be either an attached property, or an enum
+ resolveData.object = bindContext->d_func()->defaultObjects.first();
+ resolveData.type = type;
+ resolveData.ns = ns;
+ return QScriptClass::HandlesReadAccess;
+ }
+
+ }
+
+ QScriptClass::QueryFlags rv = 0;
for (int ii = 0; !rv && ii < bindContext->d_func()->defaultObjects.count(); ++ii) {
rv = queryObject(propName, id,
bindContext->d_func()->defaultObjects.at(ii));
@@ -252,7 +278,14 @@ QmlEnginePrivate::propertyContext(const QScriptString &name,
Q_ASSERT(id == resolveData.safetyCheckId);
- if (resolveData.context) {
+ if (resolveData.type || resolveData.ns) {
+ QmlTypeNameBridge tnb = {
+ resolveData.object,
+ resolveData.type,
+ resolveData.ns
+ };
+ return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb)));
+ } else if (resolveData.context) {
QmlContext *bindContext = resolveData.context;
QmlContextPrivate *contextPrivate = bindContext->d_func();
int index = resolveData.contextIndex;
@@ -314,13 +347,13 @@ QmlEnginePrivate::queryObject(const QString &propName,
QPair<const QMetaObject *, QString> key =
qMakePair(obj->metaObject(), propName);
bool isFunction = false;
- if (functionCache()->contains(key)) {
- isFunction = functionCache()->value(key);
+ if (functionCache.contains(key)) {
+ isFunction = functionCache.value(key);
} else {
QScriptValue sobj = scriptEngine.newQObject(obj);
QScriptValue func = sobj.property(propName);
isFunction = func.isFunction();
- functionCache()->insert(key, isFunction);
+ functionCache.insert(key, isFunction);
}
if (isFunction) {
@@ -340,13 +373,6 @@ QmlEnginePrivate::queryObject(const QString &propName,
return rv;
}
-struct QmlValueTypeReference {
- QmlValueType *type;
- QGuard<QObject> object;
- int property;
-};
-Q_DECLARE_METATYPE(QmlValueTypeReference);
-
QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName,
QObject *obj, uint id)
{
@@ -1084,6 +1110,81 @@ void QmlContextScriptClass::setProperty(QScriptValue &object,
}
/////////////////////////////////////////////////////////////
+QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *engine)
+: QmlScriptClass(engine), object(0), type(0)
+{
+}
+
+QmlTypeNameScriptClass::~QmlTypeNameScriptClass()
+{
+}
+
+QmlTypeNameScriptClass::QueryFlags
+QmlTypeNameScriptClass::queryProperty(const QScriptValue &scriptObject,
+ const QScriptString &name,
+ QueryFlags flags, uint *id)
+{
+ QmlTypeNameBridge bridge =
+ qvariant_cast<QmlTypeNameBridge>(scriptObject.data().toVariant());
+
+ object = 0;
+ type = 0;
+ QmlEnginePrivate *ep = QmlEnginePrivate::get(engine);
+
+ if (bridge.ns) {
+ QmlType *type = 0;
+ ep->resolveTypeInNamespace(bridge.ns, name.toString().toUtf8(),
+ &type, 0, 0, 0);
+ if (type) {
+ object = bridge.object;
+ this->type = type;
+ return HandlesReadAccess;
+ } else {
+ return 0;
+ }
+
+ } else {
+ Q_ASSERT(bridge.type);
+ QString strName = name.toString();
+ if (strName.at(0).isUpper()) {
+ // Must be an enum
+ // ### Optimize
+ const char *enumName = strName.toUtf8().constData();
+ const QMetaObject *metaObject = bridge.type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ int value = e.keyToValue(enumName);
+ if (value != -1) {
+ enumValue = value;
+ return HandlesReadAccess;
+ }
+ }
+ return 0;
+ } else {
+ // Must be an attached property
+ this->object = qmlAttachedPropertiesObjectById(bridge.type->index(), bridge.object);
+ Q_ASSERT(this->object);
+ return ep->queryObject(strName, id, this->object);
+ }
+ }
+}
+
+QScriptValue QmlTypeNameScriptClass::property(const QScriptValue &,
+ const QScriptString &propName,
+ uint id)
+{
+ QmlEnginePrivate *ep = QmlEnginePrivate::get(engine);
+ if (type) {
+ QmlTypeNameBridge tnb = { object, type, 0 };
+ return ep->scriptEngine.newObject(ep->typeNameClass, ep->scriptEngine.newVariant(qVariantFromValue(tnb)));
+ } else if (object) {
+ return ep->propertyObject(propName, object, id);
+ } else {
+ return QScriptValue(enumValue);
+ }
+}
+
+/////////////////////////////////////////////////////////////
QmlValueTypeScriptClass::QmlValueTypeScriptClass(QmlEngine *bindEngine)
: QmlScriptClass(bindEngine)
{
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 451276d..f492ccb 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -82,6 +82,7 @@ class QmlExpression;
class QmlBasicScriptNodeCache;
class QmlContextScriptClass;
class QmlObjectScriptClass;
+class QmlTypeNameScriptClass;
class QmlValueTypeScriptClass;
class QScriptEngineDebugger;
class QNetworkReply;
@@ -127,16 +128,22 @@ public:
QScriptEngineDebugger *debugger;
#endif
+ struct ImportedNamespace;
struct ResolveData {
ResolveData() : safetyCheckId(0) {}
int safetyCheckId;
void clear() {
- object = 0; context = 0; contextIndex = -1; isFunction = false;
+ object = 0; context = 0;
+ type = 0; ns = 0;
+ contextIndex = -1; isFunction = false;
}
QObject *object;
QmlContext *context;
+ QmlType *type;
+ QmlEnginePrivate::ImportedNamespace *ns;
+
int contextIndex;
bool isFunction;
QmlMetaProperty property;
@@ -144,6 +151,7 @@ public:
QmlContextScriptClass *contextClass;
QmlObjectScriptClass *objectClass;
QmlValueTypeScriptClass *valueTypeClass;
+ QmlTypeNameScriptClass *typeNameClass;
// Used by DOM Core 3 API
QScriptClass *nodeListClass;
QScriptClass *namedNodeMapClass;
@@ -199,6 +207,9 @@ public:
}
QmlValueTypeFactory valueTypes;
+ // ### Fixme
+ typedef QHash<QPair<const QMetaObject *, QString>, bool> FunctionCache;
+ FunctionCache functionCache;
QHash<const QMetaObject *, QmlMetaObjectCache> propertyCache;
static QmlMetaObjectCache *cache(QmlEnginePrivate *priv, QObject *obj) {
if (!priv || !obj || QObjectPrivate::get(obj)->metaObject) return 0;
@@ -219,7 +230,6 @@ public:
QmlImportsPrivate *d;
};
- struct ImportedNamespace;
bool addToImport(Imports*, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const;
bool resolveType(const Imports&, const QByteArray& type,
QmlType** type_return, QUrl* url_return,
@@ -313,6 +323,25 @@ public:
const QScriptValue &value);
};
+class QmlTypeNameScriptClass : public QmlScriptClass
+{
+public:
+ QmlTypeNameScriptClass(QmlEngine *);
+ ~QmlTypeNameScriptClass();
+
+ virtual QueryFlags queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object,
+ const QScriptString &name,
+ uint id);
+
+private:
+ QObject *object;
+ QmlType *type;
+ quint32 enumValue;
+};
+
class QmlValueTypeScriptClass : public QmlScriptClass
{
public:
diff --git a/tests/auto/declarative/qmlbindengine/enums.1.qml b/tests/auto/declarative/qmlbindengine/enums.1.qml
new file mode 100644
index 0000000..6351823
--- /dev/null
+++ b/tests/auto/declarative/qmlbindengine/enums.1.qml
@@ -0,0 +1,20 @@
+import Qt.test 1.0
+import Qt.test 1.0 as Namespace
+
+MyQmlObject {
+ // Enums from non-namespaced type
+ property int a: MyQmlObject.EnumValue1
+ property int b: MyQmlObject.EnumValue2
+ property int c: MyQmlObject.EnumValue3
+ property int d: MyQmlObject.EnumValue4
+
+ // Enums from namespaced type
+ property int e: Namespace.MyQmlObject.EnumValue1
+ property int f: Namespace.MyQmlObject.EnumValue2
+ property int g: Namespace.MyQmlObject.EnumValue3
+ property int h: Namespace.MyQmlObject.EnumValue4
+
+ // Test that enums don't mask attached properties
+ property int i: MyQmlObject.value
+ property int j: Namespace.MyQmlObject.value
+}
diff --git a/tests/auto/declarative/qmlbindengine/testtypes.h b/tests/auto/declarative/qmlbindengine/testtypes.h
index f5b309e..f27c0b0 100644
--- a/tests/auto/declarative/qmlbindengine/testtypes.h
+++ b/tests/auto/declarative/qmlbindengine/testtypes.h
@@ -5,9 +5,21 @@
#include <QtDeclarative/qml.h>
#include <QtDeclarative/qmlexpression.h>
+class MyQmlAttachedObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value CONSTANT)
+public:
+ MyQmlAttachedObject(QObject *parent) : QObject(parent) {}
+
+ int value() const { return 19; }
+};
+
class MyQmlObject : public QObject
{
Q_OBJECT
+ Q_ENUMS(MyEnum)
+ Q_ENUMS(MyEnum2)
Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT)
Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT)
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
@@ -15,6 +27,9 @@ class MyQmlObject : public QObject
public:
MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false), m_object(0) {}
+ enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 };
+ enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3 };
+
bool trueProperty() const { return true; }
bool falseProperty() const { return false; }
@@ -39,6 +54,10 @@ public:
bool methodIntCalled() const { return m_methodIntCalled; }
QString string() const { return m_string; }
+
+ static MyQmlAttachedObject *qmlAttachedProperties(QObject *o) {
+ return new MyQmlAttachedObject(o);
+ }
signals:
void basicSignal();
void argumentSignal(int a, QString b, qreal c);
diff --git a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp
index 01cb54b..80373fe 100644
--- a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp
+++ b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp
@@ -38,6 +38,7 @@ private slots:
void objectPropertiesTriggerReeval();
void deferredProperties();
void extensionObjects();
+ void enums();
private:
QmlEngine engine;
@@ -366,6 +367,24 @@ void tst_qmlbindengine::extensionObjects()
QCOMPARE(object->baseProperty(), 92);
}
+void tst_qmlbindengine::enums()
+{
+ QmlComponent component(&engine, TEST_FILE("enums.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("a").toInt(), 0);
+ QCOMPARE(object->property("b").toInt(), 1);
+ QCOMPARE(object->property("c").toInt(), 2);
+ QCOMPARE(object->property("d").toInt(), 3);
+ QCOMPARE(object->property("e").toInt(), 0);
+ QCOMPARE(object->property("f").toInt(), 1);
+ QCOMPARE(object->property("g").toInt(), 2);
+ QCOMPARE(object->property("h").toInt(), 3);
+ QCOMPARE(object->property("i").toInt(), 19);
+ QCOMPARE(object->property("j").toInt(), 19);
+}
+
QTEST_MAIN(tst_qmlbindengine)
#include "tst_qmlbindengine.moc"