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 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 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 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