From b2120975bf3cae6ba9c51d79ccab8104cfc16e75 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 11 May 2009 10:55:55 +1000 Subject: Add simple loop detection to anchoring system. --- src/declarative/fx/qfxanchors.cpp | 192 +++++++++++++++---------- src/declarative/fx/qfxanchors_p.h | 6 +- tests/auto/declarative/anchors/anchors.pro | 5 + tests/auto/declarative/anchors/data/loop1.qml | 6 + tests/auto/declarative/anchors/data/loop2.qml | 18 +++ tests/auto/declarative/anchors/tst_anchors.cpp | 52 +++++++ 6 files changed, 206 insertions(+), 73 deletions(-) create mode 100644 tests/auto/declarative/anchors/anchors.pro create mode 100644 tests/auto/declarative/anchors/data/loop1.qml create mode 100644 tests/auto/declarative/anchors/data/loop2.qml create mode 100644 tests/auto/declarative/anchors/tst_anchors.cpp diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index 540e1cb..f570663 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -424,23 +424,31 @@ void QFxAnchors::updateTopAnchor() { Q_D(QFxAnchors); if (d->usedAnchors & HasTopAnchor) { - //Handle stretching - bool invalid = true; - int height = 0; - if (d->usedAnchors & HasBottomAnchor) { - invalid = d->calcStretch(d->top, d->bottom, d->topMargin, -d->bottomMargin, QFxAnchorLine::Top, height); - } else if (d->usedAnchors & HasVCenterAnchor) { - invalid = d->calcStretch(d->top, d->vCenter, d->topMargin, d->vCenterOffset, QFxAnchorLine::Top, height); - height *= 2; - } - if (!invalid) - d->item->setHeight(height); + if (!d->updatingVerticalAnchor) { + d->updatingVerticalAnchor = true; - //Handle top - if (d->top.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->top.item, d->top.anchorLine) + d->topMargin); - } else if (d->top.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->top.item, d->top.anchorLine) + d->topMargin); + //Handle stretching + bool invalid = true; + int height = 0; + if (d->usedAnchors & HasBottomAnchor) { + invalid = d->calcStretch(d->top, d->bottom, d->topMargin, -d->bottomMargin, QFxAnchorLine::Top, height); + } else if (d->usedAnchors & HasVCenterAnchor) { + invalid = d->calcStretch(d->top, d->vCenter, d->topMargin, d->vCenterOffset, QFxAnchorLine::Top, height); + height *= 2; + } + if (!invalid) + d->item->setHeight(height); + + //Handle top + if (d->top.item == d->item->itemParent()) { + d->item->setY(adjustedPosition(d->top.item, d->top.anchorLine) + d->topMargin); + } else if (d->top.item->itemParent() == d->item->itemParent()) { + d->item->setY(position(d->top.item, d->top.anchorLine) + d->topMargin); + } + + d->updatingVerticalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; } } } @@ -449,20 +457,28 @@ void QFxAnchors::updateBottomAnchor() { Q_D(QFxAnchors); if (d->usedAnchors & HasBottomAnchor) { - //Handle stretching (top + bottom case is handled in updateLeftAnchor) - if (d->usedAnchors & HasVCenterAnchor) { - int height = 0; - bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin, - QFxAnchorLine::Top, height); - if (!invalid) - d->item->setHeight(height*2); - } - - //Handle bottom - if (d->bottom.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); - } else if (d->bottom.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); + if (!d->updatingVerticalAnchor) { + d->updatingVerticalAnchor = true; + + //Handle stretching (top + bottom case is handled in updateLeftAnchor) + if (d->usedAnchors & HasVCenterAnchor) { + int height = 0; + bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin, + QFxAnchorLine::Top, height); + if (!invalid) + d->item->setHeight(height*2); + } + + //Handle bottom + if (d->bottom.item == d->item->itemParent()) { + d->item->setY(adjustedPosition(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); + } else if (d->bottom.item->itemParent() == d->item->itemParent()) { + d->item->setY(position(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); + } + + d->updatingVerticalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; } } } @@ -471,14 +487,22 @@ void QFxAnchors::updateVCenterAnchor() { Q_D(QFxAnchors); if (d->usedAnchors & HasVCenterAnchor) { - //(stetching handled in other update functions) + if (!d->updatingVerticalAnchor) { + d->updatingVerticalAnchor = true; - //Handle vCenter - if (d->vCenter.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->vCenter.item, d->vCenter.anchorLine) - - d->item->height()/2 + d->vCenterOffset); - } else if (d->vCenter.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->vCenter.item, d->vCenter.anchorLine) - d->item->height()/2 + d->vCenterOffset); + //(stetching handled in other update functions) + + //Handle vCenter + if (d->vCenter.item == d->item->itemParent()) { + d->item->setY(adjustedPosition(d->vCenter.item, d->vCenter.anchorLine) + - d->item->height()/2 + d->vCenterOffset); + } else if (d->vCenter.item->itemParent() == d->item->itemParent()) { + d->item->setY(position(d->vCenter.item, d->vCenter.anchorLine) - d->item->height()/2 + d->vCenterOffset); + } + + d->updatingVerticalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; } } } @@ -487,23 +511,31 @@ void QFxAnchors::updateLeftAnchor() { Q_D(QFxAnchors); if (d->usedAnchors & HasLeftAnchor) { - //Handle stretching - bool invalid = true; - int width = 0; - if (d->usedAnchors & HasRightAnchor) { - invalid = d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width); - } else if (d->usedAnchors & HasHCenterAnchor) { - invalid = d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width); - width *= 2; - } - if (!invalid) - d->item->setWidth(width); + if (!d->updatingHorizontalAnchor) { + d->updatingHorizontalAnchor = true; - //Handle left - if (d->left.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); - } else if (d->left.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); + //Handle stretching + bool invalid = true; + int width = 0; + if (d->usedAnchors & HasRightAnchor) { + invalid = d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width); + } else if (d->usedAnchors & HasHCenterAnchor) { + invalid = d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width); + width *= 2; + } + if (!invalid) + d->item->setWidth(width); + + //Handle left + if (d->left.item == d->item->itemParent()) { + d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); + } else if (d->left.item->itemParent() == d->item->itemParent()) { + d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); + } + + d->updatingHorizontalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; } } } @@ -512,20 +544,28 @@ void QFxAnchors::updateRightAnchor() { Q_D(QFxAnchors); if (d->usedAnchors & HasRightAnchor) { - //Handle stretching (left + right case is handled in updateLeftAnchor) - if (d->usedAnchors & HasHCenterAnchor) { - int width = 0; - bool invalid = d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, - QFxAnchorLine::Left, width); - if (!invalid) - d->item->setWidth(width*2); - } - - //Handle right - if (d->right.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } else if (d->right.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + if (!d->updatingHorizontalAnchor) { + d->updatingHorizontalAnchor = true; + + //Handle stretching (left + right case is handled in updateLeftAnchor) + if (d->usedAnchors & HasHCenterAnchor) { + int width = 0; + bool invalid = d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, + QFxAnchorLine::Left, width); + if (!invalid) + d->item->setWidth(width*2); + } + + //Handle right + if (d->right.item == d->item->itemParent()) { + d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + } else if (d->right.item->itemParent() == d->item->itemParent()) { + d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + } + + d->updatingHorizontalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; } } } @@ -534,11 +574,19 @@ void QFxAnchors::updateHCenterAnchor() { Q_D(QFxAnchors); if (d->usedAnchors & HasHCenterAnchor) { - //Handle hCenter - if (d->hCenter.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + if (!d->updatingHorizontalAnchor) { + d->updatingHorizontalAnchor = true; + + //Handle hCenter + if (d->hCenter.item == d->item->itemParent()) { + d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { + d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + } + + d->updatingHorizontalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; } } } diff --git a/src/declarative/fx/qfxanchors_p.h b/src/declarative/fx/qfxanchors_p.h index 3a5d1c7..76f83a8 100644 --- a/src/declarative/fx/qfxanchors_p.h +++ b/src/declarative/fx/qfxanchors_p.h @@ -64,7 +64,8 @@ class QFxAnchorsPrivate : public QObjectPrivate public: QFxAnchorsPrivate() : item(0), usedAnchors(0), fill(0), centeredIn(0), leftMargin(0), rightMargin(0), - topMargin(0), bottomMargin(0), vCenterOffset(0), hCenterOffset(0) + topMargin(0), bottomMargin(0), vCenterOffset(0), hCenterOffset(0), + updatingHorizontalAnchor(false), updatingVerticalAnchor(false) { } @@ -99,6 +100,9 @@ public: int bottomMargin; int vCenterOffset; int hCenterOffset; + + bool updatingHorizontalAnchor; + bool updatingVerticalAnchor; }; QT_END_NAMESPACE diff --git a/tests/auto/declarative/anchors/anchors.pro b/tests/auto/declarative/anchors/anchors.pro new file mode 100644 index 0000000..7b22cfb --- /dev/null +++ b/tests/auto/declarative/anchors/anchors.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_anchors.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/anchors/data/loop1.qml b/tests/auto/declarative/anchors/data/loop1.qml new file mode 100644 index 0000000..a4de1bf --- /dev/null +++ b/tests/auto/declarative/anchors/data/loop1.qml @@ -0,0 +1,6 @@ +Rect { + id: rect + width: 120; height: 200; color: "white" + Text { id: Text1; anchors.right: Text2.right; text: "Hello" } + Text { id: Text2; anchors.right: Text1.right; anchors.rightMargin: 10; text: "World" } +} diff --git a/tests/auto/declarative/anchors/data/loop2.qml b/tests/auto/declarative/anchors/data/loop2.qml new file mode 100644 index 0000000..4b2c74e --- /dev/null +++ b/tests/auto/declarative/anchors/data/loop2.qml @@ -0,0 +1,18 @@ +Rect { + id: container; + width: 600; + height: 600; + + Image { + id: Image1 + source: "http://labs.trolltech.com/blogs/wp-content/uploads/2009/03/3311388091_ac2a257feb.jpg" + anchors.right: Image2.left + } + + Image { + id: Image2 + source: "http://labs.trolltech.com/blogs/wp-content/uploads/2009/03/oslo_groupphoto.jpg" + anchors.left: Image1.right + anchors.leftMargin: 20 + } +} diff --git a/tests/auto/declarative/anchors/tst_anchors.cpp b/tests/auto/declarative/anchors/tst_anchors.cpp new file mode 100644 index 0000000..7d920af --- /dev/null +++ b/tests/auto/declarative/anchors/tst_anchors.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +class tst_anchors : public QObject +{ + Q_OBJECT +public: + tst_anchors() {} + +private slots: + void loops(); +}; + +// mostly testing that we don't crash +void tst_anchors::loops() +{ + { + QFxView *view = new QFxView; + + view->setUrl(QUrl("file://" SRCDIR "/data/loop1.qml")); + + //### ignoreMessage doesn't seem to work + //QTest::ignoreMessage(QtWarningMsg, "QML QFxText (unknown location): Anchor loop detected on horizontal anchor."); + //QTest::ignoreMessage(QtWarningMsg, "QML QFxText (unknown location): Anchor loop detected on horizontal anchor."); + view->execute(); + qApp->processEvents(); + + delete view; + } + + { + QFxView *view = new QFxView; + + view->setUrl(QUrl("file://" SRCDIR "/data/loop2.qml")); + + //### ignoreMessage doesn't seem to work + //QTest::ignoreMessage(QtWarningMsg, "QML QFxImage (unknown location): Anchor loop detected on horizontal anchor."); + //QTest::ignoreMessage(QtWarningMsg, "QML QFxImage (unknown location): Anchor loop detected on horizontal anchor."); + view->execute(); + qApp->processEvents(); + + delete view; + } +} + +QTEST_MAIN(tst_anchors) + +#include "tst_anchors.moc" -- cgit v0.12 From f0e828c05e8263078b0eb5a45ddea24e7a0782eb Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Mon, 11 May 2009 11:29:41 +1000 Subject: Change pathview angle. --- demos/declarative/flickr/flickr.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/declarative/flickr/flickr.qml b/demos/declarative/flickr/flickr.qml index 092aef6..fa3bc35 100644 --- a/demos/declarative/flickr/flickr.qml +++ b/demos/declarative/flickr/flickr.qml @@ -153,7 +153,7 @@ Item { } PathAttribute { name: "scale"; value: 1 } - PathAttribute { name: "angle"; value: -45 } + PathAttribute { name: "angle"; value: 45 } } } -- cgit v0.12 From 738fe5730a55279bf3c033bad7317768d81f40af Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 11:36:57 +1000 Subject: Handle QmlParserStatus's and QmlBindableValeus being deleted during component creation --- src/declarative/qml/qmlbindablevalue.cpp | 5 +++- src/declarative/qml/qmlbindablevalue_p.h | 2 ++ src/declarative/qml/qmlcompiler.cpp | 25 ++++++++++++++++---- src/declarative/qml/qmlcomponent.cpp | 40 +++++++++++++++++++++++--------- src/declarative/qml/qmlcomponent_p.h | 7 ++++-- src/declarative/qml/qmlengine.cpp | 29 +++++++++++++++++++++++ src/declarative/qml/qmlengine_p.h | 31 +++++++++++++++++++++++-- src/declarative/qml/qmlinstruction_p.h | 2 ++ src/declarative/qml/qmlparserstatus.cpp | 12 +++++++--- src/declarative/qml/qmlparserstatus.h | 7 ++++++ src/declarative/qml/qmlvme.cpp | 35 +++++++++++++++++++++------- 11 files changed, 164 insertions(+), 31 deletions(-) diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp index 3950f82..9f4886a 100644 --- a/src/declarative/qml/qmlbindablevalue.cpp +++ b/src/declarative/qml/qmlbindablevalue.cpp @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); QmlBindableValuePrivate::QmlBindableValuePrivate() -: inited(false) +: inited(false), mePtr(0) { } @@ -75,6 +75,9 @@ QmlBindableValue::QmlBindableValue(const QString &str, QObject *obj, bool sse, Q QmlBindableValue::~QmlBindableValue() { + Q_D(QmlBindableValue); + if(d->mePtr) + *(d->mePtr) = 0; } void QmlBindableValue::setTarget(const QmlMetaProperty &prop) diff --git a/src/declarative/qml/qmlbindablevalue_p.h b/src/declarative/qml/qmlbindablevalue_p.h index b6de5b7..70c001b 100644 --- a/src/declarative/qml/qmlbindablevalue_p.h +++ b/src/declarative/qml/qmlbindablevalue_p.h @@ -56,6 +56,8 @@ public: bool inited; QmlMetaProperty property; + + QmlBindableValue **mePtr; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 13fc332..5dbc5c3 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -526,6 +526,8 @@ void QmlCompiler::compileTree(Object *tree) init.type = QmlInstruction::Init; init.line = 0; init.init.dataSize = 0; + init.init.bindingsSize = 0; + init.init.parserStatusSize = 0; output->bytecode << init; if (!compileObject(tree, 0)) // Compile failed @@ -698,6 +700,8 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) QmlInstruction init; init.type = QmlInstruction::Init; init.init.dataSize = 0; + init.init.bindingsSize = 0; + init.init.parserStatusSize = 0; init.line = obj->location.start.line; output->bytecode << init; @@ -1378,6 +1382,8 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) QHash ids; int saveCount = 0; int newInstrs = 0; + int bindingsCount = 0; + int parserStatusCount = 0; for (int ii = start; ii <= end; ++ii) { const QmlInstruction &instr = output->bytecode.at(ii); @@ -1400,6 +1406,17 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) ii += instr.createComponent.count - 1; continue; } + + if (instr.type == QmlInstruction::AssignBinding || + instr.type == QmlInstruction::AssignCompiledBinding || + instr.type == QmlInstruction::StoreBinding || + instr.type == QmlInstruction::StoreCompiledBinding) { + ++bindingsCount; + } else if (instr.type == QmlInstruction::TryBeginObject || + instr.type == QmlInstruction::BeginObject) { + ++parserStatusCount; + } + if (instr.type == QmlInstruction::StoreCompiledBinding) { QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); @@ -1437,12 +1454,12 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) ++newInstrs; } } - } - + } } - if (saveCount) - output->bytecode[patch].init.dataSize = saveCount; + output->bytecode[patch].init.dataSize = saveCount; + output->bytecode[patch].init.bindingsSize = bindingsCount; + output->bytecode[patch].init.parserStatusSize = parserStatusCount;; return newInstrs; } diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 027c2a8..da8f26d 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -171,6 +171,11 @@ QmlComponent::~QmlComponent() } if (d->cc) d->cc->release(); + + for(int ii = 0; ii < d->bindValues.count(); ++ii) + QmlEnginePrivate::clear(d->bindValues[ii]); + for(int ii = 0; ii < d->parserStatus.count(); ++ii) + QmlEnginePrivate::clear(d->parserStatus[ii]); } /*! @@ -483,10 +488,10 @@ QObject *QmlComponent::beginCreate(QmlContext *context) if (ep->rootComponent == this) { ep->rootComponent = 0; - d->bindValues = ep->currentBindValues; - d->parserStatus = ep->currentParserStatus; - ep->currentBindValues.clear(); - ep->currentParserStatus.clear(); + d->bindValues = ep->bindValues; + d->parserStatus = ep->parserStatus; + ep->bindValues.clear(); + ep->parserStatus.clear(); d->completePending = true; } } else { @@ -511,16 +516,29 @@ void QmlComponent::completeCreate() #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer bi; #endif - for (int ii = 0; ii < d->bindValues.count(); ++ii) - d->bindValues.at(ii)->init(); + for (int ii = 0; ii < d->bindValues.count(); ++ii) { + QmlEnginePrivate::SimpleList bv = + d->bindValues.at(ii); + for (int jj = 0; jj < bv.count; ++jj) { + if(bv.at(jj)) + bv.at(jj)->init(); + } + QmlEnginePrivate::clear(bv); + } } - QSet done; + for (int ii = 0; ii < d->parserStatus.count(); ++ii) { - QmlParserStatus *ps = d->parserStatus.at(ii); - if (!done.contains(ps)) { - done.insert(ps); - ps->componentComplete(); + QmlEnginePrivate::SimpleList ps = + d->parserStatus.at(ii); + + for (int jj = 0; jj < ps.count; ++jj) { + QmlParserStatus *status = ps.at(jj); + if (status && status->d) { + status->d = 0; + status->componentComplete(); + } } + QmlEnginePrivate::clear(ps); } d->bindValues.clear(); diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 6a5345e..4de47c6 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -46,6 +46,7 @@ #include #include #include "private/qobject_p.h" +#include "private/qmlengine_p.h" #include "private/qmlcompositetypemanager_p.h" #include #include "qmlcomponent.h" @@ -75,8 +76,10 @@ public: int start; int count; QmlCompiledComponent *cc; - QList bindValues; - QList parserStatus; + + QList > bindValues; + QList > parserStatus; + bool completePending; QmlEngine *engine; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 50c0981..f0ec334 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -70,6 +70,7 @@ #include #include #include "private/qmlmetaproperty_p.h" +#include QT_BEGIN_NAMESPACE @@ -160,6 +161,34 @@ QmlEnginePrivate::~QmlEnginePrivate() objectClass = 0; delete networkAccessManager; networkAccessManager = 0; + + for(int ii = 0; ii < bindValues.count(); ++ii) + clear(bindValues[ii]); + for(int ii = 0; ii < parserStatus.count(); ++ii) + clear(parserStatus[ii]); +} + +void QmlEnginePrivate::clear(SimpleList &bvs) +{ + for (int ii = 0; ii < bvs.count; ++ii) { + QmlBindableValue *bv = bvs.at(ii); + if(bv) { + QmlBindableValuePrivate *p = + static_cast(QObjectPrivate::get(bv)); + p->mePtr = 0; + } + } + bvs.clear(); +} + +void QmlEnginePrivate::clear(SimpleList &pss) +{ + for (int ii = 0; ii < pss.count; ++ii) { + QmlParserStatus *ps = pss.at(ii); + if(ps) + ps->d = 0; + } + pss.clear(); } void QmlEnginePrivate::init() diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 63df0ba..9402fa9 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -107,8 +107,35 @@ public: QScriptEngine scriptEngine; - QList currentBindValues; - QList currentParserStatus; + template + struct SimpleList { + SimpleList() + : count(0), values(0) {} + SimpleList(int r) + : count(0), values(new T*[r]) {} + + int count; + T **values; + + void append(T *v) { + values[count++] = v; + } + + T *at(int idx) const { + return values[idx]; + } + + void clear() { + delete [] values; + } + }; + + static void clear(SimpleList &); + static void clear(SimpleList &); + + QList > bindValues; + QList > parserStatus; + QmlComponent *rootComponent; mutable QNetworkAccessManager *networkAccessManager; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 02e084d..86bddf8 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -173,6 +173,8 @@ public: union { struct { int dataSize; + int bindingsSize; + int parserStatusSize; } init; struct { int type; diff --git a/src/declarative/qml/qmlparserstatus.cpp b/src/declarative/qml/qmlparserstatus.cpp index 71b7adf..fceac05 100644 --- a/src/declarative/qml/qmlparserstatus.cpp +++ b/src/declarative/qml/qmlparserstatus.cpp @@ -48,11 +48,17 @@ QT_BEGIN_NAMESPACE \brief The QmlParserStatus class provides updates on the parser state. */ -/*! - Destroys the parser status instance. -*/ +/*! \internal */ +QmlParserStatus::QmlParserStatus() +: d(0) +{ +} + +/*! \internal */ QmlParserStatus::~QmlParserStatus() { + if(d) + (*d) = 0; } /*! diff --git a/src/declarative/qml/qmlparserstatus.h b/src/declarative/qml/qmlparserstatus.h index bb3691c..0e58229 100644 --- a/src/declarative/qml/qmlparserstatus.h +++ b/src/declarative/qml/qmlparserstatus.h @@ -53,11 +53,18 @@ QT_MODULE(Declarative) class Q_DECLARATIVE_EXPORT QmlParserStatus { public: + QmlParserStatus(); virtual ~QmlParserStatus(); virtual void classBegin(); virtual void classComplete(); virtual void componentComplete(); + +private: + friend class QmlVME; + friend class QmlComponent; + friend class QmlEnginePrivate; + QmlParserStatus **d; }; Q_DECLARE_INTERFACE(QmlParserStatus, "com.trolltech.qml.QmlParserStatus"); diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index ca4f9c9..e42b2fc 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -62,6 +62,8 @@ #include #include "private/qmlvmemetaobject_p.h" #include +#include +#include QT_BEGIN_NAMESPACE Q_DECLARE_PERFORMANCE_LOG(QFxCompiler) { @@ -219,9 +221,8 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer cr; #endif - - QList parserStatuses; - QList bindableValues; + QmlEnginePrivate::SimpleList bindValues; + QmlEnginePrivate::SimpleList parserStatus; QStack stack; QStack qliststack; @@ -252,6 +253,11 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in ::memset(savedObjects, 0, sizeof(QObject *)*instr.init.dataSize); } + + if (instr.init.bindingsSize) + bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); + if (instr.init.parserStatusSize) + parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); } break; @@ -523,8 +529,10 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in #endif QObject *target = stack.top(); QmlParserStatus *status = reinterpret_cast(reinterpret_cast(target) + instr.begin.castValue); + parserStatus.append(status); + status->d = &parserStatus.values[parserStatus.count - 1]; + status->classBegin(); - parserStatuses << status; } break; @@ -634,10 +642,13 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, 0); + bindValues.append(bind); + QmlBindableValuePrivate *p = + static_cast(QObjectPrivate::get(bind)); + p->mePtr = &bindValues.values[bindValues.count - 1]; QFx_setParent_noEvent(bind, target); bind->setTarget(mp); - bindableValues << bind; } break; @@ -656,10 +667,13 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, false); + bindValues.append(bind); + QmlBindableValuePrivate *p = + static_cast(QObjectPrivate::get(bind)); + p->mePtr = &bindValues.values[bindValues.count - 1]; QFx_setParent_noEvent(bind, target); bind->setTarget(mp); - bindableValues << bind; } break; @@ -1045,12 +1059,17 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in if (!stack.isEmpty()) { delete stack.at(0); } + + QmlEnginePrivate::clear(bindValues); + QmlEnginePrivate::clear(parserStatus); return 0; } QmlEnginePrivate *ep = ctxt->engine()->d_func(); - ep->currentBindValues << bindableValues; - ep->currentParserStatus << parserStatuses; + if (bindValues.count) + ep->bindValues << bindValues; + if (parserStatus.count) + ep->parserStatus << parserStatus; comp->dumpPost(); -- cgit v0.12 From 2c0907297938e1c948774b0e02b9ee6a26c3984b Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 11 May 2009 11:43:56 +1000 Subject: Lower case role names are needed. --- src/corelib/kernel/qabstractitemmodel.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index a23c137..00a3306 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -471,12 +471,12 @@ const QHash &QAbstractItemModelPrivate::defaultRoleNames() { static QHash roleNames; if (roleNames.isEmpty()) { - roleNames[Qt::DisplayRole] = "Display"; - roleNames[Qt::DecorationRole] = "Decoration"; - roleNames[Qt::EditRole] = "Edit"; - roleNames[Qt::ToolTipRole] = "ToolTip"; - roleNames[Qt::StatusTipRole] = "StatusTip"; - roleNames[Qt::WhatsThisRole] = "WhatsThis"; + roleNames[Qt::DisplayRole] = "display"; + roleNames[Qt::DecorationRole] = "decoration"; + roleNames[Qt::EditRole] = "edit"; + roleNames[Qt::ToolTipRole] = "toolTip"; + roleNames[Qt::StatusTipRole] = "statusTip"; + roleNames[Qt::WhatsThisRole] = "whatsThis"; } return roleNames; @@ -1859,6 +1859,7 @@ void QAbstractItemModel::setRoleNames(const QHash &roleNames) const QHash &QAbstractItemModel::roleNames() const { Q_D(const QAbstractItemModel); + qDebug() << "roles" << d->roleNames; return d->roleNames; } -- cgit v0.12 From 5c69031b23f349d199ed43e484a608a2b691bb95 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 11:56:34 +1000 Subject: When a QmlContext is destroyed, associated objects must be disassociated --- src/declarative/qml/qmlcontext.cpp | 12 ++++++++++++ src/declarative/qml/qmlcontext.h | 1 + src/declarative/qml/qmlcontext_p.h | 1 + src/declarative/qml/qmldeclarativedata_p.h | 1 + src/declarative/qml/qmlengine.cpp | 14 ++++++++++---- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index dfcf413..16399bc 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -231,6 +231,18 @@ QmlContext::QmlContext(QmlContext *parentContext, QObject *parent) */ QmlContext::~QmlContext() { + Q_D(QmlContext); + for(int ii = 0; ii < d->contextObjects.count(); ++ii) { + QObjectPrivate *p = QObjectPrivate::get(d->contextObjects.at(ii)); + QmlSimpleDeclarativeData *data = + static_cast(p->declarativeData); + if(data && (data->flags & QmlSimpleDeclarativeData::Extended)) { + data->context = 0; + } else { + p->declarativeData = 0; + } + } + d->contextObjects.clear(); } diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h index 39d565a..935c7ca 100644 --- a/src/declarative/qml/qmlcontext.h +++ b/src/declarative/qml/qmlcontext.h @@ -95,6 +95,7 @@ private: friend class QmlComponent; friend class QmlScriptPrivate; friend class QmlBoundSignalProxy; + friend class QmlSimpleDeclarativeData; QmlContext(QmlEngine *); }; diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index d7c6d29..9faa7b7 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -88,6 +88,7 @@ public: void addDefaultObject(QObject *, Priority); QmlSimpleDeclarativeData contextData; + QObjectList contextObjects; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index a934442..fb7a015 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -51,6 +51,7 @@ class QmlSimpleDeclarativeData : public QDeclarativeData public: QmlSimpleDeclarativeData() : flags(0), context(0) {} + virtual void destroyed(QObject *); enum Flag { Extended = 0x00000001 }; quint32 flags; QmlContext *context; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index f0ec334..fc209c6 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -659,11 +659,10 @@ void QmlEngine::setContextForObject(QObject *object, QmlContext *context) if (!data) { priv->declarativeData = &context->d_func()->contextData; } else { - // ### - Don't have to use extended data here - QmlExtendedDeclarativeData *data = new QmlExtendedDeclarativeData; data->context = context; - priv->declarativeData = data; } + + context->d_func()->contextObjects.append(object); } QmlContext *qmlContext(const QObject *obj) @@ -713,8 +712,15 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object) return rv; } -void QmlExtendedDeclarativeData::destroyed(QObject *) +void QmlSimpleDeclarativeData::destroyed(QObject *object) +{ + if (context) + context->d_func()->contextObjects.removeAll(object); +} + +void QmlExtendedDeclarativeData::destroyed(QObject *object) { + QmlSimpleDeclarativeData::destroyed(object); delete this; } -- cgit v0.12 From b9f263eb1e5871ed724452e7454b8414e554ead6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 12:13:04 +1000 Subject: Clean up QmlContext's and QmlExpression's when a context gets deleted --- src/declarative/qml/qmlcontext.cpp | 34 +++++++++++++++++++++++++++++++++- src/declarative/qml/qmlcontext_p.h | 5 +++++ src/declarative/qml/qmlengine.cpp | 12 ++++++++++-- src/declarative/qml/qmlexpression.h | 1 + 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 16399bc..df5f90e 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -86,6 +86,10 @@ void QmlContextPrivate::destroyed(QObject *obj) void QmlContextPrivate::init() { Q_Q(QmlContext); + + if (parent) + parent->d_func()->childContexts.insert(q); + //set scope chain QScriptEngine *scriptEngine = engine->scriptEngine(); QScriptValue scopeObj = @@ -232,7 +236,24 @@ QmlContext::QmlContext(QmlContext *parentContext, QObject *parent) QmlContext::~QmlContext() { Q_D(QmlContext); - for(int ii = 0; ii < d->contextObjects.count(); ++ii) { + if (d->parent) + d->parent->d_func()->childContexts.remove(this); + + for (QSet::ConstIterator iter = d->childContexts.begin(); + iter != d->childContexts.end(); + ++iter) { + (*iter)->d_func()->invalidateEngines(); + (*iter)->d_func()->parent = 0; + } + + for (QSet::ConstIterator iter = + d->childExpressions.begin(); + iter != d->childExpressions.end(); + ++iter) { + (*iter)->d->ctxt = 0; + } + + for (int ii = 0; ii < d->contextObjects.count(); ++ii) { QObjectPrivate *p = QObjectPrivate::get(d->contextObjects.at(ii)); QmlSimpleDeclarativeData *data = static_cast(p->declarativeData); @@ -245,6 +266,17 @@ QmlContext::~QmlContext() d->contextObjects.clear(); } +void QmlContextPrivate::invalidateEngines() +{ + if (!engine) + return; + engine = 0; + for (QSet::ConstIterator iter = childContexts.begin(); + iter != childContexts.end(); + ++iter) { + (*iter)->d_func()->invalidateEngines(); + } +} /*! Return the context's QmlEngine, or 0 if the context has no QmlEngine or the diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 9faa7b7..c265474 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -47,6 +47,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class QmlContext; @@ -87,6 +88,10 @@ public: }; void addDefaultObject(QObject *, Priority); + void invalidateEngines(); + QSet childContexts; + QSet childExpressions; + QmlSimpleDeclarativeData contextData; QObjectList contextObjects; }; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index fc209c6..c39a0d5 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -805,6 +805,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, d->ctxt = ctxt; if(ctxt && ctxt->engine()) d->id = ctxt->engine()->d_func()->getUniqueId(); + if(ctxt) + ctxt->d_func()->childExpressions.insert(this); d->me = me; } @@ -816,6 +818,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr, d->ctxt = ctxt; if(ctxt && ctxt->engine()) d->id = ctxt->engine()->d_func()->getUniqueId(); + if(ctxt) + ctxt->d_func()->childExpressions.insert(this); d->me = me; } @@ -833,6 +837,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, d->ctxt = ctxt; if(ctxt && ctxt->engine()) d->id = ctxt->engine()->d_func()->getUniqueId(); + if(ctxt) + ctxt->d_func()->childExpressions.insert(this); d->me = scope; } @@ -841,6 +847,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, */ QmlExpression::~QmlExpression() { + if (d->ctxt) + d->ctxt->d_func()->childExpressions.remove(this); delete d; d = 0; } @@ -850,7 +858,7 @@ QmlExpression::~QmlExpression() */ QmlEngine *QmlExpression::engine() const { - return d->ctxt->engine(); + return d->ctxt?d->ctxt->engine():0; } /*! @@ -927,7 +935,7 @@ void BindExpressionProxy::changed() QVariant QmlExpression::value() { QVariant rv; - if (!d->ctxt || (!d->sse.isValid() && d->expression.isEmpty())) + if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty())) return rv; #ifdef Q_ENABLE_PERFORMANCE_LOG diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index bb6980a..2c6b1ad 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -87,6 +87,7 @@ protected: private: friend class BindExpressionProxy; friend class QmlDebugger; + friend class QmlContext; QmlExpressionPrivate *d; }; -- cgit v0.12 From 9edfcd1ecd905ca27fbe9f241e37ab5fb204f89a Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 13:10:28 +1000 Subject: Update repaint region when removing items --- src/declarative/canvas/qsimplecanvasitem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/declarative/canvas/qsimplecanvasitem.cpp b/src/declarative/canvas/qsimplecanvasitem.cpp index ba33a41..90ee688 100644 --- a/src/declarative/canvas/qsimplecanvasitem.cpp +++ b/src/declarative/canvas/qsimplecanvasitem.cpp @@ -1332,6 +1332,7 @@ QSimpleCanvasItem::~QSimpleCanvasItem() parent()->remChild(this); delete d->graphicsItem; } else { + update(); setOptions(MouseFilter, false); if (d->canvas){ -- cgit v0.12 From 8bb9edaeda5e14df3402c5990a0630a664048ac9 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Mon, 11 May 2009 13:15:05 +1000 Subject: Compile --- src/declarative/qml/qmlcontext_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index c265474..99dc669 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE class QmlContext; +class QmlExpression; class QmlEngine; class QmlCompiledComponent; -- cgit v0.12 From 865c022c2df25496055de897f37f8206cb4fc730 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 11 May 2009 13:21:05 +1000 Subject: d-pointerize QmlOpenMetaObject --- src/declarative/fx/qfxvisualitemmodel.cpp | 1 + src/declarative/qml/qmlcontext_p.h | 1 + src/declarative/util/qmlopenmetaobject.cpp | 120 +++++++++++++++++------------ src/declarative/util/qmlopenmetaobject.h | 17 ++-- 4 files changed, 78 insertions(+), 61 deletions(-) diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp index 9428281..61f08de 100644 --- a/src/declarative/fx/qfxvisualitemmodel.cpp +++ b/src/declarative/fx/qfxvisualitemmodel.cpp @@ -47,6 +47,7 @@ #include "qhash.h" #include "qlist.h" #include "private/qobject_p.h" +#include "private/qmetaobjectbuilder_p.h" #include "qmlopenmetaobject.h" #include "qmllistaccessor.h" #include "qfxvisualitemmodel.h" diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index c265474..97a816c 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE class QmlContext; class QmlEngine; +class QmlExpression; class QmlCompiledComponent; class QmlContextPrivate : public QObjectPrivate diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp index fc20fa9..d0dd817 100644 --- a/src/declarative/util/qmlopenmetaobject.cpp +++ b/src/declarative/util/qmlopenmetaobject.cpp @@ -40,102 +40,124 @@ ****************************************************************************/ #include "qmlopenmetaobject.h" +#include "private/qmetaobjectbuilder_p.h" #include QT_BEGIN_NAMESPACE + +class QmlOpenMetaObjectPrivate +{ +public: + QmlOpenMetaObjectPrivate() : parent(0), mem(0) {} + + bool autoCreate; + QAbstractDynamicMetaObject *parent; + int propertyOffset; + int signalOffset; + QList data; + QHash names; + QMetaObjectBuilder mob; + QMetaObject *mem; + QObject *object; +}; + QmlOpenMetaObject::QmlOpenMetaObject(QObject *obj, bool automatic) -: autoCreate(automatic), parent(0), mem(0), _object(obj) +: d(new QmlOpenMetaObjectPrivate) { - mob.setSuperClass(obj->metaObject()); - mob.setClassName(obj->metaObject()->className()); - mob.setFlags(QMetaObjectBuilder::DynamicMetaObject); + d->autoCreate = automatic; + d->object = obj; + + d->mob.setSuperClass(obj->metaObject()); + d->mob.setClassName(obj->metaObject()->className()); + d->mob.setFlags(QMetaObjectBuilder::DynamicMetaObject); QObjectPrivate *op = QObjectPrivate::get(obj); if (op->metaObject) - mob.setSuperClass(op->metaObject); + d->mob.setSuperClass(op->metaObject); - mem = mob.toMetaObject(); - *static_cast(this) = *mem; + d->mem = d->mob.toMetaObject(); + *static_cast(this) = *d->mem; op->metaObject = this; - _propertyOffset = propertyOffset(); - _signalOffset = methodOffset(); + d->propertyOffset = propertyOffset(); + d->signalOffset = methodOffset(); } QmlOpenMetaObject::~QmlOpenMetaObject() { - if (parent) - delete parent; - qFree(mem); + if (d->parent) + delete d->parent; + qFree(d->mem); + delete d; } int QmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) { if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) - && id >= _propertyOffset) { - int propId = id - _propertyOffset; + && id >= d->propertyOffset) { + int propId = id - d->propertyOffset; if (c == QMetaObject::ReadProperty) { propertyRead(propId); - *reinterpret_cast(a[0]) = data[propId]; + *reinterpret_cast(a[0]) = d->data[propId]; } else if (c == QMetaObject::WriteProperty) { - if (data[propId] != *reinterpret_cast(a[0])) { + if (d->data[propId] != *reinterpret_cast(a[0])) { propertyWrite(propId); - data[propId] = *reinterpret_cast(a[0]); - activate(_object, _signalOffset + propId, 0); + d->data[propId] = *reinterpret_cast(a[0]); + activate(d->object, d->signalOffset + propId, 0); } } return -1; } else { - if (parent) - return parent->metaCall(c, id, a); + if (d->parent) + return d->parent->metaCall(c, id, a); else - return _object->qt_metacall(c, id, a); + return d->object->qt_metacall(c, id, a); } } QVariant QmlOpenMetaObject::value(int id) const { - Q_ASSERT(id >= 0 && id < data.count()); - return data.at(id); + Q_ASSERT(id >= 0 && id < d->data.count()); + return d->data.at(id); } void QmlOpenMetaObject::setValue(int id, const QVariant &value) { - Q_ASSERT(id >= 0 && id < data.count()); - data[id] = value; - activate(_object, id + _signalOffset, 0); + Q_ASSERT(id >= 0 && id < d->data.count()); + d->data[id] = value; + activate(d->object, id + d->signalOffset, 0); } QVariant QmlOpenMetaObject::value(const QByteArray &name) const { - QHash::ConstIterator iter = names.find(name); - if (iter == names.end()) + QHash::ConstIterator iter = d->names.find(name); + if (iter == d->names.end()) return QVariant(); - return data.at(*iter); + return d->data.at(*iter); } void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { - QHash::ConstIterator iter = names.find(name); + QHash::ConstIterator iter = d->names.find(name); int id = -1; - if (iter == names.end()) { - id = doCreateProperty(name.constData()) - _propertyOffset; + if (iter == d->names.end()) { + id = doCreateProperty(name.constData()) - d->propertyOffset; } else { id = *iter; } - if (data[id] == val) + if (d->data[id] == val) return; - data[id] = val; - activate(_object, id + _signalOffset, 0); + d->data[id] = val; + activate(d->object, id + d->signalOffset, 0); } int QmlOpenMetaObject::createProperty(const char *name, const char *) { - if (autoCreate) + if (d->autoCreate) return doCreateProperty(name); else return -1; @@ -143,17 +165,17 @@ int QmlOpenMetaObject::createProperty(const char *name, const char *) int QmlOpenMetaObject::doCreateProperty(const char *name) { - int id = mob.propertyCount(); - mob.addSignal("__" + QByteArray::number(id) + "()"); - QMetaPropertyBuilder build = mob.addProperty(name, "QVariant", id); + int id = d->mob.propertyCount(); + d->mob.addSignal("__" + QByteArray::number(id) + "()"); + QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id); build.setDynamic(true); - data << propertyCreated(id, build); - qFree(mem); - mem = mob.toMetaObject(); - *static_cast(this) = *mem; - names.insert(name, id); + d->data << propertyCreated(id, build); + qFree(d->mem); + d->mem = d->mob.toMetaObject(); + *static_cast(this) = *d->mem; + d->names.insert(name, id); - return _propertyOffset + id; + return d->propertyOffset + id; } void QmlOpenMetaObject::propertyRead(int) @@ -171,19 +193,19 @@ QVariant QmlOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &) int QmlOpenMetaObject::count() const { - return data.count(); + return d->data.count(); } QByteArray QmlOpenMetaObject::name(int idx) const { - Q_ASSERT(idx >= 0 && idx < data.count()); + Q_ASSERT(idx >= 0 && idx < d->data.count()); - return mob.property(idx).name(); + return d->mob.property(idx).name(); } QObject *QmlOpenMetaObject::object() const { - return _object; + return d->object; } QT_END_NAMESPACE diff --git a/src/declarative/util/qmlopenmetaobject.h b/src/declarative/util/qmlopenmetaobject.h index 17cecd87..f842f96 100644 --- a/src/declarative/util/qmlopenmetaobject.h +++ b/src/declarative/util/qmlopenmetaobject.h @@ -43,16 +43,16 @@ #define QMLOPENMETAOBJECT_H #include -#include "private/qmetaobjectbuilder_p.h" -#include +#include #include - QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class QmlOpenMetaObjectPrivate; +class QMetaPropertyBuilder; class Q_DECLARATIVE_EXPORT QmlOpenMetaObject : public QAbstractDynamicMetaObject { public: @@ -78,15 +78,8 @@ protected: private: int doCreateProperty(const char *); - bool autoCreate; - QAbstractDynamicMetaObject *parent; - int _propertyOffset; - int _signalOffset; - QList data; - QHash names; - QMetaObjectBuilder mob; - QMetaObject *mem; - QObject *_object; + + QmlOpenMetaObjectPrivate *d; }; -- cgit v0.12 From 62ca28e8bfd469a227f7099eb0c2e76b0b2cb2e8 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 11 May 2009 13:33:09 +1000 Subject: Detect binding loops. Don't crash when a looping binding has been established. Instead, print a warning and stop looping. --- src/declarative/qml/qmlbindablevalue.cpp | 185 +++++++++++---------- src/declarative/qml/qmlbindablevalue_p.h | 1 + .../qmlbindengine/tst_qmlbindengine.cpp | 39 ++++- 3 files changed, 135 insertions(+), 90 deletions(-) diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp index 9f4886a..d5157b6 100644 --- a/src/declarative/qml/qmlbindablevalue.cpp +++ b/src/declarative/qml/qmlbindablevalue.cpp @@ -43,16 +43,17 @@ #include "qmlbindablevalue.h" #include "qmlbindablevalue_p.h" #include +#include #include #include #include - QT_BEGIN_NAMESPACE + DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); QmlBindableValuePrivate::QmlBindableValuePrivate() -: inited(false), mePtr(0) +: inited(false), updating(false), mePtr(0) { } @@ -121,102 +122,110 @@ void QmlBindableValue::update() if (!d->inited) return; - if (d->property.propertyCategory() == QmlMetaProperty::List) { - QVariant value = this->value(); - int listType = QmlMetaType::listType(d->property.propertyType()); - - if (value.userType() == qMetaTypeId >()) { - const QList &list = - qvariant_cast >(value); - QVariant listVar = d->property.read(); - QmlMetaType::clear(listVar); - for (int ii = 0; ii < list.count(); ++ii) { - QVariant v = QmlMetaType::fromObject(list.at(ii), listType); - QmlMetaType::append(listVar, v); - } + if (!d->updating) { + d->updating = true; + + if (d->property.propertyCategory() == QmlMetaProperty::List) { + QVariant value = this->value(); + int listType = QmlMetaType::listType(d->property.propertyType()); + + if (value.userType() == qMetaTypeId >()) { + const QList &list = + qvariant_cast >(value); + QVariant listVar = d->property.read(); + QmlMetaType::clear(listVar); + for (int ii = 0; ii < list.count(); ++ii) { + QVariant v = QmlMetaType::fromObject(list.at(ii), listType); + QmlMetaType::append(listVar, v); + } - } else if (value.type() == uint(listType) || - value.userType() == listType) { - QVariant listVar = d->property.read(); - QmlMetaType::clear(listVar); - QmlMetaType::append(listVar, value); - } - } else if (d->property.propertyCategory() == QmlMetaProperty::QmlList) { - // XXX - optimize! - QVariant value = this->value(); - QVariant list = d->property.read(); - QmlPrivate::ListInterface *li = - *(QmlPrivate::ListInterface **)list.constData(); - - int type = li->type(); - - if (QObject *obj = QmlMetaType::toQObject(value)) { - const QMetaObject *mo = - QmlMetaType::rawMetaObjectForType(type); - - const QMetaObject *objMo = obj->metaObject(); - bool found = false; - while(!found && objMo) { - if (objMo == mo) - found = true; - else - objMo = objMo->superClass(); + } else if (value.type() == uint(listType) || + value.userType() == listType) { + QVariant listVar = d->property.read(); + QmlMetaType::clear(listVar); + QmlMetaType::append(listVar, value); } + } else if (d->property.propertyCategory() == QmlMetaProperty::QmlList) { + // XXX - optimize! + QVariant value = this->value(); + QVariant list = d->property.read(); + QmlPrivate::ListInterface *li = + *(QmlPrivate::ListInterface **)list.constData(); + + int type = li->type(); + + if (QObject *obj = QmlMetaType::toQObject(value)) { + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(type); + + const QMetaObject *objMo = obj->metaObject(); + bool found = false; + while(!found && objMo) { + if (objMo == mo) + found = true; + else + objMo = objMo->superClass(); + } - if (!found) { - qWarning() << "Unable to assign object to list"; - return; - } + if (!found) { + qWarning() << "Unable to assign object to list"; + return; + } - // NOTE: This assumes a cast to QObject does not alter - // the object pointer - void *d = (void *)&obj; - li->append(d); - } - } else if (d->property.propertyCategory() == QmlMetaProperty::Bindable) { - - // NOTE: We assume that only core properties can have - // propertyType == Bindable - int idx = d->property.coreIndex(); - Q_ASSERT(idx != -1); - - void *a[1]; - QmlBindableValue *t = this; - a[0] = (void *)&t; - d->property.object()->qt_metacall(QMetaObject::WriteProperty, - idx, a); - - } else if (d->property.propertyCategory() == QmlMetaProperty::Object) { - - QVariant value = this->value(); - if ((int)value.type() != qMetaTypeId()) { - if (scriptWarnings()) { - if (!value.isValid()) { - qWarning() << "QmlBindableValue: Unable to assign invalid value to object property"; - } else { - qWarning() << "QmlBindableValue: Unable to assign non-object to object property"; + // NOTE: This assumes a cast to QObject does not alter + // the object pointer + void *d = (void *)&obj; + li->append(d); + } + } else if (d->property.propertyCategory() == QmlMetaProperty::Bindable) { + + // NOTE: We assume that only core properties can have + // propertyType == Bindable + int idx = d->property.coreIndex(); + Q_ASSERT(idx != -1); + + void *a[1]; + QmlBindableValue *t = this; + a[0] = (void *)&t; + d->property.object()->qt_metacall(QMetaObject::WriteProperty, + idx, a); + + } else if (d->property.propertyCategory() == QmlMetaProperty::Object) { + + QVariant value = this->value(); + if ((int)value.type() != qMetaTypeId()) { + if (scriptWarnings()) { + if (!value.isValid()) { + qWarning() << "QmlBindableValue: Unable to assign invalid value to object property"; + } else { + qWarning() << "QmlBindableValue: Unable to assign non-object to object property"; + } } + return; } - return; - } - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - QObject *obj = *(QObject **)value.data(); + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *obj = *(QObject **)value.data(); + + // NOTE: We assume that only core properties can have + // propertyType == Object + int idx = d->property.coreIndex(); + Q_ASSERT(idx != -1); - // NOTE: We assume that only core properties can have - // propertyType == Object - int idx = d->property.coreIndex(); - Q_ASSERT(idx != -1); + void *a[1]; + a[0] = (void *)&obj; + d->property.object()->qt_metacall(QMetaObject::WriteProperty, + idx, a); - void *a[1]; - a[0] = (void *)&obj; - d->property.object()->qt_metacall(QMetaObject::WriteProperty, - idx, a); + } else if (d->property.propertyCategory() == QmlMetaProperty::Normal) { + QVariant value = this->value(); + d->property.write(value); + } - } else if (d->property.propertyCategory() == QmlMetaProperty::Normal) { - QVariant value = this->value(); - d->property.write(value); + d->updating = false; + } else { + qmlInfo(d->property.object()) << "Binding loop detected for property" << d->property.name(); } } diff --git a/src/declarative/qml/qmlbindablevalue_p.h b/src/declarative/qml/qmlbindablevalue_p.h index 70c001b..d9af0ef 100644 --- a/src/declarative/qml/qmlbindablevalue_p.h +++ b/src/declarative/qml/qmlbindablevalue_p.h @@ -55,6 +55,7 @@ public: QmlBindableValuePrivate(); bool inited; + bool updating; QmlMetaProperty property; QmlBindableValue **mePtr; diff --git a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp index 0875690..ca840f4 100644 --- a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp +++ b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp @@ -7,7 +7,7 @@ class MyQmlObject : public QObject Q_OBJECT Q_PROPERTY(bool trueProperty READ trueProperty) Q_PROPERTY(bool falseProperty READ falseProperty) - Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) + Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) public: MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false) {} @@ -15,7 +15,13 @@ public: bool falseProperty() const { return false; } QString stringProperty() const { return m_string; } - void setStringProperty(const QString &s) { m_string = s; } + void setStringProperty(const QString &s) + { + if (s == m_string) + return; + m_string = s; + emit stringChanged(); + } bool methodCalled() const { return m_methodCalled; } bool methodIntCalled() const { return m_methodIntCalled; } @@ -24,6 +30,7 @@ public: signals: void basicSignal(); void argumentSignal(int a, QString b, qreal c); + void stringChanged(); public slots: void method() { m_methodCalled = true; } @@ -41,6 +48,22 @@ private: QML_DECLARE_TYPE(MyQmlObject); QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); +class MyQmlContainer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QList* children READ children) +public: + MyQmlContainer() {} + + QList *children() { return &m_children; } + +private: + QList m_children; +}; + +QML_DECLARE_TYPE(MyQmlContainer); +QML_DEFINE_TYPE(MyQmlContainer,MyQmlContainer); + class tst_qmlbindengine : public QObject { Q_OBJECT @@ -51,6 +74,7 @@ private slots: void boolPropertiesEvaluateAsBool(); void methods(); void signalAssignment(); + void bindingLoop(); private: QmlEngine engine; @@ -117,6 +141,17 @@ void tst_qmlbindengine::methods() QCOMPARE(object->methodIntCalled(), true); } } +#include +void tst_qmlbindengine::bindingLoop() +{ + QmlComponent component(&engine, "MyQmlContainer { children : [ "\ + "MyQmlObject { id: Object1; stringProperty: \"hello\" + Object2.stringProperty }, "\ + "MyQmlObject { id: Object2; stringProperty: \"hello\" + Object1.stringProperty } ] }"); + //### ignoreMessage doesn't seem to work here + //QTest::ignoreMessage(QtWarningMsg, "QML MyQmlObject (unknown location): Binding loop detected for property \"stringProperty\""); + QObject *object = component.create(); + QVERIFY(object != 0); +} QTEST_MAIN(tst_qmlbindengine) -- cgit v0.12 From 0d8c3504eb13ab45955cb80d7fa8062e2bf1a1a5 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 11 May 2009 13:34:55 +1000 Subject: Apply a states binding changes even if there is no transition. --- src/declarative/util/qmlstate.cpp | 17 +++++++++++------ src/declarative/util/qmlstate_p.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index cd33f5e..194cc1b 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -247,17 +247,20 @@ static void dump(const QmlStateOperation::ActionList &list) } #endif -void QmlStatePrivate::complete() +void QmlStatePrivate::applyBindings() { - Q_Q(QmlState); - //apply bindings (now that all transitions are complete) - ////////////////////////////////////////////////////////// foreach(const Action &action, bindingsList) { if (action.bv && !action.toBinding.isEmpty()) { action.bv->setExpression(action.toBinding); } } - ////////////////////////////////////////////////////////// +} + +void QmlStatePrivate::complete() +{ + Q_Q(QmlState); + //apply bindings (now that all transitions are complete) + applyBindings(); for (int ii = 0; ii < reverting.count(); ++ii) { for (int jj = 0; jj < revertList.count(); ++jj) { @@ -369,7 +372,7 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever a.toValue = d->revertList.at(ii).value; a.toBinding = d->revertList.at(ii).binding; if (!a.toBinding.isEmpty()) { - a.fromBinding = d->revertList.at(ii).bv->expression(); //### relies on clearExpression not clearing string + a.fromBinding = d->revertList.at(ii).bv->expression(); a.bv = d->revertList.at(ii).bv; } applyList << a; @@ -456,6 +459,8 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever else action.property.write(action.toValue); } + if (!trans) + d->applyBindings(); //### merge into above foreach? } QML_DEFINE_TYPE(QmlStateOperation,StateOperation); diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h index 20d1c1a..28e1781 100644 --- a/src/declarative/util/qmlstate_p.h +++ b/src/declarative/util/qmlstate_p.h @@ -69,6 +69,7 @@ public: QmlStateGroup *group; QmlStateOperation::ActionList generateActionList(QmlStateGroup *) const; + void applyBindings(); void complete(); }; -- cgit v0.12 From 56010993aaa90f39379f38f51b7975d8a72f56f4 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 11 May 2009 13:40:48 +1000 Subject: Remove debug. --- src/declarative/fx/qfxtextedit.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 3bc9696..42f5743 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -821,7 +821,6 @@ void QFxTextEditPrivate::updateDefaultTextOption() QTextOption::WrapMode oldWrapMode = opt.wrapMode(); -qDebug() << "wrap mode is" << opt.wrapMode(); if (wrap) opt.setWrapMode(QTextOption::WordWrap); else @@ -829,7 +828,6 @@ qDebug() << "wrap mode is" << opt.wrapMode(); if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment()) return; -qDebug() << "wrap mode set to" << opt.wrapMode(); document->setDefaultTextOption(opt); } -- cgit v0.12 From 554999e97a350b3c04123a6ef03d21a841ab73ad Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 13:58:38 +1000 Subject: Fix crash Component {} would crash the compiler. --- src/declarative/qml/qmlcompiler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 5dbc5c3..a40b7c8 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -665,6 +665,9 @@ bool QmlCompiler::compileComponent(Object *obj, int ctxt) if (obj->defaultProperty && obj->defaultProperty->values.count()) root = obj->defaultProperty->values.first()->object; + if (!root) + COMPILE_EXCEPTION("Cannot create empty component specification"); + COMPILE_CHECK(compileComponentFromRoot(root, ctxt)); if (idProp && idProp->values.count()) { -- cgit v0.12 From c0f26c449d0d20915b65af6172ede1dc5659ba01 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 15:15:16 +1000 Subject: Add context property test --- .../qmlbindengine/tst_qmlbindengine.cpp | 30 +++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp index ca840f4..c63caf4 100644 --- a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp +++ b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include class MyQmlObject : public QObject { @@ -75,6 +77,7 @@ private slots: void methods(); void signalAssignment(); void bindingLoop(); + void contextPropertiesTriggerReeval(); private: QmlEngine engine; @@ -141,7 +144,7 @@ void tst_qmlbindengine::methods() QCOMPARE(object->methodIntCalled(), true); } } -#include + void tst_qmlbindengine::bindingLoop() { QmlComponent component(&engine, "MyQmlContainer { children : [ "\ @@ -153,6 +156,31 @@ void tst_qmlbindengine::bindingLoop() QVERIFY(object != 0); } +class MyExpression : public QmlExpression +{ +public: + MyExpression(QmlContext *ctxt, const QString &expr) + : QmlExpression(ctxt, expr, 0), changed(false) + { + } + + bool changed; +}; + +void tst_qmlbindengine::contextPropertiesTriggerReeval() +{ + QmlContext context(engine.rootContext()); + context.setContextProperty("testProp", QVariant(1)); + + MyExpression expr(&context, "testProp + 1"); + QCOMPARE(expr.changed, false); + QCOMPARE(expr.value(), QVariant(2)); + + context.setContextProperty("testProp", QVariant(2)); + QCOMPARE(expr.changed, true); + QCOMPARE(expr.value(), QVariant(3)); +} + QTEST_MAIN(tst_qmlbindengine) #include "tst_qmlbindengine.moc" -- cgit v0.12 From 04599cd17221b269028cab81054525a7f0a0e394 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Mon, 11 May 2009 15:30:14 +1000 Subject: Fix webbrowser demo --- demos/declarative/webbrowser/content/RectSoftShadow.qml | 2 +- demos/declarative/webbrowser/content/pics/footer.sci | 6 ++++++ demos/declarative/webbrowser/webbrowser.qml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 demos/declarative/webbrowser/content/pics/footer.sci diff --git a/demos/declarative/webbrowser/content/RectSoftShadow.qml b/demos/declarative/webbrowser/content/RectSoftShadow.qml index 5817f00..1734433 100644 --- a/demos/declarative/webbrowser/content/RectSoftShadow.qml +++ b/demos/declarative/webbrowser/content/RectSoftShadow.qml @@ -24,7 +24,7 @@ Item { source: "pics/softshadow-bottom.png" x: 0 y: parent.height - width: webview.width*webview.scale + width: WebView.width*WebView.scale height: 16 } } diff --git a/demos/declarative/webbrowser/content/pics/footer.sci b/demos/declarative/webbrowser/content/pics/footer.sci new file mode 100644 index 0000000..be1d086 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/footer.sci @@ -0,0 +1,6 @@ +gridLeft: 5 +gridTop: 0 +gridBottom: 0 +gridRight: 5 +imageFile: footer.png + diff --git a/demos/declarative/webbrowser/webbrowser.qml b/demos/declarative/webbrowser/webbrowser.qml index c754543..4b03b63 100644 --- a/demos/declarative/webbrowser/webbrowser.qml +++ b/demos/declarative/webbrowser/webbrowser.qml @@ -73,7 +73,7 @@ Item { color: "white" styleColor: "black" - style: Raised + style: "Raised" font.family: "Helvetica" font.size: 10 @@ -85,7 +85,7 @@ Item { anchors.rightMargin: 4 anchors.top: Header.top anchors.topMargin: 4 - hAlign: AlignHCenter + hAlign: "AlignHCenter" } Item { width: parent.width -- cgit v0.12 From 692931ae2fec4fa8fc4ebcbcff20c952d6319536 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 11 May 2009 15:53:34 +1000 Subject: Add support for removing anchors. This makes it possible to remove an anchor that was previously set. Trying to set a new anchor after one was removed isn't working yet. --- src/declarative/fx/qfxanchors.cpp | 344 ++++++++++++++++--------- src/declarative/fx/qfxanchors.h | 30 ++- src/declarative/fx/qfxanchors_p.h | 4 +- tests/auto/declarative/anchors/tst_anchors.cpp | 2 +- 4 files changed, 238 insertions(+), 142 deletions(-) diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index f570663..53d0187 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -43,9 +43,10 @@ #include "qfxitem.h" #include #include - +#include QT_BEGIN_NAMESPACE + QML_DEFINE_TYPE(QFxAnchors,Anchors); //TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)? @@ -227,7 +228,7 @@ void QFxAnchors::setCenteredIn(QFxItem* c) setVerticalCenter(c->verticalCenter()); } -void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge, const char *slotString) +void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge) { //### should we do disconnects first? (will it be called more than once?) Q_Q(QFxAnchors); @@ -235,7 +236,7 @@ void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge, const char *sl switch(edge.anchorLine) { case QFxAnchorLine::Bottom: case QFxAnchorLine::VCenter: - QObject::connect(edge.item, SIGNAL(heightChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(heightChanged()), q, SLOT(updateVerticalAnchors())); break; case QFxAnchorLine::Top: //no connection needed default: @@ -244,13 +245,13 @@ void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge, const char *sl } else if (edge.item->itemParent() == item->itemParent()) { //siblings switch(edge.anchorLine) { case QFxAnchorLine::Top: - QObject::connect(edge.item, SIGNAL(topChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(topChanged()), q, SLOT(updateVerticalAnchors())); break; case QFxAnchorLine::Bottom: - QObject::connect(edge.item, SIGNAL(bottomChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(bottomChanged()), q, SLOT(updateVerticalAnchors())); break; case QFxAnchorLine::VCenter: - QObject::connect(edge.item, SIGNAL(vcenterChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(vcenterChanged()), q, SLOT(updateVerticalAnchors())); break; default: break; @@ -267,49 +268,44 @@ void QFxAnchors::connectVAnchors() return; if (d->usedAnchors & HasTopAnchor) { - const char *slotStr = SLOT(updateTopAnchor()); - //Handle stretching connections (if we have multiple horizontal anchors) QFxAnchorLine *edge = 0; if (d->usedAnchors & HasBottomAnchor) { edge = &d->bottom; - connect(this, SIGNAL(bottomMarginChanged()), this, slotStr); + connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); } else if (d->usedAnchors & HasVCenterAnchor) { edge = &d->vCenter; - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, slotStr); + connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); } if (edge) { //we need to stretch - d->connectVHelper(*edge, slotStr); + d->connectVHelper(*edge); } //Handle top - d->connectVHelper(d->top, slotStr); - connect(this, SIGNAL(topMarginChanged()), this, slotStr); - updateTopAnchor(); + d->connectVHelper(d->top); + connect(this, SIGNAL(topMarginChanged()), this, SLOT(updateVerticalAnchors())); + updateVerticalAnchors(); } else if (d->usedAnchors & HasBottomAnchor) { - const char *slotStr = SLOT(updateBottomAnchor()); - //Handle stretching connections (if we have multiple horizontal anchors) if (d->usedAnchors & HasVCenterAnchor) { - d->connectVHelper(d->vCenter, slotStr); - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, slotStr); + d->connectVHelper(d->vCenter); + connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); } //Handle bottom - d->connectVHelper(d->bottom, slotStr); - connect(this, SIGNAL(bottomMarginChanged()), this, slotStr); - updateBottomAnchor(); + d->connectVHelper(d->bottom); + connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); + updateVerticalAnchors(); } else if (d->usedAnchors & HasVCenterAnchor) { //Handle vCenter - const char *slotStr = SLOT(updateVCenterAnchor()); - d->connectVHelper(d->vCenter, slotStr); - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, slotStr); - updateVCenterAnchor(); + d->connectVHelper(d->vCenter); + connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); + updateVerticalAnchors(); } } -void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge, const char *slotString) +void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge) { //### should we do disconnects first? (will it be called more than once?) Q_Q(QFxAnchors); @@ -317,7 +313,7 @@ void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge, const char *sl switch(edge.anchorLine) { case QFxAnchorLine::Right: case QFxAnchorLine::HCenter: - QObject::connect(edge.item, SIGNAL(widthChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(widthChanged()), q, SLOT(updateHorizontalAnchors())); break; case QFxAnchorLine::Left: //no connection needed default: @@ -326,13 +322,13 @@ void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge, const char *sl } else if (edge.item->itemParent() == item->itemParent()) { //siblings switch(edge.anchorLine) { case QFxAnchorLine::Left: - QObject::connect(edge.item, SIGNAL(leftChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(leftChanged()), q, SLOT(updateHorizontalAnchors())); break; case QFxAnchorLine::Right: - QObject::connect(edge.item, SIGNAL(rightChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(rightChanged()), q, SLOT(updateHorizontalAnchors())); break; case QFxAnchorLine::HCenter: - QObject::connect(edge.item, SIGNAL(hcenterChanged()), q, slotString); + QObject::connect(edge.item, SIGNAL(hcenterChanged()), q, SLOT(updateHorizontalAnchors())); break; default: break; @@ -349,45 +345,40 @@ void QFxAnchors::connectHAnchors() return; if (d->usedAnchors & HasLeftAnchor) { - const char *slotStr = SLOT(updateLeftAnchor()); - //Handle stretching connections (if we have multiple horizontal anchors) QFxAnchorLine *edge = 0; if (d->usedAnchors & HasRightAnchor) { edge = &d->right; - connect(this, SIGNAL(rightMarginChanged()), this, slotStr); + connect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); } else if (d->usedAnchors & HasHCenterAnchor) { edge = &d->hCenter; - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, slotStr); + connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); } if (edge) { //we need to stretch - d->connectHHelper(*edge, slotStr); + d->connectHHelper(*edge); } //Handle left - d->connectHHelper(d->left, slotStr); - connect(this, SIGNAL(leftMarginChanged()), this, slotStr); - updateLeftAnchor(); + d->connectHHelper(d->left); + connect(this, SIGNAL(leftMarginChanged()), this, SLOT(updateHorizontalAnchors())); + updateHorizontalAnchors(); } else if (d->usedAnchors & HasRightAnchor) { - const char *slotStr = SLOT(updateRightAnchor()); - //Handle stretching connections (if we have multiple horizontal anchors) if (d->usedAnchors & HasHCenterAnchor) { - d->connectHHelper(d->hCenter, slotStr); - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, slotStr); + d->connectHHelper(d->hCenter); + connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); } //Handle right - d->connectHHelper(d->right, slotStr); - connect(this, SIGNAL(rightMarginChanged()), this, slotStr); - updateRightAnchor(); + d->connectHHelper(d->right); + connect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); + updateHorizontalAnchors(); } else if (d->usedAnchors & HasHCenterAnchor) { //Handle hCenter - const char *slotStr = SLOT(updateHCenterAnchor()); - d->connectHHelper(d->hCenter, slotStr); - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, slotStr); - updateHCenterAnchor(); + d->connectHHelper(d->hCenter); + connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); + updateHorizontalAnchors(); } } @@ -420,13 +411,12 @@ bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1, return invalid; } -void QFxAnchors::updateTopAnchor() +void QFxAnchors::updateVerticalAnchors() { Q_D(QFxAnchors); - if (d->usedAnchors & HasTopAnchor) { - if (!d->updatingVerticalAnchor) { - d->updatingVerticalAnchor = true; - + if (!d->updatingVerticalAnchor) { + d->updatingVerticalAnchor = true; + if (d->usedAnchors & HasTopAnchor) { //Handle stretching bool invalid = true; int height = 0; @@ -445,22 +435,8 @@ void QFxAnchors::updateTopAnchor() } else if (d->top.item->itemParent() == d->item->itemParent()) { d->item->setY(position(d->top.item, d->top.anchorLine) + d->topMargin); } - - d->updatingVerticalAnchor = false; - } else { - qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; - } - } -} - -void QFxAnchors::updateBottomAnchor() -{ - Q_D(QFxAnchors); - if (d->usedAnchors & HasBottomAnchor) { - if (!d->updatingVerticalAnchor) { - d->updatingVerticalAnchor = true; - - //Handle stretching (top + bottom case is handled in updateLeftAnchor) + } else if (d->usedAnchors & HasBottomAnchor) { + //Handle stretching (top + bottom case is handled above) if (d->usedAnchors & HasVCenterAnchor) { int height = 0; bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin, @@ -476,21 +452,9 @@ void QFxAnchors::updateBottomAnchor() d->item->setY(position(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); } - d->updatingVerticalAnchor = false; - } else { - qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; - } - } -} -void QFxAnchors::updateVCenterAnchor() -{ - Q_D(QFxAnchors); - if (d->usedAnchors & HasVCenterAnchor) { - if (!d->updatingVerticalAnchor) { - d->updatingVerticalAnchor = true; - - //(stetching handled in other update functions) + } else if (d->usedAnchors & HasVCenterAnchor) { + //(stetching handled above) //Handle vCenter if (d->vCenter.item == d->item->itemParent()) { @@ -499,21 +463,70 @@ void QFxAnchors::updateVCenterAnchor() } else if (d->vCenter.item->itemParent() == d->item->itemParent()) { d->item->setY(position(d->vCenter.item, d->vCenter.anchorLine) - d->item->height()/2 + d->vCenterOffset); } - - d->updatingVerticalAnchor = false; - } else { - qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; } + d->updatingVerticalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; } } -void QFxAnchors::updateLeftAnchor() +void QFxAnchors::updateHorizontalAnchors() { Q_D(QFxAnchors); - if (d->usedAnchors & HasLeftAnchor) { - if (!d->updatingHorizontalAnchor) { - d->updatingHorizontalAnchor = true; + if (!d->updatingHorizontalAnchor) { + d->updatingHorizontalAnchor = true; + //alternate implementation (needs performance testing) + /*switch(d->usedAnchors & QFxAnchors::Horizontal_Mask) { + case 0x03: //(HasLeftAnchor | HasRightAnchor) + { + int width = 0; + if (!d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width)) + d->item->setWidth(width); + //fall though + } + case 0x11: //(HasLeftAnchor | HasHCenterAnchor) + { + if (d->usedAnchors & HasHCenterAnchor) { + int width = 0; + if (!d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width)) + d->item->setWidth(width*2); + } + //fall though + } + case HasLeftAnchor: + if (d->left.item == d->item->itemParent()) { + d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); + } else if (d->left.item->itemParent() == d->item->itemParent()) { + d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); + } + break; + case 0x12: //(HasRightAnchor | HasHCenterAnchor) + { + int width = 0; + if (!d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, QFxAnchorLine::Left, width)) + d->item->setWidth(width*2); + //fall though + } + case HasRightAnchor: + if (d->right.item == d->item->itemParent()) { + d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + } else if (d->right.item->itemParent() == d->item->itemParent()) { + d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + } + break; + case HasHCenterAnchor: + if (d->hCenter.item == d->item->itemParent()) { + d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { + d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + } + break; + default: + break; + }*/ + + if (d->usedAnchors & HasLeftAnchor) { //Handle stretching bool invalid = true; int width = 0; @@ -532,21 +545,7 @@ void QFxAnchors::updateLeftAnchor() } else if (d->left.item->itemParent() == d->item->itemParent()) { d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); } - - d->updatingHorizontalAnchor = false; - } else { - qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; - } - } -} - -void QFxAnchors::updateRightAnchor() -{ - Q_D(QFxAnchors); - if (d->usedAnchors & HasRightAnchor) { - if (!d->updatingHorizontalAnchor) { - d->updatingHorizontalAnchor = true; - + } else if (d->usedAnchors & HasRightAnchor) { //Handle stretching (left + right case is handled in updateLeftAnchor) if (d->usedAnchors & HasHCenterAnchor) { int width = 0; @@ -562,32 +561,18 @@ void QFxAnchors::updateRightAnchor() } else if (d->right.item->itemParent() == d->item->itemParent()) { d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); } - - d->updatingHorizontalAnchor = false; - } else { - qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; - } - } -} - -void QFxAnchors::updateHCenterAnchor() -{ - Q_D(QFxAnchors); - if (d->usedAnchors & HasHCenterAnchor) { - if (!d->updatingHorizontalAnchor) { - d->updatingHorizontalAnchor = true; - + } else if (d->usedAnchors & HasHCenterAnchor) { //Handle hCenter if (d->hCenter.item == d->item->itemParent()) { d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); } - - d->updatingHorizontalAnchor = false; - } else { - qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; } + + d->updatingHorizontalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; } } @@ -610,6 +595,24 @@ void QFxAnchors::setTop(const QFxAnchorLine &edge) d->top = edge; } +void QFxAnchors::resetTop() +{ + Q_D(QFxAnchors); + + //update flags + d->usedAnchors &= ~HasTopAnchor; + + //clear binding + QmlMetaProperty prop(this, "top"); + prop.binding()->clearExpression(); + + //disconnect signal/slot connections as needed + disconnect(this, SIGNAL(topMarginChanged()), this, SLOT(updateVerticalAnchors())); + disconnect(d->top.item, 0, this, 0); + + updateVerticalAnchors(); +} + QFxAnchorLine QFxAnchors::bottom() const { Q_D(const QFxAnchors); @@ -627,7 +630,24 @@ void QFxAnchors::setBottom(const QFxAnchorLine &edge) d->checkVValid(); d->bottom = edge; +} + +void QFxAnchors::resetBottom() +{ + Q_D(QFxAnchors); + + //update flags + d->usedAnchors &= ~HasBottomAnchor; + + //clear binding + QmlMetaProperty prop(this, "bottom"); + prop.binding()->clearExpression(); + + //disconnect signal/slot connections as needed + disconnect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); + disconnect(d->bottom.item, 0, this, 0); + updateVerticalAnchors(); } QFxAnchorLine QFxAnchors::verticalCenter() const @@ -649,6 +669,24 @@ void QFxAnchors::setVerticalCenter(const QFxAnchorLine &edge) d->vCenter = edge; } +void QFxAnchors::resetVerticalCenter() +{ + Q_D(QFxAnchors); + + //update flags + d->usedAnchors &= ~HasVCenterAnchor; + + //clear binding + QmlMetaProperty prop(this, "verticalCenter"); + prop.binding()->clearExpression(); + + //disconnect signal/slot connections as needed + disconnect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); + disconnect(d->vCenter.item, 0, this, 0); + + updateVerticalAnchors(); +} + QFxAnchorLine QFxAnchors::left() const { Q_D(const QFxAnchors); @@ -668,6 +706,24 @@ void QFxAnchors::setLeft(const QFxAnchorLine &edge) d->left = edge; } +void QFxAnchors::resetLeft() +{ + Q_D(QFxAnchors); + + //update flags + d->usedAnchors &= ~HasLeftAnchor; + + //clear binding + QmlMetaProperty prop(this, "left"); + prop.binding()->clearExpression(); + + //disconnect signal/slot connections as needed + disconnect(this, SIGNAL(leftMarginChanged()), this, SLOT(updateHorizontalAnchors())); + disconnect(d->left.item, 0, this, 0); + + updateHorizontalAnchors(); +} + QFxAnchorLine QFxAnchors::right() const { Q_D(const QFxAnchors); @@ -685,7 +741,24 @@ void QFxAnchors::setRight(const QFxAnchorLine &edge) d->checkHValid(); d->right = edge; +} + +void QFxAnchors::resetRight() +{ + Q_D(QFxAnchors); + //update flags + d->usedAnchors &= ~HasRightAnchor; + + //clear binding + QmlMetaProperty prop(this, "right"); + prop.binding()->clearExpression(); + + //disconnect signal/slot connections as needed + disconnect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); + disconnect(d->right.item, 0, this, 0); + + updateHorizontalAnchors(); } QFxAnchorLine QFxAnchors::horizontalCenter() const @@ -707,6 +780,24 @@ void QFxAnchors::setHorizontalCenter(const QFxAnchorLine &edge) d->hCenter = edge; } +void QFxAnchors::resetHorizontalCenter() +{ + Q_D(QFxAnchors); + + //update flags + d->usedAnchors &= ~HasHCenterAnchor; + + //clear binding + QmlMetaProperty prop(this, "horizontalCenter"); + prop.binding()->clearExpression(); + + //disconnect signal/slot connections as needed + disconnect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); + disconnect(d->hCenter.item, 0, this, 0); + + updateHorizontalAnchors(); +} + int QFxAnchors::leftMargin() const { Q_D(const QFxAnchors); @@ -902,4 +993,5 @@ bool QFxAnchorsPrivate::checkVAnchorValid(QFxAnchorLine anchor) const return true; } + QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxanchors.h b/src/declarative/fx/qfxanchors.h index 3a250b9..5a8cc1a 100644 --- a/src/declarative/fx/qfxanchors.h +++ b/src/declarative/fx/qfxanchors.h @@ -84,12 +84,12 @@ class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject { Q_OBJECT - Q_PROPERTY(QFxAnchorLine left READ left WRITE setLeft); - Q_PROPERTY(QFxAnchorLine right READ right WRITE setRight); - Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter); - Q_PROPERTY(QFxAnchorLine top READ top WRITE setTop); - Q_PROPERTY(QFxAnchorLine bottom READ bottom WRITE setBottom); - Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter); + Q_PROPERTY(QFxAnchorLine left READ left WRITE setLeft RESET resetLeft); + Q_PROPERTY(QFxAnchorLine right READ right WRITE setRight RESET resetRight); + Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter); + Q_PROPERTY(QFxAnchorLine top READ top WRITE setTop RESET resetTop); + Q_PROPERTY(QFxAnchorLine bottom READ bottom WRITE setBottom RESET resetBottom); + Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter); Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged); Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged); Q_PROPERTY(int horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged()); @@ -109,27 +109,35 @@ public: HasBottomAnchor = 0x08, HasHCenterAnchor = 0x10, HasVCenterAnchor = 0x20, - HasBaselineAnchor = 0x40 + HasBaselineAnchor = 0x40, + Horizontal_Mask = HasLeftAnchor | HasRightAnchor | HasHCenterAnchor, + Vertical_Mask = HasTopAnchor | HasBottomAnchor | HasVCenterAnchor | HasBaselineAnchor }; Q_DECLARE_FLAGS(UsedAnchors, UsedAnchor); QFxAnchorLine left() const; void setLeft(const QFxAnchorLine &edge); + Q_INVOKABLE void resetLeft(); //### temporarily invokable for testing QFxAnchorLine right() const; void setRight(const QFxAnchorLine &edge); + void resetRight(); QFxAnchorLine horizontalCenter() const; void setHorizontalCenter(const QFxAnchorLine &edge); + void resetHorizontalCenter(); QFxAnchorLine top() const; void setTop(const QFxAnchorLine &edge); + void resetTop(); QFxAnchorLine bottom() const; void setBottom(const QFxAnchorLine &edge); + void resetBottom(); QFxAnchorLine verticalCenter() const; void setVerticalCenter(const QFxAnchorLine &edge); + void resetVerticalCenter(); int leftMargin() const; void setLeftMargin(int); @@ -172,12 +180,8 @@ Q_SIGNALS: private Q_SLOTS: void fillChanged(); - void updateLeftAnchor(); - void updateRightAnchor(); - void updateHCenterAnchor(); - void updateTopAnchor(); - void updateBottomAnchor(); - void updateVCenterAnchor(); + void updateHorizontalAnchors(); + void updateVerticalAnchors(); private: //### should item be a friend? (and make some of the public methods private or protected) diff --git a/src/declarative/fx/qfxanchors_p.h b/src/declarative/fx/qfxanchors_p.h index 76f83a8..82c2086 100644 --- a/src/declarative/fx/qfxanchors_p.h +++ b/src/declarative/fx/qfxanchors_p.h @@ -77,8 +77,8 @@ public: bool checkVValid() const; bool checkHAnchorValid(QFxAnchorLine anchor) const; bool checkVAnchorValid(QFxAnchorLine anchor) const; - void connectHHelper(const QFxAnchorLine &anchorLine, const char *slotString); - void connectVHelper(const QFxAnchorLine &anchorLine, const char *slotString); + void connectHHelper(const QFxAnchorLine &anchorLine); + void connectVHelper(const QFxAnchorLine &anchorLine); bool calcStretch(const QFxAnchorLine &edge1, const QFxAnchorLine &edge2, int offset1, int offset2, QFxAnchorLine::AnchorLine line, int &stretch); QFxItem *item; diff --git a/tests/auto/declarative/anchors/tst_anchors.cpp b/tests/auto/declarative/anchors/tst_anchors.cpp index 7d920af..683a7b9 100644 --- a/tests/auto/declarative/anchors/tst_anchors.cpp +++ b/tests/auto/declarative/anchors/tst_anchors.cpp @@ -37,7 +37,7 @@ void tst_anchors::loops() view->setUrl(QUrl("file://" SRCDIR "/data/loop2.qml")); - //### ignoreMessage doesn't seem to work + //### ignoreMessage doesn't seem to work here //QTest::ignoreMessage(QtWarningMsg, "QML QFxImage (unknown location): Anchor loop detected on horizontal anchor."); //QTest::ignoreMessage(QtWarningMsg, "QML QFxImage (unknown location): Anchor loop detected on horizontal anchor."); view->execute(); -- cgit v0.12