diff options
32 files changed, 450 insertions, 287 deletions
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/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/declarative/extra/qmlbehavior.cpp b/src/declarative/extra/qmlbehavior.cpp index b40024e..7784ef5 100644 --- a/src/declarative/extra/qmlbehavior.cpp +++ b/src/declarative/extra/qmlbehavior.cpp @@ -122,7 +122,7 @@ public: */ QmlBehavior::QmlBehavior(QObject *parent) -: QmlPropertyValueSource(*(new QmlBehaviorPrivate), parent) +: QObject(*(new QmlBehaviorPrivate), parent) { Q_D(QmlBehavior); d->group = new QParallelAnimationGroup; diff --git a/src/declarative/extra/qmlbehavior.h b/src/declarative/extra/qmlbehavior.h index 1be00c9..a4a0679 100644 --- a/src/declarative/extra/qmlbehavior.h +++ b/src/declarative/extra/qmlbehavior.h @@ -54,7 +54,7 @@ QT_MODULE(Declarative) class QmlAbstractAnimation; class QmlBehaviorPrivate; -class Q_DECLARATIVE_EXPORT QmlBehavior : public QmlPropertyValueSource +class Q_DECLARATIVE_EXPORT QmlBehavior : public QObject, public QmlPropertyValueSource { Q_OBJECT Q_DECLARE_PRIVATE(QmlBehavior) 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<QFxItem *>(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 b2c9a59..4030a0b 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/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<QAbstractItemModel*>(d->dataSource.value<QObject*>())) { + 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<int> roles; + QStringList roleNames; + QHash<int,QVariant> data; + for (QHash<int,QByteArray>::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<QObject*>()) { // A single object (i.e. list of size 1). // Properties are the roles (excluding objectName). 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 <QtDeclarative/qmlmetatype.h> #include <QtDeclarative/qmlmetaproperty.h> #include <QtDeclarative/qmlparserstatus.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> #include <QtDeclarative/qmllist.h> QT_BEGIN_HEADER diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b5edc38..764699e 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 <QtCore/qbitarray.h> #include <QtDeclarative/qmlprivate.h> #include <QtDeclarative/qmlparserstatus.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> 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<T>(), QmlPrivate::attachedPropertiesMetaObject<T>(), QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), - QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), 0, 0, 0); } @@ -191,6 +195,7 @@ int qmlRegisterType(const char *uri, int version_maj, int version_min_from, int QmlPrivate::attachedPropertiesMetaObject<T>(), QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), 0, 0, 0); } @@ -216,7 +221,8 @@ int qmlRegisterExtendedType(const char *typeName) return QmlMetaType::registerType(ids, QmlPrivate::list_nocreate_op<T>, 0, 0, 0, 0, 0, &T::staticMetaObject, attached, attachedMo, QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), - QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), &QmlPrivate::CreateParent<E>::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<T,QmlParserStatus>::cast(), - QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), &QmlPrivate::CreateParent<E>::create, &E::staticMetaObject, 0); } @@ -280,7 +287,8 @@ int qmlRegisterCustomType(const char *uri, int version_maj, int version_min_from QmlPrivate::attachedPropertiesFunc<T>(), QmlPrivate::attachedPropertiesMetaObject<T>(), QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), - QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::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 <QtDeclarative/qfxglobal.h> -#include <QtDeclarative/qml.h> -#include <QtCore/QObject> +#include <QtCore/qobject.h> 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<QObject *> &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::StoreValueSource: { - QmlPropertyValueSource *vs = - static_cast<QmlPropertyValueSource *>(stack.pop()); - QObject *target = - stack.at(stack.count() - 1 - instr.assignValueSource.owner); + QObject *obj = stack.pop(); + QmlPropertyValueSource *vs = reinterpret_cast<QmlPropertyValueSource *>(reinterpret_cast<char *>(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 cbf4114..c535045 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 ba1e430..a898be8 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) 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 <QDebug> + 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<QGraphicsItem **> 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..af137e7 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<QGraphicsScene *>(this))); + qVariantFromValue<QGraphicsScene *>(q))); QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(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,101 @@ 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<QGraphicsWidget *>(item)->windowType() == Qt::Popup) - d->addPopup(static_cast<QGraphicsWidget *>(item)); + addPopup(static_cast<QGraphicsWidget *>(item)); // Update creation order focus chain. Make sure to leave the widget's // internal tab order intact. if (item->isWidget()) { QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(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<QGraphicsWidget *>(item)); + if (activationRefCount > 0 && !activeWindow && item->isWindow()) + q->setActiveWindow(static_cast<QGraphicsWidget *>(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() || + focusScope && !focusScope->d_ptr->focusScopeItem && item->focusItem()) item->focusItem()->setFocus(); - d->updateInputMethodSensitivityInViews(); + 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; |