From dbd48151f6260743056edd9b906fc28acd02b390 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 15 Dec 2009 15:44:03 +1000 Subject: Binding optimizer extensions --- src/declarative/qml/qmlbindingvme.cpp | 55 ++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index 692be68..e5cbdfc 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -67,6 +67,7 @@ struct Register { QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } QString *getstringptr() { return (QString *)typeDataPtr(); } + QUrl *geturlptr() { return (QUrl *)typeDataPtr(); } void *typeDataPtr() { return (void *)&data; } void *typeMemory() { return (void *)data; } @@ -110,6 +111,9 @@ struct Instr { GreaterThanReal, // binaryop NewString, // construct + NewUrl, // construct + + CleanupUrl, // cleanup CleanupString, // cleanup Copy, // copy @@ -130,6 +134,7 @@ struct Instr { ConvertGenericToReal, // genericunaryop ConvertGenericToBool, // genericunaryop ConvertGenericToString, // genericunaryop + ConvertGenericToUrl, // genericunaryop } type; @@ -572,12 +577,15 @@ inline static QUrl toUrl(Register *reg, int type, QmlContextPrivate *context, bo if (ok) *ok = false; return QUrl(); } - } else { + } else { if (ok) *ok = false; return QUrl(); } - return QUrl(); + if (base.isRelative()) + return context->url.resolved(base); + else + return base; } void QmlBindingVME::run(const char *programData, Config *config, @@ -710,8 +718,16 @@ void QmlBindingVME::run(const char *programData, Config *config, new (registers[instr->construct.reg].typeMemory()) QString; break; + case Instr::NewUrl: + new (registers[instr->construct.reg].typeMemory()) QUrl; + break; + case Instr::CleanupString: - ((QString *)(registers[instr->cleanup.reg].typeDataPtr()))->~QString(); + registers[instr->cleanup.reg].getstringptr()->~QString(); + break; + + case Instr::CleanupUrl: + registers[instr->cleanup.reg].geturlptr()->~QUrl(); break; case Instr::Fetch: @@ -815,6 +831,14 @@ void QmlBindingVME::run(const char *programData, Config *config, } break; + case Instr::ConvertGenericToUrl: + { + int type = registers[instr->genericunaryop.srcType].getint(); + void *regPtr = registers[instr->genericunaryop.output].typeDataPtr(); + new (regPtr) QUrl(toUrl(registers + instr->genericunaryop.src, type, context)); + } + break; + default: qFatal("EEK"); break; @@ -903,9 +927,15 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::NewString: qWarning().nospace() << "NewString" << "\t\t" << instr->construct.reg; break; + case Instr::NewUrl: + qWarning().nospace() << "NewUrl" << "\t\t\t" << instr->construct.reg; + break; case Instr::CleanupString: qWarning().nospace() << "CleanupString" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg; break; + case Instr::CleanupUrl: + qWarning().nospace() << "CleanupUrl" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg; + break; case Instr::Fetch: qWarning().nospace() << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg; break; @@ -948,6 +978,9 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::ConvertGenericToString: qWarning().nospace() << "ConvertGenericToString" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; break; + case Instr::ConvertGenericToUrl: + qWarning().nospace() << "ConvertGenericToUrl" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; + break; default: qWarning().nospace() << "Unknown"; break; @@ -990,7 +1023,8 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) if (type.unknownType) { if (destination->type != QMetaType::QReal && destination->type != QVariant::String && - destination->type != QMetaType::Bool) + destination->type != QMetaType::Bool && + destination->type != QVariant::Url) return false; int convertReg = acquireReg(); @@ -1016,6 +1050,13 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) convert.genericunaryop.src = type.reg; convert.genericunaryop.srcType = 2; // XXX bytecode << convert; + } else if (destination->type == QVariant::Url) { + Instr convert; + convert.type = Instr::ConvertGenericToUrl; + convert.genericunaryop.output = convertReg; + convert.genericunaryop.src = type.reg; + convert.genericunaryop.srcType = 2; // XXX + bytecode << convert; } Instr cleanup; @@ -1037,6 +1078,12 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) cleanup.cleanup.reg = convertReg; cleanup.cleanup.typeReg = -1; bytecode << cleanup; + } else if (destination->type == QVariant::Url) { + Instr cleanup; + cleanup.type = Instr::CleanupUrl; + cleanup.cleanup.reg = convertReg; + cleanup.cleanup.typeReg = -1; + bytecode << cleanup; } releaseReg(convertReg); -- cgit v0.12 From 889b15f62121fd79b28b9f903569fc101578a139 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 08:22:16 +1000 Subject: Watch item geometry changes without using signal/slot connections. --- src/declarative/graphicsitems/graphicsitems.pri | 1 + .../graphicsitems/qmlgraphicsanchors.cpp | 8 +-- .../graphicsitems/qmlgraphicsanchors_p_p.h | 9 ++- src/declarative/graphicsitems/qmlgraphicsitem.cpp | 40 ++++++++----- src/declarative/graphicsitems/qmlgraphicsitem_p.h | 6 +- .../qmlgraphicsitemgeometrylistener_p.h | 70 ++++++++++++++++++++++ .../graphicsitems/qmlgraphicslistview.cpp | 37 ++++-------- .../graphicsitems/qmlgraphicslistview_p.h | 1 - .../graphicsitems/qmlgraphicspositioners.cpp | 7 +-- .../graphicsitems/qmlgraphicspositioners_p_p.h | 9 ++- 10 files changed, 133 insertions(+), 55 deletions(-) create mode 100644 src/declarative/graphicsitems/qmlgraphicsitemgeometrylistener_p.h diff --git a/src/declarative/graphicsitems/graphicsitems.pri b/src/declarative/graphicsitems/graphicsitems.pri index 728c9c0..5199c5d 100644 --- a/src/declarative/graphicsitems/graphicsitems.pri +++ b/src/declarative/graphicsitems/graphicsitems.pri @@ -48,6 +48,7 @@ HEADERS += \ $$PWD/qmlgraphicsgraphicsobjectcontainer_p.h \ $$PWD/qmlgraphicsparticles_p.h \ $$PWD/qmlgraphicslayoutitem_p.h \ + $$PWD/qmlgraphicsitemgeometrylistener_p.h \ $$PWD/qmlgraphicseffects.cpp SOURCES += \ diff --git a/src/declarative/graphicsitems/qmlgraphicsanchors.cpp b/src/declarative/graphicsitems/qmlgraphicsanchors.cpp index 96d76cf..0febf08 100644 --- a/src/declarative/graphicsitems/qmlgraphicsanchors.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsanchors.cpp @@ -241,22 +241,20 @@ void QmlGraphicsAnchorsPrivate::clearItem(QmlGraphicsItem *item) void QmlGraphicsAnchorsPrivate::addDepend(QmlGraphicsItem *item) { - Q_Q(QmlGraphicsAnchors); if (!item) return; QmlGraphicsItemPrivate *p = static_cast(QGraphicsItemPrivate::get(item)); - p->dependantAnchors.append(q); + p->addGeometryListener(this); } void QmlGraphicsAnchorsPrivate::remDepend(QmlGraphicsItem *item) { - Q_Q(QmlGraphicsAnchors); if (!item) return; QmlGraphicsItemPrivate *p = static_cast(QGraphicsItemPrivate::get(item)); - p->dependantAnchors.removeOne(q); + p->removeGeometryListener(this); } bool QmlGraphicsAnchorsPrivate::isItemComplete() const @@ -332,7 +330,7 @@ void QmlGraphicsAnchorsPrivate::updateOnComplete() updateVerticalAnchors(); } -void QmlGraphicsAnchorsPrivate::update(QmlGraphicsItem *, const QRectF &newG, const QRectF &oldG) +void QmlGraphicsAnchorsPrivate::itemGeometryChanged(QmlGraphicsItem *, const QRectF &newG, const QRectF &oldG) { fillChanged(); centerInChanged(); diff --git a/src/declarative/graphicsitems/qmlgraphicsanchors_p_p.h b/src/declarative/graphicsitems/qmlgraphicsanchors_p_p.h index 4f7fde0..91c8ff1 100644 --- a/src/declarative/graphicsitems/qmlgraphicsanchors_p_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsanchors_p_p.h @@ -54,7 +54,7 @@ // #include "qmlgraphicsanchors_p.h" - +#include "qmlgraphicsitemgeometrylistener_p.h" #include QT_BEGIN_NAMESPACE @@ -91,7 +91,7 @@ Q_DECLARE_METATYPE(QmlGraphicsAnchorLine) -class QmlGraphicsAnchorsPrivate : public QObjectPrivate +class QmlGraphicsAnchorsPrivate : public QObjectPrivate, public QmlGraphicsItemGeometryListener { Q_DECLARE_PUBLIC(QmlGraphicsAnchors) public: @@ -128,7 +128,10 @@ public: void updateOnComplete(); void updateMe(); - void update(QmlGraphicsItem *, const QRectF &, const QRectF &); + + // QmlGraphicsItemGeometryListener interface + void itemGeometryChanged(QmlGraphicsItem *, const QRectF &, const QRectF &); + QmlGraphicsAnchorsPrivate *anchorPrivate() { return this; } bool checkHValid() const; bool checkVValid() const; diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.cpp b/src/declarative/graphicsitems/qmlgraphicsitem.cpp index ef4dfc2..0315c69 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitem.cpp @@ -1478,17 +1478,18 @@ QmlGraphicsItem::QmlGraphicsItem(QmlGraphicsItemPrivate &dd, QmlGraphicsItem *pa QmlGraphicsItem::~QmlGraphicsItem() { Q_D(QmlGraphicsItem); - for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { - QmlGraphicsAnchors *anchor = d->dependantAnchors.at(ii); - anchor->d_func()->clearItem(this); + for (int ii = 0; ii < d->geometryListeners.count(); ++ii) { + QmlGraphicsAnchorsPrivate *anchor = d->geometryListeners.at(ii)->anchorPrivate(); + if (anchor) + anchor->clearItem(this); } if (!d->parent || (parentItem() && !parentItem()->QGraphicsItem::d_ptr->inDestructor)) - for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { - QmlGraphicsAnchors *anchor = d->dependantAnchors.at(ii); - if (anchor->d_func()->item && anchor->d_func()->item->parentItem() != this) //child will be deleted anyway - anchor->d_func()->updateOnComplete(); + for (int ii = 0; ii < d->geometryListeners.count(); ++ii) { + QmlGraphicsAnchorsPrivate *anchor = d->geometryListeners.at(ii)->anchorPrivate(); + if (anchor && anchor->item && anchor->item->parentItem() != this) //child will be deleted anyway + anchor->updateOnComplete(); } - d->dependantAnchors.clear(); + d->geometryListeners.clear(); delete d->_anchorLines; d->_anchorLines = 0; delete d->_anchors; d->_anchors = 0; delete d->_stateGroup; d->_stateGroup = 0; @@ -1974,12 +1975,22 @@ void QmlGraphicsItem::geometryChanged(const QRectF &newGeometry, if (newGeometry.height() != oldGeometry.height()) emit heightChanged(); - for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) { - QmlGraphicsAnchors *anchor = d->dependantAnchors.at(ii); - anchor->d_func()->update(this, newGeometry, oldGeometry); + for(int ii = 0; ii < d->geometryListeners.count(); ++ii) { + QmlGraphicsItemGeometryListener *listener = d->geometryListeners.at(ii); + listener->itemGeometryChanged(this, newGeometry, oldGeometry); } } +void QmlGraphicsItemPrivate::addGeometryListener(QmlGraphicsItemGeometryListener *listener) +{ + geometryListeners.append(listener); +} + +void QmlGraphicsItemPrivate::removeGeometryListener(QmlGraphicsItemGeometryListener *listener) +{ + geometryListeners.removeAll(listener); +} + /*! \internal */ void QmlGraphicsItem::keyPressEvent(QKeyEvent *event) { @@ -2227,9 +2238,10 @@ void QmlGraphicsItem::setBaselineOffset(qreal offset) d->_baselineOffset = offset; emit baselineOffsetChanged(); - for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) { - QmlGraphicsAnchors *anchor = d->dependantAnchors.at(ii); - anchor->d_func()->updateVerticalAnchors(); + for(int ii = 0; ii < d->geometryListeners.count(); ++ii) { + QmlGraphicsAnchorsPrivate *anchor = d->geometryListeners.at(ii)->anchorPrivate(); + if (anchor) + anchor->updateVerticalAnchors(); } } diff --git a/src/declarative/graphicsitems/qmlgraphicsitem_p.h b/src/declarative/graphicsitems/qmlgraphicsitem_p.h index 304e36c..9496590 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsitem_p.h @@ -57,6 +57,7 @@ #include "qmlgraphicsanchors_p.h" #include "qmlgraphicsanchors_p_p.h" +#include "qmlgraphicsitemgeometrylistener_p.h" #include "../util/qmlstate_p.h" #include "../util/qmlnullablevalue_p_p.h" @@ -182,7 +183,6 @@ public: } return _anchors; } - QList dependantAnchors; QmlGraphicsAnchors *_anchors; QmlGraphicsContents *_contents; @@ -206,6 +206,10 @@ public: return _anchorLines; } + void addGeometryListener(QmlGraphicsItemGeometryListener *); + void removeGeometryListener(QmlGraphicsItemGeometryListener *); + QList geometryListeners; + QmlStateGroup *states(); QmlStateGroup *_stateGroup; diff --git a/src/declarative/graphicsitems/qmlgraphicsitemgeometrylistener_p.h b/src/declarative/graphicsitems/qmlgraphicsitemgeometrylistener_p.h new file mode 100644 index 0000000..6230e93 --- /dev/null +++ b/src/declarative/graphicsitems/qmlgraphicsitemgeometrylistener_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLGRAPHICSITEMGEOMETRYLISTENER +#define QMLGRAPHICSITEMGEOMETRYLISTENER + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QRectF; +class QmlGraphicsItem; +class QmlGraphicsAnchorsPrivate; +class QmlGraphicsItemGeometryListener +{ +public: + virtual void itemGeometryChanged(QmlGraphicsItem *, const QRectF &newGeometry, const QRectF &oldGeometry) = 0; + virtual QmlGraphicsAnchorsPrivate *anchorPrivate() { return 0; } +}; + +QT_END_NAMESPACE + +#endif // QMLGRAPHICSITEMGEOMETRYLISTENER diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index 16e9d6e..989970e 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -166,7 +166,7 @@ public: //---------------------------------------------------------------------------- -class QmlGraphicsListViewPrivate : public QmlGraphicsFlickablePrivate +class QmlGraphicsListViewPrivate : public QmlGraphicsFlickablePrivate, private QmlGraphicsItemGeometryListener { Q_DECLARE_PUBLIC(QmlGraphicsListView) @@ -410,6 +410,13 @@ public: q->setViewportWidth(q->minXExtent() - q->maxXExtent()); } + void itemGeometryChanged(QmlGraphicsItem *, const QRectF &newGeometry, const QRectF &oldGeometry) { + if (orient == QmlGraphicsListView::Vertical && newGeometry.height() != oldGeometry.height() + || newGeometry.width() != oldGeometry.width()) { + layout(); + fixupPosition(); + } + } // for debugging only void checkVisible() const { @@ -486,12 +493,8 @@ public: bool correctFlick : 1; bool inFlickCorrection : 1; bool lazyRelease : 1; - - static int itemResizedIdx; }; -int QmlGraphicsListViewPrivate::itemResizedIdx = -1; - void QmlGraphicsListViewPrivate::init() { Q_Q(QmlGraphicsListView); @@ -500,8 +503,6 @@ void QmlGraphicsListViewPrivate::init() QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(refill())); QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped())); q->setFlickDirection(QmlGraphicsFlickable::VerticalFlick); - if (itemResizedIdx == -1) - itemResizedIdx = QmlGraphicsListView::staticMetaObject.indexOfSlot("itemResized()"); } void QmlGraphicsListViewPrivate::clear() @@ -543,10 +544,7 @@ FxListItem *QmlGraphicsListViewPrivate::createItem(int modelIndex) listItem->item->setZValue(1); listItem->item->setParent(q->viewport()); QmlGraphicsItemPrivate *itemPrivate = static_cast(QGraphicsItemPrivate::get(item)); - if (orient == QmlGraphicsListView::Vertical) - itemPrivate->connectToHeightChanged(q, itemResizedIdx); - else - itemPrivate->connectToWidthChanged(q, itemResizedIdx); + itemPrivate->addGeometryListener(this); } requestedIndex = -1; @@ -565,14 +563,11 @@ void QmlGraphicsListViewPrivate::releaseItem(FxListItem *item) QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged())); trackedItem = 0; } + QmlGraphicsItemPrivate *itemPrivate = static_cast(QGraphicsItemPrivate::get(item->item)); + itemPrivate->removeGeometryListener(this); if (model->release(item->item) == 0) { // item was not destroyed, and we no longer reference it. unrequestedItems.insert(item->item, model->indexOf(item->item, q)); - QmlGraphicsItemPrivate *itemPrivate = static_cast(QGraphicsItemPrivate::get(item->item)); - if (orient == QmlGraphicsListView::Vertical) - itemPrivate->disconnectFromHeightChanged(q, itemResizedIdx); - else - itemPrivate->disconnectFromWidthChanged(q, itemResizedIdx); } delete item; } @@ -2207,16 +2202,6 @@ void QmlGraphicsListView::trackedPositionChanged() } } -void QmlGraphicsListView::itemResized() -{ - Q_D(QmlGraphicsListView); - QmlGraphicsItem *item = qobject_cast(sender()); - if (item) { - d->layout(); - d->fixupPosition(); - } -} - void QmlGraphicsListView::itemsInserted(int modelIndex, int count) { Q_D(QmlGraphicsListView); diff --git a/src/declarative/graphicsitems/qmlgraphicslistview_p.h b/src/declarative/graphicsitems/qmlgraphicslistview_p.h index 6dc131c..cb9f5c4 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicslistview_p.h @@ -188,7 +188,6 @@ protected: private Q_SLOTS: void refill(); void trackedPositionChanged(); - void itemResized(); void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); diff --git a/src/declarative/graphicsitems/qmlgraphicspositioners.cpp b/src/declarative/graphicsitems/qmlgraphicspositioners.cpp index b96b8b8..ecaab80 100644 --- a/src/declarative/graphicsitems/qmlgraphicspositioners.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspositioners.cpp @@ -67,8 +67,7 @@ void QmlGraphicsBasePositionerPrivate::watchChanges(QmlGraphicsItem *other) QmlGraphicsItemPrivate *otherPrivate = static_cast(QGraphicsItemPrivate::get(other)); - otherPrivate->connectToHeightChanged(q, prePosIdx); - otherPrivate->connectToWidthChanged(q, prePosIdx); + otherPrivate->addGeometryListener(this); otherPrivate->registerSiblingOrderNotification(this); watched << other; @@ -81,8 +80,8 @@ void QmlGraphicsBasePositionerPrivate::unwatchChanges(QmlGraphicsItem* other) bool stillAlive = false; //Use the returns from disconnect to see if it was deleted or just reparented stillAlive |= QMetaObject::disconnect(other, visibleIdx, q, prePosIdx); stillAlive |= QMetaObject::disconnect(other, opacityIdx, q, prePosIdx); - stillAlive |= otherPrivate->disconnectFromHeightChanged(q, prePosIdx); - stillAlive |= otherPrivate->disconnectFromWidthChanged(q, prePosIdx); + + otherPrivate->removeGeometryListener(this); if(stillAlive) otherPrivate->unregisterSiblingOrderNotification(this); diff --git a/src/declarative/graphicsitems/qmlgraphicspositioners_p_p.h b/src/declarative/graphicsitems/qmlgraphicspositioners_p_p.h index db795ec..63c1c83 100644 --- a/src/declarative/graphicsitems/qmlgraphicspositioners_p_p.h +++ b/src/declarative/graphicsitems/qmlgraphicspositioners_p_p.h @@ -66,7 +66,7 @@ #include QT_BEGIN_NAMESPACE -class QmlGraphicsBasePositionerPrivate : public QmlGraphicsItemPrivate +class QmlGraphicsBasePositionerPrivate : public QmlGraphicsItemPrivate, public QmlGraphicsItemGeometryListener { Q_DECLARE_PUBLIC(QmlGraphicsBasePositioner) @@ -125,6 +125,13 @@ public: queuedPositioning = true; } } + + void itemGeometryChanged(QmlGraphicsItem *, const QRectF &newGeometry, const QRectF &oldGeometry) + { + Q_Q(QmlGraphicsBasePositioner); + if (newGeometry.size() != oldGeometry.size()) + q->prePositioning(); + } }; QT_END_NAMESPACE -- cgit v0.12 From 211a63a1e3669055e28dfba4cff1e2b7f6e5e3ca Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 08:36:13 +1000 Subject: removeGeometryListener should only remove one instance of that listener. --- src/declarative/graphicsitems/qmlgraphicsitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.cpp b/src/declarative/graphicsitems/qmlgraphicsitem.cpp index 0315c69..4d587e4d 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitem.cpp @@ -1988,7 +1988,7 @@ void QmlGraphicsItemPrivate::addGeometryListener(QmlGraphicsItemGeometryListener void QmlGraphicsItemPrivate::removeGeometryListener(QmlGraphicsItemGeometryListener *listener) { - geometryListeners.removeAll(listener); + geometryListeners.removeOne(listener); } /*! \internal */ -- cgit v0.12 From 0957269eac949f20685a4437a5252d6cd3b40375 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 16 Dec 2009 09:40:17 +1000 Subject: Improve property alias exceptions. Make sure the proper location is given, and provide more specific error messages. --- src/declarative/qml/qmlcompiler.cpp | 4 ++-- src/declarative/qml/qmlscriptparser.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 53ea18e..00c37b6 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2344,10 +2344,10 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, QStringList alias = astNodeToStringList(node); if (alias.count() != 1 && alias.count() != 2) - COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias location")); + COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias reference. An alias reference must be specified as or .")); if (!compileState.ids.contains(alias.at(0))) - COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias location")); + COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); Object *idObject = compileState.ids[alias.at(0)]; diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 35234ec..a24ef51 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -600,6 +600,9 @@ bool ProcessAST::visit(AST::UiPublicMember *node) if (node->expression) { // default value property.defaultValue = new Property; property.defaultValue->parent = _stateStack.top().object; + property.defaultValue->location = + location(node->expression->firstSourceLocation(), + node->expression->lastSourceLocation()); Value *value = new Value; value->location = location(node->expression->firstSourceLocation(), node->expression->lastSourceLocation()); -- cgit v0.12 From bef6f93997a4ad0f0658e2c76da70a0afb414a5b Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 16 Dec 2009 12:03:30 +1000 Subject: Optimize . type enum assignments. Treat it as a literal assignment rather than a binding. --- src/declarative/qml/qmlcompiler.cpp | 52 +++++++++++++++++++++++++++++++++++++ src/declarative/qml/qmlcompiler_p.h | 4 +++ 2 files changed, 56 insertions(+) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 00c37b6..9df9b40 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2029,6 +2029,14 @@ bool QmlCompiler::buildPropertyLiteralAssignment(QmlParser::Property *prop, if (v->value.isScript()) { + //optimization for . enum assignments + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment)); + if (isEnumAssignment) { + v->type = Value::Literal; + return true; + } + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; @@ -2043,6 +2051,50 @@ bool QmlCompiler::buildPropertyLiteralAssignment(QmlParser::Property *prop, return true; } +bool QmlCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop, + QmlParser::Object *obj, + QmlParser::Value *v, + bool *isAssignment) +{ + *isAssignment = false; + if (!prop.isEnumType()) + return true; + + if (!prop.isWritable()) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + + QString string = v->value.asString(); + if (!string.at(0).isUpper()) + return true; + + QStringList parts = string.split(QLatin1Char('.')); + if (parts.count() != 2) + return true; + + QString typeName = parts.at(0); + QmlType *type = 0; + QmlEnginePrivate::get(engine)->resolveType(unit->imports, typeName.toUtf8(), + &type, 0, 0, 0, 0); + + if (!type || obj->typeName != type->qmlTypeName()) + return true; + + QString enumValue = parts.at(1); + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(enumValue.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(enumValue.toUtf8().constData()); + if (value == -1) + return true; + + v->type = Value::Literal; + v->value = QmlParser::Variant(enumValue); + *isAssignment = true; + + return true; +} + // Ensures that the dynamic meta specification on obj is valid bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) { diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index d734a12..108505f 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -219,6 +219,10 @@ private: bool doesPropertyExist(QmlParser::Property *prop, QmlParser::Object *obj); bool testLiteralAssignment(const QMetaProperty &prop, QmlParser::Value *value); + bool testQualifiedEnumAssignment(const QMetaProperty &prop, + QmlParser::Object *obj, + QmlParser::Value *value, + bool *isAssignment); enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation }; bool mergeDynamicMetaProperties(QmlParser::Object *obj); bool buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode); -- cgit v0.12 From 3f9d0888c7ad79063b8a53c85e89ff95dce2a45b Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 12:12:49 +1000 Subject: Faster sections. --- examples/declarative/listview/sections.qml | 3 +- .../graphicsitems/qmlgraphicslistview.cpp | 89 +++++++++++++++------- .../graphicsitems/qmlgraphicslistview_p.h | 32 +++++++- .../graphicsitems/qmlgraphicsvisualitemmodel.cpp | 45 +++++++++-- .../graphicsitems/qmlgraphicsvisualitemmodel_p.h | 3 + src/declarative/qml/qmlcontext.cpp | 24 ++++++ src/declarative/qml/qmlcontext.h | 2 + 7 files changed, 161 insertions(+), 37 deletions(-) diff --git a/examples/declarative/listview/sections.qml b/examples/declarative/listview/sections.qml index 6b1a589..b51cf58 100644 --- a/examples/declarative/listview/sections.qml +++ b/examples/declarative/listview/sections.qml @@ -64,7 +64,8 @@ Rectangle { highlight: petHighlight // The sectionExpression is simply the size of the pet. // We use this to determine which section we are in above. - sectionExpression: "size" + section.property: "size" + section.criteria: ViewSection.FullString focus: true } } diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index 989970e..bf734b8 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -51,6 +51,31 @@ #include QT_BEGIN_NAMESPACE + +void QmlGraphicsViewSection::setProperty(const QString &property) +{ + if (property != m_property) { + m_property = property; + emit changed(); + } +} + +void QmlGraphicsViewSection::setCriteria(QmlGraphicsViewSection::SectionCriteria criteria) +{ + if (criteria != m_criteria) { + m_criteria = criteria; + emit changed(); + } +} + +QString QmlGraphicsViewSection::sectionString(const QString &value) +{ + if (m_criteria == FirstCharacter) + return value.at(0); + else + return value; +} + class QmlGraphicsListViewAttached : public QObject { Q_OBJECT @@ -177,7 +202,8 @@ public: , averageSize(100.0), currentIndex(-1), requestedIndex(-1) , highlightRangeStart(0), highlightRangeEnd(0) , highlightComponent(0), highlight(0), trackedItem(0) - , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0), spacing(0.0) + , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0) + , sectionCriteria(0), spacing(0.0) , highlightMoveSpeed(400), highlightResizeSpeed(400), highlightRange(QmlGraphicsListView::NoHighlightRange) , snapMode(QmlGraphicsListView::NoSnap), overshootDist(0.0) , footerComponent(0), footer(0), headerComponent(0), header(0) @@ -291,12 +317,15 @@ public: } QString sectionAt(int modelIndex) { - Q_Q(QmlGraphicsListView); if (FxListItem *item = visibleItem(modelIndex)) return item->attached->section(); + QString section; - if (!sectionExpression.isEmpty()) - section = model->evaluate(modelIndex, sectionExpression, q).toString(); + if (sectionCriteria) { + QString propValue = model->value(modelIndex, sectionCriteria->property()).toString(); + section = sectionCriteria->sectionString(propValue); + } + return section; } @@ -411,7 +440,7 @@ public: } void itemGeometryChanged(QmlGraphicsItem *, const QRectF &newGeometry, const QRectF &oldGeometry) { - if (orient == QmlGraphicsListView::Vertical && newGeometry.height() != oldGeometry.height() + if ((orient == QmlGraphicsListView::Vertical && newGeometry.height() != oldGeometry.height()) || newGeometry.width() != oldGeometry.width()) { layout(); fixupPosition(); @@ -471,7 +500,7 @@ public: int buffer; QmlEaseFollow *highlightPosAnimator; QmlEaseFollow *highlightSizeAnimator; - QString sectionExpression; + QmlGraphicsViewSection *sectionCriteria; QString currentSection; qreal spacing; qreal highlightMoveSpeed; @@ -528,10 +557,9 @@ FxListItem *QmlGraphicsListViewPrivate::createItem(int modelIndex) listItem = new FxListItem(item, q); listItem->index = modelIndex; // initialise attached properties - if (!sectionExpression.isEmpty()) { - QmlExpression e(qmlContext(listItem->item), sectionExpression, q); - e.setTrackChange(false); - listItem->attached->m_section = e.value().toString(); + if (sectionCriteria) { + QString propValue = model->value(modelIndex, sectionCriteria->property()).toString(); + listItem->attached->m_section = sectionCriteria->sectionString(propValue); if (modelIndex > 0) { if (FxListItem *item = visibleItem(modelIndex-1)) listItem->attached->m_prevSection = item->attached->section(); @@ -649,7 +677,7 @@ void QmlGraphicsListViewPrivate::refill(qreal from, qreal to, bool doBuffer) if (visibleItems.count()) visiblePos = visibleItems.first()->position(); updateAverage(); - if (!sectionExpression.isEmpty()) + if (sectionCriteria) updateCurrentSection(); if (header) updateHeader(); @@ -816,7 +844,7 @@ void QmlGraphicsListViewPrivate::updateHighlight() void QmlGraphicsListViewPrivate::updateSections() { - if (!sectionExpression.isEmpty()) { + if (sectionCriteria) { QString prevSection; if (visibleIndex > 0) prevSection = sectionAt(visibleIndex-1); @@ -832,7 +860,7 @@ void QmlGraphicsListViewPrivate::updateSections() void QmlGraphicsListViewPrivate::updateCurrentSection() { - if (sectionExpression.isEmpty() || visibleItems.isEmpty()) { + if (sectionCriteria || visibleItems.isEmpty()) { currentSection = QString(); return; } @@ -1289,7 +1317,7 @@ QmlGraphicsListView::~QmlGraphicsListView() It is attached to each instance of the delegate. - The section is evaluated using the \l {ListView::sectionExpression}{sectionExpression} property. + The section is evaluated using the \l {ListView::section.property}{section} properties. */ /*! @@ -1298,7 +1326,7 @@ QmlGraphicsListView::~QmlGraphicsListView() It is attached to each instance of the delegate. - The section is evaluated using the \l {ListView::sectionExpression}{sectionExpression} property. + The section is evaluated using the \l {ListView::section.property}{section} properties. */ /*! @@ -1747,8 +1775,19 @@ void QmlGraphicsListView::setCacheBuffer(int b) } /*! - \qmlproperty string ListView::sectionExpression - This property holds the expression to be evaluated for the section attached property. + \qmlproperty string ListView::section.property + \qmlproperty enumeration ListView::section.criteria + These properties hold the expression to be evaluated for the section attached property. + + section.property hold the name of the property to use to determine + the section the item is in. + + section.criteria holds the criteria to use to get the section. It + can be either: + \list + \o ViewSection.FullString (default) - section is the value of the property. + \o ViewSection.FirstCharacter - section is the first character of the property value. + \endlist Each item in the list has attached properties named \c ListView.section and \c ListView.prevSection. These may be used to place a section header for @@ -1760,19 +1799,12 @@ void QmlGraphicsListView::setCacheBuffer(int b) \image ListViewSections.png */ -QString QmlGraphicsListView::sectionExpression() const -{ - Q_D(const QmlGraphicsListView); - return d->sectionExpression; -} - -void QmlGraphicsListView::setSectionExpression(const QString &expression) +QmlGraphicsViewSection *QmlGraphicsListView::sectionCriteria() { Q_D(QmlGraphicsListView); - if (d->sectionExpression != expression) { - d->sectionExpression = expression; - emit sectionExpressionChanged(); - } + if (!d->sectionCriteria) + d->sectionCriteria = new QmlGraphicsViewSection(this); + return d->sectionCriteria; } /*! @@ -2560,6 +2592,7 @@ QmlGraphicsListViewAttached *QmlGraphicsListView::qmlAttachedProperties(QObject } QML_DEFINE_TYPE(Qt,4,6,ListView,QmlGraphicsListView) +QML_DEFINE_TYPE(Qt,4,6,ViewSection,QmlGraphicsViewSection) QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qmlgraphicslistview_p.h b/src/declarative/graphicsitems/qmlgraphicslistview_p.h index cb9f5c4..18b2ab5 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicslistview_p.h @@ -50,6 +50,32 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class Q_DECLARATIVE_EXPORT QmlGraphicsViewSection : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY changed) + Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY changed) + Q_ENUMS(SectionCriteria) +public: + QmlGraphicsViewSection(QObject *parent=0) : QObject(parent), m_criteria(FullString) {} + + QString property() const { return m_property; } + void setProperty(const QString &); + + enum SectionCriteria { FullString, FirstCharacter }; + SectionCriteria criteria() const { return m_criteria; } + void setCriteria(SectionCriteria); + + QString sectionString(const QString &value); + +Q_SIGNALS: + void changed(); + +private: + QString m_property; + SectionCriteria m_criteria; +}; + class QmlGraphicsVisualModel; class QmlGraphicsListViewAttached; @@ -79,7 +105,7 @@ class Q_DECLARATIVE_EXPORT QmlGraphicsListView : public QmlGraphicsFlickable Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged) Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled) Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer) - Q_PROPERTY(QString sectionExpression READ sectionExpression WRITE setSectionExpression NOTIFY sectionExpressionChanged) + Q_PROPERTY(QmlGraphicsViewSection *section READ sectionCriteria CONSTANT) Q_PROPERTY(QString currentSection READ currentSection NOTIFY currentSectionChanged) Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode) @@ -138,8 +164,7 @@ public: int cacheBuffer() const; void setCacheBuffer(int); - QString sectionExpression() const; - void setSectionExpression(const QString &); + QmlGraphicsViewSection *sectionCriteria(); QString currentSection() const; qreal highlightMoveSpeed() const; @@ -201,6 +226,7 @@ QT_END_NAMESPACE QML_DECLARE_TYPEINFO(QmlGraphicsListView, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(QmlGraphicsListView) +QML_DECLARE_TYPE(QmlGraphicsViewSection) QT_END_HEADER diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp index 7c2159f..6b4a773 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp @@ -44,6 +44,7 @@ #include "qmlgraphicsitem.h" #include +#include #include #include #include @@ -208,9 +209,19 @@ void QmlGraphicsVisualItemModel::completeItem() // Nothing to do } +QVariant QmlGraphicsVisualItemModel::value(int index, const QString &name) +{ + Q_D(QmlGraphicsVisualItemModel); + if (index < 0 || index >= d->children.count()) + return QVariant(); + return QmlEngine::contextForObject(d->children.at(index))->contextProperty(name); +} + QVariant QmlGraphicsVisualItemModel::evaluate(int index, const QString &expression, QObject *objectContext) { Q_D(QmlGraphicsVisualItemModel); + if (index < 0 || index >= d->children.count()) + return QVariant(); QmlContext *ccontext = qmlContext(this); QmlContext *ctxt = new QmlContext(ccontext); ctxt->addDefaultObject(d->children.at(index)); @@ -878,6 +889,33 @@ void QmlGraphicsVisualDataModel::completeItem() d->m_delegate->completeCreate(); } +QVariant QmlGraphicsVisualDataModel::value(int index, const QString &name) +{ + Q_D(QmlGraphicsVisualDataModel); + if (d->m_visualItemModel) + return d->m_visualItemModel->value(index, name); + + if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate) + return QVariant(); + + QVariant val; + QObject *nobj = d->m_cache.item(index); + if (nobj) { + val = QmlEngine::contextForObject(nobj)->contextProperty(name); + } else { + QmlContext *ccontext = d->m_context; + if (!ccontext) ccontext = qmlContext(this); + QmlContext *ctxt = new QmlContext(ccontext); + QmlGraphicsVisualDataModelData *data = new QmlGraphicsVisualDataModelData(index, this); + ctxt->addDefaultObject(data); + val = ctxt->contextProperty(name); + delete data; + delete ctxt; + } + + return val; +} + QVariant QmlGraphicsVisualDataModel::evaluate(int index, const QString &expression, QObject *objectContext) { Q_D(QmlGraphicsVisualDataModel); @@ -914,11 +952,8 @@ QVariant QmlGraphicsVisualDataModel::evaluate(int index, const QString &expressi int QmlGraphicsVisualDataModel::indexOf(QmlGraphicsItem *item, QObject *objectContext) const { - QmlExpression e(qmlContext(item), QLatin1String("index"), objectContext); - e.setTrackChange(false); - QVariant value = e.value(); - if (value.isValid()) - return value.toInt(); + QVariant val = QmlEngine::contextForObject(item)->contextProperty("index"); + return val.toInt(); return -1; } diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h index 4e76aee..4e8a19b 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h @@ -82,6 +82,7 @@ public: virtual ReleaseFlags release(QmlGraphicsItem *item) = 0; virtual void completeItem() = 0; virtual QVariant evaluate(int index, const QString &expression, QObject *objectContext) = 0; + virtual QVariant value(int index, const QString &role) { return QVariant(); } virtual int indexOf(QmlGraphicsItem *item, QObject *objectContext) const = 0; @@ -120,6 +121,7 @@ public: virtual QmlGraphicsItem *item(int index, bool complete=true); virtual ReleaseFlags release(QmlGraphicsItem *item); virtual void completeItem(); + virtual QVariant value(int index, const QString &role); virtual QVariant evaluate(int index, const QString &expression, QObject *objectContext); virtual int indexOf(QmlGraphicsItem *item, QObject *objectContext) const; @@ -166,6 +168,7 @@ public: QmlGraphicsItem *item(int index, const QByteArray &, bool complete=true); ReleaseFlags release(QmlGraphicsItem *item); void completeItem(); + virtual QVariant value(int index, const QString &role); QVariant evaluate(int index, const QString &expression, QObject *objectContext); int indexOf(QmlGraphicsItem *item, QObject *objectContext) const; diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index c3971ae..445bf03 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -442,6 +442,30 @@ void QmlContext::setContextProperty(const QString &name, QObject *value) } } +QVariant QmlContext::contextProperty(const QString &name) const +{ + Q_D(const QmlContext); + QVariant value; + int idx = -1; + if (d->propertyNames) + idx = d->propertyNames->value(name); + + if (idx == -1) { + QByteArray utf8Name = name.toUtf8(); + for (int ii = d->defaultObjects.count() - 1; ii >= 0; --ii) { + value = d->defaultObjects.at(ii)->property(utf8Name); + if (!value.isValid() && parentContext()) + value = parentContext()->contextProperty(name); + if (value.isValid()) + break; + } + } else { + value = d->propertyValues[idx]; + } + + return value; +} + /*! Resolves the URL \a src relative to the URL of the containing component. diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h index de1d092..7547004 100644 --- a/src/declarative/qml/qmlcontext.h +++ b/src/declarative/qml/qmlcontext.h @@ -75,6 +75,8 @@ public: void setContextProperty(const QString &, QObject *); void setContextProperty(const QString &, const QVariant &); + QVariant contextProperty(const QString &) const; + QUrl resolvedUrl(const QUrl &); void setBaseUrl(const QUrl &); -- cgit v0.12 From 91fe11aeecc951c0713f7275726081017c385495 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 12:15:35 +1000 Subject: Document ListView section changed. --- src/declarative/QmlChanges.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt index 97cefd5..940dc14 100644 --- a/src/declarative/QmlChanges.txt +++ b/src/declarative/QmlChanges.txt @@ -1,3 +1,11 @@ + + +Listview: sectionExpression has been replaced by section.property, section.criteria + + +============================================================================= +The changes below are pre-4.6.0 release. + QML API Review ============== -- cgit v0.12 From b9d7f819b7bf9f7c39735377ae2e3e4d4afa1cf7 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 15:09:20 +1000 Subject: Make QListModelInterface API more sensible for our use case. --- src/declarative/3rdparty/qlistmodelinterface_p.h | 1 + src/declarative/qml/qmlcontext.cpp | 14 +++++++++++--- src/declarative/util/qmllistmodel.cpp | 23 +++++++++++++++++++++++ src/declarative/util/qmllistmodel_p.h | 1 + src/declarative/util/qmlxmllistmodel.cpp | 7 +++++++ src/declarative/util/qmlxmllistmodel_p.h | 1 + tools/qmlviewer/qmlfolderlistmodel.cpp | 14 ++++++++++++++ tools/qmlviewer/qmlfolderlistmodel.h | 1 + 8 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/declarative/3rdparty/qlistmodelinterface_p.h b/src/declarative/3rdparty/qlistmodelinterface_p.h index f7c956a..a958ead 100644 --- a/src/declarative/3rdparty/qlistmodelinterface_p.h +++ b/src/declarative/3rdparty/qlistmodelinterface_p.h @@ -60,6 +60,7 @@ class Q_DECLARATIVE_EXPORT QListModelInterface : public QObject virtual int count() const = 0; virtual QHash data(int index, const QList& roles = QList()) const = 0; + virtual QVariant data(int index, int role) const = 0; virtual bool setData(int index, const QHash& values) { Q_UNUSED(index); Q_UNUSED(values); return false; } diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 445bf03..49bb59c 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -453,12 +453,20 @@ QVariant QmlContext::contextProperty(const QString &name) const if (idx == -1) { QByteArray utf8Name = name.toUtf8(); for (int ii = d->defaultObjects.count() - 1; ii >= 0; --ii) { - value = d->defaultObjects.at(ii)->property(utf8Name); - if (!value.isValid() && parentContext()) - value = parentContext()->contextProperty(name); + QObject *obj = d->defaultObjects.at(ii); + QmlDeclarativeData *data = QmlDeclarativeData::get(obj); + if (data && data->propertyCache) { + QmlPropertyCache::Data *property = data->propertyCache->property(name); + if (property) + value = obj->metaObject()->property(property->coreIndex).read(obj); + } else { + value = obj->property(utf8Name); + } if (value.isValid()) break; } + if (!value.isValid() && parentContext()) + value = parentContext()->contextProperty(name); } else { value = d->propertyValues[idx]; } diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index f4317af..de6ee2e 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -421,6 +421,29 @@ QHash QmlListModel::data(int index, const QList &roles) const return rv; } +QVariant QmlListModel::data(int index, int role) const +{ + checkRoles(); + QVariant rv; + if (index >= count()) + return rv; + + ModelNode *node = qvariant_cast(_root->values.at(index)); + if (!node) + return rv; + + const QString &roleString = roleStrings.at(role); + + QHash::ConstIterator iter = + node->properties.find(roleString); + if (iter != node->properties.end()) { + ModelNode *row = *iter; + rv = valueForNode(row); + } + + return rv; +} + /*! \qmlproperty int ListModel::count The number of data entries in the model. diff --git a/src/declarative/util/qmllistmodel_p.h b/src/declarative/util/qmllistmodel_p.h index 2a1a57d..47236d0 100644 --- a/src/declarative/util/qmllistmodel_p.h +++ b/src/declarative/util/qmllistmodel_p.h @@ -72,6 +72,7 @@ public: virtual QString toString(int role) const; virtual int count() const; virtual QHash data(int index, const QList &roles = (QList())) const; + virtual QVariant data(int index, int role) const; Q_INVOKABLE void clear(); Q_INVOKABLE void remove(int index); diff --git a/src/declarative/util/qmlxmllistmodel.cpp b/src/declarative/util/qmlxmllistmodel.cpp index 46ef739..d31fadf 100644 --- a/src/declarative/util/qmlxmllistmodel.cpp +++ b/src/declarative/util/qmlxmllistmodel.cpp @@ -462,6 +462,13 @@ QHash QmlXmlListModel::data(int index, const QList &roles) co return rv; } +QVariant QmlXmlListModel::data(int index, int role) const +{ + Q_D(const QmlXmlListModel); + int roleIndex = d->roles.indexOf(role); + return (roleIndex == -1) ? QVariant() : d->data.at(roleIndex).at(index); +} + /*! \qmlproperty int XmlListModel::count The number of data entries in the model. diff --git a/src/declarative/util/qmlxmllistmodel_p.h b/src/declarative/util/qmlxmllistmodel_p.h index 67fc751..e4b8cab 100644 --- a/src/declarative/util/qmlxmllistmodel_p.h +++ b/src/declarative/util/qmlxmllistmodel_p.h @@ -79,6 +79,7 @@ public: ~QmlXmlListModel(); virtual QHash data(int index, const QList &roles = (QList())) const; + virtual QVariant data(int index, int role) const; virtual int count() const; virtual QList roles() const; virtual QString toString(int role) const; diff --git a/tools/qmlviewer/qmlfolderlistmodel.cpp b/tools/qmlviewer/qmlfolderlistmodel.cpp index 4f33f31..35c672d 100644 --- a/tools/qmlviewer/qmlfolderlistmodel.cpp +++ b/tools/qmlviewer/qmlfolderlistmodel.cpp @@ -142,6 +142,20 @@ QHash QmlFolderListModel::data(int index, const QList &roles) return folderData; } +QVariant QmlFolderListModel::data(int index, int role) const +{ + QVariant rv; + QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); + if (modelIndex.isValid()) { + if (role == QDirModel::FileNameRole) + rv = d->model.data(modelIndex, QDirModel::FileNameRole); + else if (role == QDirModel::FilePathRole) + rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); + } + + return rv; +} + int QmlFolderListModel::count() const { return d->count; diff --git a/tools/qmlviewer/qmlfolderlistmodel.h b/tools/qmlviewer/qmlfolderlistmodel.h index cbee8c7..7357954 100644 --- a/tools/qmlviewer/qmlfolderlistmodel.h +++ b/tools/qmlviewer/qmlfolderlistmodel.h @@ -68,6 +68,7 @@ public: ~QmlFolderListModel(); virtual QHash data(int index, const QList &roles = (QList())) const; + virtual QVariant data(int index, int role) const; virtual int count() const; virtual QList roles() const; virtual QString toString(int role) const; -- cgit v0.12 From 0bd5787e4d4c89fd860ff70bcdb0ddb9e4a4f8db Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 16 Dec 2009 15:31:19 +1000 Subject: Binding optimizer extensions --- src/declarative/qml/qmlbinding.cpp | 5 + src/declarative/qml/qmlbinding.h | 2 + src/declarative/qml/qmlbindingoptimizations.cpp | 112 +++++--- src/declarative/qml/qmlbindingoptimizations_p.h | 54 ++-- src/declarative/qml/qmlbindingvme.cpp | 324 +++++++++++++++++------- src/declarative/qml/qmlbindingvme_p.h | 25 +- src/declarative/qml/qmlcompiler.cpp | 29 ++- src/declarative/qml/qmlcompiler_p.h | 4 + src/declarative/qml/qmlengine.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 1 + src/declarative/qml/qmlvme.cpp | 22 +- 11 files changed, 408 insertions(+), 172 deletions(-) diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 56d5807..d1a8fe8 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -276,6 +276,11 @@ QmlAbstractBinding::~QmlAbstractBinding() *m_mePtr = 0; } +void QmlAbstractBinding::destroy() +{ + delete this; +} + void QmlAbstractBinding::addToObject(QObject *object) { Q_ASSERT(object); diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index 6f2d4f1..177a0fd 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -61,6 +61,8 @@ public: QmlAbstractBinding(); virtual ~QmlAbstractBinding(); + virtual void destroy(); + virtual QString expression() const; void setEnabled(bool e) { setEnabled(e, QmlMetaProperty::DontRemoveBinding); } diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp index 120e07b..d8a2de0 100644 --- a/src/declarative/qml/qmlbindingoptimizations.cpp +++ b/src/declarative/qml/qmlbindingoptimizations.cpp @@ -47,32 +47,50 @@ QT_BEGIN_NAMESPACE -int QmlBinding_Basic::reevalIndex = -1; +int QmlOptimizedBindings::methodCount = -1; -QmlBinding_Basic::QmlBinding_Basic(QObject *target, int property, - const char *data, QmlRefCount *ref, - QObject *scope, QmlContext *context) -: m_enabled(false), m_updating(false), m_scope(scope), m_target(target), - m_property(property), m_data(data) +QmlOptimizedBindings::QmlOptimizedBindings(const char *program, QmlContext *context) +: m_program(program) { - if (reevalIndex == -1) - reevalIndex = QmlBinding_Basic::staticMetaObject.indexOfSlot("reeval()"); + if (methodCount == -1) + methodCount = QmlOptimizedBindings::staticMetaObject.methodCount(); m_config.target = this; - m_config.targetSlot = reevalIndex; - m_scope2 = m_scope; + m_config.targetSlot = metaObject()->methodCount(); + + quint32 bindings = 0; + QmlBindingVME::init(m_program, &m_config, &m_signalTable, &bindings); + + m_bindings = new Binding[bindings]; QmlAbstractExpression::setContext(context); } -QmlBinding_Basic::~QmlBinding_Basic() +QmlOptimizedBindings::~QmlOptimizedBindings() { + delete [] m_bindings; } -void QmlBinding_Basic::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) +QmlAbstractBinding *QmlOptimizedBindings::configBinding(int index, QObject *target, + QObject *scope, int property) +{ + Binding *rv = m_bindings + index; + + rv->index = index; + rv->property = property; + rv->target = target; + rv->scope = scope; + rv->parent = this; + + addref(); // This is decremented in Binding::destroy() + + return rv; +} + +void QmlOptimizedBindings::Binding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) { if (e) { - addToObject(m_target); + addToObject(target); update(flags); } else { removeFromObject(); @@ -80,56 +98,74 @@ void QmlBinding_Basic::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) QmlAbstractBinding::setEnabled(e, flags); - if (m_enabled != e) { - m_enabled = e; + if (enabled != e) { + enabled = e; if (e) update(flags); } } -int QmlBinding_Basic::propertyIndex() +int QmlOptimizedBindings::Binding::propertyIndex() { - return m_property & 0xFFFF; + return property & 0xFFFF; } -void QmlBinding_Basic::update(QmlMetaProperty::WriteFlags flags) +void QmlOptimizedBindings::Binding::update(QmlMetaProperty::WriteFlags) { - if (!m_enabled) - return; + parent->run(this); +} - if (m_updating) { - qmlInfo(m_target) << tr("Binding loop detected"); - return; +void QmlOptimizedBindings::Binding::destroy() +{ + enabled = false; + removeFromObject(); + parent->release(); +} + +int QmlOptimizedBindings::qt_metacall(QMetaObject::Call c, int id, void **) +{ + if (c == QMetaObject::InvokeMetaMethod && id >= methodCount) { + id -= methodCount; + + quint32 *reeval = m_signalTable + m_signalTable[id]; + quint32 count = *reeval; + ++reeval; + for (quint32 ii = 0; ii < count; ++ii) { + run(m_bindings + reeval[ii]); + } } + return -1; +} + +void QmlOptimizedBindings::run(Binding *binding) +{ + if (!binding->enabled) + return; + if (binding->updating) + qWarning("ERROR: Circular binding"); QmlContext *context = QmlAbstractExpression::context(); if (!context) return; QmlContextPrivate *cp = QmlContextPrivate::get(context); - m_updating = true; - - if (m_property & 0xFFFF0000) { + if (binding->property & 0xFFFF0000) { QmlEnginePrivate *ep = QmlEnginePrivate::get(cp->engine); - QmlValueType *vt = ep->valueTypes[(m_property >> 16) & 0xFF]; + QmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; Q_ASSERT(vt); - vt->read(m_target, m_property & 0xFFFF); + vt->read(binding->target, binding->property & 0xFFFF); QObject *target = vt; - QmlBindingVME::run(m_data, &m_config, cp, &m_scope, &target); + QmlBindingVME::run(m_program, binding->index, &m_config, cp, + &binding->scope, &target); - vt->write(m_target, m_property & 0xFFFF, flags); + vt->write(binding->target, binding->property & 0xFFFF, + QmlMetaProperty::DontRemoveBinding); } else { - QmlBindingVME::run(m_data, &m_config, cp, &m_scope, &m_target); + QmlBindingVME::run(m_program, binding->index, &m_config, cp, + &binding->scope, &binding->target); } - - m_updating = false; -} - -void QmlBinding_Basic::reeval() -{ - update(QmlMetaProperty::DontRemoveBinding); } /* diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlbindingoptimizations_p.h index ee2eb83..6289cc0 100644 --- a/src/declarative/qml/qmlbindingoptimizations_p.h +++ b/src/declarative/qml/qmlbindingoptimizations_p.h @@ -62,36 +62,44 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QmlBinding_Basic : public QObject, - public QmlAbstractExpression, - public QmlAbstractBinding +class QmlOptimizedBindings : public QObject, public QmlAbstractExpression, public QmlRefCount { - Q_OBJECT public: - QmlBinding_Basic(QObject *target, int property, - const char *data, QmlRefCount *ref, - QObject *scope, QmlContext *context); - virtual ~QmlBinding_Basic(); + QmlOptimizedBindings(const char *program, QmlContext *context); + virtual ~QmlOptimizedBindings(); + QmlAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property); - // Inherited from QmlAbstractBinding - virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); - virtual int propertyIndex(); - virtual void update(QmlMetaProperty::WriteFlags flags); - -private slots: - void reeval(); +protected: + int qt_metacall(QMetaObject::Call, int, void **); private: - bool m_enabled:1; - bool m_updating:1; - QObject *m_scope; - QObject *m_target; - int m_property; - const char *m_data; + struct Binding : public QmlAbstractBinding { + Binding() : enabled(false), updating(0), property(0), + scope(0), target(0), parent(0) {} + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); + virtual int propertyIndex(); + virtual void update(QmlMetaProperty::WriteFlags flags); + virtual void destroy(); + + int index:30; + bool enabled:1; + bool updating:1; + int property; + QObject *scope; + QObject *target; + + QmlOptimizedBindings *parent; + }; + void run(Binding *); + QmlBindingVME::Config m_config; - QGuard m_scope2; + const char *m_program; + Binding *m_bindings; + quint32 *m_signalTable; - static int reevalIndex; + static int methodCount; }; class QmlBinding_Id : public QmlAbstractExpression, diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index e5cbdfc..d85d7ba 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -79,8 +79,6 @@ struct Instr { enum { Noop, - Init, // init - Subscribe, // subscribe SubscribeId, // subscribe @@ -224,13 +222,18 @@ struct Instr { }; struct Program { - int dataLength; + quint32 bindings; + quint32 dataLength; + quint32 signalTableOffset; + quint16 subscriptions; + quint16 identifiers; + const char *data() const { return ((const char *)this) + sizeof(Program); } const Instr *instructions() const { return (const Instr *)(data() + dataLength); } }; } -struct QmlBindingCompiler +struct QmlBindingCompilerPrivate { struct Result { Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {} @@ -251,8 +254,12 @@ struct QmlBindingCompiler QSet subscriptionSet; }; - QmlBindingCompiler() : registers(0), strings(0) {} - void reset(); + QmlBindingCompilerPrivate() : registers(0), strings(0) { + committed.strings = 0; + } + + void resetInstanceState(); + int commitCompile(); QmlParser::Object *context; QmlParser::Object *component; @@ -261,6 +268,8 @@ struct QmlBindingCompiler QmlEnginePrivate::Imports imports; QmlEnginePrivate *engine; + QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((intptr_t)context, 16); } + bool compile(QmlJS::AST::Node *); bool parseExpression(QmlJS::AST::Node *, Result &); @@ -293,60 +302,44 @@ struct QmlBindingCompiler int strings; QByteArray data; - QSet subscriptionSet; - QHash subscriptionIds; bool subscription(const QStringList &, Result *); int subscriptionIndex(const QStringList &); bool subscriptionNeutral(const QSet &base, const QSet &lhs, const QSet &rhs); - QVector bytecode; -}; -QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression, QmlEnginePrivate *engine) -{ - if (!expression.expression.asAST()) return false; + QSet usedSubscriptionIds; + QSet subscriptionSet; + QHash subscriptionIds; + QVector bytecode; - QmlBindingCompiler bsc; - bsc.context = expression.context; - bsc.component = expression.component; - bsc.destination = expression.property; - bsc.ids = expression.ids; - bsc.imports = expression.imports; - bsc.engine = engine; + // Committed binding data + struct { + QList offsets; + QList > dependencies; - bool ok = bsc.compile(expression.expression.asAST()); + QVector bytecode; + QByteArray data; + int strings; + QHash subscriptionIds; - if (ok) { - Program prog; - prog.dataLength = 4 * ((bsc.data.size() + 3) / 4); - int size = sizeof(Program) + bsc.bytecode.count() * sizeof(Instr); - size += prog.dataLength; + int count() const { return offsets.count(); } + } committed; - QByteArray data; - data.resize(size); - memcpy(data.data(), &prog, sizeof(Program)); - if (prog.dataLength) - memcpy((char *)((Program *)data.data())->data(), bsc.data.constData(), - bsc.data.size()); - memcpy((char *)((Program *)data.data())->instructions(), bsc.bytecode.constData(), - bsc.bytecode.count() * sizeof(Instr)); - return data; - } else { - return QByteArray(); - } -} + QByteArray buildSignalTable() const; +}; -inline void subscribe(QObject *o, int notifyIndex, QmlBindingVME::Config::Subscription *s, - QmlBindingVME::Config *config) +inline void subscribe(QObject *o, int notifyIndex, + int subIndex, QmlBindingVME::Config *config) { + QmlBindingVME::Config::Subscription *s = config->subscriptions + subIndex; if (o != s->source || notifyIndex != s->notifyIndex) { if (s->source) QMetaObject::disconnect(s->source, s->notifyIndex, - config->target, config->targetSlot); + config->target, config->targetSlot + subIndex); s->source = o; s->notifyIndex = notifyIndex; - if (s->source && s->notifyIndex != -1) + if (s->source && s->notifyIndex != -1) QMetaObject::connect(s->source, s->notifyIndex, config->target, - config->targetSlot, Qt::DirectConnection); + config->targetSlot + subIndex, Qt::DirectConnection); } } @@ -436,7 +429,7 @@ static bool findproperty(QObject *obj, } if (subIdx != -1) - subscribe(obj, property->notifyIndex, config->subscriptions + subIdx, config); + subscribe(obj, property->notifyIndex, subIdx, config); return true; } else { @@ -588,8 +581,24 @@ inline static QUrl toUrl(Register *reg, int type, QmlContextPrivate *context, bo return base; } -void QmlBindingVME::run(const char *programData, Config *config, - QmlContextPrivate *context, +/*! +Returns the signal/binding table. +*/ +void QmlBindingVME::init(const char *programData, Config *config, + quint32 **sigTable, quint32 *bindingCount) +{ + Program *program = (Program *)programData; + if (program->subscriptions) + config->subscriptions = new Config::Subscription[program->subscriptions]; + if (program->identifiers) + config->identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers]; + + *sigTable = (quint32 *)(program->data() + program->signalTableOffset); + *bindingCount = program->bindings; +} + +void QmlBindingVME::run(const char *programData, int instrIndex, + Config *config, QmlContextPrivate *context, QObject **scopes, QObject **outputs) { Register registers[32]; @@ -598,6 +607,7 @@ void QmlBindingVME::run(const char *programData, Config *config, QmlEnginePrivate *engine = QmlEnginePrivate::get(context->engine); Program *program = (Program *)programData; const Instr *instr = program->instructions(); + instr += instrIndex; const char *data = program->data(); while (instr) { @@ -605,18 +615,11 @@ void QmlBindingVME::run(const char *programData, Config *config, switch (instr->type) { case Instr::Noop: break; - case Instr::Init: - if (!config->subscriptions && instr->init.subscriptions) - config->subscriptions = new Config::Subscription[instr->init.subscriptions]; - if (!config->identifiers && instr->init.identifiers) - config->identifiers = new QScriptDeclarativeClass::PersistentIdentifier[instr->init.identifiers]; - break; case Instr::SubscribeId: case Instr::Subscribe: { QObject *o = registers[instr->subscribe.reg].getQObject(); - Config::Subscription *s = config->subscriptions + instr->subscribe.offset; int notifyIndex = instr->subscribe.index; if (instr->type == Instr::SubscribeId) { @@ -624,7 +627,7 @@ void QmlBindingVME::run(const char *programData, Config *config, notifyIndex += context->notifyIndex; } - subscribe(o, instr->subscribe.index, s, config); + subscribe(o, instr->subscribe.index, instr->subscribe.offset, config); } break; @@ -852,6 +855,11 @@ void QmlBindingVME::dump(const QByteArray &programData) { const Program *program = (const Program *)programData.constData(); + qWarning() << "Program.bindings:" << program->bindings; + qWarning() << "Program.dataLength:" << program->dataLength; + qWarning() << "Program.subscriptions:" << program->subscriptions; + qWarning() << "Program.indentifiers:" << program->identifiers; + int count = (programData.size() - sizeof(Program) - program->dataLength) / sizeof(Instr); const Instr *instr = program->instructions(); @@ -861,9 +869,6 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::Noop: qWarning().nospace() << "Noop"; break; - case Instr::Init: - qWarning().nospace() << "Init" << "\t\t\t" << instr->init.subscriptions << "\t" << instr->init.identifiers; - break; case Instr::Subscribe: qWarning().nospace() << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index; break; @@ -990,18 +995,42 @@ void QmlBindingVME::dump(const QByteArray &programData) } } -void QmlBindingCompiler::reset() +/*! +Clear the state associated with attempting to compile a specific binding. +This does not clear the global "commited binding" states. +*/ +void QmlBindingCompilerPrivate::resetInstanceState() { registers = 0; - strings = 0; - data.clear(); + strings = committed.strings; + data = committed.data; + subscriptionIds = committed.subscriptionIds; subscriptionSet.clear(); + usedSubscriptionIds.clear(); bytecode.clear(); } -bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) +/*! +Mark the last compile as successful, and add it to the "committed data" +section. + +Returns the index for the committed binding. +*/ +int QmlBindingCompilerPrivate::commitCompile() { - reset(); + int rv = committed.count(); + committed.offsets << committed.bytecode.count(); + committed.dependencies << usedSubscriptionIds; + committed.bytecode << bytecode; + committed.data = data; + committed.strings = strings; + committed.subscriptionIds = subscriptionIds; + return rv; +} + +bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node) +{ + resetInstanceState(); Result type; @@ -1012,12 +1041,6 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) if (subscriptionSet.count() > 0xFFFF || strings > 0xFFFF) return false; - - Instr init; - init.type = Instr::Init; - init.init.subscriptions = subscriptionIds.count(); - init.init.identifiers = strings; - bytecode.prepend(init); } if (type.unknownType) { @@ -1141,7 +1164,7 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) } } -bool QmlBindingCompiler::parseExpression(QmlJS::AST::Node *node, Result &type) +bool QmlBindingCompilerPrivate::parseExpression(QmlJS::AST::Node *node, Result &type) { while (node->kind == AST::Node::Kind_NestedExpression) node = static_cast(node)->expression; @@ -1162,13 +1185,13 @@ bool QmlBindingCompiler::parseExpression(QmlJS::AST::Node *node, Result &type) return true; } -bool QmlBindingCompiler::tryName(QmlJS::AST::Node *node) +bool QmlBindingCompilerPrivate::tryName(QmlJS::AST::Node *node) { return node->kind == AST::Node::Kind_IdentifierExpression || node->kind == AST::Node::Kind_FieldMemberExpression; } -bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) +bool QmlBindingCompilerPrivate::parseName(AST::Node *node, Result &type) { QStringList nameParts; if (!buildName(nameParts, node)) @@ -1226,11 +1249,12 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) attach.attached.index = attachType->index(); bytecode << attach; + subscribeName << contextName(); + subscribeName << QLatin1String("$$$ATTACH_") + name; + absType = 0; type.metaObject = attachType->attachedPropertiesType(); - subscribeName << QLatin1String("$$$ATTACH_") + name; - continue; } else if (ids.contains(name)) { QmlParser::Object *idObject = ids.value(name); @@ -1287,7 +1311,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) instr.load.reg = reg; bytecode << instr; - subscribeName << QLatin1String("$$$Scope"); + subscribeName << contextName(); subscribeName << name; fetch(type, context->metaObject(), reg, d0Idx, subscribeName); @@ -1298,7 +1322,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) instr.load.reg = reg; bytecode << instr; - subscribeName << QLatin1String("$$$Root"); + subscribeName << QLatin1String("$$$ROOT"); subscribeName << name; fetch(type, component->metaObject(), reg, d1Idx, subscribeName); @@ -1395,7 +1419,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) return true; } -bool QmlBindingCompiler::tryArith(QmlJS::AST::Node *node) +bool QmlBindingCompilerPrivate::tryArith(QmlJS::AST::Node *node) { if (node->kind != AST::Node::Kind_BinaryExpression) return false; @@ -1408,7 +1432,7 @@ bool QmlBindingCompiler::tryArith(QmlJS::AST::Node *node) return false; } -bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type) +bool QmlBindingCompilerPrivate::parseArith(QmlJS::AST::Node *node, Result &type) { AST::BinaryExpression *expression = static_cast(node); @@ -1473,7 +1497,7 @@ bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type) return true; } -bool QmlBindingCompiler::tryLogic(QmlJS::AST::Node *node) +bool QmlBindingCompilerPrivate::tryLogic(QmlJS::AST::Node *node) { if (node->kind != AST::Node::Kind_BinaryExpression) return false; @@ -1487,7 +1511,7 @@ bool QmlBindingCompiler::tryLogic(QmlJS::AST::Node *node) return false; } -bool QmlBindingCompiler::parseLogic(QmlJS::AST::Node *node, Result &type) +bool QmlBindingCompilerPrivate::parseLogic(QmlJS::AST::Node *node, Result &type) { AST::BinaryExpression *expression = static_cast(node); @@ -1542,12 +1566,12 @@ bool QmlBindingCompiler::parseLogic(QmlJS::AST::Node *node, Result &type) return true; } -bool QmlBindingCompiler::tryConditional(QmlJS::AST::Node *node) +bool QmlBindingCompilerPrivate::tryConditional(QmlJS::AST::Node *node) { return (node->kind == AST::Node::Kind_ConditionalExpression); } -bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type) +bool QmlBindingCompilerPrivate::parseConditional(QmlJS::AST::Node *node, Result &type) { AST::ConditionalExpression *expression = static_cast(node); @@ -1610,14 +1634,14 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type) return true; } -bool QmlBindingCompiler::tryConstant(QmlJS::AST::Node *node) +bool QmlBindingCompilerPrivate::tryConstant(QmlJS::AST::Node *node) { return node->kind == AST::Node::Kind_TrueLiteral || node->kind == AST::Node::Kind_FalseLiteral || node->kind == AST::Node::Kind_NumericLiteral; } -bool QmlBindingCompiler::parseConstant(QmlJS::AST::Node *node, Result &type) +bool QmlBindingCompilerPrivate::parseConstant(QmlJS::AST::Node *node, Result &type) { type.metaObject = 0; type.type = -1; @@ -1652,7 +1676,7 @@ bool QmlBindingCompiler::parseConstant(QmlJS::AST::Node *node, Result &type) } } -bool QmlBindingCompiler::buildName(QStringList &name, +bool QmlBindingCompilerPrivate::buildName(QStringList &name, QmlJS::AST::Node *node) { if (node->kind == AST::Node::Kind_IdentifierExpression) { @@ -1673,7 +1697,7 @@ bool QmlBindingCompiler::buildName(QStringList &name, } -bool QmlBindingCompiler::fetch(Result &rv, const QMetaObject *mo, int reg, int idx, const QStringList &subName) +bool QmlBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, int idx, const QStringList &subName) { QMetaProperty prop = mo->property(idx); rv.metaObject = 0; @@ -1731,12 +1755,12 @@ bool QmlBindingCompiler::fetch(Result &rv, const QMetaObject *mo, int reg, int i return true; } -void QmlBindingCompiler::registerCleanup(int reg, int cleanup, int cleanupType) +void QmlBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType) { registerCleanups.insert(reg, qMakePair(cleanup, cleanupType)); } -int QmlBindingCompiler::acquireReg(int cleanup, int cleanupType) +int QmlBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType) { for (int ii = 0; ii < 32; ++ii) { if (!(registers & (1 << ii))) { @@ -1751,7 +1775,7 @@ int QmlBindingCompiler::acquireReg(int cleanup, int cleanupType) return -1; } -void QmlBindingCompiler::releaseReg(int reg) +void QmlBindingCompilerPrivate::releaseReg(int reg) { Q_ASSERT(reg >= 0 && reg <= 31); @@ -1769,7 +1793,7 @@ void QmlBindingCompiler::releaseReg(int reg) registers &= ~mask; } -int QmlBindingCompiler::registerString(const QString &string) +int QmlBindingCompilerPrivate::registerString(const QString &string) { Q_ASSERT(!string.isEmpty()); @@ -1788,7 +1812,7 @@ int QmlBindingCompiler::registerString(const QString &string) return strings - 1; } -bool QmlBindingCompiler::subscription(const QStringList &sub, Result *result) +bool QmlBindingCompilerPrivate::subscription(const QStringList &sub, Result *result) { QString str = sub.join(QLatin1String(".")); result->subscriptionSet.insert(str); @@ -1801,12 +1825,13 @@ bool QmlBindingCompiler::subscription(const QStringList &sub, Result *result) } } -int QmlBindingCompiler::subscriptionIndex(const QStringList &sub) +int QmlBindingCompilerPrivate::subscriptionIndex(const QStringList &sub) { QString str = sub.join(QLatin1String(".")); QHash::ConstIterator iter = subscriptionIds.find(str); if (iter == subscriptionIds.end()) iter = subscriptionIds.insert(str, subscriptionIds.count()); + usedSubscriptionIds.insert(*iter); return *iter; } @@ -1814,7 +1839,7 @@ int QmlBindingCompiler::subscriptionIndex(const QStringList &sub) Returns true if lhs contains no subscriptions that aren't also in base or rhs AND rhs contains no subscriptions that aren't also in base or lhs. */ -bool QmlBindingCompiler::subscriptionNeutral(const QSet &base, +bool QmlBindingCompilerPrivate::subscriptionNeutral(const QSet &base, const QSet &lhs, const QSet &rhs) { @@ -1828,5 +1853,118 @@ bool QmlBindingCompiler::subscriptionNeutral(const QSet &base, return difflhs.isEmpty(); } + + +QmlBindingCompiler::QmlBindingCompiler() +: d(new QmlBindingCompilerPrivate) +{ +} + +QmlBindingCompiler::~QmlBindingCompiler() +{ + delete d; d = 0; +} + +/* +Returns true if any bindings were compiled. +*/ +bool QmlBindingCompiler::isValid() const +{ + return d->bytecode.count(); +} + +/* +-1 on failure, otherwise the binding index to use. +*/ +int QmlBindingCompiler::compile(const QmlBasicScript::Expression &expression, + QmlEnginePrivate *engine) +{ + if (!expression.expression.asAST()) return false; + + d->context = expression.context; + d->component = expression.component; + d->destination = expression.property; + d->ids = expression.ids; + d->imports = expression.imports; + d->engine = engine; + + if (d->compile(expression.expression.asAST())) { + return d->commitCompile(); + } else { + return -1; + } +} + + +QByteArray QmlBindingCompilerPrivate::buildSignalTable() const +{ + QHash > table; + + for (int ii = 0; ii < committed.count(); ++ii) { + const QSet &deps = committed.dependencies.at(ii); + for (QSet::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter) + table[*iter].append(ii); + } + + QVector header; + QVector data; + for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) { + header.append(committed.subscriptionIds.count() + data.count()); + const QList &bindings = table[ii]; + data.append(bindings.count()); + for (int jj = 0; jj < bindings.count(); ++jj) + data.append(bindings.at(jj)); + } + header << data; + + return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32)); +} + +/* +Returns the compiled program. +*/ +QByteArray QmlBindingCompiler::program() const +{ + QByteArray programData; + + if (isValid()) { + Program prog; + prog.bindings = d->committed.count(); + + QVector bytecode; + Instr skip; + skip.type = Instr::Skip; + skip.skip.reg = -1; + for (int ii = 0; ii < d->committed.count(); ++ii) { + skip.skip.count = d->committed.count() - ii - 1; + skip.skip.count+= d->committed.offsets.at(ii); + bytecode << skip; + } + bytecode << d->committed.bytecode; + + QByteArray data = d->committed.data; + while (data.count() % 4) data.append('\0'); + prog.signalTableOffset = data.count(); + data += d->buildSignalTable(); + + prog.dataLength = 4 * ((data.size() + 3) / 4); + prog.subscriptions = d->committed.subscriptionIds.count(); + prog.identifiers = d->committed.strings; + int size = sizeof(Program) + bytecode.count() * sizeof(Instr); + size += prog.dataLength; + + programData.resize(size); + memcpy(programData.data(), &prog, sizeof(Program)); + if (prog.dataLength) + memcpy((char *)((Program *)programData.data())->data(), data.constData(), + data.size()); + memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(), + bytecode.count() * sizeof(Instr)); + } + + return programData; +} + + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h index a01c308..de73037 100644 --- a/src/declarative/qml/qmlbindingvme_p.h +++ b/src/declarative/qml/qmlbindingvme_p.h @@ -80,13 +80,34 @@ public: QScriptDeclarativeClass::PersistentIdentifier *identifiers; }; - static QByteArray compile(const QmlBasicScript::Expression &, QmlEnginePrivate *); - static void run(const char *program, + static void init(const char *program, Config *config, + quint32 **sigTable, quint32 *bindingCount); + static void run(const char *program, int instr, Config *config, QmlContextPrivate *context, QObject **scopes, QObject **outputs); static void dump(const QByteArray &); }; +class QmlBindingCompilerPrivate; +class QmlBindingCompiler +{ +public: + QmlBindingCompiler(); + ~QmlBindingCompiler(); + + // Returns true if bindings were compiled + bool isValid() const; + + // -1 on failure, otherwise the binding index to use + int compile(const QmlBasicScript::Expression &, QmlEnginePrivate *); + + // Returns the compiled program + QByteArray program() const; + +private: + QmlBindingCompilerPrivate *d; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 53ea18e..f25f8b8 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -643,6 +643,10 @@ void QmlCompiler::compileTree(Object *tree) init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; init.init.contextCache = genContextCache(); + if (compileState.compiledBindingData.isEmpty()) + init.init.compiledBinding = -1; + else + init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); output->bytecode << init; genObject(tree); @@ -1010,6 +1014,10 @@ void QmlCompiler::genComponent(QmlParser::Object *obj) init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; init.init.contextCache = genContextCache(); + if (compileState.compiledBindingData.isEmpty()) + init.init.compiledBinding = -1; + else + init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); init.line = obj->location.start.line; output->bytecode << init; @@ -2423,7 +2431,7 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, if (ref.dataType == BindingReference::Experimental) { QmlInstruction store; store.type = QmlInstruction::StoreCompiledBinding; - store.assignBinding.value = output->indexForByteArray(ref.compiledData); + store.assignBinding.value = ref.compiledIndex; store.assignBinding.context = ref.bindingContext.stack; store.assignBinding.owner = ref.bindingContext.owner; if (valueTypeProperty) @@ -2529,6 +2537,8 @@ bool QmlCompiler::completeComponentBuild() expr.component = compileState.root; expr.ids = compileState.ids; + QmlBindingCompiler bindingCompiler; + for (QHash::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { BindingReference &binding = *iter; @@ -2541,15 +2551,15 @@ bool QmlCompiler::completeComponentBuild() bs.compile(expr); if (qmlExperimental() && (!bs.isValid() || (!bs.isSingleIdFetch() && !bs.isSingleContextProperty()))) { - - QByteArray qmvdata = QmlBindingVME::compile(expr, QmlEnginePrivate::get(engine)); - if (!qmvdata.isEmpty()) { - qWarning() << expr.expression.asScript(); - QmlBindingVME::dump(qmvdata); + int index = bindingCompiler.compile(expr, QmlEnginePrivate::get(engine)); + if (index != -1) { + qWarning() << "Accepted for optimization:" << qPrintable(expr.expression.asScript()); binding.dataType = BindingReference::Experimental; - binding.compiledData = qmvdata; + binding.compiledIndex = index; componentStat.optimizedBindings++; continue; + } else { + qWarning() << "Rejected for optimization:" << qPrintable(expr.expression.asScript()); } } @@ -2599,6 +2609,11 @@ bool QmlCompiler::completeComponentBuild() sizeof(quint32))); } + if (bindingCompiler.isValid()) { + compileState.compiledBindingData = bindingCompiler.program(); + QmlBindingVME::dump(compileState.compiledBindingData); + } + saveComponentState(); return true; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index d734a12..3fcba15 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -273,6 +273,8 @@ private: enum DataType { QtScript, BasicScript, Experimental }; DataType dataType; + int compiledIndex; + QByteArray compiledData; BindingContext bindingContext; }; @@ -287,6 +289,8 @@ private: int parserStatusCount; int pushedProperties; + QByteArray compiledBindingData; + QHash bindings; QList aliasingObjects; QmlParser::Object *root; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index ad68c8f..6b66095 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -564,7 +564,7 @@ void QmlDeclarativeData::destroyed(QObject * /*object*/) QmlAbstractBinding *next = binding->m_nextBinding; binding->m_prevBinding = 0; binding->m_nextBinding = 0; - delete binding; + binding->destroy(); binding = next; } diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index d06ac86..6e2b452 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -170,6 +170,7 @@ public: int bindingsSize; int parserStatusSize; int contextCache; + int compiledBinding; } init; struct { int type; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index e4295a1..ae7bf51 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -161,6 +161,8 @@ QObject *QmlVME::run(QmlVMEStack &stack, QmlContext *ctxt, int status = -1; //for dbus QmlMetaProperty::WriteFlags flags = QmlMetaProperty::BypassInterceptor; + QmlOptimizedBindings *optimizedBindings = 0; + for (int ii = start; !isError() && ii < (start + count); ++ii) { const QmlInstruction &instr = comp->bytecode.at(ii); @@ -171,9 +173,10 @@ QObject *QmlVME::run(QmlVMEStack &stack, QmlContext *ctxt, bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); - if (instr.init.contextCache != -1) cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); + if (instr.init.compiledBinding != -1) + optimizedBindings = new QmlOptimizedBindings(datas.at(instr.init.compiledBinding).constData(), ctxt); } break; @@ -619,13 +622,11 @@ QObject *QmlVME::run(QmlVMEStack &stack, QmlContext *ctxt, if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF)) break; - const char *data = datas.at(instr.assignBinding.value).constData(); - - QmlBinding_Basic *bind = - new QmlBinding_Basic(target, property, data, comp, scope, ctxt); - bindValues.append(bind); - bind->m_mePtr = &bindValues.values[bindValues.count - 1]; - bind->addToObject(target); + QmlAbstractBinding *binding = + optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property); + bindValues.append(binding); + binding->m_mePtr = &bindValues.values[bindValues.count - 1]; + binding->addToObject(target); } break; @@ -894,6 +895,11 @@ QObject *QmlVME::run(QmlVMEStack &stack, QmlContext *ctxt, } } + if (optimizedBindings) { + optimizedBindings->release(); + optimizedBindings = 0; + } + if (isError()) { if (!stack.isEmpty()) { delete stack.at(0); -- cgit v0.12 From e528394f428ba815fe61e4d2f5248b9bd11db375 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 16 Dec 2009 14:50:39 +1000 Subject: Include more info for state debugging. --- src/declarative/util/qmlstate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index 98cc0b6..1749c3a 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -444,10 +444,10 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever if (stateChangeDebug()) { foreach(const Action &action, applyList) { if (action.event) - qWarning() << " Action event:" << action.event; + qWarning() << " Action event:" << action.event->typeName(); else qWarning() << " Action:" << action.property.object() - << action.property.name() << action.toValue; + << action.property.name() << action.fromValue << action.toValue; } } -- cgit v0.12 From 6fe6e803f08750534a6c14b4a2847a6ec1b29350 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 16 Dec 2009 15:35:44 +1000 Subject: Use the component name as the base class name for dynamic meta objects when appropriate. This allows for much improved debug presentation. e.g. what used to be shown as "QmlGraphicsRectangle_QML_3" can now be show as "MyComponent". --- src/declarative/qml/qmlcompiler.cpp | 8 ++++++++ src/declarative/qml/qmlenginedebug.cpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 9df9b40..197cc0f 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2182,6 +2182,14 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) newClassName.append("_QML_"); int idx = classIndexCounter()->fetchAndAddRelaxed(1); newClassName.append(QByteArray::number(idx)); + if (compileState.root == obj) { + QString path = output->url.path(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + if (lastSlash > -1) { + QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx); + } + } QMetaObjectBuilder builder; builder.setClassName(newClassName); diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index 6cb57b2..46490fb 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -285,6 +285,9 @@ QmlEngineDebugServer::objectData(QObject *object) rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1); } else { rv.objectType = QString::fromUtf8(object->metaObject()->className()); + int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_")); + if (marker != -1) + rv.objectType = rv.objectType.left(marker); } return rv; -- cgit v0.12 From cc581fd06ed8b017aa7c87f740056921479f23f8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 16 Dec 2009 16:37:24 +1000 Subject: Crash --- src/declarative/qml/qmlbindingvme.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index d85d7ba..5abcdb8 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -1002,11 +1002,12 @@ This does not clear the global "commited binding" states. void QmlBindingCompilerPrivate::resetInstanceState() { registers = 0; + registerCleanups.clear(); strings = committed.strings; data = committed.data; - subscriptionIds = committed.subscriptionIds; - subscriptionSet.clear(); usedSubscriptionIds.clear(); + subscriptionSet.clear(); + subscriptionIds = committed.subscriptionIds; bytecode.clear(); } @@ -1870,7 +1871,7 @@ Returns true if any bindings were compiled. */ bool QmlBindingCompiler::isValid() const { - return d->bytecode.count(); + return !d->committed.bytecode.isEmpty(); } /* -- cgit v0.12 From 7e8d529d1542b3c581cff27641ba7b37b40ca161 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 17:34:38 +1000 Subject: Allow a ListView.section.delegate to avoid creating sections in delegate. --- examples/declarative/listview/sections.qml | 25 +++---- .../graphicsitems/qmlgraphicslistview.cpp | 84 ++++++++++++++++++---- .../graphicsitems/qmlgraphicslistview_p.h | 8 ++- 3 files changed, 88 insertions(+), 29 deletions(-) diff --git a/examples/declarative/listview/sections.qml b/examples/declarative/listview/sections.qml index b51cf58..6e72ce7 100644 --- a/examples/declarative/listview/sections.qml +++ b/examples/declarative/listview/sections.qml @@ -17,25 +17,11 @@ Rectangle { id: wrapper width: 200 // My height is the combined height of the description and the section separator - height: separator.height + desc.height - Rectangle { - id: separator - color: "lightsteelblue" - width: parent.width - // Only show the section separator when we are the beginning of a new section - // Note that for this to work nicely, the list must be ordered by section. - height: wrapper.ListView.prevSection != wrapper.ListView.section ? 20 : 0 - opacity: wrapper.ListView.prevSection != wrapper.ListView.section ? 1 : 0 - Text { - text: wrapper.ListView.section; font.bold: true - x: 2; height: parent.height; verticalAlignment: 'AlignVCenter' - } - } + height: desc.height Item { id: desc x: 5 height: layout.height + 4 - anchors.top: separator.bottom Column { id: layout y: 2 @@ -66,6 +52,15 @@ Rectangle { // We use this to determine which section we are in above. section.property: "size" section.criteria: ViewSection.FullString + section.delegate: Rectangle { + color: "lightsteelblue" + width: 200 + height: 20 + Text { + text: section; font.bold: true + x: 2; height: parent.height; verticalAlignment: 'AlignVCenter' + } + } focus: true } } diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index bf734b8..77761ac 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -68,6 +68,14 @@ void QmlGraphicsViewSection::setCriteria(QmlGraphicsViewSection::SectionCriteria } } +void QmlGraphicsViewSection::setDelegate(QmlComponent *delegate) +{ + if (delegate != m_delegate) { + m_delegate = delegate; + emit delegateChanged(); + } +} + QString QmlGraphicsViewSection::sectionString(const QString &value) { if (m_criteria == FirstCharacter) @@ -162,14 +170,23 @@ QHash QmlGraphicsListViewAttached::attac class FxListItem { public: - FxListItem(QmlGraphicsItem *i, QmlGraphicsListView *v) : item(i), view(v) { + FxListItem(QmlGraphicsItem *i, QmlGraphicsListView *v) : item(i), section(0), view(v) { attached = QmlGraphicsListViewAttached::properties(item); attached->m_view = view; } ~FxListItem() {} - - qreal position() const { return (view->orientation() == QmlGraphicsListView::Vertical ? item->y() : item->x()); } - int size() const { return (view->orientation() == QmlGraphicsListView::Vertical ? item->height() : item->width()); } + qreal position() const { + if (section) + return (view->orientation() == QmlGraphicsListView::Vertical ? section->y() : section->x()); + else + return (view->orientation() == QmlGraphicsListView::Vertical ? item->y() : item->x()); + } + int size() const { + if (section) + return (view->orientation() == QmlGraphicsListView::Vertical ? item->height()+section->height() : item->width()+section->height()); + else + return (view->orientation() == QmlGraphicsListView::Vertical ? item->height() : item->width()); + } qreal endPosition() const { return (view->orientation() == QmlGraphicsListView::Vertical ? item->y() + (item->height() > 0 ? item->height() : 1) @@ -177,13 +194,22 @@ public: } void setPosition(qreal pos) { if (view->orientation() == QmlGraphicsListView::Vertical) { + if (section) { + section->setY(pos); + pos += section->height(); + } item->setY(pos); } else { + if (section) { + section->setX(pos); + pos += section->width(); + } item->setX(pos); } } QmlGraphicsItem *item; + QmlGraphicsItem *section; QmlGraphicsListView *view; QmlGraphicsListViewAttached *attached; int index; @@ -467,6 +493,7 @@ public: void updateTrackedItem(); void createHighlight(); void updateHighlight(); + void createSection(FxListItem *); void updateSections(); void updateCurrentSection(); void updateCurrent(int); @@ -573,6 +600,11 @@ FxListItem *QmlGraphicsListViewPrivate::createItem(int modelIndex) listItem->item->setParent(q->viewport()); QmlGraphicsItemPrivate *itemPrivate = static_cast(QGraphicsItemPrivate::get(item)); itemPrivate->addGeometryListener(this); + if (sectionCriteria && sectionCriteria->delegate()) { + qDebug() << "have delegate"; + if (listItem->attached->m_prevSection != listItem->attached->m_section) + createSection(listItem); + } } requestedIndex = -1; @@ -597,6 +629,8 @@ void QmlGraphicsListViewPrivate::releaseItem(FxListItem *item) // item was not destroyed, and we no longer reference it. unrequestedItems.insert(item->item, model->indexOf(item->item, q)); } + if (item->section) + delete item->section; delete item; } @@ -693,6 +727,7 @@ void QmlGraphicsListViewPrivate::refill(qreal from, qreal to, bool doBuffer) void QmlGraphicsListViewPrivate::layout() { Q_Q(QmlGraphicsListView); + updateSections(); if (!visibleItems.isEmpty()) { int oldEnd = visibleItems.last()->endPosition(); int pos = visibleItems.first()->endPosition() + spacing + 1; @@ -842,6 +877,36 @@ void QmlGraphicsListViewPrivate::updateHighlight() updateTrackedItem(); } +void QmlGraphicsListViewPrivate::createSection(FxListItem *listItem) +{ + Q_Q(QmlGraphicsListView); + if (!sectionCriteria || !sectionCriteria->delegate()) + return; + if (listItem->attached->m_prevSection != listItem->attached->m_section) { + if (!listItem->section) { + qDebug() << "create Section"; + QmlContext *context = new QmlContext(qmlContext(q)); + QObject *nobj = sectionCriteria->delegate()->create(context); + if (nobj) { + context->setParent(nobj); + listItem->section = qobject_cast(nobj); + if (!listItem->section) { + delete nobj; + } else { + context->setContextProperty(QLatin1String("section"), listItem->attached->m_section); + listItem->section->setZValue(1); + listItem->section->setParent(q->viewport()); + } + } else { + delete context; + } + } + } else { + delete listItem->section; + listItem->section = 0; + } +} + void QmlGraphicsListViewPrivate::updateSections() { if (sectionCriteria) { @@ -852,6 +917,7 @@ void QmlGraphicsListViewPrivate::updateSections() if (visibleItems.at(i)->index != -1) { QmlGraphicsListViewAttached *attached = visibleItems.at(i)->attached; attached->setPrevSection(prevSection); + createSection(visibleItems.at(i)); prevSection = attached->section(); } } @@ -2240,7 +2306,6 @@ void QmlGraphicsListView::itemsInserted(int modelIndex, int count) d->updateUnrequestedIndexes(); if (!d->visibleItems.count() || d->model->count() <= 1) { d->layout(); - d->updateSections(); d->updateCurrent(qMax(0, qMin(d->currentIndex, d->model->count()-1))); emit countChanged(); return; @@ -2351,11 +2416,7 @@ void QmlGraphicsListView::itemsInserted(int modelIndex, int count) // everything is in order now - emit add() signal for (int j = 0; j < added.count(); ++j) added.at(j)->attached->emitAdd(); - d->updateUnrequestedPositions(); - d->updateViewport(); - d->updateSections(); - d->updateHeader(); - d->updateFooter(); + d->layout(); emit countChanged(); } @@ -2386,7 +2447,6 @@ void QmlGraphicsListView::itemsRemoved(int modelIndex, int count) d->updateCurrent(qMin(modelIndex, d->model->count()-1)); } d->layout(); - d->updateSections(); emit countChanged(); return; } @@ -2459,7 +2519,6 @@ void QmlGraphicsListView::itemsRemoved(int modelIndex, int count) } else { // Correct the positioning of the items d->layout(); - d->updateSections(); } emit countChanged(); @@ -2557,7 +2616,6 @@ void QmlGraphicsListView::itemsMoved(int from, int to, int count) d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + moveBy); d->layout(); - d->updateSections(); } void QmlGraphicsListView::createdItem(int index, QmlGraphicsItem *item) diff --git a/src/declarative/graphicsitems/qmlgraphicslistview_p.h b/src/declarative/graphicsitems/qmlgraphicslistview_p.h index 18b2ab5..2a2ef8a 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicslistview_p.h @@ -55,9 +55,10 @@ class Q_DECLARATIVE_EXPORT QmlGraphicsViewSection : public QObject Q_OBJECT Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY changed) Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY changed) + Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_ENUMS(SectionCriteria) public: - QmlGraphicsViewSection(QObject *parent=0) : QObject(parent), m_criteria(FullString) {} + QmlGraphicsViewSection(QObject *parent=0) : QObject(parent), m_criteria(FullString), m_delegate(0) {} QString property() const { return m_property; } void setProperty(const QString &); @@ -66,14 +67,19 @@ public: SectionCriteria criteria() const { return m_criteria; } void setCriteria(SectionCriteria); + QmlComponent *delegate() const { return m_delegate; } + void setDelegate(QmlComponent *delegate); + QString sectionString(const QString &value); Q_SIGNALS: void changed(); + void delegateChanged(); private: QString m_property; SectionCriteria m_criteria; + QmlComponent *m_delegate; }; -- cgit v0.12 From 6ac1fa11ecc929ed9be1ff5a353cf7d776c5835b Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 17:56:35 +1000 Subject: Set section delegate "section" property before creation. --- src/declarative/graphicsitems/qmlgraphicslistview.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index 77761ac..28ce781 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -601,7 +601,6 @@ FxListItem *QmlGraphicsListViewPrivate::createItem(int modelIndex) QmlGraphicsItemPrivate *itemPrivate = static_cast(QGraphicsItemPrivate::get(item)); itemPrivate->addGeometryListener(this); if (sectionCriteria && sectionCriteria->delegate()) { - qDebug() << "have delegate"; if (listItem->attached->m_prevSection != listItem->attached->m_section) createSection(listItem); } @@ -884,8 +883,8 @@ void QmlGraphicsListViewPrivate::createSection(FxListItem *listItem) return; if (listItem->attached->m_prevSection != listItem->attached->m_section) { if (!listItem->section) { - qDebug() << "create Section"; QmlContext *context = new QmlContext(qmlContext(q)); + context->setContextProperty(QLatin1String("section"), listItem->attached->m_section); QObject *nobj = sectionCriteria->delegate()->create(context); if (nobj) { context->setParent(nobj); @@ -893,7 +892,6 @@ void QmlGraphicsListViewPrivate::createSection(FxListItem *listItem) if (!listItem->section) { delete nobj; } else { - context->setContextProperty(QLatin1String("section"), listItem->attached->m_section); listItem->section->setZValue(1); listItem->section->setParent(q->viewport()); } -- cgit v0.12 From 87a939fa289a0d96c1f0eb10fa74b1cb89fc05f1 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 16 Dec 2009 19:01:19 +1000 Subject: Set a more reasonable default maximumFlickVelocity. --- src/declarative/graphicsitems/qmlgraphicsflickable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp index f3f138b..79c7659 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp @@ -155,7 +155,7 @@ QmlGraphicsFlickablePrivate::QmlGraphicsFlickablePrivate() : viewport(new QmlGraphicsItem), _moveX(viewport, &QmlGraphicsItem::setX), _moveY(viewport, &QmlGraphicsItem::setY) , vWidth(-1), vHeight(-1), overShoot(true), flicked(false), moving(false), stealMouse(false) , pressed(false), atXEnd(false), atXBeginning(true), atYEnd(false), atYBeginning(true) - , interactive(true), deceleration(500), maxVelocity(5000), reportedVelocitySmoothing(100) + , interactive(true), deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100) , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0) , horizontalVelocity(this), verticalVelocity(this), vTime(0), visibleArea(0) , flickDirection(QmlGraphicsFlickable::AutoFlickDirection) @@ -1166,7 +1166,7 @@ bool QmlGraphicsFlickable::sceneEventFilter(QGraphicsItem *i, QEvent *e) \qmlproperty real Flickable::maximumFlickVelocity This property holds the maximum velocity that the user can flick the view in pixels/second. - The default is 5000 pixels/s + The default is 2000 pixels/s */ qreal QmlGraphicsFlickable::maximumFlickVelocity() const { -- cgit v0.12