From 5be67ef5ad9b2f6020ffe47eecc9fd3338957bb7 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 15 May 2009 22:56:21 +1000 Subject: Implement SetProperties as a custom parser This will allow us to remove all "Assign*" style instructions from the QML compiler and have it depend only on static data. --- src/declarative/qml/qmlcustomparser.cpp | 28 +-- src/declarative/qml/qmlcustomparser_p.h | 2 + src/declarative/qml/qmlparser_p.h | 1 + src/declarative/util/qmllistmodel.cpp | 6 +- src/declarative/util/qmlsetproperties.cpp | 314 +++++++++++++++++++----------- src/declarative/util/qmlsetproperties.h | 10 +- 6 files changed, 228 insertions(+), 133 deletions(-) diff --git a/src/declarative/qml/qmlcustomparser.cpp b/src/declarative/qml/qmlcustomparser.cpp index e864df9..a60f783 100644 --- a/src/declarative/qml/qmlcustomparser.cpp +++ b/src/declarative/qml/qmlcustomparser.cpp @@ -120,6 +120,7 @@ QmlCustomParserNodePrivate::fromObject(QmlParser::Object *root) return rootNode; } +#include QmlCustomParserProperty QmlCustomParserNodePrivate::fromProperty(QmlParser::Property *p) { @@ -127,20 +128,23 @@ QmlCustomParserNodePrivate::fromProperty(QmlParser::Property *p) prop.d->name = p->name; prop.d->isList = (p->values.count() > 1); - for(int ii = 0; ii < p->values.count(); ++ii) { - Value *v = p->values.at(ii); + if (p->value) { + QmlCustomParserNode node = fromObject(p->value); + QList props = node.properties(); + for (int ii = 0; ii < props.count(); ++ii) + prop.d->values << QVariant::fromValue(props.at(ii)); + } else { + for(int ii = 0; ii < p->values.count(); ++ii) { + Value *v = p->values.at(ii); + + if(v->object) { + QmlCustomParserNode node = fromObject(v->object); + prop.d->values << QVariant::fromValue(node); + } else { + prop.d->values << QVariant::fromValue(v->value); + } - // We skip fetched properties for now - if(v->object && v->object->type == -1) - continue; - - if(v->object) { - QmlCustomParserNode node = fromObject(v->object); - prop.d->values << QVariant::fromValue(node); - } else { - prop.d->values << QVariant::fromValue(v->primitive()); } - } return prop; diff --git a/src/declarative/qml/qmlcustomparser_p.h b/src/declarative/qml/qmlcustomparser_p.h index e4e6089..fd780d6 100644 --- a/src/declarative/qml/qmlcustomparser_p.h +++ b/src/declarative/qml/qmlcustomparser_p.h @@ -65,6 +65,8 @@ public: QByteArray name() const; bool isList() const; + // Will be one of QmlParser::Variant, QmlCustomParserProperty or + // QmlCustomParserNode QList assignedValues() const; private: diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 5cc810e..95b21e6 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -272,6 +272,7 @@ namespace QmlParser void dump(int = 0) const; }; } +Q_DECLARE_METATYPE(QmlParser::Variant); QT_END_NAMESPACE diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 8184bda..80eb9c3 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "qmlopenmetaobject.h" #include #include @@ -414,8 +415,11 @@ bool ListModelParser::compileProperty(const QmlCustomParserProperty &prop, QList } else { + QmlParser::Variant variant = + qvariant_cast(value); + int ref = data.count(); - QByteArray d = value.toString().toLatin1(); + QByteArray d = variant.asScript().toLatin1(); d.append('\0'); data.append(d); diff --git a/src/declarative/util/qmlsetproperties.cpp b/src/declarative/util/qmlsetproperties.cpp index 9b5a58e..9a1095c 100644 --- a/src/declarative/util/qmlsetproperties.cpp +++ b/src/declarative/util/qmlsetproperties.cpp @@ -44,61 +44,12 @@ #include "qmlsetproperties.h" #include #include +#include +#include +#include QT_BEGIN_NAMESPACE -class QmlSetPropertiesMetaObject : public QmlOpenMetaObject -{ -public: - QmlSetPropertiesMetaObject(QObject *); - -protected: - virtual void propertyRead(int); - virtual void propertyWrite(int); -}; - -class QmlSetPropertiesProxyObject : public QObject -{ -Q_OBJECT -public: - QmlSetPropertiesProxyObject(QObject *); - - QmlSetPropertiesMetaObject *fxMetaObject() const { return _mo; } -private: - QmlSetPropertiesMetaObject *_mo; -}; - -QmlSetPropertiesProxyObject::QmlSetPropertiesProxyObject(QObject *parent) -: QObject(parent), _mo(new QmlSetPropertiesMetaObject(this)) -{ -} - -QmlSetPropertiesMetaObject::QmlSetPropertiesMetaObject(QObject *obj) -: QmlOpenMetaObject(obj) -{ -} - -void QmlSetPropertiesMetaObject::propertyRead(int id) -{ - if (!value(id).isValid()) - setValue(id, QVariant::fromValue((QObject *)new QmlSetPropertiesProxyObject(object()))); - - QmlOpenMetaObject::propertyRead(id); -} - -void QmlSetPropertiesMetaObject::propertyWrite(int id) -{ - if (value(id).userType() == qMetaTypeId()) { - QObject *val = qvariant_cast(value(id)); - QmlSetPropertiesProxyObject *proxy = qobject_cast(val); - if (proxy) { - setValue(id, QVariant()); - delete proxy; - } - } - QmlOpenMetaObject::propertyWrite(id); -} - /*! \qmlclass SetProperties QmlSetProperties \brief The SetProperties element describes new property values for a state. @@ -149,109 +100,248 @@ void QmlSetPropertiesMetaObject::propertyWrite(int id) \sa QmlSetProperty */ +/*! + \qmlproperty Object SetProperties::target + This property holds the object that the properties to change belong to +*/ + +/*! + \property QmlSetProperties::target + \brief the object that the properties to change belong to +*/ class QmlSetPropertiesPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QmlSetProperties) public: - QmlSetPropertiesPrivate() : obj(0), mo(0) {} + QmlSetPropertiesPrivate() : object(0), decoded(true) {} - QObject *obj; - QmlSetPropertiesMetaObject *mo; + QObject *object; + QByteArray data; + bool decoded; + void decode(); + + QList > properties; + QList > expressions; + + QmlMetaProperty property(const QByteArray &); }; -QML_DEFINE_TYPE(QmlSetProperties,SetProperties); -QmlSetProperties::QmlSetProperties() - : QmlStateOperation(*(new QmlSetPropertiesPrivate)) +class QmlSetPropertiesParser : public QmlCustomParser { - Q_D(QmlSetProperties); - d->mo = new QmlSetPropertiesMetaObject(this); +public: + void compileList(QList > &list, const QByteArray &pre, const QmlCustomParserProperty &prop); + + virtual QByteArray compile(const QList &, bool *ok); + virtual void setCustomData(QObject *, const QByteArray &); +}; + +void +QmlSetPropertiesParser::compileList(QList > &list, + const QByteArray &pre, + const QmlCustomParserProperty &prop) +{ + QByteArray propName = pre + prop.name(); + + QList values = prop.assignedValues(); + for (int ii = 0; ii < values.count(); ++ii) { + const QVariant &value = values.at(ii); + + if (value.userType() == qMetaTypeId()) { + continue; + } else if(value.userType() == qMetaTypeId()) { + + QmlCustomParserProperty prop = + qvariant_cast(value); + QByteArray pre = propName + "."; + compileList(list, pre, prop); + + } else { + list << qMakePair(propName, value); + } + } } -QmlSetProperties::QmlSetProperties(QObject *parent) - : QmlStateOperation(*(new QmlSetPropertiesPrivate), parent) +QByteArray +QmlSetPropertiesParser::compile(const QList &props, + bool *ok) { - Q_D(QmlSetProperties); - d->mo = new QmlSetPropertiesMetaObject(this); + *ok = true; + + QList > data; + for(int ii = 0; ii < props.count(); ++ii) + compileList(data, QByteArray(), props.at(ii)); + + QByteArray rv; + QDataStream ds(&rv, QIODevice::WriteOnly); + + ds << data.count(); + for(int ii = 0; ii < data.count(); ++ii) { + QmlParser::Variant v = qvariant_cast(data.at(ii).second); + QVariant var; + bool isScript = v.isScript(); + switch(v.type()) { + case QmlParser::Variant::Boolean: + var = QVariant(v.asBoolean()); + break; + case QmlParser::Variant::Number: + var = QVariant(v.asNumber()); + break; + case QmlParser::Variant::String: + var = QVariant(v.asString()); + break; + case QmlParser::Variant::Invalid: + case QmlParser::Variant::Script: + var = QVariant(v.asScript()); + break; + } + + ds << data.at(ii).first << isScript << var; + } + + return rv; } -QmlSetProperties::~QmlSetProperties() +void QmlSetPropertiesPrivate::decode() { + if (decoded) + return; + + QDataStream ds(&data, QIODevice::ReadOnly); + + int count; + ds >> count; + for (int ii = 0; ii < count; ++ii) { + QByteArray name; + bool isScript; + QVariant data; + ds >> name; + ds >> isScript; + ds >> data; + + if (isScript) { + QmlExpression *expression = new QmlExpression(qmlContext(object), data.toString(), object); + expression->setTrackChange(false); + expressions << qMakePair(name, expression); + } else { + properties << qMakePair(name, data); + } + } + + decoded = true; + data.clear(); } -/*! - \qmlproperty Object SetProperties::target - This property holds the object that the properties to change belong to -*/ +void QmlSetPropertiesParser::setCustomData(QObject *object, + const QByteArray &data) +{ + QmlSetPropertiesPrivate *p = + static_cast(QObjectPrivate::get(object)); + p->data = data; + p->decoded = false; +} -/*! - \property QmlSetProperties::target - \brief the object that the properties to change belong to -*/ -QObject *QmlSetProperties::object() +QmlSetProperties::QmlSetProperties() +: QmlStateOperation(*(new QmlSetPropertiesPrivate)) +{ +} + +QmlSetProperties::~QmlSetProperties() { Q_D(QmlSetProperties); - return d->obj; + for(int ii = 0; ii < d->expressions.count(); ++ii) + delete d->expressions.at(ii).second; +} + +QObject *QmlSetProperties::object() const +{ + Q_D(const QmlSetProperties); + return d->object; } void QmlSetProperties::setObject(QObject *o) { Q_D(QmlSetProperties); - d->obj = o; + d->object = o; } -QmlSetProperties::ActionList -QmlSetProperties::doAction(QmlSetPropertiesMetaObject *metaObject, - QObject *object) +QmlMetaProperty +QmlSetPropertiesPrivate::property(const QByteArray &property) { + Q_Q(QmlSetProperties); + QList path = property.split('.'); + + QObject *obj = this->object; + + for (int jj = 0; jj < path.count() - 1; ++jj) { + const QByteArray &pathName = path.at(jj); + QmlMetaProperty prop(obj, QLatin1String(pathName)); + QObject *objVal = QmlMetaType::toQObject(prop.read()); + if (!objVal) { + qmlInfo(q) << obj->metaObject()->className() + << "has no object property named" << pathName; + return QmlMetaProperty(); + } + obj = objVal; + } + + const QByteArray &name = path.last(); + QmlMetaProperty prop(obj, QLatin1String(name)); + if (!prop.isValid()) { + qmlInfo(q) << obj->metaObject()->className() + << "has no property named" << name; + return QmlMetaProperty(); + } else if (!prop.isWritable()) { + qmlInfo(q) << obj->metaObject()->className() + << name << "is not writable, and cannot be set."; + return QmlMetaProperty(); + } else { + return prop; + } +} + +QmlSetProperties::ActionList QmlSetProperties::actions() +{ + Q_D(QmlSetProperties); + + d->decode(); + ActionList list; - for (int ii = 0; ii < metaObject->count(); ++ii) { + for (int ii = 0; ii < d->properties.count(); ++ii) { + + QByteArray property = d->properties.at(ii).first; + QmlMetaProperty prop = d->property(property); - QByteArray name = metaObject->name(ii); - QVariant value = metaObject->value(ii); + if (prop.isValid()) { + Action a; + a.property = prop; + a.fromValue = a.property.read(); + a.toValue = d->properties.at(ii).second; - QmlSetPropertiesProxyObject *po = qobject_cast(qvariant_cast(value)); + list << a; + } + } - QmlMetaProperty prop(object, QLatin1String(name)); + for (int ii = 0; ii < d->expressions.count(); ++ii) { - if (po) { - QObject *objVal = QmlMetaType::toQObject(prop.read()); - if (!objVal) { - qmlInfo(this) << object->metaObject()->className() - << "has no object property named" << name; - continue; - } + QByteArray property = d->expressions.at(ii).first; + QmlMetaProperty prop = d->property(property); - list << doAction(po->fxMetaObject(), objVal); - } else if (!prop.isValid()) { - qmlInfo(this) << object->metaObject()->className() - << "has no property named" << name; - continue; - } else if (!prop.isWritable()) { - qmlInfo(this) << object->metaObject()->className() - << name << "is not writable, and cannot be set."; - continue; - } else { - //append action + if (prop.isValid()) { Action a; a.property = prop; - a.fromValue = prop.read(); - a.toValue = value; + a.fromValue = a.property.read(); + a.toValue = d->expressions.at(ii).second->value(); list << a; } + } return list; } -QmlSetProperties::ActionList QmlSetProperties::actions() -{ - Q_D(QmlSetProperties); - if (!d->obj) - return ActionList(); - - return doAction(d->mo, d->obj); -} +QML_DEFINE_CUSTOM_TYPE(QmlSetProperties,SetProperties,QmlSetPropertiesParser); QT_END_NAMESPACE #include "qmlsetproperties.moc" diff --git a/src/declarative/util/qmlsetproperties.h b/src/declarative/util/qmlsetproperties.h index f1f59ed..bd036c1 100644 --- a/src/declarative/util/qmlsetproperties.h +++ b/src/declarative/util/qmlsetproperties.h @@ -50,7 +50,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QmlSetPropertiesMetaObject; + class QmlSetPropertiesPrivate; class Q_DECLARATIVE_EXPORT QmlSetProperties : public QmlStateOperation { @@ -58,20 +58,14 @@ class Q_DECLARATIVE_EXPORT QmlSetProperties : public QmlStateOperation Q_DECLARE_PRIVATE(QmlSetProperties); Q_PROPERTY(QObject *target READ object WRITE setObject); - public: QmlSetProperties(); - QmlSetProperties(QObject *parent); ~QmlSetProperties(); - QObject *object(); + QObject *object() const; void setObject(QObject *); virtual ActionList actions(); - -private: - ActionList doAction(QmlSetPropertiesMetaObject *, QObject *); - //QmlSetProperties::ActionList appendDotActions(const QVariant &, const QVariant &); }; QML_DECLARE_TYPE(QmlSetProperties); -- cgit v0.12