From e82735cb4d65025693204346e0e0359da0afd6c3 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 26 Aug 2009 09:08:24 +1000 Subject: Update docs to reflect layouts renaming --- doc/src/declarative/anchor-layout.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/declarative/anchor-layout.qdoc b/doc/src/declarative/anchor-layout.qdoc index 69e2eda..5b2f068 100644 --- a/doc/src/declarative/anchor-layout.qdoc +++ b/doc/src/declarative/anchor-layout.qdoc @@ -3,11 +3,11 @@ \target anchor-layout \title Anchor-based Layout -In additional to the more traditional Fx layouts GridLayout, HorizontalLayout, and VerticalLayout, QML also provides a way to layout items using the concept of anchors. Each visual Fx item can be thought of as having a set of 6 invisible "anchor lines": \e left, \e horizontalCenter, \e right, \e top, \e verticalCenter, and \e bottom. +In additional to the more traditional layouts Grid, Row, and Column, QML also provides a way to layout items using the concept of anchors. Each visual item can be thought of as having a set of 6 invisible "anchor lines": \e left, \e horizontalCenter, \e right, \e top, \e verticalCenter, and \e bottom. \image edges_qml.png -The Fx anchoring system allows you to define relationships between the anchor lines of different items. For example, you can write: +The anchoring system allows you to define relationships between the anchor lines of different items. For example, you can write: \code Rectangle { id: rect1; ... } -- cgit v0.12 From 0cb67317e8c22282901a73568cf903ea1bec725d Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 27 Aug 2009 10:08:10 +1000 Subject: Fix potential crash on deletion. If an item's parent is being destructed, no need to update anchors. --- src/declarative/fx/qfxitem.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index 666369a..c3c6bc4 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -1164,11 +1164,12 @@ QFxItem::~QFxItem() QFxAnchors *anchor = d->dependantAnchors.at(ii); anchor->d_func()->clearItem(this); } - for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { - QFxAnchors *anchor = d->dependantAnchors.at(ii); - if (anchor->d_func()->item && anchor->d_func()->item->parentItem() != this) //child will be deleted anyway - anchor->d_func()->updateOnComplete(); - } + if (!d->parent || (parentItem() && !parentItem()->QGraphicsItem::d_ptr->inDestructor)) + for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + if (anchor->d_func()->item && anchor->d_func()->item->parentItem() != this) //child will be deleted anyway + anchor->d_func()->updateOnComplete(); + } delete d->_anchorLines; d->_anchorLines = 0; delete d->_anchors; d->_anchors = 0; } -- cgit v0.12 From a488a04e5a5af4255d560d5dfa6423caa48ed5f3 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 27 Aug 2009 11:01:55 +1000 Subject: Make QmlPropertyValueSource an interface. 1st step in animation class heirarchy redesign. --- src/declarative/extra/qmlbehaviour.cpp | 2 +- src/declarative/extra/qmlbehaviour.h | 2 +- src/declarative/qml/qml.h | 1 + src/declarative/qml/qmlcompiler.cpp | 29 ++++++++----------------- src/declarative/qml/qmlinstruction.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 1 + src/declarative/qml/qmlmetatype.cpp | 30 ++++++++++++++++++++------ src/declarative/qml/qmlmetatype.h | 20 +++++++++++------ src/declarative/qml/qmlpropertyvaluesource.cpp | 22 +++---------------- src/declarative/qml/qmlpropertyvaluesource.h | 23 +++++--------------- src/declarative/qml/qmlvme.cpp | 9 ++++---- src/declarative/util/qmlanimation.cpp | 4 ++-- src/declarative/util/qmlanimation.h | 2 +- src/declarative/util/qmlfollow.cpp | 2 +- src/declarative/util/qmlfollow.h | 3 ++- 15 files changed, 70 insertions(+), 82 deletions(-) diff --git a/src/declarative/extra/qmlbehaviour.cpp b/src/declarative/extra/qmlbehaviour.cpp index 767f1ed..5401b0d 100644 --- a/src/declarative/extra/qmlbehaviour.cpp +++ b/src/declarative/extra/qmlbehaviour.cpp @@ -122,7 +122,7 @@ public: */ QmlBehaviour::QmlBehaviour(QObject *parent) -: QmlPropertyValueSource(*(new QmlBehaviourPrivate), parent) +: QObject(*(new QmlBehaviourPrivate), parent) { Q_D(QmlBehaviour); d->group = new QParallelAnimationGroup; diff --git a/src/declarative/extra/qmlbehaviour.h b/src/declarative/extra/qmlbehaviour.h index 99fc779..b33d72a 100644 --- a/src/declarative/extra/qmlbehaviour.h +++ b/src/declarative/extra/qmlbehaviour.h @@ -54,7 +54,7 @@ QT_MODULE(Declarative) class QmlAbstractAnimation; class QmlBehaviourPrivate; -class Q_DECLARATIVE_EXPORT QmlBehaviour : public QmlPropertyValueSource +class Q_DECLARATIVE_EXPORT QmlBehaviour : public QObject, public QmlPropertyValueSource { Q_OBJECT Q_DECLARE_PRIVATE(QmlBehaviour) diff --git a/src/declarative/qml/qml.h b/src/declarative/qml/qml.h index bced8f2..23f2f1e 100644 --- a/src/declarative/qml/qml.h +++ b/src/declarative/qml/qml.h @@ -50,6 +50,7 @@ #include #include #include +#include #include QT_BEGIN_HEADER diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index bbcc64d..3af7137 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -1411,7 +1411,6 @@ void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop, } } else if (v->type == Value::ValueSource) { - genObject(v->object); QmlInstruction store; @@ -1425,6 +1424,8 @@ void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop, QmlMetaPropertyPrivate::saveProperty(prop->index); store.assignValueSource.owner = 0; } + QmlType *valueType = QmlMetaType::qmlType(v->object->metatype); + store.assignValueSource.castValue = valueType->propertyValueSourceCast(); output->bytecode << store; } else if (v->type == Value::PropertyBinding) { @@ -1584,15 +1585,7 @@ bool QmlCompiler::buildValueTypeProperty(QObject *type, Value *value = prop->values.at(0); if (value->object) { - const QMetaObject *c = - output->types.at(value->object->type).metaObject(); - bool isPropertyValue = false; - while (c && !isPropertyValue) { - isPropertyValue = - (c == &QmlPropertyValueSource::staticMetaObject); - c = c->superClass(); - } - + bool isPropertyValue = output->types.at(value->object->type).type->propertyValueSourceCast() != -1; if (!isPropertyValue) { COMPILE_EXCEPTION(prop, "Invalid property use"); } else { @@ -1762,30 +1755,26 @@ bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop, v->object->metatype = output->types.at(v->object->type).metaObject(); Q_ASSERT(v->object->metaObject()); + // Will be true if the assigned type inherits QmlPropertyValueSource + bool isPropertyValue = false; + if (QmlType *valueType = QmlMetaType::qmlType(v->object->metatype)) + isPropertyValue = valueType->propertyValueSourceCast() != -1; + // We want to raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might // effect the properties on the type, but don't effect assignability const QMetaObject *propertyMetaObject = QmlMetaType::rawMetaObjectForType(prop->type); - // Will be true if the assigned type inherits QmlPropertyValueSource - bool isPropertyValue = false; // Will be true if the assgned type inherits propertyMetaObject bool isAssignable = false; - // Determine isPropertyValue and isAssignable values + // Determine isAssignable value if (propertyMetaObject) { const QMetaObject *c = v->object->metatype; while(c) { - isPropertyValue |= (c == &QmlPropertyValueSource::staticMetaObject); isAssignable |= (c == propertyMetaObject); c = c->superClass(); } - } else { - const QMetaObject *c = v->object->metatype; - while(!isPropertyValue && c) { - isPropertyValue |= (c == &QmlPropertyValueSource::staticMetaObject); - c = c->superClass(); - } } if (isAssignable) { diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 02e4883..b71c6e3 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -147,7 +147,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) qWarning() << idx << "\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context; break; case QmlInstruction::StoreValueSource: - qWarning() << idx << "\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property; + qWarning() << idx << "\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue; break; case QmlInstruction::BeginObject: qWarning() << idx << "\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 0f2995a..8861609a 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -183,6 +183,7 @@ public: struct { int property; int owner; + int castValue; } assignValueSource; struct { int property; diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index ab64079..c488c13 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -120,6 +120,7 @@ public: QmlAttachedPropertiesFunc m_attachedPropertiesFunc; const QMetaObject *m_attachedPropertiesType; int m_parserStatusCast; + int m_propertyValueSourceCast; QmlPrivate::CreateFunc m_extFunc; const QMetaObject *m_extMetaObject; int m_index; @@ -132,8 +133,8 @@ public: QmlTypePrivate::QmlTypePrivate() : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_qmlListId(0), m_opFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), m_attachedPropertiesType(0), - m_parserStatusCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), - m_customParser(0), m_isSetup(false) + m_parserStatusCast(-1), m_propertyValueSourceCast(-1), m_extFunc(0), m_extMetaObject(0), + m_index(-1), m_customParser(0), m_isSetup(false) { } @@ -161,7 +162,7 @@ QmlType::QmlType(int type, int listType, int qmlListType, const QMetaObject *metaObject, QmlAttachedPropertiesFunc attachedPropertiesFunc, const QMetaObject *attachedType, - int parserStatusCast, QmlPrivate::CreateFunc extFunc, + int parserStatusCast, int propertyValueSourceCast, QmlPrivate::CreateFunc extFunc, const QMetaObject *extMetaObject, int index, QmlCustomParser *customParser) : d(new QmlTypePrivate) @@ -178,6 +179,7 @@ QmlType::QmlType(int type, int listType, int qmlListType, d->m_attachedPropertiesFunc = attachedPropertiesFunc; d->m_attachedPropertiesType = attachedType; d->m_parserStatusCast = parserStatusCast; + d->m_propertyValueSourceCast = propertyValueSourceCast; d->m_extFunc = extFunc; d->m_index = index; d->m_customParser = customParser; @@ -397,6 +399,11 @@ int QmlType::parserStatusCast() const return d->m_parserStatusCast; } +int QmlType::propertyValueSourceCast() const +{ + return d->m_propertyValueSourceCast; +} + QVariant QmlType::fromObject(QObject *obj) const { QVariant rv; @@ -452,7 +459,7 @@ int QmlMetaType::registerInterface(const QmlPrivate::MetaTypeIds &id, int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Func func, const char *uri, int version_maj, int version_min_from, int version_min_to, const char *cname, const QMetaObject *mo, QmlAttachedPropertiesFunc attach, const QMetaObject *attachMo, - int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *parser) + int pStatus, int object, int valueSource, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *parser) { Q_UNUSED(object); @@ -476,8 +483,8 @@ int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Fun name.replace('.','/'); QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, - func, name, version_maj, version_min_from, version_min_to, mo, attach, attachMo, pStatus, extFunc, - extmo, index, parser); + func, name, version_maj, version_min_from, version_min_to, mo, attach, attachMo, pStatus, + valueSource, extFunc, extmo, index, parser); data->types.append(type); data->idToType.insert(type->typeId(), type); @@ -513,6 +520,17 @@ int QmlMetaType::qmlParserStatusCast(int userType) return -1; } +int QmlMetaType::qmlPropertyValueSourceCast(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + if (type && type->typeId() == userType) + return type->propertyValueSourceCast(); + else + return -1; +} + QObject *QmlMetaType::toQObject(const QVariant &v) { if (!isObject(v.userType())) diff --git a/src/declarative/qml/qmlmetatype.h b/src/declarative/qml/qmlmetatype.h index c388b1a..5ed9a5a 100644 --- a/src/declarative/qml/qmlmetatype.h +++ b/src/declarative/qml/qmlmetatype.h @@ -47,6 +47,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -59,7 +60,7 @@ class QmlCustomParser; class Q_DECLARATIVE_EXPORT QmlMetaType { public: - static int registerType(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *, int vmaj, int vmin_from, int vmin_to, const char *qmlName, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *); + static int registerType(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *, int vmaj, int vmin_from, int vmin_to, const char *qmlName, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int pStatus, int object, int valueSource, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *); static int registerInterface(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *); static bool copy(int type, void *data, const void *copy = 0); @@ -78,6 +79,7 @@ public: static QMetaProperty property(QObject *, const char *); static QObject *toQObject(const QVariant &); static int qmlParserStatusCast(int); + static int qmlPropertyValueSourceCast(int); static int listType(int); static bool clear(const QVariant &); static bool append(const QVariant &, const QVariant &); @@ -143,13 +145,14 @@ public: int parserStatusCast() const; QVariant fromObject(QObject *) const; const char *interfaceIId() const; + int propertyValueSourceCast() const; int index() const; private: friend class QmlMetaType; friend class QmlTypePrivate; QmlType(int, int, int, QmlPrivate::Func, const char *, int); - QmlType(int, int, int, QmlPrivate::Func, const char *, int, int, int, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int, QmlPrivate::CreateFunc, const QMetaObject *, int, QmlCustomParser *); + QmlType(int, int, int, QmlPrivate::Func, const char *, int, int, int, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int, int, QmlPrivate::CreateFunc, const QMetaObject *, int, QmlCustomParser *); ~QmlType(); QmlTypePrivate *d; @@ -170,7 +173,8 @@ int qmlRegisterType(const char *typeName) QmlPrivate::attachedPropertiesFunc(), QmlPrivate::attachedPropertiesMetaObject(), QmlPrivate::StaticCastSelector::cast(), - QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), 0, 0, 0); } @@ -191,6 +195,7 @@ int qmlRegisterType(const char *uri, int version_maj, int version_min_from, int QmlPrivate::attachedPropertiesMetaObject(), QmlPrivate::StaticCastSelector::cast(), QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), 0, 0, 0); } @@ -216,7 +221,8 @@ int qmlRegisterExtendedType(const char *typeName) return QmlMetaType::registerType(ids, QmlPrivate::list_nocreate_op, 0, 0, 0, 0, 0, &T::staticMetaObject, attached, attachedMo, QmlPrivate::StaticCastSelector::cast(), - QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), &QmlPrivate::CreateParent::create, &E::staticMetaObject, 0); } @@ -244,7 +250,8 @@ int qmlRegisterExtendedType(const char *uri, int version_maj, int version_min_fr &T::staticMetaObject, attached, attachedMo, QmlPrivate::StaticCastSelector::cast(), - QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), &QmlPrivate::CreateParent::create, &E::staticMetaObject, 0); } @@ -280,7 +287,8 @@ int qmlRegisterCustomType(const char *uri, int version_maj, int version_min_from QmlPrivate::attachedPropertiesFunc(), QmlPrivate::attachedPropertiesMetaObject(), QmlPrivate::StaticCastSelector::cast(), - QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), + QmlPrivate::StaticCastSelector::cast(), 0, 0, parser); } diff --git a/src/declarative/qml/qmlpropertyvaluesource.cpp b/src/declarative/qml/qmlpropertyvaluesource.cpp index c6ff596..429080b 100644 --- a/src/declarative/qml/qmlpropertyvaluesource.cpp +++ b/src/declarative/qml/qmlpropertyvaluesource.cpp @@ -48,34 +48,18 @@ QT_BEGIN_NAMESPACE \class QmlPropertyValueSource \brief The QmlPropertyValueSource class is inherited by property value sources such as animations and bindings. */ -QML_DEFINE_NOCREATE_TYPE(QmlPropertyValueSource) /*! - Constructs a QmlPropertyValueSource with parent \a parent. + Constructs a QmlPropertyValueSource. */ -QmlPropertyValueSource::QmlPropertyValueSource(QObject *parent) - : QObject(parent) - -{ -} - -/*! - \internal - */ -QmlPropertyValueSource::QmlPropertyValueSource(QObjectPrivate &dd, QObject *parent) - : QObject(dd, parent) +QmlPropertyValueSource::QmlPropertyValueSource() { } /*! + \fn void QmlPropertyValueSource::setTarget(const QmlMetaProperty &property) Set the target \a property for the value source. This method will be called by the QML engine when assigning a value source. - - The default implementation does nothing. */ -void QmlPropertyValueSource::setTarget(const QmlMetaProperty &property) -{ - Q_UNUSED(property); -} QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertyvaluesource.h b/src/declarative/qml/qmlpropertyvaluesource.h index 4e5f1c5..ee4ea2c 100644 --- a/src/declarative/qml/qmlpropertyvaluesource.h +++ b/src/declarative/qml/qmlpropertyvaluesource.h @@ -42,9 +42,7 @@ #ifndef QMLPROPERTYVALUESOURCE_H #define QMLPROPERTYVALUESOURCE_H -#include -#include -#include +#include QT_BEGIN_HEADER @@ -52,28 +50,17 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QObjectPrivate; class QmlMetaProperty; -class Q_DECLARATIVE_EXPORT QmlPropertyValueSource : public QObject +class Q_DECLARATIVE_EXPORT QmlPropertyValueSource { - Q_OBJECT - Q_DECLARE_PRIVATE(QObject) - public: - QmlPropertyValueSource(QObject *parent); - virtual void setTarget(const QmlMetaProperty &); - -protected: - QmlPropertyValueSource(QObjectPrivate &dd, QObject *parent); - -private: - Q_DISABLE_COPY(QmlPropertyValueSource) + QmlPropertyValueSource(); + virtual void setTarget(const QmlMetaProperty &) = 0; }; +Q_DECLARE_INTERFACE(QmlPropertyValueSource, "com.trolltech.qml.QmlPropertyValueSource") QT_END_NAMESPACE -QML_DECLARE_TYPE(QmlPropertyValueSource) - QT_END_HEADER #endif // QMLPROPERTYVALUESOURCE_H diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 7455eb4..930e6e4 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -591,13 +591,12 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::StoreValueSource: { - QmlPropertyValueSource *vs = - static_cast(stack.pop()); - QObject *target = - stack.at(stack.count() - 1 - instr.assignValueSource.owner); + QObject *obj = stack.pop(); + QmlPropertyValueSource *vs = reinterpret_cast(reinterpret_cast(obj) + instr.assignValueSource.castValue); + QObject *target = stack.at(stack.count() - 1 - instr.assignValueSource.owner); QmlMetaProperty prop; prop.restore(instr.assignValueSource.property, target, ctxt); - vs->setParent(target); + obj->setParent(target); vs->setTarget(prop); } break; diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 720a045..6cc6db7 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -154,7 +154,7 @@ QML_DEFINE_NOCREATE_TYPE(QmlAbstractAnimation) */ QmlAbstractAnimation::QmlAbstractAnimation(QObject *parent) -: QmlPropertyValueSource(*(new QmlAbstractAnimationPrivate), parent) +: QObject(*(new QmlAbstractAnimationPrivate), parent) { } @@ -163,7 +163,7 @@ QmlAbstractAnimation::~QmlAbstractAnimation() } QmlAbstractAnimation::QmlAbstractAnimation(QmlAbstractAnimationPrivate &dd, QObject *parent) -: QmlPropertyValueSource(dd, parent) +: QObject(dd, parent) { } diff --git a/src/declarative/util/qmlanimation.h b/src/declarative/util/qmlanimation.h index f5180a5..67a2045 100644 --- a/src/declarative/util/qmlanimation.h +++ b/src/declarative/util/qmlanimation.h @@ -58,7 +58,7 @@ QT_MODULE(Declarative) class QmlAbstractAnimationPrivate; class QmlAnimationGroup; -class QmlAbstractAnimation : public QmlPropertyValueSource, public QmlParserStatus +class QmlAbstractAnimation : public QObject, public QmlPropertyValueSource, public QmlParserStatus { Q_OBJECT Q_DECLARE_PRIVATE(QmlAbstractAnimation) diff --git a/src/declarative/util/qmlfollow.cpp b/src/declarative/util/qmlfollow.cpp index eec2480..fe5303f 100644 --- a/src/declarative/util/qmlfollow.cpp +++ b/src/declarative/util/qmlfollow.cpp @@ -239,7 +239,7 @@ void QmlFollowPrivate::stop() */ QmlFollow::QmlFollow(QObject *parent) -: QmlPropertyValueSource(*(new QmlFollowPrivate),parent) +: QObject(*(new QmlFollowPrivate),parent) { } diff --git a/src/declarative/util/qmlfollow.h b/src/declarative/util/qmlfollow.h index 07b2f49..1f6376a 100644 --- a/src/declarative/util/qmlfollow.h +++ b/src/declarative/util/qmlfollow.h @@ -52,11 +52,12 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QmlFollowPrivate; -class Q_DECLARATIVE_EXPORT QmlFollow : public QmlPropertyValueSource, +class Q_DECLARATIVE_EXPORT QmlFollow : public QObject, public QmlPropertyValueSource, public QmlParserStatus { Q_OBJECT Q_DECLARE_PRIVATE(QmlFollow) + Q_INTERFACES(QmlPropertyValueSource) Q_INTERFACES(QmlParserStatus) Q_PROPERTY(qreal source READ sourceValue WRITE setSourceValue) -- cgit v0.12 From 0d12a574ca3624ecfe62d4183e02e43f3bfb6509 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 27 Aug 2009 11:25:21 +1000 Subject: Repeater API updates. --- examples/declarative/easing/easing.qml | 2 +- examples/declarative/follow/pong.qml | 2 +- examples/declarative/listview/itemlist.qml | 2 +- examples/declarative/minehunt/minehunt.qml | 2 +- examples/declarative/velocity/Day.qml | 2 +- examples/declarative/velocity/velocity.qml | 2 +- src/declarative/fx/qfxlistview.cpp | 2 +- src/declarative/fx/qfxrepeater.cpp | 93 ++++++++++++------------------ src/declarative/fx/qfxrepeater.h | 19 +++--- src/declarative/fx/qfxrepeater_p.h | 1 + 10 files changed, 57 insertions(+), 70 deletions(-) diff --git a/examples/declarative/easing/easing.qml b/examples/declarative/easing/easing.qml index 60c2040..df301d8 100644 --- a/examples/declarative/easing/easing.qml +++ b/examples/declarative/easing/easing.qml @@ -56,7 +56,7 @@ Rectangle { anchors.left: Window.left anchors.right: Window.right Repeater { - dataSource: EasingTypes + model: EasingTypes Component { Text { id: Text diff --git a/examples/declarative/follow/pong.qml b/examples/declarative/follow/pong.qml index d2aaba9..0314bb8 100644 --- a/examples/declarative/follow/pong.qml +++ b/examples/declarative/follow/pong.qml @@ -63,7 +63,7 @@ Rectangle { Rectangle { color: "#00ee00"; x: Page.width/2+40; y: 0; width: 40; height: 60 } Rectangle { color: "#000000"; x: Page.width/2+50; y: 10; width: 20; height: 40 } Repeater { - dataSource: Page.height/20 + model: Page.height/20 Rectangle { color: "#00ee00"; x: Page.width/2-5; y: index*20; width: 10; height: 10 } } } diff --git a/examples/declarative/listview/itemlist.qml b/examples/declarative/listview/itemlist.qml index c25ee59..061fab3 100644 --- a/examples/declarative/listview/itemlist.qml +++ b/examples/declarative/listview/itemlist.qml @@ -44,7 +44,7 @@ Rectangle { anchors.centerIn: parent spacing: 20 Repeater { - dataSource: ItemModel.count + model: ItemModel.count Rectangle { width: 5; height: 5 radius: 3 diff --git a/examples/declarative/minehunt/minehunt.qml b/examples/declarative/minehunt/minehunt.qml index 11748a8..4bae64d 100644 --- a/examples/declarative/minehunt/minehunt.qml +++ b/examples/declarative/minehunt/minehunt.qml @@ -130,7 +130,7 @@ Item { anchors.verticalCenter: parent.verticalCenter } Repeater { - dataSource: tiles + model: tiles x: 1 y: 1 Component { diff --git a/examples/declarative/velocity/Day.qml b/examples/declarative/velocity/Day.qml index e488ae1..1a336b7 100644 --- a/examples/declarative/velocity/Day.qml +++ b/examples/declarative/velocity/Day.qml @@ -26,7 +26,7 @@ Rectangle { styleColor: "#dedede" } Repeater { - dataSource: Page.stickies + model: Page.stickies Item { x: Math.random() * 200 + 100 y: Math.random() * 300 + 50 diff --git a/examples/declarative/velocity/velocity.qml b/examples/declarative/velocity/velocity.qml index c2425da..8ac42e1 100644 --- a/examples/declarative/velocity/velocity.qml +++ b/examples/declarative/velocity/velocity.qml @@ -101,7 +101,7 @@ Rectangle { Row { id: Lay Repeater { - dataSource: List + model: List Component { Day { day: name diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 048cb0f..b2c9a59 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -894,7 +894,7 @@ QFxListView::~QFxListView() provided by a C++ model object. The C++ model object must be a \l {QAbstractItemModel} subclass, a VisualModel, or a simple list. - Models can also be created directly in QML, using a \l{ListModel}. + Models can also be created directly in QML, using a \l{ListModel} or \l{XmlListModel}. */ QVariant QFxListView::model() const { diff --git a/src/declarative/fx/qfxrepeater.cpp b/src/declarative/fx/qfxrepeater.cpp index a9d9977..fa44f8f 100644 --- a/src/declarative/fx/qfxrepeater.cpp +++ b/src/declarative/fx/qfxrepeater.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE QFxRepeaterPrivate::QFxRepeaterPrivate() -: component(0) +: component(0), count(0) { } @@ -112,42 +112,8 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Repeater,QFxRepeater) /*! \internal \class QFxRepeater - \ingroup group_utility \qmlclass Repeater - \brief The QFxRepeater class allows you to repeat a component based on a - data source. - - The QFxRepeater class is used when you want to create a large number of - similar items. For each entry in the data source, an item is instantiated - in a context seeded with data from the data source. - - The data source may be either an object list, a string list or a Qt model. - In each case, the data element and the index is exposed to each instantiated - component. The index is always exposed as an accessible \c index property. - In the case of an object or string list, the data element (of type string - or object) is available as the \c modelData property. In the case of a Qt model, - all roles are available as named properties just like in the view classes. - - As a special case the data source can also be merely a number. In this case it will - create that many instances of the component. They will also be assigned an index - based on the order they are created. - - Items instantiated by the QFxRepeater class are inserted, in order, as - children of the repeater's parent. The insertion starts immediately after - the repeater's position in its parent stacking list. This is to allow - you to use a repeater inside a layout. The following QML example shows how - the instantiated items would visually appear stacked between the red and - blue rectangles. - - \snippet doc/src/snippets/declarative/repeater.qml 0 - - The QFxRepeater instance continues to own all items it instantiates, even - if they are otherwise manipulated. It is illegal to manually delete an item - created by the repeater. On destruction, the repeater will clean up any - items it has instantiated. - - XXX Repeater is very conservative in how it instatiates/deletes items. Also new model entries will not be created and old ones will not be removed. */ @@ -177,27 +143,27 @@ QFxRepeater::~QFxRepeater() } /*! - \qmlproperty any Repeater::dataSource + \qmlproperty any Repeater::model - The Repeater's data source. + The model providing data for the repeater. - The data source may be either an object list, a string list or a Qt model. + The model may be either an object list, a string list or a Qt model. In each case, the data element and the index is exposed to each instantiated component. The index is always exposed as an accessible \c index property. In the case of an object or string list, the data element (of type string or object) is available as the \c modelData property. In the case of a Qt model, all roles are available as named properties just like in the view classes. - As a special case the data source can also be merely a number. In this case it will + As a special case the model can also be merely a number. In this case it will create that many instances of the component. They will also be assigned an index based on the order they are created. */ -QVariant QFxRepeater::dataSource() const +QVariant QFxRepeater::model() const { return QVariant(); } -void QFxRepeater::setDataSource(const QVariant &v) +void QFxRepeater::setModel(const QVariant &v) { Q_D(QFxRepeater); d->dataSource = v; @@ -205,18 +171,18 @@ void QFxRepeater::setDataSource(const QVariant &v) } /*! - \qmlproperty Component Repeater::component + \qmlproperty Component Repeater::delegate \default - The component to repeat. + The delegate provides a template describing what each item instantiated by the repeater should look and act like. */ -QmlComponent *QFxRepeater::component() const +QmlComponent *QFxRepeater::delegate() const { Q_D(const QFxRepeater); return d->component; } -void QFxRepeater::setComponent(QmlComponent *_c) +void QFxRepeater::setDelegate(QmlComponent *_c) { Q_D(QFxRepeater); d->component = _c; @@ -224,6 +190,18 @@ void QFxRepeater::setComponent(QmlComponent *_c) } /*! + \qmlproperty int Repeater::count + + This property holds the number of items in the repeater. +*/ +int QFxRepeater::count() const +{ + Q_D(const QFxRepeater); + return d->count; +} + + +/*! \internal */ void QFxRepeater::componentComplete() @@ -260,10 +238,13 @@ void QFxRepeater::regenerate() QFxItem *lastItem = this; + int count = 0; + if (d->dataSource.type() == QVariant::StringList) { QStringList sl = qvariant_cast(d->dataSource); - for (int ii = 0; ii < sl.size(); ++ii) { + count = sl.size(); + for (int ii = 0; ii < count; ++ii) { QmlContext *ctxt = new QmlContext(qmlContext(this), this); d->deletables << ctxt; @@ -274,11 +255,11 @@ void QFxRepeater::regenerate() lastItem = item; } } else if (QmlMetaType::isList(d->dataSource)) { - int cnt = QmlMetaType::listCount(d->dataSource); - if (cnt <= 0) + count = QmlMetaType::listCount(d->dataSource); + if (count <= 0) return; - for (int ii = 0; ii < cnt; ++ii) { + for (int ii = 0; ii < count; ++ii) { QVariant v = QmlMetaType::listAt(d->dataSource, ii); QObject *o = QmlMetaType::toQObject(v); @@ -292,11 +273,11 @@ void QFxRepeater::regenerate() lastItem = item; } } else if (QListModelInterface *model = qobject_cast(d->dataSource.value())) { - int cnt = model->count(); - if (cnt <= 0) + count = model->count(); + if (count <= 0) return; - for (int ii = 0; ii < cnt; ++ii) { + for (int ii = 0; ii < count; ++ii) { QmlContext *ctxt = new QmlContext(qmlContext(this), this); d->deletables << ctxt; @@ -322,13 +303,14 @@ void QFxRepeater::regenerate() d->deletables << ctxt; ctxt->setContextProperty(QLatin1String("index"), QVariant(0)); - for (int ii = 1; ii < object->metaObject()->propertyCount(); ++ii) { + count = object->metaObject()->propertyCount(); + for (int ii = 1; ii < count; ++ii) { const QMetaProperty &prop = object->metaObject()->property(ii); ctxt->setContextProperty(QLatin1String(prop.name()), prop.read(object)); } //for compatability with other lists, assign data if there is only a single role (excluding objectName) - if (object->metaObject()->propertyCount() == 2) { + if (count == 2) { const QMetaProperty &prop = object->metaObject()->property(1); ctxt->setContextProperty(QLatin1String("modelData"), prop.read(object)); } @@ -337,7 +319,7 @@ void QFxRepeater::regenerate() } else if (d->dataSource.canConvert(QVariant::Int)){ - int count = qvariant_cast(d->dataSource); + count = qvariant_cast(d->dataSource); for (int ii = 0; ii < count; ++ii) { QmlContext *ctxt = new QmlContext(qmlContext(this), this); @@ -349,5 +331,6 @@ void QFxRepeater::regenerate() lastItem = item; } } + d->count = count; } QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxrepeater.h b/src/declarative/fx/qfxrepeater.h index 3013b61..43afd63 100644 --- a/src/declarative/fx/qfxrepeater.h +++ b/src/declarative/fx/qfxrepeater.h @@ -55,19 +55,22 @@ class Q_DECLARATIVE_EXPORT QFxRepeater : public QFxItem { Q_OBJECT - Q_PROPERTY(QVariant dataSource READ dataSource WRITE setDataSource) //### model - Q_PROPERTY(QmlComponent *component READ component WRITE setComponent) //### delegate - Q_CLASSINFO("DefaultProperty", "component") - //### count + Q_PROPERTY(QVariant model READ model WRITE setModel) + Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate) + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_CLASSINFO("DefaultProperty", "delegate") + public: QFxRepeater(QFxItem *parent=0); virtual ~QFxRepeater(); - QVariant dataSource() const; - void setDataSource(const QVariant &); + QVariant model() const; + void setModel(const QVariant &); + + QmlComponent *delegate() const; + void setDelegate(QmlComponent *); - QmlComponent *component() const; - void setComponent(QmlComponent *); + int count() const; private: void regenerate(); diff --git a/src/declarative/fx/qfxrepeater_p.h b/src/declarative/fx/qfxrepeater_p.h index ba69658..65b0973 100644 --- a/src/declarative/fx/qfxrepeater_p.h +++ b/src/declarative/fx/qfxrepeater_p.h @@ -73,6 +73,7 @@ public: QVariant dataSource; QmlComponent *component; + int count; QList > deletables; }; -- cgit v0.12 From c8503d44bce2e038a5e2ba7597878dbcfcced4cb Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 27 Aug 2009 11:31:19 +1000 Subject: Rename Behavior cpp class to match the QML name. --- src/declarative/debugger/qpacketprotocol.cpp | 2 +- src/declarative/extra/extra.pri | 4 +- src/declarative/extra/qmlbehavior.cpp | 236 +++++++++++++++++++++++++++ src/declarative/extra/qmlbehavior.h | 91 +++++++++++ src/declarative/extra/qmlbehaviour.cpp | 236 --------------------------- src/declarative/extra/qmlbehaviour.h | 91 ----------- src/declarative/fx/qfxflickable.h | 2 +- src/declarative/fx/qfxtextinput.cpp | 14 ++ src/declarative/qml/qmlcompiler.cpp | 2 +- src/declarative/util/qmlanimation.cpp | 14 +- 10 files changed, 353 insertions(+), 339 deletions(-) create mode 100644 src/declarative/extra/qmlbehavior.cpp create mode 100644 src/declarative/extra/qmlbehavior.h delete mode 100644 src/declarative/extra/qmlbehaviour.cpp delete mode 100644 src/declarative/extra/qmlbehaviour.h diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp index 6bccf4b..84882dd 100644 --- a/src/declarative/debugger/qpacketprotocol.cpp +++ b/src/declarative/debugger/qpacketprotocol.cpp @@ -391,7 +391,7 @@ QIODevice * QPacketProtocol::device() Only packets returned from QPacketProtocol::read() may be read from. QPacket instances constructed by directly by applications are for transmission only and are considered "write only". Attempting to read data from them will - result in undefined behaviour. + result in undefined behavior. \ingroup io \sa QPacketProtocol diff --git a/src/declarative/extra/extra.pri b/src/declarative/extra/extra.pri index 1f84406..ae07a19 100644 --- a/src/declarative/extra/extra.pri +++ b/src/declarative/extra/extra.pri @@ -7,7 +7,7 @@ SOURCES += \ extra/qfxanimatedimageitem.cpp \ extra/qfxflowview.cpp \ extra/qfxparticles.cpp \ - extra/qmlbehaviour.cpp \ + extra/qmlbehavior.cpp \ extra/qbindablemap.cpp \ extra/qmlfontloader.cpp @@ -21,7 +21,7 @@ HEADERS += \ extra/qfxanimatedimageitem_p.h \ extra/qfxflowview.h \ extra/qfxparticles.h \ - extra/qmlbehaviour.h \ + extra/qmlbehavior.h \ extra/qbindablemap.h \ extra/qmlfontloader.h diff --git a/src/declarative/extra/qmlbehavior.cpp b/src/declarative/extra/qmlbehavior.cpp new file mode 100644 index 0000000..b40024e --- /dev/null +++ b/src/declarative/extra/qmlbehavior.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmlanimation.h" +#include "qmltransition.h" +#include "qmlbehavior.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Behavior,QmlBehavior) + +class QmlBehaviorData : public QObject +{ +Q_OBJECT +public: + QmlBehaviorData(QObject *parent) + : QObject(parent) {} + + Q_PROPERTY(QVariant endValue READ endValue NOTIFY valuesChanged) + Q_PROPERTY(QVariant startValue READ startValue NOTIFY valuesChanged) + QVariant endValue() const { return e; } + QVariant startValue() const { return s; } + + QVariant e; + QVariant s; + +Q_SIGNALS: + void valuesChanged(); + +private: + friend class QmlBehavior; +}; + +class QmlBehaviorPrivate : public QObjectPrivate +{ +public: + QmlBehaviorPrivate() : operations(this) {} + QmlMetaProperty property; + QVariant currentValue; + + QVariant fromValue; + QVariant toValue; + class AnimationList : public QmlConcreteList + { + public: + AnimationList(QmlBehaviorPrivate *parent) : _parent(parent) {} + virtual void append(QmlAbstractAnimation *a) + { + QmlConcreteList::append(a); + _parent->group->addAnimation(a->qtAnimation()); + if (_parent->property.isValid()) { + a->setTarget(_parent->property); + } + } + virtual void clear() { QmlConcreteList::clear(); } //### + private: + QmlBehaviorPrivate *_parent; + }; + AnimationList operations; + QParallelAnimationGroup *group; +}; + +/*! + \qmlclass Behavior QmlBehavior + \brief The Behavior element allows you to specify a default animation for a property change. + + In example below, the rect will use a bounce easing curve over 200 millisecond for any changes to its y property: + \code + Rectangle { + width: 20; height: 20 + color: "#00ff00" + y: 200 //initial value + y: Behavior { + NumberAnimation { + easing: "easeOutBounce(amplitude:100)" + duration: 200 + } + } + } + \endcode +*/ + +QmlBehavior::QmlBehavior(QObject *parent) +: QmlPropertyValueSource(*(new QmlBehaviorPrivate), parent) +{ + Q_D(QmlBehavior); + d->group = new QParallelAnimationGroup; + QFx_setParent_noEvent(d->group, this); +} + +/*! + \qmlproperty QVariant Behavior::from + This property holds a selector specifying a starting value for the behavior. + + If you only want the behavior to apply when the change starts at a + specific value you can specify fromValue. This selector is used in conjunction + with the to selector. +*/ + +QVariant QmlBehavior::fromValue() const +{ + Q_D(const QmlBehavior); + return d->fromValue; +} + +void QmlBehavior::setFromValue(const QVariant &v) +{ + Q_D(QmlBehavior); + d->fromValue = v; +} + +/*! + \qmlproperty QVariant Behavior::to + This property holds a selector specifying a ending value for the behavior. + + If you only want the behavior to apply when the change ends at a + specific value you can specify toValue. This selector is used in conjunction + with the from selector. +*/ + +QVariant QmlBehavior::toValue() const +{ + Q_D(const QmlBehavior); + return d->toValue; +} + +void QmlBehavior::setToValue(const QVariant &v) +{ + Q_D(QmlBehavior); + d->toValue = v; +} + +QmlList* QmlBehavior::operations() +{ + Q_D(QmlBehavior); + return &d->operations; +} + +QmlBehavior::~QmlBehavior() +{ + //### do we need any other cleanup here? +} + +bool QmlBehavior::_ignore = false; +void QmlBehavior::propertyValueChanged() +{ + Q_D(QmlBehavior); + if (_ignore) + return; + + QVariant newValue = d->property.read(); + + if ((!fromValue().isValid() || fromValue() == d->currentValue) && + (!toValue().isValid() || toValue() == newValue)) { + + //### does this clean up everything needed? + d->group->stop(); + + QmlStateOperation::ActionList actions; + Action action; + action.property = d->property; + action.fromValue = d->currentValue; + action.toValue = newValue; + actions << action; + + _ignore = true; + d->property.write(d->currentValue); + + QList after; + for (int ii = 0; ii < d->operations.count(); ++ii) { + d->operations.at(ii)->transition(actions, after, QmlAbstractAnimation::Forward); + } + d->group->start(); + if (!after.contains(d->property)) + d->property.write(newValue); + _ignore = false; + } + + d->currentValue = newValue; +} + +void QmlBehavior::setTarget(const QmlMetaProperty &property) +{ + Q_D(QmlBehavior); + d->property = property; + d->currentValue = property.read(); + d->property.connectNotifier(this, SLOT(propertyValueChanged())); + for (int ii = 0; ii < d->operations.count(); ++ii) { + d->operations.at(ii)->setTarget(property); + } +} + +QT_END_NAMESPACE + +#include "qmlbehavior.moc" diff --git a/src/declarative/extra/qmlbehavior.h b/src/declarative/extra/qmlbehavior.h new file mode 100644 index 0000000..1be00c9 --- /dev/null +++ b/src/declarative/extra/qmlbehavior.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBEHAVIOR_H +#define QMLBEHAVIOR_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlAbstractAnimation; +class QmlBehaviorPrivate; +class Q_DECLARATIVE_EXPORT QmlBehavior : public QmlPropertyValueSource +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlBehavior) + + Q_PROPERTY(QVariant from READ fromValue WRITE setFromValue) + Q_PROPERTY(QVariant to READ toValue WRITE setToValue) + Q_CLASSINFO("DefaultProperty", "operations") + Q_PROPERTY(QmlList* operations READ operations) + +public: + QmlBehavior(QObject *parent=0); + ~QmlBehavior(); + + QVariant fromValue() const; + void setFromValue(const QVariant &); + QVariant toValue() const; + void setToValue(const QVariant &); + virtual void setTarget(const QmlMetaProperty &); + + QmlList* operations(); + + static bool _ignore; + +private Q_SLOTS: + void propertyValueChanged(); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QmlBehavior) + +QT_END_HEADER + +#endif // QMLBEHAVIOR_H diff --git a/src/declarative/extra/qmlbehaviour.cpp b/src/declarative/extra/qmlbehaviour.cpp deleted file mode 100644 index 767f1ed..0000000 --- a/src/declarative/extra/qmlbehaviour.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include "qmlanimation.h" -#include "qmltransition.h" -#include "qmlbehaviour.h" -#include -#include - -QT_BEGIN_NAMESPACE - -QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Behavior,QmlBehaviour) - -class QmlBehaviourData : public QObject -{ -Q_OBJECT -public: - QmlBehaviourData(QObject *parent) - : QObject(parent) {} - - Q_PROPERTY(QVariant endValue READ endValue NOTIFY valuesChanged) - Q_PROPERTY(QVariant startValue READ startValue NOTIFY valuesChanged) - QVariant endValue() const { return e; } - QVariant startValue() const { return s; } - - QVariant e; - QVariant s; - -Q_SIGNALS: - void valuesChanged(); - -private: - friend class QmlBehaviour; -}; - -class QmlBehaviourPrivate : public QObjectPrivate -{ -public: - QmlBehaviourPrivate() : operations(this) {} - QmlMetaProperty property; - QVariant currentValue; - - QVariant fromValue; - QVariant toValue; - class AnimationList : public QmlConcreteList - { - public: - AnimationList(QmlBehaviourPrivate *parent) : _parent(parent) {} - virtual void append(QmlAbstractAnimation *a) - { - QmlConcreteList::append(a); - _parent->group->addAnimation(a->qtAnimation()); - if (_parent->property.isValid()) { - a->setTarget(_parent->property); - } - } - virtual void clear() { QmlConcreteList::clear(); } //### - private: - QmlBehaviourPrivate *_parent; - }; - AnimationList operations; - QParallelAnimationGroup *group; -}; - -/*! - \qmlclass Behavior QmlBehaviour - \brief The Behavior element allows you to specify a default animation for a property change. - - In example below, the rect will use a bounce easing curve over 200 millisecond for any changes to its y property: - \code - Rectangle { - width: 20; height: 20 - color: "#00ff00" - y: 200 //initial value - y: Behavior { - NumberAnimation { - easing: "easeOutBounce(amplitude:100)" - duration: 200 - } - } - } - \endcode -*/ - -QmlBehaviour::QmlBehaviour(QObject *parent) -: QmlPropertyValueSource(*(new QmlBehaviourPrivate), parent) -{ - Q_D(QmlBehaviour); - d->group = new QParallelAnimationGroup; - QFx_setParent_noEvent(d->group, this); -} - -/*! - \qmlproperty QVariant Behavior::fromValue - This property holds a selector specifying a starting value for the behavior - - If you only want the behavior to apply when the change starts at a - specific value you can specify fromValue. This selector is used in conjunction - with the toValue selector. -*/ - -QVariant QmlBehaviour::fromValue() const -{ - Q_D(const QmlBehaviour); - return d->fromValue; -} - -void QmlBehaviour::setFromValue(const QVariant &v) -{ - Q_D(QmlBehaviour); - d->fromValue = v; -} - -/*! - \qmlproperty QVariant Behavior::toValue - This property holds a selector specifying a ending value for the behavior - - If you only want the behavior to apply when the change ends at a - specific value you can specify toValue. This selector is used in conjunction - with the fromValue selector. -*/ - -QVariant QmlBehaviour::toValue() const -{ - Q_D(const QmlBehaviour); - return d->toValue; -} - -void QmlBehaviour::setToValue(const QVariant &v) -{ - Q_D(QmlBehaviour); - d->toValue = v; -} - -QmlList* QmlBehaviour::operations() -{ - Q_D(QmlBehaviour); - return &d->operations; -} - -QmlBehaviour::~QmlBehaviour() -{ - //### do we need any other cleanup here? -} - -bool QmlBehaviour::_ignore = false; -void QmlBehaviour::propertyValueChanged() -{ - Q_D(QmlBehaviour); - if (_ignore) - return; - - QVariant newValue = d->property.read(); - - if ((!fromValue().isValid() || fromValue() == d->currentValue) && - (!toValue().isValid() || toValue() == newValue)) { - - //### does this clean up everything needed? - d->group->stop(); - - QmlStateOperation::ActionList actions; - Action action; - action.property = d->property; - action.fromValue = d->currentValue; - action.toValue = newValue; - actions << action; - - _ignore = true; - d->property.write(d->currentValue); - - QList after; - for (int ii = 0; ii < d->operations.count(); ++ii) { - d->operations.at(ii)->transition(actions, after, QmlAbstractAnimation::Forward); - } - d->group->start(); - if (!after.contains(d->property)) - d->property.write(newValue); - _ignore = false; - } - - d->currentValue = newValue; -} - -void QmlBehaviour::setTarget(const QmlMetaProperty &property) -{ - Q_D(QmlBehaviour); - d->property = property; - d->currentValue = property.read(); - d->property.connectNotifier(this, SLOT(propertyValueChanged())); - for (int ii = 0; ii < d->operations.count(); ++ii) { - d->operations.at(ii)->setTarget(property); - } -} - -QT_END_NAMESPACE - -#include "qmlbehaviour.moc" diff --git a/src/declarative/extra/qmlbehaviour.h b/src/declarative/extra/qmlbehaviour.h deleted file mode 100644 index 99fc779..0000000 --- a/src/declarative/extra/qmlbehaviour.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLBEHAVIOUR_H -#define QMLBEHAVIOUR_H - -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QmlAbstractAnimation; -class QmlBehaviourPrivate; -class Q_DECLARATIVE_EXPORT QmlBehaviour : public QmlPropertyValueSource -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QmlBehaviour) - - Q_PROPERTY(QVariant from READ fromValue WRITE setFromValue) - Q_PROPERTY(QVariant to READ toValue WRITE setToValue) - Q_CLASSINFO("DefaultProperty", "operations") - Q_PROPERTY(QmlList* operations READ operations) - -public: - QmlBehaviour(QObject *parent=0); - ~QmlBehaviour(); - - QVariant fromValue() const; - void setFromValue(const QVariant &); - QVariant toValue() const; - void setToValue(const QVariant &); - virtual void setTarget(const QmlMetaProperty &); - - QmlList* operations(); - - static bool _ignore; - -private Q_SLOTS: - void propertyValueChanged(); -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QmlBehaviour) - -QT_END_HEADER - -#endif // QMLBEHAVIOUR_H diff --git a/src/declarative/fx/qfxflickable.h b/src/declarative/fx/qfxflickable.h index e13fa9b..13d793f 100644 --- a/src/declarative/fx/qfxflickable.h +++ b/src/declarative/fx/qfxflickable.h @@ -70,7 +70,7 @@ class Q_DECLARATIVE_EXPORT QFxFlickable : public QFxItem Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged) Q_PROPERTY(bool locked READ isLocked WRITE setLocked) //### interactive, ensure flicking is stopped, etc. - Q_PROPERTY(DragMode dragMode READ dragMode WRITE setDragMode) //### remove. Consider a better way to implement different drag behaviour + Q_PROPERTY(DragMode dragMode READ dragMode WRITE setDragMode) //### remove. Consider a better way to implement different drag behavior Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged) Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY isAtBoundaryChanged) diff --git a/src/declarative/fx/qfxtextinput.cpp b/src/declarative/fx/qfxtextinput.cpp index b9b33ab..f491d34 100644 --- a/src/declarative/fx/qfxtextinput.cpp +++ b/src/declarative/fx/qfxtextinput.cpp @@ -320,6 +320,20 @@ void QFxTextInput::setSelectionEnd(int s) d->control->setSelection(d->lastSelectionStart, s - d->lastSelectionStart); } +/*! + \qmlproperty string TextInput::selectedText + + This read-only property provides the text currently selected in the + text input. + + It is equivalent to the following snippet, but is faster and easier + to use. + + \qmlcode + myTextInput.text.toString().substring(myTextInput.selectionStart, + myTextInput.selectionEnd); + \endcode +*/ QString QFxTextInput::selectedText() const { Q_D(const QFxTextInput); diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 4f96d12..b5edc38 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -1231,7 +1231,7 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { - // The magic "id" behaviour doesn't apply when "id" is resolved as a + // The magic "id" behavior doesn't apply when "id" is resolved as a // default property or to sub-objects (which are always in binding // sub-contexts) COMPILE_CHECK(buildIdProperty(prop, obj)); diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 89b5660..cbf4114 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -47,7 +47,7 @@ #include "qml.h" #include "qmlinfo.h" #include "qmlanimation_p.h" -#include "qmlbehaviour.h" +#include "qmlbehavior.h" #include #include #include @@ -330,7 +330,7 @@ void QmlAbstractAnimation::componentComplete() calling the \c stop() method. The \c complete() method is not effected by this value. - This behaviour is most useful when the \c repeat property is set, as the + This behavior is most useful when the \c repeat property is set, as the animation will finish playing normally but not restart. By default, the alwaysRunToEnd property is not set. @@ -1007,9 +1007,9 @@ void QmlPropertyAction::transition(QmlStateActions &actions, { for (int ii = 0; ii < actions.count(); ++ii) { const Action &action = actions.at(ii); - QmlBehaviour::_ignore = true; + QmlBehavior::_ignore = true; action.property.write(action.toValue); - QmlBehaviour::_ignore = false; + QmlBehavior::_ignore = false; } } }; @@ -1338,7 +1338,7 @@ void QmlSequentialAnimation::transition(QmlStateActions &actions, inc = -1; from = d->animations.count() - 1; } - + //needed for Behavior if (d->userProperty.isValid() && d->propertyName.isEmpty() && !target()) { for (int i = 0; i < d->animations.count(); ++i) @@ -1760,7 +1760,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, for (int ii = 0; ii < actions.count(); ++ii) { Action &action = actions[ii]; - QmlBehaviour::_ignore = true; + QmlBehavior::_ignore = true; if (v == 1.) action.property.write(action.toValue); else { @@ -1779,7 +1779,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (interpolator) action.property.write(interpolator(action.fromValue.constData(), action.toValue.constData(), v)); } - QmlBehaviour::_ignore = false; + QmlBehavior::_ignore = false; } } }; -- cgit v0.12 From 682bf305a82d748b97c5ee189c7d1033b84c0dc1 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 27 Aug 2009 12:58:50 +1000 Subject: Doc fixes --- doc/src/declarative/binding.qdoc | 2 +- src/declarative/util/qmlstate.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/declarative/binding.qdoc b/doc/src/declarative/binding.qdoc index dfddf75..7e8933f 100644 --- a/doc/src/declarative/binding.qdoc +++ b/doc/src/declarative/binding.qdoc @@ -34,7 +34,7 @@ Data can be bound to C++ objects - see \l {QML/C++ Data Binding}. \target qtbinding \title QML/C++ Data Binding -The QML mechanisms of \l {Data Binding} can also be used to bind Qt C++ objects. +The QML mechanisms of data binding can also be used to bind Qt C++ objects. The data binding framework is based on Qt's property system (see the Qt documentation for more details on this system). If a binding is meant to be dynamic (where changes in one object are reflected in another object), \c NOTIFY must be specified for the property being tracked. If \c NOTIFY is not specified, any binding to that property will be an 'intialization' binding (the tracking object will be updated only once with the initial value of the tracked object). diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index a17d16e..508ef43 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -208,7 +208,7 @@ void QmlState::setWhen(QmlBinding *when) } /*! - \qmlproperty string State::extends + \qmlproperty string State::extend This property holds the state that this state extends The state being extended is treated as the base state in regards to -- cgit v0.12 From 8edaa5f5d1d7b78007e07e65987e26bd843970e8 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 27 Aug 2009 13:11:38 +1000 Subject: Support using a QAbstractItemModel with Repeater. --- src/declarative/fx/qfxrepeater.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/declarative/fx/qfxrepeater.cpp b/src/declarative/fx/qfxrepeater.cpp index fa44f8f..67d4d69 100644 --- a/src/declarative/fx/qfxrepeater.cpp +++ b/src/declarative/fx/qfxrepeater.cpp @@ -157,10 +157,13 @@ QFxRepeater::~QFxRepeater() As a special case the model can also be merely a number. In this case it will create that many instances of the component. They will also be assigned an index based on the order they are created. + + Models can also be created directly in QML, using a \l{ListModel} or \l{XmlListModel}. */ QVariant QFxRepeater::model() const { - return QVariant(); + Q_D(const QFxRepeater); + return d->dataSource; } void QFxRepeater::setModel(const QVariant &v) @@ -296,6 +299,38 @@ void QFxRepeater::regenerate() if (QFxItem *item = d->addItem(ctxt, lastItem)) lastItem = item; } + } else if (QAbstractItemModel *model = qobject_cast(d->dataSource.value())) { + count = model->rowCount(); + if (count <= 0) + return; + + for (int ii = 0; ii < count; ++ii) { + QmlContext *ctxt = new QmlContext(qmlContext(this), this); + d->deletables << ctxt; + + ctxt->setContextProperty(QLatin1String("index"), ii); + + QList roles; + QStringList roleNames; + QHash data; + for (QHash::const_iterator it = model->roleNames().begin(); + it != model->roleNames().end(); ++it) { + roles.append(it.key()); + roleNames.append(QLatin1String(*it)); + } + + QModelIndex index = model->index(ii, 0); + for (int j = 0; j < roles.size(); ++j) { + ctxt->setContextProperty(roleNames.at(j), model->data(index, roles.at(j))); + } + + //for compatability with other lists, assign data if there is only a single role + if (roles.size() == 1) + ctxt->setContextProperty(QLatin1String("modelData"), data.value(roles.at(0))); + + if (QFxItem *item = d->addItem(ctxt, lastItem)) + lastItem = item; + } } else if (QObject *object = d->dataSource.value()) { // A single object (i.e. list of size 1). // Properties are the roles (excluding objectName). -- cgit v0.12 From 928e81b68e0b695662c7ee3dd0bfa409a7ca1ffd Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 26 Aug 2009 21:48:18 +1000 Subject: Implement Focus Scope support in GraphicsView Focus Scopes are an additional focus paradigm, designed to be more suitable for use by declarative UI. With focus scopes, graphics view continues to have a single focused item - this is the single item to which key events are *actually* delivered. To simplify the description that follows, we will say that this element has "global focus". Focus scopes partitions focus into a heirarchy. Each focus scope may have one sub-focused item, which may itself be another focus scope. The sub-focused item is said to be have "scope focus" or its ancestor focus scope. Consequently, any given QGraphicsItem may be globally focused, scope focused (which means it is focused within its ancestor focus scope) or both. A focus scope corresponds to a QGraphicsItem with the ItemIsFocusScope flag set. As graphics view doesn't have a single root item, a "virtual" focus scope is modeled as being the ancestor of all the root items. With focus scopes, when QGraphicsItem::setFocus() is called, the item's ancestors are searched until a focus scope is found (remembering the "virtual" root focus scope is used if there is no *actual* ancestor scope). The item is set as the sub-focused item of the focus scope (becoming focus scoped) and any existing sub-focused item of that focus scope has scope focus removed from it. The item that receives global focus is found by beginning at the "virtual" root focus scope and recursively decending into each item that is scope focused until a leaf (non-focus scope) item is reached. The implementation takes shortcuts here to be slightly more optimal, but the end result should be the same as though this abstract algorithm was evaluated each time. Two manual examples of focus scope are found under examples/declarative/focusscope --- examples/declarative/focusscope/test.qml | 76 +++++++++++++++ examples/declarative/focusscope/test2.qml | 40 ++++++++ src/declarative/fx/qfxcomponentinstance.cpp | 2 - src/declarative/fx/qfxfocusscope.cpp | 2 +- src/declarative/fx/qfxgridview.cpp | 2 +- src/declarative/fx/qfxitem.cpp | 56 ++++------- src/declarative/fx/qfxitem_p.h | 3 + src/declarative/fx/qfxlistview.cpp | 2 +- src/declarative/fx/qfxpathview_p.h | 2 +- src/gui/graphicsview/qgraphicsitem.cpp | 79 ++++++++------- src/gui/graphicsview/qgraphicsitem.h | 4 +- src/gui/graphicsview/qgraphicsitem_p.h | 40 +++++++- src/gui/graphicsview/qgraphicsscene.cpp | 129 +++++++++++++++---------- src/gui/graphicsview/qgraphicsscene_p.h | 2 + tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 71 -------------- 15 files changed, 306 insertions(+), 204 deletions(-) create mode 100644 examples/declarative/focusscope/test.qml create mode 100644 examples/declarative/focusscope/test2.qml diff --git a/examples/declarative/focusscope/test.qml b/examples/declarative/focusscope/test.qml new file mode 100644 index 0000000..22ffc8d --- /dev/null +++ b/examples/declarative/focusscope/test.qml @@ -0,0 +1,76 @@ +import Qt 4.6 + +Rectangle { + color: "white" + width: 800 + height: 600 + + Keys.onDigit9Pressed: print("Error - Root") + + FocusScope { + id: MyScope + focus: true + + Keys.onDigit9Pressed: print("Error - FocusScope") + + Rectangle { + height: 120 + width: 420 + + color: "transparent" + border.width: 5 + border.color: MyScope.focus?"blue":"black" + + Rectangle { + id: Item1 + x: 10; y: 10 + width: 100; height: 100; color: "green" + border.width: 5 + border.color: focus?"blue":"black" + Keys.onDigit9Pressed: print("Top Left"); + KeyNavigation.right: Item2 + focus: true + + Rectangle { + width: 50; height: 50; anchors.centerIn: parent + color: parent.activeFocus?"red":"transparent" + } + } + + Rectangle { + id: Item2 + x: 310; y: 10 + width: 100; height: 100; color: "green" + border.width: 5 + border.color: focus?"blue":"black" + KeyNavigation.left: Item1 + Keys.onDigit9Pressed: print("Top Right"); + + Rectangle { + width: 50; height: 50; anchors.centerIn: parent + color: parent.activeFocus?"red":"transparent" + } + } + } + KeyNavigation.down: Item3 + } + + Text { x:100; y:170; text: "Blue border indicates scoped focus\nBlack border indicates NOT scoped focus\nRed box indicates active focus\nUse arrow keys to navigate\nPress \"9\" to print currently focused item" } + + Rectangle { + id: Item3 + x: 10; y: 300 + width: 100; height: 100; color: "green" + border.width: 5 + border.color: focus?"blue":"black" + + Keys.onDigit9Pressed: print("Bottom Left"); + KeyNavigation.up: MyScope + + Rectangle { + width: 50; height: 50; anchors.centerIn: parent + color: parent.activeFocus?"red":"transparent" + } + } + +} diff --git a/examples/declarative/focusscope/test2.qml b/examples/declarative/focusscope/test2.qml new file mode 100644 index 0000000..0ac0f5d --- /dev/null +++ b/examples/declarative/focusscope/test2.qml @@ -0,0 +1,40 @@ +import Qt 4.6 + +Rectangle { + color: "white" + width: 800 + height: 600 + + Text { text: "All five rectangles should be red" } + + FocusScope { + y: 100 + focus: true + Rectangle { width: 50; height: 50; color: parent.focus?"red":"blue" } + + FocusScope { + y: 100 + focus: true + Rectangle { width: 50; height: 50; color: parent.focus?"red":"blue" } + + FocusScope { + y: 100 + focus: true + Rectangle { width: 50; height: 50; color: parent.focus?"red":"blue" } + + FocusScope { + y: 100 + focus: true + Rectangle { width: 50; height: 50; color: parent.focus?"red":"blue" } + + FocusScope { + y: 100 + focus: true + Rectangle { width: 50; height: 50; color: parent.focus?"red":"blue" } + } + } + } + } + } + +} diff --git a/src/declarative/fx/qfxcomponentinstance.cpp b/src/declarative/fx/qfxcomponentinstance.cpp index def7a9f..7a712aa 100644 --- a/src/declarative/fx/qfxcomponentinstance.cpp +++ b/src/declarative/fx/qfxcomponentinstance.cpp @@ -73,13 +73,11 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,ComponentInstance,QFxComponentIn QFxComponentInstance::QFxComponentInstance(QFxItem *parent) : QFxItem(*(new QFxComponentInstancePrivate), parent) { - setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); } QFxComponentInstance::QFxComponentInstance(QFxComponentInstancePrivate &dd, QFxItem *parent) : QFxItem(dd, parent) { - setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); } /*! diff --git a/src/declarative/fx/qfxfocusscope.cpp b/src/declarative/fx/qfxfocusscope.cpp index 8981256..9bcc17e 100644 --- a/src/declarative/fx/qfxfocusscope.cpp +++ b/src/declarative/fx/qfxfocusscope.cpp @@ -63,7 +63,7 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,FocusScope,QFxFocusScope) QFxFocusScope::QFxFocusScope(QFxItem *parent) : QFxItem(parent) { - setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); + setFlag(QGraphicsItem::ItemIsFocusScope); } QFxFocusScope::~QFxFocusScope() diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp index e2c7fa3..b429895 100644 --- a/src/declarative/fx/qfxgridview.cpp +++ b/src/declarative/fx/qfxgridview.cpp @@ -325,7 +325,7 @@ public: void QFxGridViewPrivate::init() { Q_Q(QFxGridView); - q->setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); + q->setFlag(QGraphicsItem::ItemIsFocusScope); QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(sizeChange())); QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(sizeChange())); } diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index a8be81f..9b9355e 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -2363,7 +2363,14 @@ QPointF QFxItemPrivate::computeTransformOrigin() const */ bool QFxItem::sceneEvent(QEvent *event) { - return QGraphicsItem::sceneEvent(event); + bool rv = QGraphicsItem::sceneEvent(event); + + if (event->type() == QEvent::FocusIn || + event->type() == QEvent::FocusOut) { + activeFocusChanged(hasActiveFocus()); + } + + return rv; } /*! @@ -2548,49 +2555,20 @@ bool QFxItem::heightValid() const bool QFxItem::hasFocus() const { - const QGraphicsItem *current = this->parentItem(); - while (current && !(current->flags() & ItemAutoDetectsFocusProxy)) - current = current->parentItem(); - - if (current) - return current->focusProxy() == this; - else - return QGraphicsItem::hasFocus(); + Q_D(const QFxItem); + return d->itemIsFocusedInScope; } void QFxItem::setFocus(bool focus) { - QGraphicsScene *s = scene(); - if (!s) { - if (focus) QGraphicsItem::setFocus(Qt::OtherFocusReason); - else QGraphicsItem::clearFocus(); - focusChanged(focus); - return; - } - - QGraphicsItem *current = this->parentItem(); - while (current && !(current->flags() & ItemAutoDetectsFocusProxy)) - current = current->parentItem(); - - if (!current) { - if (focus) QGraphicsItem::setFocus(Qt::OtherFocusReason); - else QGraphicsItem::clearFocus(); - focusChanged(focus); - return; - } - - if (current->focusProxy() && current->focusProxy() != this) { - QFxItem *currentItem = qobject_cast(current->focusProxy()); - if (currentItem) - currentItem->setFocus(false); - } - - if (current->focusProxy() == this && !focus) - current->setFocusProxy(0); - else if (focus) - current->setFocusProxy(this); + if (focus) QGraphicsItem::setFocus(Qt::OtherFocusReason); + else QGraphicsItem::clearFocus(); +} - focusChanged(focus); +void QFxItemPrivate::focusedInScopeChanged() +{ + Q_Q(QFxItem); + q->focusChanged(q->hasFocus()); } /*! diff --git a/src/declarative/fx/qfxitem_p.h b/src/declarative/fx/qfxitem_p.h index d30e324..054bdc7 100644 --- a/src/declarative/fx/qfxitem_p.h +++ b/src/declarative/fx/qfxitem_p.h @@ -223,6 +223,9 @@ public: QGraphicsItemPrivate::setPosHelper(pos); q->geometryChanged(QRectF(this->pos.x(), this->pos.y(), width, height), oldGeometry); } + + // Inherited from QGraphcisItemPrivate + virtual void focusedInScopeChanged(); }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 048cb0f..9498854 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -396,7 +396,7 @@ public: void QFxListViewPrivate::init() { Q_Q(QFxListView); - q->setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); + q->setFlag(QGraphicsItem::ItemIsFocusScope); QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(refill())); QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(refill())); } diff --git a/src/declarative/fx/qfxpathview_p.h b/src/declarative/fx/qfxpathview_p.h index a69f75f..60bfdb3 100644 --- a/src/declarative/fx/qfxpathview_p.h +++ b/src/declarative/fx/qfxpathview_p.h @@ -87,7 +87,7 @@ public: Q_Q(QFxPathView); _offset = 0; q->setAcceptedMouseButtons(Qt::LeftButton); - q->setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); + q->setFlag(QGraphicsItem::ItemIsFocusScope); q->setFiltersChildEvents(true); q->connect(&tl, SIGNAL(updated()), q, SLOT(ticked())); } diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 620f6f4..ead5aee 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -331,10 +331,6 @@ \value ItemNegativeZStacksBehindParent The item automatically stacks behind it's parent if it's z-value is negative. This flag enables setZValue() to toggle ItemStacksBehindParent. - - \value ItemAutoDetectsFocusProxy The item will assign any child that - gains input focus as its focus proxy. See also focusProxy(). - This flag was introduced in Qt 4.6. */ /*! @@ -944,17 +940,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) parent->itemChange(QGraphicsItem::ItemChildRemovedChange, thisPointerVariant); } - // Auto-update focus proxy. Any ancestor that has this as focus proxy - //needs to be nulled. - QGraphicsItem *p = parent; - while (p) { - if ((p->d_ptr->flags & QGraphicsItem::ItemAutoDetectsFocusProxy) && - (p->focusProxy() == q)) { - p->setFocusProxy(0); - } - p = p->d_ptr->parent; - } - // Update toplevelitem list. If this item is being deleted, its parent // will be 0 but we don't want to register/unregister it in the TLI list. if (scene && !inDestructor) { @@ -969,7 +954,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) bool implicitUpdate = false; if (parent->d_func()->scene && parent->d_func()->scene != scene) { // Move this item to its new parent's scene - parent->d_func()->scene->addItem(q); + + QGraphicsItem *focusScope = newParent; + while (focusScope && !(focusScope->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)) + focusScope = focusScope->d_ptr->parent; + parent->d_func()->scene->d_func()->addItem(q, focusScope); implicitUpdate = true; } else if (!parent->d_func()->scene && scene) { // Remove this item from its former scene @@ -1031,17 +1020,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) if (lastSubFocusItem) lastSubFocusItem->d_ptr->setSubFocus(); - // Auto-update focus proxy. The closest parent that detects - // focus proxies is updated as the proxy gains or loses focus. - p = newParent; - while (p) { - if (p->d_ptr->flags & QGraphicsItem::ItemAutoDetectsFocusProxy) { - p->setFocusProxy(q); - break; - } - p = p->d_ptr->parent; - } - // Deliver post-change notification q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant); @@ -2663,11 +2641,27 @@ void QGraphicsItem::setFocus(Qt::FocusReason focusReason) // Update the scene's focus item. if (d_ptr->scene) { + QGraphicsItem *s = d_ptr->focusScope(); + if (s) { + bool scopeHasFocus = + s->d_ptr->hasActiveFocus(d_ptr->scene->focusItem()); + if (s->d_ptr->focusScopeItem) + s->d_ptr->focusScopeItem->d_ptr->setItemFocusedInScope(false); + s->d_ptr->focusScopeItem = this; + d_ptr->setItemFocusedInScope(true); + if (scopeHasFocus) + d_ptr->scene->d_func()->setFocusItemHelper(s, focusReason); + return; + } + d_ptr->setItemFocusedInScope(false); + QGraphicsWidget *w = window(); if (!w || w->isActiveWindow()) { // Visible items immediately gain focus from scene. d_ptr->scene->d_func()->setFocusItemHelper(f, focusReason); } + } else { + d_ptr->setItemFocusedInScope(true); } } @@ -2684,12 +2678,31 @@ void QGraphicsItem::setFocus(Qt::FocusReason focusReason) */ void QGraphicsItem::clearFocus() { - if (!d_ptr->scene) + if (!d_ptr->scene) { + d_ptr->setItemFocusedInScope(false); return; + } // Invisible items with focus must explicitly clear subfocus. d_ptr->clearSubFocus(); + + if (d_ptr->itemIsFocusedInScope) { + d_ptr->setItemFocusedInScope(false); + QGraphicsItem *s = d_ptr->focusScope(); + if (s) { + if (s->d_ptr->focusScopeItem == this) { + bool scopeHasFocus = + s->d_ptr->hasActiveFocus(d_ptr->scene->focusItem()); + s->d_ptr->focusScopeItem = 0; + if (scopeHasFocus) + d_ptr->scene->setFocusItem(s); + return; + } + } + } + if (hasFocus()) { // If this item has the scene's input focus, clear it. + d_ptr->setItemFocusedInScope(false); d_ptr->scene->setFocusItem(0); } } @@ -2700,7 +2713,7 @@ void QGraphicsItem::clearFocus() Returns this item's focus proxy, or 0 if this item has no focus proxy. - \sa setFocusProxy(), ItemAutoDetectsFocusProxy, setFocus(), hasFocus() + \sa setFocusProxy(), setFocus(), hasFocus() */ QGraphicsItem *QGraphicsItem::focusProxy() const { @@ -2724,7 +2737,7 @@ QGraphicsItem *QGraphicsItem::focusProxy() const The focus proxy \a item must belong to the same scene as this item. - \sa focusProxy(), ItemAutoDetectsFocusProxy, setFocus(), hasFocus() + \sa focusProxy(), setFocus(), hasFocus() */ void QGraphicsItem::setFocusProxy(QGraphicsItem *item) { @@ -4770,7 +4783,7 @@ void QGraphicsItemPrivate::setSubFocus() bool hidden = !visible; do { parent->d_func()->subFocusItem = item; - } while (!parent->isWindow() && (parent = parent->d_ptr->parent) && (!hidden || !parent->d_func()->visible)); + } while (!parent->isWindow() && (parent = parent->d_ptr->parent) && (!hidden || !parent->d_func()->visible) && !(parent->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)); } /*! @@ -10437,8 +10450,8 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemNegativeZStacksBehindParent: str = "ItemNegativeZStacksBehindParent"; break; - case QGraphicsItem::ItemAutoDetectsFocusProxy: - str = "ItemAutoDetectsFocusProxy"; + case QGraphicsItem::ItemIsFocusScope: + str = "ItemIsFocusScope"; break; } debug << str; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 7af7c2f..b76f5ac 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -103,8 +103,8 @@ public: ItemHasNoContents = 0x400, ItemSendsGeometryChanges = 0x800, ItemAcceptsInputMethod = 0x1000, - ItemAutoDetectsFocusProxy = 0x2000, - ItemNegativeZStacksBehindParent = 0x4000 + ItemNegativeZStacksBehindParent = 0x4000, + ItemIsFocusScope = 0x8000 // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 11f6f53..7abd7f5 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -97,6 +97,8 @@ public: void purge(); }; +#include + class Q_GUI_EXPORT QGraphicsItemPrivate { Q_DECLARE_PUBLIC(QGraphicsItem) @@ -128,6 +130,7 @@ public: siblingIndex(-1), itemDepth(-1), focusProxy(0), + focusScopeItem(0), subFocusItem(0), imHints(Qt::ImhNone), acceptedMouseButtons(0x1f), @@ -171,6 +174,7 @@ public: notifyBoundingRectChanged(0), notifyInvalidated(0), mouseSetsFocus(1), + itemIsFocusedInScope(0), globalStackingOrder(-1), q_ptr(0) { @@ -410,6 +414,38 @@ public: void clearSubFocus(); void resetFocusProxy(); + inline QGraphicsItem *rootLevelFocusItem() const { + QGraphicsItem *fi = q_ptr; + while(QGraphicsItem *i = fi->d_ptr->focusScope()) + fi = i; + return fi; + } + + inline QGraphicsItem *focusScope() const { + QGraphicsItem *item = parent; + while (item) { + if (item->isWindow()) + return 0; + if (item->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) + return item; + item = item->d_ptr->parent; + } + return 0; + } + inline bool hasActiveFocus(QGraphicsItem *focusItem) const { + if (!(flags & QGraphicsItem::ItemIsFocusScope) || !focusScopeItem) + return focusItem == q_ptr; + else + return focusScopeItem->d_ptr->hasActiveFocus(focusItem); + } + inline void setItemFocusedInScope(bool f) { + if (itemIsFocusedInScope != f) { + itemIsFocusedInScope = f; + if (!inDestructor) focusedInScopeChanged(); + } + } + inline virtual void focusedInScopeChanged() {} + inline QTransform transformToParent() const; inline void ensureSortedChildren(); @@ -431,6 +467,7 @@ public: int siblingIndex; int itemDepth; // Lazily calculated when calling depth(). QGraphicsItem *focusProxy; + QGraphicsItem *focusScopeItem; // Only used if this is a focus scope QList focusProxyRefs; QGraphicsItem *subFocusItem; Qt::InputMethodHints imHints; @@ -463,7 +500,7 @@ public: // New 32 bits quint32 fullUpdatePending : 1; - quint32 flags : 15; + quint32 flags : 16; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; @@ -479,6 +516,7 @@ public: quint32 notifyBoundingRectChanged : 1; quint32 notifyInvalidated : 1; quint32 mouseSetsFocus : 1; + quint32 itemIsFocusedInScope : 1; quint32 unused : 1; // feel free to use // Optional stacking order diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a819822..73dba7b 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -572,6 +572,10 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, Qt::FocusReason focusReason) { Q_Q(QGraphicsScene); + + while (item && item->d_ptr->focusScopeItem) + item = item->d_ptr->focusScopeItem; + if (item == focusItem) return; @@ -589,22 +593,18 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, return; } - // Auto-update focus proxy. The closest parent that detects - // focus proxies is updated as the proxy gains or loses focus. - if (item) { - QGraphicsItem *p = item->d_ptr->parent; - while (p) { - if (p->d_ptr->flags & QGraphicsItem::ItemAutoDetectsFocusProxy) { - p->setFocusProxy(item); - break; - } - p = p->d_ptr->parent; - } - } + QGraphicsItem *itemRootLevelFocusItem = + item?item->d_ptr->rootLevelFocusItem():0; if (focusItem) { QFocusEvent event(QEvent::FocusOut, focusReason); lastFocusItem = focusItem; + + QGraphicsItem *oldRootLevelFocusItem = + focusItem->d_ptr->rootLevelFocusItem(); + if (oldRootLevelFocusItem != itemRootLevelFocusItem) + oldRootLevelFocusItem->d_ptr->setItemFocusedInScope(false); + focusItem = 0; sendEvent(lastFocusItem, &event); @@ -622,6 +622,8 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, if (item) { focusItem = item; + itemRootLevelFocusItem->d_ptr->setItemFocusedInScope(true); + item->d_ptr->setItemFocusedInScope(true); QFocusEvent event(QEvent::FocusIn, focusReason); sendEvent(item, &event); } @@ -2240,11 +2242,19 @@ void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group) void QGraphicsScene::addItem(QGraphicsItem *item) { Q_D(QGraphicsScene); + d->addItem(item); +} + +void QGraphicsScenePrivate::addItem(QGraphicsItem *item, + QGraphicsItem *focusScope) +{ + Q_Q(QGraphicsScene); + if (!item) { qWarning("QGraphicsScene::addItem: cannot add null item"); return; } - if (item->scene() == this) { + if (item->scene() == q) { qWarning("QGraphicsScene::addItem: item has already been added to this scene"); return; } @@ -2255,9 +2265,9 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // Notify the item that its scene is changing, and allow the item to // react. const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue(this))); + qVariantFromValue(q))); QGraphicsScene *targetScene = qVariantValue(newSceneVariant); - if (targetScene != this) { + if (targetScene != q) { if (targetScene && item->scene() != targetScene) targetScene->addItem(item); return; @@ -2266,7 +2276,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // Detach this item from its parent if the parent's scene is different // from this scene. if (QGraphicsItem *itemParent = item->parentItem()) { - if (itemParent->scene() != this) + if (itemParent->scene() != q) item->setParentItem(0); } @@ -2274,98 +2284,113 @@ void QGraphicsScene::addItem(QGraphicsItem *item) item->d_func()->scene = targetScene; // Add the item in the index - d->index->addItem(item); + index->addItem(item); // Add to list of toplevels if this item is a toplevel. if (!item->d_ptr->parent) - d->registerTopLevelItem(item); + registerTopLevelItem(item); // Add to list of items that require an update. We cannot assume that the // item is fully constructed, so calling item->update() can lead to a pure // virtual function call to boundingRect(). - d->markDirty(item); - d->dirtyGrowingItemsBoundingRect = true; + markDirty(item); + dirtyGrowingItemsBoundingRect = true; // Disable selectionChanged() for individual items - ++d->selectionChanging; - int oldSelectedItemSize = d->selectedItems.size(); + ++selectionChanging; + int oldSelectedItemSize = selectedItems.size(); // Enable mouse tracking if the item accepts hover events or has a cursor set. - if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) { - d->allItemsIgnoreHoverEvents = false; - d->enableMouseTrackingOnViews(); + if (allItemsIgnoreHoverEvents && itemAcceptsHoverEvents_helper(item)) { + allItemsIgnoreHoverEvents = false; + enableMouseTrackingOnViews(); } #ifndef QT_NO_CURSOR - if (d->allItemsUseDefaultCursor && item->hasCursor()) { - d->allItemsUseDefaultCursor = false; - if (d->allItemsIgnoreHoverEvents) // already enabled otherwise - d->enableMouseTrackingOnViews(); + if (allItemsUseDefaultCursor && item->hasCursor()) { + allItemsUseDefaultCursor = false; + if (allItemsIgnoreHoverEvents) // already enabled otherwise + enableMouseTrackingOnViews(); } #endif //QT_NO_CURSOR // Enable touch events if the item accepts touch events. - if (d->allItemsIgnoreTouchEvents && item->acceptTouchEvents()) { - d->allItemsIgnoreTouchEvents = false; - d->enableTouchEventsOnViews(); + if (allItemsIgnoreTouchEvents && item->acceptTouchEvents()) { + allItemsIgnoreTouchEvents = false; + enableTouchEventsOnViews(); } // Update selection lists if (item->isSelected()) - d->selectedItems << item; + selectedItems << item; if (item->isWidget() && item->isVisible() && static_cast(item)->windowType() == Qt::Popup) - d->addPopup(static_cast(item)); + addPopup(static_cast(item)); // Update creation order focus chain. Make sure to leave the widget's // internal tab order intact. if (item->isWidget()) { QGraphicsWidget *widget = static_cast(item); - if (!d->tabFocusFirst) { + if (!tabFocusFirst) { // No first tab focus widget - make this the first tab focus // widget. - d->tabFocusFirst = widget; + tabFocusFirst = widget; } else if (!widget->parentWidget()) { // Adding a widget that is not part of a tab focus chain. - QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev; + QGraphicsWidget *last = tabFocusFirst->d_func()->focusPrev; QGraphicsWidget *lastNew = widget->d_func()->focusPrev; last->d_func()->focusNext = widget; widget->d_func()->focusPrev = last; - d->tabFocusFirst->d_func()->focusPrev = lastNew; - lastNew->d_func()->focusNext = d->tabFocusFirst; + tabFocusFirst->d_func()->focusPrev = lastNew; + lastNew->d_func()->focusNext = tabFocusFirst; } } // Add all children recursively + QGraphicsItem *subFocusScope = + (item->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)?item:focusScope; foreach (QGraphicsItem *child, item->children()) - addItem(child); + addItem(child, subFocusScope); // Resolve font and palette. - item->d_ptr->resolveFont(d->font.resolve()); - item->d_ptr->resolvePalette(d->palette.resolve()); + item->d_ptr->resolveFont(font.resolve()); + item->d_ptr->resolvePalette(palette.resolve()); if (!item->d_ptr->explicitlyHidden) { - if (d->unpolishedItems.isEmpty()) - QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); - d->unpolishedItems << item; + if (unpolishedItems.isEmpty()) + QMetaObject::invokeMethod(q, "_q_polishItems", Qt::QueuedConnection); + unpolishedItems << item; } // Reenable selectionChanged() for individual items - --d->selectionChanging; - if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize) - emit selectionChanged(); + --selectionChanging; + if (!selectionChanging && selectedItems.size() != oldSelectedItemSize) + emit q->selectionChanged(); // Deliver post-change notification item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); // Auto-activate the first inactive window if the scene is active. - if (d->activationRefCount > 0 && !d->activeWindow && item->isWindow()) - setActiveWindow(static_cast(item)); + if (activationRefCount > 0 && !activeWindow && item->isWindow()) + q->setActiveWindow(static_cast(item)); // Ensure that newly added items that have subfocus set, gain // focus automatically if there isn't a focus item already. - if (!d->focusItem && item->focusItem()) + if (!focusItem && item->focusItem()) item->focusItem()->setFocus(); - d->updateInputMethodSensitivityInViews(); + // Ensure that focus scopes set themselves up at add time + if (item->d_ptr->itemIsFocusedInScope) { + if (focusScope && !focusScope->d_ptr->focusScopeItem) { + item->setFocus(); + } else if (!(focusScope && focusScope->d_ptr->focusScopeItem == item) && + !(focusItem && focusItem->d_ptr->rootLevelFocusItem() == item)) { + // We unset the focused in scope variable in this item if: + // It's not scope focused in the closest focus scope, and + // It's not the root-level item for the globally focused item + item->d_ptr->setItemFocusedInScope(false); + } + } + + updateInputMethodSensitivityInViews(); } /*! diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 4b8791e..9e62901 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -124,6 +124,8 @@ public: QBrush backgroundBrush; QBrush foregroundBrush; + void addItem(QGraphicsItem *, QGraphicsItem *focusScope = 0); + bool stickyFocus; bool hasFocus; QGraphicsItem *focusItem; diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index e9154d4..b1835c8 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -161,7 +161,6 @@ public slots: void init(); private slots: - void explicitDeleteAutoFocusProxy(); void construction(); void constructionWithParent(); void destruction(); @@ -281,9 +280,7 @@ private slots: void hitTestUntransformableItem(); void hitTestGraphicsEffectItem(); void focusProxy(); - void autoDetectFocusProxy(); void subFocus(); - void reverseCreateAutoFocusProxy(); void focusProxyDeletion(); void negativeZStacksBehindParent(); void setGraphicsEffect(); @@ -7540,31 +7537,6 @@ void tst_QGraphicsItem::focusProxy() QCOMPARE(item3->focusProxy(), (QGraphicsItem *)0); } -void tst_QGraphicsItem::autoDetectFocusProxy() -{ - QGraphicsScene scene; - QGraphicsItem *item = scene.addRect(0, 0, 10, 10); - item->setFlag(QGraphicsItem::ItemIsFocusable); - - QGraphicsItem *item2 = scene.addRect(0, 0, 10, 10); - item2->setParentItem(item); - item2->setFlag(QGraphicsItem::ItemIsFocusable); - - QGraphicsItem *item3 = scene.addRect(0, 0, 10, 10); - item3->setParentItem(item2); - item3->setFlag(QGraphicsItem::ItemIsFocusable); - - item->setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); - QCOMPARE(item->focusProxy(), (QGraphicsItem *)0); - - item2->setFocus(); - QCOMPARE(item->focusProxy(), item2); - item3->setFocus(); - QCOMPARE(item->focusProxy(), item3); - item3->clearFocus(); - QCOMPARE(item->focusProxy(), item3); -} - void tst_QGraphicsItem::subFocus() { // Construct a text item that's not part of a scene (yet) @@ -7624,49 +7596,6 @@ void tst_QGraphicsItem::subFocus() QVERIFY(text2->hasFocus()); } -void tst_QGraphicsItem::reverseCreateAutoFocusProxy() -{ - QGraphicsTextItem *text = new QGraphicsTextItem; - text->setTextInteractionFlags(Qt::TextEditorInteraction); - text->setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); - - QGraphicsTextItem *text2 = new QGraphicsTextItem; - text2->setTextInteractionFlags(Qt::TextEditorInteraction); - text2->setFocus(); - QVERIFY(!text2->hasFocus()); - QCOMPARE(text->focusProxy(), (QGraphicsItem *)0); - text2->setParentItem(text); - QCOMPARE(text->focusProxy(), (QGraphicsItem *)text2); - QCOMPARE(text->focusItem(), (QGraphicsItem *)text2); - - QGraphicsScene scene; - scene.addItem(text); - QVERIFY(text2->hasFocus()); -} - -void tst_QGraphicsItem::explicitDeleteAutoFocusProxy() -{ - QGraphicsTextItem *text = new QGraphicsTextItem; - text->setTextInteractionFlags(Qt::TextEditorInteraction); - text->setFlag(QGraphicsItem::ItemAutoDetectsFocusProxy); - - QGraphicsTextItem *text2 = new QGraphicsTextItem; - text2->setTextInteractionFlags(Qt::TextEditorInteraction); - text2->setFocus(); - QVERIFY(!text2->hasFocus()); - QCOMPARE(text->focusProxy(), (QGraphicsItem *)0); - text2->setParentItem(text); - QCOMPARE(text->focusProxy(), (QGraphicsItem *)text2); - QCOMPARE(text->focusItem(), (QGraphicsItem *)text2); - - QGraphicsScene scene; - scene.addItem(text); - QVERIFY(text2->hasFocus()); - - delete text2; - QCOMPARE(text->focusProxy(), (QGraphicsItem *)0); -} - void tst_QGraphicsItem::focusProxyDeletion() { QGraphicsRectItem *rect = new QGraphicsRectItem; -- cgit v0.12 From 7da9f68edd7819e15f33fd5803beb5f4544700ae Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 27 Aug 2009 14:14:00 +1000 Subject: Add internal note. --- src/declarative/qml/qmlmetaproperty.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index cc5e4ee..1e8ce91 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -532,7 +532,7 @@ QmlAbstractBinding *QmlMetaProperty::binding() const QmlAbstractBinding *binding = data->bindings; while (binding) { // ### This wont work for value types - if (binding->propertyIndex() == d->coreIdx) + if (binding->propertyIndex() == d->coreIdx) //### should we check for enabled? return binding; binding = binding->m_nextBinding; } -- cgit v0.12 From c52d846eda611e18fa88cf3c90239987a9108382 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 27 Aug 2009 14:29:26 +1000 Subject: Update .gitignore to show new files in declarative/examples and declarative/demos --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9e9898e..589f9d3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,11 @@ examples/*/*/* !examples/*/*/*[.]* !examples/*/*/README examples/*/*/*[.]app +!examples/declarative/* demos/*/* !demos/*/*[.]* demos/*/*[.]app +!demos/declarative/* config.tests/*/*/* !config.tests/*/*/*[.]* config.tests/*/*/*[.]app -- cgit v0.12 From 219e2fa7ace74d87fda4ed8c3a2a75005fab10b9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 27 Aug 2009 14:43:46 +1000 Subject: Fixup 928e81b68e0b695662c7ee3dd0bfa409a7ca1ffd I messed up when I reapplied this patch to the branch head. This also adds an extra test for the case fixed. --- examples/declarative/focusscope/test3.qml | 50 +++++++++++++++++++++++++++++++ src/gui/graphicsview/qgraphicsscene.cpp | 18 ++--------- 2 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 examples/declarative/focusscope/test3.qml diff --git a/examples/declarative/focusscope/test3.qml b/examples/declarative/focusscope/test3.qml new file mode 100644 index 0000000..51fa35a --- /dev/null +++ b/examples/declarative/focusscope/test3.qml @@ -0,0 +1,50 @@ +import Qt 4.6 + +Rectangle { + color: "white" + width: 800 + height: 600 + + ListModel { + id: Model + ListElement { name: "1" } + ListElement { name: "2" } + ListElement { name: "3" } + ListElement { name: "4" } + ListElement { name: "5" } + ListElement { name: "6" } + ListElement { name: "6" } + ListElement { name: "8" } + ListElement { name: "9" } + } + + Component { + id: VerticalDelegate + FocusScope { + id: Root + width: 50; height: 50; + Keys.onDigit9Pressed: print("Error - " + name) + Rectangle { + focus: true + Keys.onDigit9Pressed: print(name) + width: 50; height: 50; + color: Root.ListView.isCurrentItem?"red":"green" + Text { text: name; anchors.centerIn: parent } + } + } + } + + ListView { + width: 800; height: 50; orientation: "Horizontal" + focus: true + model: Model + delegate: VerticalDelegate + currentItemPositioning: "SnapAuto" + } + + + Text { + y: 100; x: 50 + text: "Currently selected element should be red\nPressing \"9\" should print the number of the currently selected item\nBe sure to scroll all the way to the right, pause, and then all the way to the left." + } +} diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 73dba7b..af137e7 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -602,7 +602,7 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, QGraphicsItem *oldRootLevelFocusItem = focusItem->d_ptr->rootLevelFocusItem(); - if (oldRootLevelFocusItem != itemRootLevelFocusItem) + if (oldRootLevelFocusItem != itemRootLevelFocusItem) oldRootLevelFocusItem->d_ptr->setItemFocusedInScope(false); focusItem = 0; @@ -2374,22 +2374,10 @@ void QGraphicsScenePrivate::addItem(QGraphicsItem *item, // Ensure that newly added items that have subfocus set, gain // focus automatically if there isn't a focus item already. - if (!focusItem && item->focusItem()) + if (!focusItem && item->focusItem() || + focusScope && !focusScope->d_ptr->focusScopeItem && item->focusItem()) item->focusItem()->setFocus(); - // Ensure that focus scopes set themselves up at add time - if (item->d_ptr->itemIsFocusedInScope) { - if (focusScope && !focusScope->d_ptr->focusScopeItem) { - item->setFocus(); - } else if (!(focusScope && focusScope->d_ptr->focusScopeItem == item) && - !(focusItem && focusItem->d_ptr->rootLevelFocusItem() == item)) { - // We unset the focused in scope variable in this item if: - // It's not scope focused in the closest focus scope, and - // It's not the root-level item for the globally focused item - item->d_ptr->setItemFocusedInScope(false); - } - } - updateInputMethodSensitivityInViews(); } -- cgit v0.12 From 12f4fc296578fb30ac1bf690b3eeba176b72205a Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 27 Aug 2009 14:54:32 +1000 Subject: Revert to Common.ImageDetails for now. --- demos/declarative/flickr/flickr-mobile.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/declarative/flickr/flickr-mobile.qml b/demos/declarative/flickr/flickr-mobile.qml index ee6366d..a4692a3 100644 --- a/demos/declarative/flickr/flickr-mobile.qml +++ b/demos/declarative/flickr/flickr-mobile.qml @@ -33,7 +33,7 @@ Item { } } - Mobile.ImageDetails { id: ImageDetails; width: parent.width; x: parent.width; height: parent.height } + Common.ImageDetails { id: ImageDetails; width: parent.width; x: parent.width; height: parent.height } Mobile.TitleBar { id: TitleBar; width: parent.width; height: 40; opacity: 0.9 } Mobile.ToolBar { id: ToolBar; height: 40; anchors.bottom: parent.bottom; width: parent.width; opacity: 0.9 } -- cgit v0.12 From 30f011823f0acacdfb3380a6ae52f05e2c8cdd6a Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 27 Aug 2009 15:07:05 +1000 Subject: Expressions should fail to evaluate if their engine has been destroyed Changing this check to engine() checks both if the engine() exists and if the parent context exists. --- src/declarative/qml/qmlexpression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 77463cd..845dcf6 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -315,7 +315,7 @@ QVariant QmlExpression::value() Q_D(QmlExpression); QVariant rv; - if (!d->context() || (!d->sse.isValid() && d->expression.isEmpty())) + if (!engine() || (!d->sse.isValid() && d->expression.isEmpty())) return rv; #ifdef Q_ENABLE_PERFORMANCE_LOG -- cgit v0.12 From b99fd8c53ed7ed73d9bab171918829ba0911810a Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 27 Aug 2009 15:33:12 +1000 Subject: Fix glitches when dragging a ListView. --- src/declarative/fx/qfxflickable.cpp | 19 ++++--------------- src/declarative/fx/qfxlistview.cpp | 3 ++- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/declarative/fx/qfxflickable.cpp b/src/declarative/fx/qfxflickable.cpp index 428815a..440c1ca 100644 --- a/src/declarative/fx/qfxflickable.cpp +++ b/src/declarative/fx/qfxflickable.cpp @@ -607,7 +607,6 @@ void QFxFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event) void QFxFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *) { Q_Q(QFxFlickable); - pressed = false; if (lastPosTime.isNull()) return; @@ -871,13 +870,8 @@ void QFxFlickable::setViewportWidth(int w) else d->_flick->setWidth(w); // Make sure that we're entirely in view. - if (d->_moveX.value() > minXExtent() || maxXExtent() > 0) { - d->_tl.clear(); - d->_moveX.setValue(minXExtent()); - } else if (d->_moveX.value() < maxXExtent()) { - d->_tl.clear(); - d->_moveX.setValue(maxXExtent()); - } + if (!d->pressed) + d->fixupX(); emit viewportWidthChanged(); d->updateBeginningEnd(); } @@ -919,13 +913,8 @@ void QFxFlickable::setViewportHeight(int h) else d->_flick->setHeight(h); // Make sure that we're entirely in view. - if (d->_moveY.value() > minYExtent() || maxYExtent() > 0) { - d->_tl.clear(); - d->_moveY.setValue(minYExtent()); - } else if (d->_moveY.value() < maxYExtent()) { - d->_tl.clear(); - d->_moveY.setValue(maxYExtent()); - } + if (!d->pressed) + d->fixupY(); emit viewportHeightChanged(); d->updateBeginningEnd(); } diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 4030a0b..0dfdce8 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -1396,13 +1396,14 @@ void QFxListView::trackedPositionChanged() case Free: if (d->trackedItem->position() < d->position()) { d->setPosition(d->trackedItem->position()); + d->fixupPosition(); } else if (d->trackedItem->endPosition() > d->position() + d->size()) { qreal pos = d->trackedItem->endPosition() - d->size(); if (d->trackedItem->size() > d->size()) pos = d->trackedItem->position(); d->setPosition(pos); + d->fixupPosition(); } - d->fixupPosition(); break; case Snap: if (d->trackedItem->position() < d->startPosition() + d->snapPos) -- cgit v0.12 From 09c662b1c3440d7ff0b151d1fd10fc19ef75725f Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 27 Aug 2009 15:51:46 +1000 Subject: Start adding convenience functions for value types. Allows you to write things like "geometry: Qt.rect(0,0,100,100)" and "color: Qt.hsla(.7,.5,.2)" --- src/declarative/qml/qmlengine.cpp | 66 +++++++++++++++- src/declarative/qml/qmlengine_p.h | 5 ++ tests/auto/declarative/qmlengine/functions.qml | 6 ++ tests/auto/declarative/qmlengine/tst_qmlengine.cpp | 87 ++++++++++++++++++---- 4 files changed, 145 insertions(+), 19 deletions(-) create mode 100644 tests/auto/declarative/qmlengine/functions.qml diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index ea00d65..fbd9cf1 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -71,6 +71,7 @@ #include #include #include +#include #include #include #include "private/qmlcomponentjs_p.h" @@ -104,6 +105,12 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) QScriptValue qtObject = scriptEngine.newQMetaObject(StaticQtMetaObject::get()); scriptEngine.globalObject().setProperty(QLatin1String("Qt"), qtObject); + qtObject.setProperty(QLatin1String("rgba"), scriptEngine.newFunction(QmlEnginePrivate::rgba, 4)); + qtObject.setProperty(QLatin1String("hsla"), scriptEngine.newFunction(QmlEnginePrivate::hsla, 4)); + qtObject.setProperty(QLatin1String("rect"), scriptEngine.newFunction(QmlEnginePrivate::rect, 4)); + qtObject.setProperty(QLatin1String("point"), scriptEngine.newFunction(QmlEnginePrivate::point, 2)); + qtObject.setProperty(QLatin1String("size"), scriptEngine.newFunction(QmlEnginePrivate::size, 2)); + qtObject.setProperty(QLatin1String("vector3d"), scriptEngine.newFunction(QmlEnginePrivate::vector, 3)); } QmlEnginePrivate::~QmlEnginePrivate() @@ -160,7 +167,7 @@ void QmlEnginePrivate::init() scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); scriptEngine.globalObject().setProperty(QLatin1String("vector"), - scriptEngine.newFunction(QmlEnginePrivate::vector, 1)); + scriptEngine.newFunction(QmlEnginePrivate::vector, 3)); if (QCoreApplication::instance()->thread() == q->thread() && QmlEngineDebugServer::isDebuggingEnabled()) { @@ -698,7 +705,7 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi QVector3D as usual. This function takes three numeric components and combines them into a - QMLJS string that can be used with any property that takes a + QVector3D value that can be used with any property that takes a QVector3D argument. The following QML code: \code @@ -729,6 +736,59 @@ QScriptValue QmlEnginePrivate::vector(QScriptContext *ctxt, QScriptEngine *engin return engine->newVariant(qVariantFromValue(QVector3D(x, y, z))); } +QScriptValue QmlEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3) + return engine->nullValue(); + qsreal r = ctxt->argument(0).toNumber(); + qsreal g = ctxt->argument(1).toNumber(); + qsreal b = ctxt->argument(2).toNumber(); + qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1; + return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromRgbF(r, g, b, a))); +} + +QScriptValue QmlEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3) + return engine->nullValue(); + qsreal h = ctxt->argument(0).toNumber(); + qsreal s = ctxt->argument(1).toNumber(); + qsreal l = ctxt->argument(2).toNumber(); + qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1; + return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromHslF(h, s, l, a))); +} + +QScriptValue QmlEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() < 4) + return engine->nullValue(); + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + qsreal w = ctxt->argument(2).toNumber(); + qsreal h = ctxt->argument(3).toNumber(); + return qScriptValueFromValue(engine, qVariantFromValue(QRectF(x, y, w, h))); +} + +QScriptValue QmlEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() < 2) + return engine->nullValue(); + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + return qScriptValueFromValue(engine, qVariantFromValue(QPointF(x, y))); +} + +QScriptValue QmlEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() < 2) + return engine->nullValue(); + qsreal w = ctxt->argument(0).toNumber(); + qsreal h = ctxt->argument(1).toNumber(); + return qScriptValueFromValue(engine, qVariantFromValue(QSizeF(w, h))); +} + QmlScriptClass::QmlScriptClass(QmlEngine *bindengine) : QScriptClass(QmlEnginePrivate::getScriptEngine(bindengine)), engine(bindengine) @@ -971,7 +1031,7 @@ QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) ret += QString::number((quintptr)obj,16); ret += QLatin1String(")"); }else{ - ret += "null"; + ret += QLatin1String("null"); } return engine->newVariant(ret); } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 53b2967..c2de72b 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -214,6 +214,11 @@ public: static QScriptValue createComponent(QScriptContext*, QScriptEngine*); static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*); static QScriptValue vector(QScriptContext*, QScriptEngine*); + static QScriptValue rgba(QScriptContext*, QScriptEngine*); + static QScriptValue hsla(QScriptContext*, QScriptEngine*); + static QScriptValue point(QScriptContext*, QScriptEngine*); + static QScriptValue size(QScriptContext*, QScriptEngine*); + static QScriptValue rect(QScriptContext*, QScriptEngine*); static QScriptEngine *getScriptEngine(QmlEngine *e) { return &e->d_func()->scriptEngine; } static QmlEnginePrivate *get(QmlEngine *e) { return e->d_func(); } diff --git a/tests/auto/declarative/qmlengine/functions.qml b/tests/auto/declarative/qmlengine/functions.qml new file mode 100644 index 0000000..28e8ed4 --- /dev/null +++ b/tests/auto/declarative/qmlengine/functions.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +MyTypeObject { + rectProperty: Qt.rect(0,0,100,100) + rectFProperty: Qt.rect(0,0.5,100,99.5) +} diff --git a/tests/auto/declarative/qmlengine/tst_qmlengine.cpp b/tests/auto/declarative/qmlengine/tst_qmlengine.cpp index 9a04c61..8c050cb 100644 --- a/tests/auto/declarative/qmlengine/tst_qmlengine.cpp +++ b/tests/auto/declarative/qmlengine/tst_qmlengine.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -12,30 +14,83 @@ public: tst_qmlengine() {} private slots: - void componentSearchPath(); -}; + void valueTypeFunctions(); +private: + QmlEngine engine; +}; -void tst_qmlengine::componentSearchPath() +class MyTypeObject : public QObject { - QFile file(SRCDIR "/imports.qml"); - QVERIFY(file.open(QIODevice::ReadOnly)); + Q_OBJECT + Q_PROPERTY(QPoint pointProperty READ pointProperty WRITE setPointProperty); + Q_PROPERTY(QPointF pointFProperty READ pointFProperty WRITE setPointFProperty); + Q_PROPERTY(QSize sizeProperty READ sizeProperty WRITE setSizeProperty); + Q_PROPERTY(QSizeF sizeFProperty READ sizeFProperty WRITE setSizeFProperty); + Q_PROPERTY(QRect rectProperty READ rectProperty WRITE setRectProperty NOTIFY rectPropertyChanged); + Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty); + +public: + MyTypeObject() {} - QmlEngine engine; + QPoint pointPropertyValue; + QPoint pointProperty() const { + return pointPropertyValue; + } + void setPointProperty(const QPoint &v) { + pointPropertyValue = v; + } - QList searchPath = engine.componentSearchPath(file.readAll(), - QUrl::fromLocalFile(file.fileName())); + QPointF pointFPropertyValue; + QPointF pointFProperty() const { + return pointFPropertyValue; + } + void setPointFProperty(const QPointF &v) { + pointFPropertyValue = v; + } - QList expected; - expected << QUrl::fromLocalFile(SRCDIR); - expected << QUrl::fromLocalFile(file.fileName()).resolved(QUrl("import1")); - expected << QUrl::fromLocalFile(file.fileName()).resolved(QUrl("import2")); + QSize sizePropertyValue; + QSize sizeProperty() const { + return sizePropertyValue; + } + void setSizeProperty(const QSize &v) { + sizePropertyValue = v; + } - QCOMPARE(searchPath.size(), expected.size()); - for (int i = 0; i < expected.size(); ++i) { - QCOMPARE(searchPath.at(i).toString(QUrl::StripTrailingSlash), - expected.at(i).toString(QUrl::StripTrailingSlash)); + QSizeF sizeFPropertyValue; + QSizeF sizeFProperty() const { + return sizeFPropertyValue; } + void setSizeFProperty(const QSizeF &v) { + sizeFPropertyValue = v; + } + + QRect rectPropertyValue; + QRect rectProperty() const { + return rectPropertyValue; + } + void setRectProperty(const QRect &v) { + rectPropertyValue = v; + } + + QRectF rectFPropertyValue; + QRectF rectFProperty() const { + return rectFPropertyValue; + } + void setRectFProperty(const QRectF &v) { + rectFPropertyValue = v; + } + +}; +QML_DECLARE_TYPE(MyTypeObject); +QML_DEFINE_TYPE(Test, 1, 0, 0, MyTypeObject, MyTypeObject); + +void tst_qmlengine::valueTypeFunctions() +{ + QmlComponent component(&engine, SRCDIR "/functions.qml"); + MyTypeObject *obj = qobject_cast(component.create()); + QCOMPARE(obj->rectProperty(), QRect(0,0,100,100)); + QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5)); } QTEST_MAIN(tst_qmlengine) -- cgit v0.12 From f80f58b857d1fa9ad53ba6780daaaafa1c4b1111 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 27 Aug 2009 17:07:12 +1000 Subject: Make sure current item is released when removed but not visible. --- src/declarative/fx/qfxgridview.cpp | 5 +++-- src/declarative/fx/qfxlistview.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp index b429895..bf6e863 100644 --- a/src/declarative/fx/qfxgridview.cpp +++ b/src/declarative/fx/qfxgridview.cpp @@ -1254,6 +1254,7 @@ void QFxGridView::itemsInserted(int modelIndex, int count) void QFxGridView::itemsRemoved(int modelIndex, int count) { Q_D(QFxGridView); + bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count; int index = d->mapFromModel(modelIndex); if (index == -1) { if (modelIndex + count - 1 < d->visibleIndex) { @@ -1269,7 +1270,7 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->currentIndex -= count; if (d->currentItem) d->currentItem->index -= count; - } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { + } else if (currentRemoved) { // current item has been removed. d->releaseItem(d->currentItem); d->currentItem = 0; @@ -1311,7 +1312,7 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->currentIndex -= count; if (d->currentItem) d->currentItem->index -= count; - } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { + } else if (currentRemoved) { // current item has been removed. d->releaseItem(d->currentItem); d->currentItem = 0; diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 0dfdce8..c1e03dd 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -1522,6 +1522,7 @@ void QFxListView::itemsRemoved(int modelIndex, int count) { Q_D(QFxListView); d->updateUnrequestedIndexes(); + bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count; if (!d->mapRangeFromModel(modelIndex, count)) { if (modelIndex + count - 1 < d->visibleIndex) { // Items removed before our visible items. @@ -1536,7 +1537,7 @@ void QFxListView::itemsRemoved(int modelIndex, int count) d->currentIndex -= count; if (d->currentItem) d->currentItem->index -= count; - } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { + } else if (currentRemoved) { // current item has been removed. d->releaseItem(d->currentItem); d->currentItem = 0; @@ -1579,8 +1580,9 @@ void QFxListView::itemsRemoved(int modelIndex, int count) d->currentIndex -= count; if (d->currentItem) d->currentItem->index -= count; - } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { + } else if (currentRemoved) { // current item has been removed. + d->currentItem->attached->setIsCurrentItem(false); d->releaseItem(d->currentItem); d->currentItem = 0; d->currentIndex = -1; -- cgit v0.12 From 2d384efd8e85515c9f3e7ed628cc3fd57b044a00 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 27 Aug 2009 17:44:17 +1000 Subject: Revert "Fix setting the id property" This reverts commit f51450571addf2cb9a55153b209b8c1a45898193. We apparently do not want to either make the id easily accessible or have a special case the turns things into strings. And the autotests are all broken anyways - fixing something only they use isn't important --- src/declarative/qml/qmlcompiler.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 764699e..070add7 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -1235,13 +1235,9 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, // default property or to sub-objects (which are always in binding // sub-contexts) COMPILE_CHECK(buildIdProperty(prop, obj)); - if (prop->type == QVariant::String){ - if(!prop->values.at(0)->value.isString()){ - //Need to convert to string to assign to the QString id property - prop->values.at(0)->value = Variant(prop->values.at(0)->value.asString()); - } + if (prop->type == QVariant::String && + prop->values.at(0)->value.isString()) COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); - } } else if (isAttachedPropertyName(prop->name)) { @@ -1702,7 +1698,7 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop, // children: [ Item {}, Item {} ] // } // -// We allow assigning multiple values to single value properties +// We allow assignming multiple values to single value properties bool QmlCompiler::buildPropertyAssignment(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt) -- cgit v0.12 From 1975260b35906a3cc0ca25f25b553e4572238e05 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 27 Aug 2009 18:12:33 +1000 Subject: Expose some functionality through Qt.DesktopServices Only openUrl() currently. Reviewed-by:Aaron Kennedy --- src/declarative/qml/qmlengine.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index ea00d65..cf90fe7 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,14 @@ struct StaticQtMetaObject : public QObject { return &static_cast (0)->staticQtMetaObject; } }; +QScriptValue desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e) +{ + if(!ctxt->argumentCount()) + return e->newVariant(QVariant(false)); + bool ret = QDesktopServices::openUrl(QUrl(ctxt->argument(0).toString())); + return e->newVariant(QVariant(ret)); +} + QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentBindContext(0), currentExpression(0), isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), @@ -103,6 +112,9 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) { QScriptValue qtObject = scriptEngine.newQMetaObject(StaticQtMetaObject::get()); + QScriptValue desktopObject = scriptEngine.newObject(); + desktopObject.setProperty(QLatin1String("openUrl"),scriptEngine.newFunction(desktopOpenUrl, 1)); + qtObject.setProperty(QLatin1String("DesktopServices"), desktopObject); scriptEngine.globalObject().setProperty(QLatin1String("Qt"), qtObject); } -- cgit v0.12 From dd60bef7c93a09a92228574bade084d520e711f9 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 27 Aug 2009 18:16:53 +1000 Subject: Flickr tweak for more generic components Using TitleBar in twitter too, this slight change prevents a copy of the whole component. --- demos/declarative/flickr/mobile/TitleBar.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/demos/declarative/flickr/mobile/TitleBar.qml b/demos/declarative/flickr/mobile/TitleBar.qml index 6d655a6..49d670f 100644 --- a/demos/declarative/flickr/mobile/TitleBar.qml +++ b/demos/declarative/flickr/mobile/TitleBar.qml @@ -3,6 +3,8 @@ import Qt 4.6 Item { id: TitleBar + property string untaggedString: "Uploads from everyone" + property string taggedString: "Recent uploads tagged " BorderImage { source: "images/titlebar2.sci"; width: parent.width; height: parent.height + 14; y: -7 } Item { @@ -22,13 +24,14 @@ Item { anchors.leftMargin: 10; anchors.rightMargin: 10 anchors.verticalCenter: parent.verticalCenter elide: "ElideLeft" - text: (RssModel.tags=="" ? "Uploads from everyone" : "Recent Uploads tagged " + RssModel.tags) + text: (RssModel.tags=="" ? untaggedString : taggedString + RssModel.tags) font.bold: true; color: "white"; style: "Raised"; styleColor: "black" } Button { - id: TagButton; x: TitleBar.width - 50; y: 3; width: 45; height: 32; text: "..." + id: TagButton; x: TitleBar.width - 50; width: 45; height: 32; text: "..." onClicked: if (TitleBar.state == "Tags") accept(); else TitleBar.state = "Tags" + anchors.verticalCenter: parent.verticalCenter } Item { -- cgit v0.12 From 70e650500e6e13be336857dac17a110097da70ef Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 28 Aug 2009 09:53:20 +1000 Subject: Implement (parts of) XMLHttpRequest This is the first step to allowing QML to interact with REST style APIs in the same way as a webbrowser can. --- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlengine.cpp | 3 + src/declarative/qml/qmlengine_p.h | 2 + src/declarative/qml/qmlxmlhttprequest.cpp | 535 ++++++++++++++++++++++++++++++ src/declarative/qml/qmlxmlhttprequest_p.h | 60 ++++ tools/qmlviewer/main.cpp | 1 + 6 files changed, 605 insertions(+), 2 deletions(-) create mode 100644 src/declarative/qml/qmlxmlhttprequest.cpp create mode 100644 src/declarative/qml/qmlxmlhttprequest_p.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 05bdade..9a8d3f2 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -30,7 +30,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlrewrite.cpp \ qml/qmlbasicscript.cpp \ qml/qmlvaluetype.cpp \ - qml/qmlbindingoptimizations.cpp + qml/qmlbindingoptimizations.cpp \ + qml/qmlxmlhttprequest.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -77,7 +78,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlrewrite_p.h \ qml/qpodvector_p.h \ qml/qmlvaluetype_p.h \ - qml/qmlbindingoptimizations_p.h + qml/qmlbindingoptimizations_p.h \ + qml/qmlxmlhttprequest_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index ea00d65..3f6f9b4 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -78,6 +78,7 @@ #include #include #include +#include Q_DECLARE_METATYPE(QmlMetaProperty) Q_DECLARE_METATYPE(QList); @@ -104,6 +105,8 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) QScriptValue qtObject = scriptEngine.newQMetaObject(StaticQtMetaObject::get()); scriptEngine.globalObject().setProperty(QLatin1String("Qt"), qtObject); + + qt_add_qmlxmlhttprequest(&scriptEngine); } QmlEnginePrivate::~QmlEnginePrivate() diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 53b2967..5506b56 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -216,7 +216,9 @@ public: static QScriptValue vector(QScriptContext*, QScriptEngine*); static QScriptEngine *getScriptEngine(QmlEngine *e) { return &e->d_func()->scriptEngine; } + static QmlEngine *getEngine(QScriptEngine *e) { return static_cast(e)->p->q_func(); } static QmlEnginePrivate *get(QmlEngine *e) { return e->d_func(); } + static QmlEnginePrivate *get(QScriptEngine *e) { return static_cast(e)->p; } }; diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp new file mode 100644 index 0000000..fb92c54 --- /dev/null +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "qmlxmlhttprequest_p.h" + +#include + +// ### Find real values +#define INVALID_STATE_ERR ((QScriptContext::Error)15) + +class QmlXMLHttpRequest : public QObject +{ +Q_OBJECT +public: + enum State { Unsent = 0, + Opened = 1, HeadersReceived = 2, + Loading = 3, Done = 4 }; + + QmlXMLHttpRequest(QmlEngine *engine); + virtual ~QmlXMLHttpRequest(); + + QScriptValue callback() const; + void setCallback(const QScriptValue &); + + bool sendFlag() const; + bool errorFlag() const; + quint32 readyState() const; + int replyStatus() const; + QString replyStatusText() const; + + void open(const QString &, const QUrl &); + void addHeader(const QString &, const QString &); + void send(const QByteArray &); + void abort(); + + QString responseBody() const; +private slots: + void downloadProgress(qint64); + void error(QNetworkReply::NetworkError); + void finished(); + +private: + QmlEngine *m_engine; + + State m_state; + bool m_errorFlag; + bool m_sendFlag; + QString m_method; + QUrl m_url; + QByteArray m_responseEntityBody; + + void dispatchCallback(); + QScriptValue m_callback; + + int m_status; + QString m_statusText; + QNetworkRequest m_request; + QNetworkReply *m_network; + void destroyNetwork(); +}; + +QmlXMLHttpRequest::QmlXMLHttpRequest(QmlEngine *engine) +: m_engine(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false), + m_network(0) +{ + Q_ASSERT(m_engine); +} + +QmlXMLHttpRequest::~QmlXMLHttpRequest() +{ + destroyNetwork(); +} + +QScriptValue QmlXMLHttpRequest::callback() const +{ + return m_callback; +} + +void QmlXMLHttpRequest::setCallback(const QScriptValue &c) +{ + m_callback = c; +} + +bool QmlXMLHttpRequest::sendFlag() const +{ + return m_sendFlag; +} + +bool QmlXMLHttpRequest::errorFlag() const +{ + return m_errorFlag; +} + +quint32 QmlXMLHttpRequest::readyState() const +{ + return m_state; +} + +int QmlXMLHttpRequest::replyStatus() const +{ + return m_status; +} + +QString QmlXMLHttpRequest::replyStatusText() const +{ + return m_statusText; +} + +void QmlXMLHttpRequest::open(const QString &method, const QUrl &url) +{ + destroyNetwork(); + m_sendFlag = false; + m_errorFlag = false; + m_responseEntityBody = QByteArray(); + m_method = method; + m_url = url; + m_state = Opened; + dispatchCallback(); +} + +void QmlXMLHttpRequest::addHeader(const QString &name, const QString &value) +{ + QByteArray utfname = name.toUtf8(); + + if (m_request.hasRawHeader(utfname)) { + m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + "," + value.toUtf8()); + } else { + m_request.setRawHeader(utfname, value.toUtf8()); + } +} + +void QmlXMLHttpRequest::send(const QByteArray &data) +{ + m_errorFlag = false; + m_sendFlag = true; + + dispatchCallback(); + + m_request.setUrl(m_url); + + if (m_method == QLatin1String("GET")) + m_network = m_engine->networkAccessManager()->get(m_request); + else if (m_method == QLatin1String("HEAD")) + m_network = m_engine->networkAccessManager()->head(m_request); + else if(m_method == QLatin1String("POST")) + m_network = m_engine->networkAccessManager()->post(m_request, data); + else if(m_method == QLatin1String("PUT")) + m_network = m_engine->networkAccessManager()->put(m_request, data); + + QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(downloadProgress(qint64))); + QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(error(QNetworkReply::NetworkError))); + QObject::connect(m_network, SIGNAL(finished()), + this, SLOT(finished())); +} + +void QmlXMLHttpRequest::abort() +{ + destroyNetwork(); + m_responseEntityBody = QByteArray(); + m_errorFlag = true; + m_request = QNetworkRequest(); + + if (!(m_state == Unsent || + (m_state == Opened && !m_sendFlag) || + m_state == Done)) { + + m_state = Done; + m_sendFlag = false; + dispatchCallback(); + } + + m_state = Unsent; +} + +void QmlXMLHttpRequest::downloadProgress(qint64 bytes) +{ + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QLatin1String(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + // ### We assume if this is called the headers are now available + if (m_state < HeadersReceived) { + m_state = HeadersReceived; + dispatchCallback(); + } + + bool wasEmpty = m_responseEntityBody.isEmpty(); + m_responseEntityBody.append(m_network->readAll()); + if (wasEmpty && !m_responseEntityBody.isEmpty()) { + m_state = Loading; + dispatchCallback(); + } +} + +void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error) +{ + m_responseEntityBody = QByteArray(); + m_errorFlag = true; + m_request = QNetworkRequest(); + + destroyNetwork(); + + m_state = Done; + dispatchCallback(); +} + +void QmlXMLHttpRequest::finished() +{ + // ### We need to transparently redirect as dictated by the spec + + if (m_state < HeadersReceived) { + m_state = HeadersReceived; + dispatchCallback(); + } + m_responseEntityBody.append(m_network->readAll()); + destroyNetwork(); + if (m_state < Loading) { + m_state = Loading; + dispatchCallback(); + } + m_state = Done; + dispatchCallback(); +} + + +QString QmlXMLHttpRequest::responseBody() const +{ + return QString::fromUtf8(m_responseEntityBody); +} + +void QmlXMLHttpRequest::dispatchCallback() +{ + m_callback.call(); +} + +void QmlXMLHttpRequest::destroyNetwork() +{ + if (m_network) { + m_network->disconnect(); + m_network->deleteLater(); + m_network = 0; + } +} + +// XMLHttpRequest methods +static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount() < 2 || context->argumentCount() > 5) + return context->throwError(QScriptContext::SyntaxError, "Incorrect argument count"); + + // Argument 0 - Method + QString method = context->argument(0).toString().toUpper(); + if (method != QLatin1String("GET") && + method != QLatin1String("PUT") && + method != QLatin1String("HEAD") && + method != QLatin1String("POST")) + return context->throwError(QScriptContext::SyntaxError, "Unsupported method"); + + + // Argument 1 - URL + QUrl url(context->argument(1).toString()); // ### Need to resolve correctly + + if (url.isRelative()) // ### Fix me + return context->throwError(QScriptContext::SyntaxError, "Relative URLs not supported"); + + // Argument 2 - async (optional) + if (context->argumentCount() > 2 && !context->argument(2).toBoolean()) + return context->throwError(QScriptContext::SyntaxError, "Synchronous call not supported"); + + + // Argument 3/4 - user/pass (optional) + QString username, password; + if (context->argumentCount() > 3) + username = context->argument(3).toString(); + if (context->argumentCount() > 4) + password = context->argument(4).toString(); + + + // Clear the fragment (if any) + url.setFragment(QString()); + // Set username/password + if (!username.isNull()) url.setUserName(username); + if (!password.isNull()) url.setPassword(password); + + request->open(method, url); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount() != 2) + return context->throwError(QScriptContext::SyntaxError, "Incorrect argument count"); + + + if (request->readyState() != QmlXMLHttpRequest::Opened || + request->sendFlag()) + return context->throwError(INVALID_STATE_ERR, "Invalid state"); + + + QString name = context->argument(0).toString(); + QString value = context->argument(1).toString(); + + // ### Check that name and value are well formed + + QString nameUpper = name.toUpper(); + if (nameUpper == QLatin1String("ACCEPT-CHARSET") || + nameUpper == QLatin1String("ACCEPT-ENCODING") || + nameUpper == QLatin1String("CONNECTION") || + nameUpper == QLatin1String("CONTENT-LENGTH") || + nameUpper == QLatin1String("COOKIE") || + nameUpper == QLatin1String("COOKIE2") || + nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") || + nameUpper == QLatin1String("DATE") || + nameUpper == QLatin1String("EXPECT") || + nameUpper == QLatin1String("HOST") || + nameUpper == QLatin1String("KEEP-ALIVE") || + nameUpper == QLatin1String("REFERER") || + nameUpper == QLatin1String("TE") || + nameUpper == QLatin1String("TRAILER") || + nameUpper == QLatin1String("TRANSFER-ENCODING") || + nameUpper == QLatin1String("UPGRADE") || + nameUpper == QLatin1String("USER-AGENT") || + nameUpper == QLatin1String("VIA") || + nameUpper.startsWith(QLatin1String("PROXY-")) || + nameUpper.startsWith(QLatin1String("SEC-"))) + return engine->undefinedValue(); + + request->addHeader(nameUpper, value); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() != QmlXMLHttpRequest::Opened) + return context->throwError(INVALID_STATE_ERR, "Invalid state"); + + if (request->sendFlag()) + return context->throwError(INVALID_STATE_ERR, "Invalid state"); + + QByteArray data; + if (context->argumentCount() > 0) + data = context->argument(0).toString().toUtf8(); + + request->send(data); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + request->abort(); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine) +{ + // ### Implement + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine) +{ + // ### Implement + + return engine->undefinedValue(); +} + +// XMLHttpRequest properties +static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + return QScriptValue(request->readyState()); +} + +static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() == QmlXMLHttpRequest::Unsent || + request->readyState() == QmlXMLHttpRequest::Opened) + return context->throwError(INVALID_STATE_ERR, "Invalid state"); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatus()); +} + +static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() == QmlXMLHttpRequest::Unsent || + request->readyState() == QmlXMLHttpRequest::Opened) + return context->throwError(INVALID_STATE_ERR, "Invalid state"); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatusText()); +} + +static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done) + return QScriptValue(QString()); + else + return QScriptValue(request->responseBody()); +} + +static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount()) + request->setCallback(context->argument(0)); + + return request->callback(); +} + +// Constructor +static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine) +{ + QScriptValue rv = engine->newObject(); + rv.setPrototype(context->callee().data()); + rv.setData(engine->newQObject(new QmlXMLHttpRequest(QmlEnginePrivate::getEngine(engine)), QScriptEngine::ScriptOwnership)); + return rv; +} + +void qt_add_qmlxmlhttprequest(QScriptEngine *engine) +{ + QScriptValue prototype = engine->newObject(); + + // Constants + prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + // Methods + prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2)); + prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2)); + prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send)); + prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort)); + prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1)); + prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders)); + + // Read-only properties + prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + + // Constructor + QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new); + constructor.setData(prototype); + engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor); +} + +#include "qmlxmlhttprequest.moc" diff --git a/src/declarative/qml/qmlxmlhttprequest_p.h b/src/declarative/qml/qmlxmlhttprequest_p.h new file mode 100644 index 0000000..2142bc6 --- /dev/null +++ b/src/declarative/qml/qmlxmlhttprequest_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLXMLHTTPREQUEST_P_H +#define QMLXMLHTTPREQUEST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +class QScriptEngine; +void qt_add_qmlxmlhttprequest(QScriptEngine *engine); + +#endif // QMLXMLHTTPREQUEST_P_H + diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index ca159f3..a4ed054 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -161,6 +161,7 @@ int main(int argc, char ** argv) viewer.show(); viewer.open(); } + viewer.raise(); return app.exec(); } -- cgit v0.12