diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2009-05-11 05:57:50 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2009-05-11 05:57:50 (GMT) |
commit | b3526f5edf6425289ef2aa5c8adfc89892817ac0 (patch) | |
tree | 6291a50711e80dbe7037f52d71f538b1a5410741 | |
parent | 7f22443b3cb6cd56a906dbb6edb0c2f7a1314887 (diff) | |
parent | 692931ae2fec4fa8fc4ebcbcff20c952d6319536 (diff) | |
download | Qt-b3526f5edf6425289ef2aa5c8adfc89892817ac0.zip Qt-b3526f5edf6425289ef2aa5c8adfc89892817ac0.tar.gz Qt-b3526f5edf6425289ef2aa5c8adfc89892817ac0.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
36 files changed, 905 insertions, 370 deletions
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 } } } 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 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<int,QByteArray> &QAbstractItemModelPrivate::defaultRoleNames() { static QHash<int,QByteArray> 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<int,QByteArray> &roleNames) const QHash<int,QByteArray> &QAbstractItemModel::roleNames() const { Q_D(const QAbstractItemModel); + qDebug() << "roles" << d->roleNames; return d->roleNames; } diff --git a/src/declarative/canvas/qsimplecanvasitem.cpp b/src/declarative/canvas/qsimplecanvasitem.cpp index c8c949a..12c725c 100644 --- a/src/declarative/canvas/qsimplecanvasitem.cpp +++ b/src/declarative/canvas/qsimplecanvasitem.cpp @@ -1343,6 +1343,7 @@ QSimpleCanvasItem::~QSimpleCanvasItem() parent()->remChild(this); delete d->graphicsItem; } else { + update(); setOptions(MouseFilter, false); if (d->canvas){ diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index 540e1cb..53d0187 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -43,9 +43,10 @@ #include "qfxitem.h" #include <QDebug> #include <QtDeclarative/qmlinfo.h> - +#include <QtDeclarative/qmlbindablevalue.h> 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,126 +411,168 @@ bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1, return invalid; } -void QFxAnchors::updateTopAnchor() +void QFxAnchors::updateVerticalAnchors() { 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); - - //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); - } - } -} - -void QFxAnchors::updateBottomAnchor() -{ - Q_D(QFxAnchors); - if (d->usedAnchors & HasBottomAnchor) { - //Handle stretching (top + bottom case is handled in updateLeftAnchor) - if (d->usedAnchors & HasVCenterAnchor) { + if (!d->updatingVerticalAnchor) { + d->updatingVerticalAnchor = true; + if (d->usedAnchors & HasTopAnchor) { + //Handle stretching + bool invalid = true; int height = 0; - bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin, - QFxAnchorLine::Top, height); + 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*2); - } + 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); + } + } 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, + 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); + } - //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); + + } else if (d->usedAnchors & HasVCenterAnchor) { + //(stetching handled above) + + //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."; } } -void QFxAnchors::updateVCenterAnchor() +void QFxAnchors::updateHorizontalAnchors() { Q_D(QFxAnchors); - if (d->usedAnchors & HasVCenterAnchor) { - //(stetching handled in other update functions) + if (!d->updatingHorizontalAnchor) { + d->updatingHorizontalAnchor = 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); + //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 } - } -} - -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; + 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 } - 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); + 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; + }*/ -void QFxAnchors::updateRightAnchor() -{ - Q_D(QFxAnchors); - if (d->usedAnchors & HasRightAnchor) { - //Handle stretching (left + right case is handled in updateLeftAnchor) - if (d->usedAnchors & HasHCenterAnchor) { + if (d->usedAnchors & HasLeftAnchor) { + //Handle stretching + bool invalid = true; int width = 0; - bool invalid = d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, - QFxAnchorLine::Left, width); + 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*2); + 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); + } + } else 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); + } + } 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); + } } - //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); - } - } -} - -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); - } + d->updatingHorizontalAnchor = false; + } else { + qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; } } @@ -562,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); @@ -579,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 @@ -601,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); @@ -620,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); @@ -637,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 @@ -659,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); @@ -854,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 3a5d1c7..82c2086 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) { } @@ -76,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; @@ -99,6 +100,9 @@ public: int bottomMargin; int vCenterOffset; int hCenterOffset; + + bool updatingHorizontalAnchor; + bool updatingVerticalAnchor; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index fb46a0e..74c9b5b 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -851,7 +851,6 @@ void QFxTextEditPrivate::updateDefaultTextOption() QTextOption::WrapMode oldWrapMode = opt.wrapMode(); -qDebug() << "wrap mode is" << opt.wrapMode(); if (wrap) opt.setWrapMode(QTextOption::WordWrap); else @@ -859,7 +858,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); } 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/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp index 3950f82..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 <qmlcontext.h> +#include <qmlinfo.h> #include <QVariant> #include <qfxperf.h> #include <QtCore/qdebug.h> - QT_BEGIN_NAMESPACE + DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); QmlBindableValuePrivate::QmlBindableValuePrivate() -: inited(false) +: inited(false), updating(false), mePtr(0) { } @@ -75,6 +76,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) @@ -118,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<QList<QObject *> >()) { - const QList<QObject *> &list = - qvariant_cast<QList<QObject *> >(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<QList<QObject *> >()) { + const QList<QObject *> &list = + qvariant_cast<QList<QObject *> >(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<QObject *>()) { - 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<QObject *>()) { + 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 b6de5b7..d9af0ef 100644 --- a/src/declarative/qml/qmlbindablevalue_p.h +++ b/src/declarative/qml/qmlbindablevalue_p.h @@ -55,7 +55,10 @@ public: QmlBindableValuePrivate(); bool inited; + bool updating; QmlMetaProperty property; + + QmlBindableValue **mePtr; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 13fc332..a40b7c8 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 @@ -663,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()) { @@ -698,6 +703,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 +1385,8 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) QHash<QString, int> 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 +1409,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 +1457,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<QFxPerf::BindInit> 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<QmlBindableValue> 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<QmlParserStatus *> 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<QmlParserStatus> 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 <QStringList> #include <QList> #include "private/qobject_p.h" +#include "private/qmlengine_p.h" #include "private/qmlcompositetypemanager_p.h" #include <qmlerror.h> #include "qmlcomponent.h" @@ -75,8 +76,10 @@ public: int start; int count; QmlCompiledComponent *cc; - QList<QmlBindableValue *> bindValues; - QList<QmlParserStatus *> parserStatus; + + QList<QmlEnginePrivate::SimpleList<QmlBindableValue> > bindValues; + QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; + bool completePending; QmlEngine *engine; diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index dfcf413..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 = @@ -231,8 +235,48 @@ QmlContext::QmlContext(QmlContext *parentContext, QObject *parent) */ QmlContext::~QmlContext() { + Q_D(QmlContext); + if (d->parent) + d->parent->d_func()->childContexts.remove(this); + + for (QSet<QmlContext *>::ConstIterator iter = d->childContexts.begin(); + iter != d->childContexts.end(); + ++iter) { + (*iter)->d_func()->invalidateEngines(); + (*iter)->d_func()->parent = 0; + } + + for (QSet<QmlExpression *>::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<QmlSimpleDeclarativeData *>(p->declarativeData); + if(data && (data->flags & QmlSimpleDeclarativeData::Extended)) { + data->context = 0; + } else { + p->declarativeData = 0; + } + } + d->contextObjects.clear(); } +void QmlContextPrivate::invalidateEngines() +{ + if (!engine) + return; + engine = 0; + for (QSet<QmlContext *>::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.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..f527bb8 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -47,10 +47,13 @@ #include <private/qmldeclarativedata_p.h> #include <qhash.h> #include <qscriptvalue.h> +#include <QtCore/qset.h> QT_BEGIN_NAMESPACE class QmlContext; +class QmlExpression; class QmlEngine; +class QmlExpression; class QmlCompiledComponent; class QmlContextPrivate : public QObjectPrivate @@ -87,7 +90,12 @@ public: }; void addDefaultObject(QObject *, Priority); + void invalidateEngines(); + QSet<QmlContext *> childContexts; + QSet<QmlExpression *> childExpressions; + 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 50c0981..c39a0d5 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -70,6 +70,7 @@ #include <QtCore/qdir.h> #include <qmlcomponent.h> #include "private/qmlmetaproperty_p.h" +#include <private/qmlbindablevalue_p.h> 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<QmlBindableValue> &bvs) +{ + for (int ii = 0; ii < bvs.count; ++ii) { + QmlBindableValue *bv = bvs.at(ii); + if(bv) { + QmlBindableValuePrivate *p = + static_cast<QmlBindableValuePrivate *>(QObjectPrivate::get(bv)); + p->mePtr = 0; + } + } + bvs.clear(); +} + +void QmlEnginePrivate::clear(SimpleList<QmlParserStatus> &pss) +{ + for (int ii = 0; ii < pss.count; ++ii) { + QmlParserStatus *ps = pss.at(ii); + if(ps) + ps->d = 0; + } + pss.clear(); } void QmlEnginePrivate::init() @@ -630,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) @@ -684,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; } @@ -770,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; } @@ -781,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; } @@ -798,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; } @@ -806,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; } @@ -815,7 +858,7 @@ QmlExpression::~QmlExpression() */ QmlEngine *QmlExpression::engine() const { - return d->ctxt->engine(); + return d->ctxt?d->ctxt->engine():0; } /*! @@ -892,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/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<QmlBindableValue *> currentBindValues; - QList<QmlParserStatus *> currentParserStatus; + template<class T> + 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<QmlBindableValue> &); + static void clear(SimpleList<QmlParserStatus> &); + + QList<SimpleList<QmlBindableValue> > bindValues; + QList<SimpleList<QmlParserStatus> > parserStatus; + QmlComponent *rootComponent; mutable QNetworkAccessManager *networkAccessManager; 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; }; 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 <private/qmlcomponent_p.h> #include "private/qmlvmemetaobject_p.h" #include <QtCore/qdebug.h> +#include <QtCore/qvarlengtharray.h> +#include <private/qmlbindablevalue_p.h> 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<QFxPerf::CompileRun> cr; #endif - - QList<QmlParserStatus *> parserStatuses; - QList<QmlBindableValue *> bindableValues; + QmlEnginePrivate::SimpleList<QmlBindableValue> bindValues; + QmlEnginePrivate::SimpleList<QmlParserStatus> parserStatus; QStack<QObject *> stack; QStack<ListInstance> 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<QmlBindableValue>(instr.init.bindingsSize); + if (instr.init.parserStatusSize) + parserStatus = QmlEnginePrivate::SimpleList<QmlParserStatus>(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<QmlParserStatus *>(reinterpret_cast<char *>(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<QmlBindableValuePrivate *>(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<QmlBindableValuePrivate *>(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(); 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 <QDebug> QT_BEGIN_NAMESPACE + +class QmlOpenMetaObjectPrivate +{ +public: + QmlOpenMetaObjectPrivate() : parent(0), mem(0) {} + + bool autoCreate; + QAbstractDynamicMetaObject *parent; + int propertyOffset; + int signalOffset; + QList<QVariant> data; + QHash<QByteArray, int> 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<QMetaObject *>(this) = *mem; + d->mem = d->mob.toMetaObject(); + *static_cast<QMetaObject *>(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<QVariant *>(a[0]) = data[propId]; + *reinterpret_cast<QVariant *>(a[0]) = d->data[propId]; } else if (c == QMetaObject::WriteProperty) { - if (data[propId] != *reinterpret_cast<QVariant *>(a[0])) { + if (d->data[propId] != *reinterpret_cast<QVariant *>(a[0])) { propertyWrite(propId); - data[propId] = *reinterpret_cast<QVariant *>(a[0]); - activate(_object, _signalOffset + propId, 0); + d->data[propId] = *reinterpret_cast<QVariant *>(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<QByteArray, int>::ConstIterator iter = names.find(name); - if (iter == names.end()) + QHash<QByteArray, int>::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<QByteArray, int>::ConstIterator iter = names.find(name); + QHash<QByteArray, int>::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<QMetaObject *>(this) = *mem; - names.insert(name, id); + d->data << propertyCreated(id, build); + qFree(d->mem); + d->mem = d->mob.toMetaObject(); + *static_cast<QMetaObject *>(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 <QMetaObject> -#include "private/qmetaobjectbuilder_p.h" -#include <private/qobject_p.h> +#include <QtCore/private/qobject_p.h> #include <QObject> - 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<QVariant> data; - QHash<QByteArray, int> names; - QMetaObjectBuilder mob; - QMetaObject *mem; - QObject *_object; + + QmlOpenMetaObjectPrivate *d; }; 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(); }; 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..683a7b9 --- /dev/null +++ b/tests/auto/declarative/anchors/tst_anchors.cpp @@ -0,0 +1,52 @@ +#include <qtest.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qfxview.h> +#include <QtDeclarative/qfximage.h> +#include <QtDeclarative/qfxtext.h> + +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 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(); + qApp->processEvents(); + + delete view; + } +} + +QTEST_MAIN(tst_anchors) + +#include "tst_anchors.moc" diff --git a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp index 0875690..c63caf4 100644 --- a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp +++ b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp @@ -1,13 +1,15 @@ #include <qtest.h> #include <QtDeclarative/qmlcomponent.h> #include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlexpression.h> +#include <QtDeclarative/qmlcontext.h> 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 +17,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 +32,7 @@ public: signals: void basicSignal(); void argumentSignal(int a, QString b, qreal c); + void stringChanged(); public slots: void method() { m_methodCalled = true; } @@ -41,6 +50,22 @@ private: QML_DECLARE_TYPE(MyQmlObject); QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); +class MyQmlContainer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QList<MyQmlContainer*>* children READ children) +public: + MyQmlContainer() {} + + QList<MyQmlContainer*> *children() { return &m_children; } + +private: + QList<MyQmlContainer*> m_children; +}; + +QML_DECLARE_TYPE(MyQmlContainer); +QML_DEFINE_TYPE(MyQmlContainer,MyQmlContainer); + class tst_qmlbindengine : public QObject { Q_OBJECT @@ -51,6 +76,8 @@ private slots: void boolPropertiesEvaluateAsBool(); void methods(); void signalAssignment(); + void bindingLoop(); + void contextPropertiesTriggerReeval(); private: QmlEngine engine; @@ -118,6 +145,42 @@ void tst_qmlbindengine::methods() } } +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); +} + +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" |