From 418bd7fa550da97ac27a34c72e75ec7ab0448d78 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 29 Mar 2010 11:57:41 +1000 Subject: Don't emit QDeclarativePropertyMap::valueChanged() before the value has changed. Task-number: QTBUG-9386 --- src/declarative/util/qdeclarativeopenmetaobject.cpp | 10 ++++++++++ src/declarative/util/qdeclarativeopenmetaobject_p.h | 2 ++ src/declarative/util/qdeclarativepropertymap.cpp | 18 +++++++++--------- src/declarative/util/qdeclarativepropertymap.h | 2 +- .../tst_qdeclarativepropertymap.cpp | 4 +++- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/declarative/util/qdeclarativeopenmetaobject.cpp b/src/declarative/util/qdeclarativeopenmetaobject.cpp index 8c23354..70ecf95 100644 --- a/src/declarative/util/qdeclarativeopenmetaobject.cpp +++ b/src/declarative/util/qdeclarativeopenmetaobject.cpp @@ -225,6 +225,7 @@ int QDeclarativeOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) if (d->data[propId].first != *reinterpret_cast(a[0])) { propertyWrite(propId); d->writeData(propId, *reinterpret_cast(a[0])); + propertyWritten(propId); activate(d->object, d->type->d->signalOffset + propId, 0); } } @@ -270,6 +271,11 @@ QVariant &QDeclarativeOpenMetaObject::operator[](const QByteArray &name) return d->getData(*iter); } +QVariant &QDeclarativeOpenMetaObject::operator[](int id) +{ + return d->getData(id); +} + void QDeclarativeOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { QHash::ConstIterator iter = d->type->d->names.find(name); @@ -326,6 +332,10 @@ void QDeclarativeOpenMetaObject::propertyWrite(int) { } +void QDeclarativeOpenMetaObject::propertyWritten(int) +{ +} + void QDeclarativeOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &) { } diff --git a/src/declarative/util/qdeclarativeopenmetaobject_p.h b/src/declarative/util/qdeclarativeopenmetaobject_p.h index ec5ac17..9bb4c34 100644 --- a/src/declarative/util/qdeclarativeopenmetaobject_p.h +++ b/src/declarative/util/qdeclarativeopenmetaobject_p.h @@ -90,6 +90,7 @@ public: QVariant value(int) const; void setValue(int, const QVariant &); QVariant &operator[](const QByteArray &); + QVariant &operator[](int); int count() const; QByteArray name(int) const; @@ -109,6 +110,7 @@ protected: virtual void propertyRead(int); virtual void propertyWrite(int); + virtual void propertyWritten(int); virtual void propertyCreated(int, QMetaPropertyBuilder &); QAbstractDynamicMetaObject *parent() const; diff --git a/src/declarative/util/qdeclarativepropertymap.cpp b/src/declarative/util/qdeclarativepropertymap.cpp index fcea515..d3e1d7c 100644 --- a/src/declarative/util/qdeclarativepropertymap.cpp +++ b/src/declarative/util/qdeclarativepropertymap.cpp @@ -55,7 +55,7 @@ public: QDeclarativePropertyMapMetaObject(QDeclarativePropertyMap *obj, QDeclarativePropertyMapPrivate *objPriv); protected: - virtual void propertyWrite(int index); + virtual void propertyWritten(int index); private: QDeclarativePropertyMap *map; @@ -68,13 +68,13 @@ class QDeclarativePropertyMapPrivate : public QObjectPrivate public: QDeclarativePropertyMapMetaObject *mo; QStringList keys; - void emitChanged(const QString &key); + void emitChanged(const QString &key, const QVariant &value); }; -void QDeclarativePropertyMapPrivate::emitChanged(const QString &key) +void QDeclarativePropertyMapPrivate::emitChanged(const QString &key, const QVariant &value) { Q_Q(QDeclarativePropertyMap); - emit q->valueChanged(key); + emit q->valueChanged(key, value); } QDeclarativePropertyMapMetaObject::QDeclarativePropertyMapMetaObject(QDeclarativePropertyMap *obj, QDeclarativePropertyMapPrivate *objPriv) : QDeclarativeOpenMetaObject(obj) @@ -83,14 +83,14 @@ QDeclarativePropertyMapMetaObject::QDeclarativePropertyMapMetaObject(QDeclarativ priv = objPriv; } -void QDeclarativePropertyMapMetaObject::propertyWrite(int index) +void QDeclarativePropertyMapMetaObject::propertyWritten(int index) { - priv->emitChanged(QString::fromUtf8(name(index))); + priv->emitChanged(QString::fromUtf8(name(index)), operator[](index)); } /*! \class QDeclarativePropertyMap - \since 4.7 + \since 4.7 \brief The QDeclarativePropertyMap class allows you to set key-value pairs that can be used in bindings. QDeclarativePropertyMap provides a convenient way to expose domain data to the UI layer. @@ -268,9 +268,9 @@ const QVariant QDeclarativePropertyMap::operator[](const QString &key) const } /*! - \fn void QDeclarativePropertyMap::valueChanged(const QString &key) + \fn void QDeclarativePropertyMap::valueChanged(const QString &key, const QVariant &value) This signal is emitted whenever one of the values in the map is changed. \a key - is the key corresponding to the value that was changed. + is the key corresponding to the \a value that was changed. \note valueChanged() is \bold NOT emitted when changes are made by calling insert() or clear() - it is only emitted when a value is updated from QML. diff --git a/src/declarative/util/qdeclarativepropertymap.h b/src/declarative/util/qdeclarativepropertymap.h index 513089f..e0b7ce3 100644 --- a/src/declarative/util/qdeclarativepropertymap.h +++ b/src/declarative/util/qdeclarativepropertymap.h @@ -76,7 +76,7 @@ public: const QVariant operator[](const QString &key) const; Q_SIGNALS: - void valueChanged(const QString &key); + void valueChanged(const QString &key, const QVariant &value); private: Q_DECLARE_PRIVATE(QDeclarativePropertyMap) diff --git a/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp b/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp index 22c5581..d23de43 100644 --- a/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp +++ b/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp @@ -123,7 +123,7 @@ void tst_QDeclarativePropertyMap::clear() void tst_QDeclarativePropertyMap::changed() { QDeclarativePropertyMap map; - QSignalSpy spy(&map, SIGNAL(valueChanged(const QString&))); + QSignalSpy spy(&map, SIGNAL(valueChanged(const QString&, const QVariant&))); map.insert(QLatin1String("key1"),100); map.insert(QLatin1String("key2"),200); QCOMPARE(spy.count(), 0); @@ -144,7 +144,9 @@ void tst_QDeclarativePropertyMap::changed() QCOMPARE(txt->text(), QString('X')); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); + QCOMPARE(arguments.count(), 2); QCOMPARE(arguments.at(0).toString(),QLatin1String("key1")); + QCOMPARE(arguments.at(1).value(),QVariant("Hello World")); QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); } -- cgit v0.12 From 067d5e0dc318e767a817bdb2bf6f0f647cf49909 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 25 Mar 2010 15:49:27 +1000 Subject: Fix memory leak and clean up deletion. --- src/declarative/util/qdeclarativelistmodel.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index 3904458..1a28176 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -1250,14 +1250,9 @@ ModelNode::ModelNode() ModelNode::~ModelNode() { - ModelNode *node; - - QList nodeValues = properties.values(); - for (int ii = 0; ii < nodeValues.count(); ++ii) { - node = nodeValues[ii]; - if (node) { delete node; node = 0; } - } + qDeleteAll(properties.values()); + ModelNode *node; for (int ii = 0; ii < values.count(); ++ii) { node = qvariant_cast(values.at(ii)); if (node) { delete node; node = 0; } @@ -1279,7 +1274,9 @@ void ModelNode::setObjectValue(const QScriptValue& valuemap) { } else { value->values << v.toVariant(); } - properties.insert(it.name(),value); + if (properties.contains(it.name())) + delete properties[it.name()]; + properties.insert(it.name(), value); } } -- cgit v0.12 From cc4a21c61d6d68ce49c2b8755e0edfb9571a0306 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 29 Mar 2010 12:50:51 +1000 Subject: Add missing pro file. --- tests/auto/declarative/qmlvisual/qmlvisual.pro | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/auto/declarative/qmlvisual/qmlvisual.pro diff --git a/tests/auto/declarative/qmlvisual/qmlvisual.pro b/tests/auto/declarative/qmlvisual/qmlvisual.pro new file mode 100644 index 0000000..f2b3bca --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qmlvisual.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +macx:CONFIG -= app_bundle + +SOURCES += tst_qmlvisual.cpp + +DEFINES += QT_TEST_SOURCE_DIR=\"\\\"$$PWD\\\"\" -- cgit v0.12 From eac3500387fcd966e936cbe16b75db6cf9df3abe Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 29 Mar 2010 13:07:29 +1000 Subject: Optimization: Don't use QVariant in QDeclarativeVMEMetaObject --- src/declarative/qml/qdeclarativevmemetaobject.cpp | 430 +++++++++++++++++++-- src/declarative/qml/qdeclarativevmemetaobject_p.h | 15 +- .../qmltime/tests/vmemetaobject/null.qml | 13 + .../qmltime/tests/vmemetaobject/property.qml | 18 + 4 files changed, 447 insertions(+), 29 deletions(-) create mode 100644 tests/benchmarks/declarative/qmltime/tests/vmemetaobject/null.qml create mode 100644 tests/benchmarks/declarative/qmltime/tests/vmemetaobject/property.qml diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp index f9c99ee..7a08a2c 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject.cpp +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp @@ -47,19 +47,316 @@ #include "qdeclarativeexpression_p.h" #include "qdeclarativecontext_p.h" -#include -#include -#include -#include +Q_DECLARE_METATYPE(QScriptValue); QT_BEGIN_NAMESPACE +class QDeclarativeVMEVariant +{ +public: + inline QDeclarativeVMEVariant(); + inline ~QDeclarativeVMEVariant(); + + inline const void *dataPtr() const; + inline void *dataPtr(); + inline int dataType() const; + + inline QObject *asQObject(); + inline const QVariant &asQVariant(); + inline int asInt(); + inline bool asBool(); + inline double asDouble(); + inline const QString &asQString(); + inline const QUrl &asQUrl(); + inline const QColor &asQColor(); + inline const QDate &asQDate(); + inline const QDateTime &asQDateTime(); + inline const QScriptValue &asQScriptValue(); + + inline void setValue(QObject *); + inline void setValue(const QVariant &); + inline void setValue(int); + inline void setValue(bool); + inline void setValue(double); + inline void setValue(const QString &); + inline void setValue(const QUrl &); + inline void setValue(const QColor &); + inline void setValue(const QDate &); + inline void setValue(const QDateTime &); + inline void setValue(const QScriptValue &); + +private: + int type; + void *data[4]; // Large enough to hold all types + + inline void cleanup(); +}; + +QDeclarativeVMEVariant::QDeclarativeVMEVariant() +: type(QVariant::Invalid) +{ +} + +QDeclarativeVMEVariant::~QDeclarativeVMEVariant() +{ + cleanup(); +} + +void QDeclarativeVMEVariant::cleanup() +{ + if (type == QVariant::Invalid) { + } else if (type == QMetaType::QObjectStar || + type == QMetaType::Int || + type == QMetaType::Bool || + type == QMetaType::Double) { + type = QVariant::Invalid; + } else if (type == QMetaType::QString) { + ((QString *)dataPtr())->~QString(); + type = QVariant::Invalid; + } else if (type == QMetaType::QUrl) { + ((QUrl *)dataPtr())->~QUrl(); + type = QVariant::Invalid; + } else if (type == QMetaType::QColor) { + ((QColor *)dataPtr())->~QColor(); + type = QVariant::Invalid; + } else if (type == QMetaType::QDate) { + ((QDate *)dataPtr())->~QDate(); + type = QVariant::Invalid; + } else if (type == QMetaType::QDateTime) { + ((QDateTime *)dataPtr())->~QDateTime(); + type = QVariant::Invalid; + } else if (type == qMetaTypeId()) { + ((QVariant *)dataPtr())->~QVariant(); + type = QVariant::Invalid; + } else if (type == qMetaTypeId()) { + ((QScriptValue *)dataPtr())->~QScriptValue(); + type = QVariant::Invalid; + } + +} + +int QDeclarativeVMEVariant::dataType() const +{ + return type; +} + +const void *QDeclarativeVMEVariant::dataPtr() const +{ + return &data; +} + +void *QDeclarativeVMEVariant::dataPtr() +{ + return &data; +} + +QObject *QDeclarativeVMEVariant::asQObject() +{ + if (type != QMetaType::QObjectStar) + setValue((QObject *)0); + + return *(QObject **)(dataPtr()); +} + +const QVariant &QDeclarativeVMEVariant::asQVariant() +{ + if (type != QMetaType::QVariant) + setValue(QVariant()); + + return *(QVariant *)(dataPtr()); +} + +int QDeclarativeVMEVariant::asInt() +{ + if (type != QMetaType::Int) + setValue(int(0)); + + return *(int *)(dataPtr()); +} + +bool QDeclarativeVMEVariant::asBool() +{ + if (type != QMetaType::Bool) + setValue(bool(false)); + + return *(bool *)(dataPtr()); +} + +double QDeclarativeVMEVariant::asDouble() +{ + if (type != QMetaType::Double) + setValue(double(0)); + + return *(double *)(dataPtr()); +} + +const QString &QDeclarativeVMEVariant::asQString() +{ + if (type != QMetaType::QString) + setValue(QString()); + + return *(QString *)(dataPtr()); +} + +const QUrl &QDeclarativeVMEVariant::asQUrl() +{ + if (type != QMetaType::QUrl) + setValue(QUrl()); + + return *(QUrl *)(dataPtr()); +} + +const QColor &QDeclarativeVMEVariant::asQColor() +{ + if (type != QMetaType::QColor) + setValue(QColor()); + + return *(QColor *)(dataPtr()); +} + +const QDate &QDeclarativeVMEVariant::asQDate() +{ + if (type != QMetaType::QDate) + setValue(QDate()); + + return *(QDate *)(dataPtr()); +} + +const QDateTime &QDeclarativeVMEVariant::asQDateTime() +{ + if (type != QMetaType::QDateTime) + setValue(QDateTime()); + + return *(QDateTime *)(dataPtr()); +} + +const QScriptValue &QDeclarativeVMEVariant::asQScriptValue() +{ + if (type != qMetaTypeId()) + setValue(QScriptValue()); + + return *(QScriptValue *)(dataPtr()); +} + +void QDeclarativeVMEVariant::setValue(QObject *v) +{ + if (type != QMetaType::QObjectStar) { + cleanup(); + type = QMetaType::QObjectStar; + } + *(QObject **)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(const QVariant &v) +{ + if (type != qMetaTypeId()) { + cleanup(); + type = qMetaTypeId(); + new (dataPtr()) QVariant(v); + } else { + *(QVariant *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(int v) +{ + if (type != QMetaType::Int) { + cleanup(); + type = QMetaType::Int; + } + *(int *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(bool v) +{ + if (type != QMetaType::Bool) { + cleanup(); + type = QMetaType::Bool; + } + *(bool *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(double v) +{ + if (type != QMetaType::Double) { + cleanup(); + type = QMetaType::Double; + } + *(double *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(const QString &v) +{ + if (type != QMetaType::QString) { + cleanup(); + type = QMetaType::QString; + new (dataPtr()) QString(v); + } else { + *(QString *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QUrl &v) +{ + if (type != QMetaType::QUrl) { + cleanup(); + type = QMetaType::QUrl; + new (dataPtr()) QUrl(v); + } else { + *(QUrl *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QColor &v) +{ + if (type != QMetaType::QColor) { + cleanup(); + type = QMetaType::QColor; + new (dataPtr()) QColor(v); + } else { + *(QColor *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QDate &v) +{ + if (type != QMetaType::QDate) { + cleanup(); + type = QMetaType::QDate; + new (dataPtr()) QDate(v); + } else { + *(QDate *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QDateTime &v) +{ + if (type != QMetaType::QDateTime) { + cleanup(); + type = QMetaType::QDateTime; + new (dataPtr()) QDateTime(v); + } else { + *(QDateTime *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QScriptValue &v) +{ + if (type != qMetaTypeId()) { + cleanup(); + type = qMetaTypeId(); + new (dataPtr()) QScriptValue(v); + } else { + *(QScriptValue *)(dataPtr()) = v; + } +} + QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj, const QMetaObject *other, const QDeclarativeVMEMetaData *meta, QDeclarativeCompiledData *cdata) : object(obj), compiledData(cdata), ctxt(QDeclarativeDeclarativeData::get(obj)->outerContext), - metaData(meta), methods(0), parent(0) + metaData(meta), data(0), methods(0), parent(0) { compiledData->addref(); @@ -74,20 +371,17 @@ QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj, propOffset = QAbstractDynamicMetaObject::propertyOffset(); methodOffset = QAbstractDynamicMetaObject::methodOffset(); - data = new QVariant[metaData->propertyCount]; + data = new QDeclarativeVMEVariant[metaData->propertyCount]; aConnected.resize(metaData->aliasCount); - int list_type = qMetaTypeId >(); + // ### Optimize for (int ii = 0; ii < metaData->propertyCount; ++ii) { int t = (metaData->propertyData() + ii)->propertyType; if (t == list_type) { listProperties.append(new List(methodOffset + ii)); - data[ii] = QVariant::fromValue(QDeclarativeListProperty(obj, listProperties.last(), list_append, - list_count, list_at, list_clear)); - } else if (t != -1) { - data[ii] = QVariant((QVariant::Type)t); - } + data[ii].setValue(listProperties.count() - 1); + } } } @@ -145,11 +439,10 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) if (t == -1) { if (c == QMetaObject::ReadProperty) { - *reinterpret_cast(a[0]) = data[id]; + *reinterpret_cast(a[0]) = readVarPropertyAsVariant(id); } else if (c == QMetaObject::WriteProperty) { - needActivate = - (data[id] != *reinterpret_cast(a[0])); - data[id] = *reinterpret_cast(a[0]); + needActivate = (data[id].asQVariant() != *reinterpret_cast(a[0])); + data[id].setValue(*reinterpret_cast(a[0])); } } else { @@ -157,42 +450,83 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) if (c == QMetaObject::ReadProperty) { switch(t) { case QVariant::Int: - *reinterpret_cast(a[0]) = data[id].toInt(); + *reinterpret_cast(a[0]) = data[id].asInt(); break; case QVariant::Bool: - *reinterpret_cast(a[0]) = data[id].toBool(); + *reinterpret_cast(a[0]) = data[id].asBool(); break; case QVariant::Double: - *reinterpret_cast(a[0]) = data[id].toDouble(); + *reinterpret_cast(a[0]) = data[id].asDouble(); break; case QVariant::String: - *reinterpret_cast(a[0]) = data[id].toString(); + *reinterpret_cast(a[0]) = data[id].asQString(); break; case QVariant::Url: - *reinterpret_cast(a[0]) = data[id].toUrl(); + *reinterpret_cast(a[0]) = data[id].asQUrl(); break; case QVariant::Color: - *reinterpret_cast(a[0]) = data[id].value(); + *reinterpret_cast(a[0]) = data[id].asQColor(); break; case QVariant::Date: - *reinterpret_cast(a[0]) = data[id].toDate(); + *reinterpret_cast(a[0]) = data[id].asQDate(); + break; + case QVariant::DateTime: + *reinterpret_cast(a[0]) = data[id].asQDateTime(); break; case QMetaType::QObjectStar: - *reinterpret_cast(a[0]) = data[id].value(); + *reinterpret_cast(a[0]) = data[id].asQObject(); break; default: break; } if (t == qMetaTypeId >()) { *reinterpret_cast *>(a[0]) = - data[id].value >(); + QDeclarativeListProperty(object, (void *)&listProperties.at(data[id].asInt()), + list_append, list_count, list_at, list_clear); } } else if (c == QMetaObject::WriteProperty) { - QVariant value = QVariant((QVariant::Type)data[id].type(), a[0]); - needActivate = (data[id] != value); - data[id] = value; + switch(t) { + case QVariant::Int: + needActivate = *reinterpret_cast(a[0]) != data[id].asInt(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Bool: + needActivate = *reinterpret_cast(a[0]) != data[id].asBool(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Double: + needActivate = *reinterpret_cast(a[0]) != data[id].asDouble(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::String: + needActivate = *reinterpret_cast(a[0]) != data[id].asQString(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Url: + needActivate = *reinterpret_cast(a[0]) != data[id].asQUrl(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Color: + needActivate = *reinterpret_cast(a[0]) != data[id].asQColor(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Date: + needActivate = *reinterpret_cast(a[0]) != data[id].asQDate(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::DateTime: + needActivate = *reinterpret_cast(a[0]) != data[id].asQDateTime(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QMetaType::QObjectStar: + needActivate = *reinterpret_cast(a[0]) != data[id].asQObject(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + default: + break; + } } } @@ -316,6 +650,28 @@ QScriptValue QDeclarativeVMEMetaObject::method(int index) return methods[index]; } +QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id) +{ + if (data[id].dataType() == qMetaTypeId()) + return data[id].asQScriptValue(); + else + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueFromVariant(data[id].asQVariant()); +} + +QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id) +{ + if (data[id].dataType() == qMetaTypeId()) + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue()); + else + return data[id].asQVariant(); +} + +void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &value) +{ + data[id].setValue(value); + activate(object, methodOffset + id, 0); +} + void QDeclarativeVMEMetaObject::listChanged(int id) { activate(object, methodOffset + id, 0); @@ -364,4 +720,22 @@ QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index) return method(index - methodOffset - plainSignals); } +QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index) +{ + if (index < propOffset) { + Q_ASSERT(parent); + return static_cast(parent)->vmeProperty(index); + } + return readVarProperty(index - propOffset); +} + +void QDeclarativeVMEMetaObject::setVMEProperty(int index, const QScriptValue &v) +{ + if (index < propOffset) { + Q_ASSERT(parent); + static_cast(parent)->setVMEProperty(index, v); + } + return writeVarProperty(index - propOffset, v); +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h index e11f6fa..4718fa7 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject_p.h +++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h @@ -58,6 +58,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -106,6 +110,7 @@ struct QDeclarativeVMEMetaData } }; +class QDeclarativeVMEVariant; class QDeclarativeRefCount; class QDeclarativeVMEMetaObject : public QAbstractDynamicMetaObject { @@ -116,6 +121,9 @@ public: void registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor); QScriptValue vmeMethod(int index); + QScriptValue vmeProperty(int index); + void setVMEProperty(int index, const QScriptValue &); + protected: virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); @@ -128,7 +136,8 @@ private: int propOffset; int methodOffset; - QVariant *data; + QDeclarativeVMEVariant *data; + QBitArray aConnected; QBitArray aInterceptors; QHash > interceptors; @@ -136,6 +145,10 @@ private: QScriptValue *methods; QScriptValue method(int); + QScriptValue readVarProperty(int); + QVariant readVarPropertyAsVariant(int); + void writeVarProperty(int, const QScriptValue &); + QAbstractDynamicMetaObject *parent; void listChanged(int); diff --git a/tests/benchmarks/declarative/qmltime/tests/vmemetaobject/null.qml b/tests/benchmarks/declarative/qmltime/tests/vmemetaobject/null.qml new file mode 100644 index 0000000..a31af5a --- /dev/null +++ b/tests/benchmarks/declarative/qmltime/tests/vmemetaobject/null.qml @@ -0,0 +1,13 @@ +import Qt 4.6 +import QmlTime 1.0 as QmlTime + +Item { + + QmlTime.Timer { + component: Component { + QtObject { + } + } + } + +} diff --git a/tests/benchmarks/declarative/qmltime/tests/vmemetaobject/property.qml b/tests/benchmarks/declarative/qmltime/tests/vmemetaobject/property.qml new file mode 100644 index 0000000..007d12a --- /dev/null +++ b/tests/benchmarks/declarative/qmltime/tests/vmemetaobject/property.qml @@ -0,0 +1,18 @@ +import Qt 4.6 +import QmlTime 1.0 as QmlTime + +Item { + + QmlTime.Timer { + component: Component { + QtObject { + property string s + property string s2 + property string s3 + property string s4 + } + } + } + +} + -- cgit v0.12 From 373e3915ca223dcb7c2d59d300e16b7981111500 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Mon, 29 Mar 2010 11:42:05 +1000 Subject: Add example on how to use Qt widgets in qml. --- examples/declarative/widgets/MyWidgets/qmldir | 1 + examples/declarative/widgets/mywidgets.cpp | 99 +++++++++++++++++++++++++++ examples/declarative/widgets/mywidgets.pro | 19 +++++ examples/declarative/widgets/mywidgets.qml | 53 ++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 examples/declarative/widgets/MyWidgets/qmldir create mode 100644 examples/declarative/widgets/mywidgets.cpp create mode 100644 examples/declarative/widgets/mywidgets.pro create mode 100644 examples/declarative/widgets/mywidgets.qml diff --git a/examples/declarative/widgets/MyWidgets/qmldir b/examples/declarative/widgets/MyWidgets/qmldir new file mode 100644 index 0000000..dc1d10e --- /dev/null +++ b/examples/declarative/widgets/MyWidgets/qmldir @@ -0,0 +1 @@ +plugin mywidgetsplugin diff --git a/examples/declarative/widgets/mywidgets.cpp b/examples/declarative/widgets/mywidgets.cpp new file mode 100644 index 0000000..e17240d --- /dev/null +++ b/examples/declarative/widgets/mywidgets.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +class MyPushButton : public QGraphicsProxyWidget +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + +public: + MyPushButton(QGraphicsItem* parent = 0) + : QGraphicsProxyWidget(parent) + { + widget = new QPushButton("MyPushButton"); + widget->setAttribute(Qt::WA_NoSystemBackground); + setWidget(widget); + + QObject::connect(widget, SIGNAL(clicked(bool)), this, SIGNAL(clicked(bool))); + } + + QString text() const + { + return widget->text(); + } + + void setText(const QString& text) + { + if (text != widget->text()) { + widget->setText(text); + emit textChanged(); + } + } + +Q_SIGNALS: + void clicked(bool); + void textChanged(); + +private: + QPushButton *widget; +}; + +class MyWidgetsPlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + void registerTypes(const char *uri) + { + qmlRegisterType(uri, 1, 0, "MyPushButton"); + } +}; + +#include "mywidgets.moc" + +QML_DECLARE_TYPE(MyPushButton) + +Q_EXPORT_PLUGIN2(mywidgetsplugin, MyWidgetsPlugin); diff --git a/examples/declarative/widgets/mywidgets.pro b/examples/declarative/widgets/mywidgets.pro new file mode 100644 index 0000000..258edb1 --- /dev/null +++ b/examples/declarative/widgets/mywidgets.pro @@ -0,0 +1,19 @@ +TEMPLATE = lib +DESTDIR = MyWidgets +TARGET = mywidgetsplugin +CONFIG += qt plugin +QT += declarative +VERSION = 1.0.0 + +SOURCES += mywidgets.cpp + +sources.files += mywidgets.pro mywidgets.cpp mywidgets.qml + +sources.path += $$[QT_INSTALL_EXAMPLES]/declarative/plugins + +target.path += $$[QT_INSTALL_EXAMPLES]/declarative/plugins + +INSTALLS += sources target + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + diff --git a/examples/declarative/widgets/mywidgets.qml b/examples/declarative/widgets/mywidgets.qml new file mode 100644 index 0000000..b1efed4 --- /dev/null +++ b/examples/declarative/widgets/mywidgets.qml @@ -0,0 +1,53 @@ +import Qt 4.6 +import "MyWidgets" 1.0 + +Rectangle { + id: window + width: 640; height: 480; color: palette.window + + property int margin: 30 + + SystemPalette { id: palette } + + MyPushButton { + id: button1; x: margin; y: margin; text: "Right"; onClicked: window.state = "right" + transformOriginPoint: Qt.point(width / 2, height / 2) + } + + MyPushButton { + id: button2; x: margin; y: margin + 30; text: "Bottom"; onClicked: window.state = "bottom" + transformOriginPoint: Qt.point(width / 2, height / 2) + } + + MyPushButton { + id: button3; x: margin; y: margin + 60; text: "Quit"; onClicked: Qt.quit() + transformOriginPoint: Qt.point(width / 2, height / 2) + } + + states: [ + State { + name: "right" + PropertyChanges { target: button1; x: window.width - width - margin; text: "Left"; onClicked: window.state = "" } + PropertyChanges { target: button2; x: window.width - width - margin } + PropertyChanges { target: button3; x: window.width - width - margin } + PropertyChanges { target: window; color: Qt.darker(palette.window) } + }, + State { + name: "bottom" + PropertyChanges { target: button1; y: window.height - height - margin; rotation: 180 } + PropertyChanges { + target: button2; x: button1.x + button1.width + 10; y: window.height - height - margin; rotation: 180 + text: "Top"; onClicked: window.state = "" + } + PropertyChanges { target: button3; x: button2.x + button2.width + 10; y: window.height - height - margin; rotation: 180 } + PropertyChanges { target: window; color: Qt.lighter(palette.window) } + } + ] + + transitions: Transition { + ParallelAnimation { + NumberAnimation { properties: "x,y,rotation"; duration: 600; easing.type: "OutQuad" } + ColorAnimation { target: window; duration: 600 } + } + } +} -- cgit v0.12 From 0f39158778ad3a7deb96303596f7b365802ffb5d Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Mon, 29 Mar 2010 13:32:27 +1000 Subject: Add focus and key navigation example. --- examples/declarative/focus/Core/ContextMenu.qml | 15 ++++++ examples/declarative/focus/Core/GridMenu.qml | 54 +++++++++++++++++++++ .../declarative/focus/Core/ListViewDelegate.qml | 39 +++++++++++++++ examples/declarative/focus/Core/ListViews.qml | 47 ++++++++++++++++++ examples/declarative/focus/Core/images/arrow.png | Bin 0 -> 583 bytes examples/declarative/focus/Core/images/qt-logo.png | Bin 0 -> 5149 bytes examples/declarative/focus/Core/qmldir | 4 ++ examples/declarative/focus/focus.qml | 50 +++++++++++++++++++ 8 files changed, 209 insertions(+) create mode 100644 examples/declarative/focus/Core/ContextMenu.qml create mode 100644 examples/declarative/focus/Core/GridMenu.qml create mode 100644 examples/declarative/focus/Core/ListViewDelegate.qml create mode 100644 examples/declarative/focus/Core/ListViews.qml create mode 100644 examples/declarative/focus/Core/images/arrow.png create mode 100644 examples/declarative/focus/Core/images/qt-logo.png create mode 100644 examples/declarative/focus/Core/qmldir create mode 100644 examples/declarative/focus/focus.qml diff --git a/examples/declarative/focus/Core/ContextMenu.qml b/examples/declarative/focus/Core/ContextMenu.qml new file mode 100644 index 0000000..bd6d8a2 --- /dev/null +++ b/examples/declarative/focus/Core/ContextMenu.qml @@ -0,0 +1,15 @@ +import Qt 4.6 + +FocusScope { + id: container + property bool open: false + + Item { + anchors.fill: parent + + Rectangle { + anchors.fill: parent; color: "#D1DBBD"; focus: true + Keys.onRightPressed: mainView.focus = true + } + } +} diff --git a/examples/declarative/focus/Core/GridMenu.qml b/examples/declarative/focus/Core/GridMenu.qml new file mode 100644 index 0000000..03d837a --- /dev/null +++ b/examples/declarative/focus/Core/GridMenu.qml @@ -0,0 +1,54 @@ +import Qt 4.6 + +FocusScope { + property alias interactive: gridView.interactive + + onWantsFocusChanged: if (wantsFocus) mainView.state = "" + + Rectangle { + clip: true; anchors.fill: parent + gradient: Gradient { + GradientStop { position: 0.0; color: "#193441" } + GradientStop { position: 1.0; color: Qt.darker("#193441") } + } + + GridView { + id: gridView; cellWidth: 152; cellHeight: 152; focus: true + x: 20; width: parent.width - 40; height: parent.height + model: 12 + KeyNavigation.down: listViews + KeyNavigation.left: contextMenu + + delegate: Item { + id: container; width: GridView.view.cellWidth; height: GridView.view.cellHeight + + Rectangle { + id: content + color: "transparent"; smooth: true + anchors.centerIn: parent; width: container.width - 40; height: container.height - 40; radius: 10 + Rectangle { color: "#91AA9D"; x: 3; y: 3; width: parent.width - 6; height: parent.height - 6; radius: 8 } + Image { source: "images/qt-logo.png"; anchors.centerIn: parent; smooth: true } + } + + MouseArea { + id: mouseArea; anchors.fill: parent; hoverEnabled: true + onClicked: { + GridView.view.currentIndex = index + container.focus = true + gridMenu.focus = true + mainView.focus = true + } + } + + states: State { + name: "active"; when: container.focus == true + PropertyChanges { target: content; color: "#FCFFF5"; scale: 1.1 } + } + + transitions: Transition { + NumberAnimation { properties: "scale"; duration: 100 } + } + } + } + } +} diff --git a/examples/declarative/focus/Core/ListViewDelegate.qml b/examples/declarative/focus/Core/ListViewDelegate.qml new file mode 100644 index 0000000..b7e067a --- /dev/null +++ b/examples/declarative/focus/Core/ListViewDelegate.qml @@ -0,0 +1,39 @@ +import Qt 4.6 + +Component { + Item { + id: container + x: 5; width: ListView.view.width - 10; height: 60 + + Rectangle { + id: content + color: "transparent"; smooth: true + anchors.centerIn: parent; width: container.width - 40; height: container.height - 10; radius: 10 + Rectangle { color: "#91AA9D"; x: 3; y: 3; width: parent.width - 6; height: parent.height - 6; radius: 8 } + Text { + text: "List element " + (index + 1); color: "#193441"; font.bold: false; anchors.centerIn: parent + font.pixelSize: 14 + } + } + + MouseArea { + id: mouseArea; anchors.fill: parent; hoverEnabled: true + onClicked: { + ListView.view.currentIndex = index + container.focus = true + ListView.view.focus = true + listViews.focus = true + mainView.focus = true + } + } + + states: State { + name: "active"; when: container.focus == true + PropertyChanges { target: content; color: "#FCFFF5"; scale: 1.1 } + } + + transitions: Transition { + NumberAnimation { properties: "scale"; duration: 100 } + } + } +} diff --git a/examples/declarative/focus/Core/ListViews.qml b/examples/declarative/focus/Core/ListViews.qml new file mode 100644 index 0000000..3cc4836 --- /dev/null +++ b/examples/declarative/focus/Core/ListViews.qml @@ -0,0 +1,47 @@ +import Qt 4.6 + +FocusScope { + clip: true + + onWantsFocusChanged: if (wantsFocus) mainView.state = "showListViews" + + ListView { + id: list1 + delegate: ListViewDelegate {} + y: wantsFocus ? 10 : 40; focus: true; width: parent.width / 3; height: parent.height - 20 + model: 10; KeyNavigation.up: gridMenu; KeyNavigation.left: contextMenu; KeyNavigation.right: list2 + Behavior on y { NumberAnimation { duration: 600; easing.type: "OutQuint" } } + } + + ListView { + id: list2 + delegate: ListViewDelegate {} + y: wantsFocus ? 10 : 40; x: parent.width / 3; width: parent.width / 3; height: parent.height - 20 + model: 10; KeyNavigation.up: gridMenu; KeyNavigation.left: list1; KeyNavigation.right: list3 + Behavior on y { NumberAnimation { duration: 600; easing.type: "OutQuint" } } + } + + ListView { + id: list3 + delegate: ListViewDelegate {} + y: wantsFocus ? 10 : 40; x: 2 * parent.width / 3; width: parent.width / 3; height: parent.height - 20 + model: 10; KeyNavigation.up: gridMenu; KeyNavigation.left: list2 + Behavior on y { NumberAnimation { duration: 600; easing.type: "OutQuint" } } + } + + Rectangle { width: parent.width; height: 1; color: "#D1DBBD" } + Rectangle { + y: 1; width: parent.width; height: 10 + gradient: Gradient { + GradientStop { position: 0.0; color: "#3E606F" } + GradientStop { position: 1.0; color: "transparent" } + } + } + Rectangle { + y: parent.height - 10; width: parent.width; height: 10 + gradient: Gradient { + GradientStop { position: 1.0; color: "#3E606F" } + GradientStop { position: 0.0; color: "transparent" } + } + } +} diff --git a/examples/declarative/focus/Core/images/arrow.png b/examples/declarative/focus/Core/images/arrow.png new file mode 100644 index 0000000..14978c2 Binary files /dev/null and b/examples/declarative/focus/Core/images/arrow.png differ diff --git a/examples/declarative/focus/Core/images/qt-logo.png b/examples/declarative/focus/Core/images/qt-logo.png new file mode 100644 index 0000000..14ddf2a Binary files /dev/null and b/examples/declarative/focus/Core/images/qt-logo.png differ diff --git a/examples/declarative/focus/Core/qmldir b/examples/declarative/focus/Core/qmldir new file mode 100644 index 0000000..0460d9c --- /dev/null +++ b/examples/declarative/focus/Core/qmldir @@ -0,0 +1,4 @@ +ContextMenu ContextMenu.qml +GridMenu GridMenu.qml +ListViews Listviews.qml +ListViewDelegate ListViewDelegate.qml diff --git a/examples/declarative/focus/focus.qml b/examples/declarative/focus/focus.qml new file mode 100644 index 0000000..a8dc3c8 --- /dev/null +++ b/examples/declarative/focus/focus.qml @@ -0,0 +1,50 @@ +import Qt 4.6 +import "Core" 1.0 + +Rectangle { + id: window; width: 800; height: 480; color: "#3E606F" + + FocusScope { + id: mainView; focus: true; width: parent.width; height: parent.height + + GridMenu { + id: gridMenu; focus: true + width: parent.width; height: 320; interactive: parent.wantsFocus + } + + ListViews { id: listViews; y: 320; width: parent.width; height: 320 } + + Rectangle { id: shade; color: "black"; opacity: 0; anchors.fill: parent } + + states: State { + name: "showListViews" + PropertyChanges { target: gridMenu; y: -160 } + PropertyChanges { target: listViews; y: 160 } + } + + transitions: Transition { + NumberAnimation { properties: "y"; duration: 600; easing.type: "OutQuint" } + } + } + + Image { + source: "Core/images/arrow.png"; rotation: 90; anchors.verticalCenter: parent.verticalCenter + MouseArea { + anchors { fill: parent; leftMargin: -10; topMargin: -10; rightMargin: -10; bottomMargin: -10 } + onClicked: window.state = "contextMenuOpen" + } + } + + ContextMenu { id: contextMenu; x: -265; width: 260; height: parent.height } + + states: State { + name: "contextMenuOpen"; when: !mainView.wantsFocus + PropertyChanges { target: contextMenu; x: 0; open: true } + PropertyChanges { target: mainView; x: 130 } + PropertyChanges { target: shade; opacity: 0.25 } + } + + transitions: Transition { + NumberAnimation { properties: "x,opacity"; duration: 600; easing.type: "OutQuint" } + } +} -- cgit v0.12