diff options
-rw-r--r-- | src/declarative/extra/qmlxmllistmodel.cpp | 407 | ||||
-rw-r--r-- | src/declarative/extra/qmlxmllistmodel.h | 5 | ||||
-rw-r--r-- | src/declarative/fx/qfxgridview.cpp | 158 | ||||
-rw-r--r-- | src/declarative/fx/qfxgridview.h | 2 | ||||
-rw-r--r-- | src/declarative/fx/qfxlistview.cpp | 181 | ||||
-rw-r--r-- | src/declarative/fx/qfxlistview.h | 2 | ||||
-rw-r--r-- | src/declarative/fx/qfxpathview.cpp | 14 | ||||
-rw-r--r-- | src/declarative/fx/qfxpathview.h | 2 | ||||
-rw-r--r-- | src/declarative/fx/qfxpathview_p.h | 3 | ||||
-rw-r--r-- | src/declarative/fx/qfxvisualitemmodel.cpp | 178 | ||||
-rw-r--r-- | src/declarative/fx/qfxvisualitemmodel.h | 13 | ||||
-rw-r--r-- | src/declarative/util/qmlpackage.cpp | 5 |
12 files changed, 603 insertions, 367 deletions
diff --git a/src/declarative/extra/qmlxmllistmodel.cpp b/src/declarative/extra/qmlxmllistmodel.cpp index bba817d..3732323 100644 --- a/src/declarative/extra/qmlxmllistmodel.cpp +++ b/src/declarative/extra/qmlxmllistmodel.cpp @@ -45,6 +45,10 @@ #include <QtDeclarative/qmlcontext.h> #include <QtDeclarative/qmlengine.h> #include <QDebug> +#include <QApplication> +#include <QThread> +#include <QMutex> +#include <QWaitCondition> #include <QXmlQuery> #include <QXmlResultItems> #include <QXmlNodeModelIndex> @@ -57,6 +61,197 @@ QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(XmlListModelRole, Role); QML_DEFINE_TYPE(QmlXmlListModel, XmlListModel); + +class QmlXmlListModelPrivate; +struct QmlXmlRoleList : public QmlConcreteList<XmlListModelRole *> +{ + QmlXmlRoleList(QmlXmlListModelPrivate *p) + : model(p) {} + virtual void append(XmlListModelRole *role); + //XXX clear, removeAt, and insert need to invalidate any cached data (in data table) as well + // (and the model should emit the appropriate signals) + virtual void clear(); + virtual void removeAt(int i); + virtual void insert(int i, XmlListModelRole *role); + + QmlXmlListModelPrivate *model; +}; + + + +class QmlXmlQuery : public QThread +{ + Q_OBJECT +public: + QmlXmlQuery(QObject *parent=0) + : QThread(parent), m_quit(false), m_restart(false), m_abort(false), m_queryId(0) { + } + ~QmlXmlQuery() { + m_mutex.lock(); + m_quit = true; + m_condition.wakeOne(); + m_mutex.unlock(); + + wait(); + } + + void abort() { + QMutexLocker locker(&m_mutex); + m_abort = true; + } + + int doQuery(QString query, QString namespaces, QByteArray data, QmlXmlRoleList *roleObjects) { + QMutexLocker locker(&m_mutex); + m_modelData.clear(); + m_size = 0; + m_data = data; + m_query = query; + m_namespaces = namespaces; + m_roleObjects = roleObjects; + if (!isRunning()) { + m_abort = false; + start(); + } else { + m_restart = true; + m_condition.wakeOne(); + } + m_queryId++; + return m_queryId; + } + + QList<QList<QVariant> > modelData() { + QMutexLocker locker(&m_mutex); + return m_modelData; + } + +signals: + void queryCompleted(int queryId, int size); + +protected: + void run() { + while (!m_quit) { + m_mutex.lock(); + int queryId = m_queryId; + doQueryJob(); + if (m_size > 0) + doSubQueryJob(); + m_data.clear(); // no longer needed + m_mutex.unlock(); + + m_mutex.lock(); + if (!m_abort && m_size > 0) + emit queryCompleted(queryId, m_size); + if (!m_restart) + m_condition.wait(&m_mutex); + m_abort = false; + m_restart = false; + m_mutex.unlock(); + } + } + +private: + void doQueryJob(); + void doSubQueryJob(); + +private: + QMutex m_mutex; + QWaitCondition m_condition; + bool m_quit; + bool m_restart; + bool m_abort; + QByteArray m_data; + QString m_query; + QString m_namespaces; + QString m_prefix; + int m_size; + int m_queryId; + const QmlXmlRoleList *m_roleObjects; + QList<QList<QVariant> > m_modelData; +}; + +void QmlXmlQuery::doQueryJob() +{ + QString r; + QXmlQuery query; + QBuffer buffer(&m_data); + buffer.open(QIODevice::ReadOnly); + query.bindVariable(QLatin1String("src"), &buffer); + query.setQuery(m_namespaces + m_query); + query.evaluateTo(&r); + + //qDebug() << r; + + //always need a single root element + QByteArray xml = "<dummy:items xmlns:dummy=\"http://qtsotware.com/dummy\">\n" + r.toUtf8() + "</dummy:items>"; + QBuffer b(&xml); + b.open(QIODevice::ReadOnly); + //qDebug() << xml; + + QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + m_namespaces; + QString prefix = QLatin1String("doc($inputDocument)/dummy:items") + + m_query.mid(m_query.lastIndexOf(QLatin1Char('/'))); + + //figure out how many items we are dealing with + int count = -1; + { + QXmlResultItems result; + QXmlQuery countquery; + countquery.bindVariable(QLatin1String("inputDocument"), &b); + countquery.setQuery(namespaces + QLatin1String("count(") + prefix + QLatin1String(")")); + countquery.evaluateTo(&result); + QXmlItem item(result.next()); + if (item.isAtomicValue()) + count = item.toAtomicValue().toInt(); + prefix += QLatin1String("[%1]/"); + } + //qDebug() << count; + + m_prefix = namespaces + prefix; + m_data = xml; + if (count > 0) + m_size = count; +} + +void QmlXmlQuery::doSubQueryJob() +{ + m_modelData.clear(); + + QBuffer b(&m_data); + b.open(QIODevice::ReadOnly); + + QXmlQuery subquery; + subquery.bindVariable(QLatin1String("inputDocument"), &b); + + //XXX should we use an array of objects or something else rather than a table? + for (int j = 0; j < m_size; ++j) { + QList<QVariant> resultList; + for (int i = 0; i < m_roleObjects->size(); ++i) { + XmlListModelRole *role = m_roleObjects->at(i); + subquery.setQuery(m_prefix.arg(j+1) + role->query()); + if (role->isStringList()) { + QStringList data; + subquery.evaluateTo(&data); + resultList << QVariant(data); + //qDebug() << data; + } else { + QString s; + subquery.evaluateTo(&s); + if (role->isCData()) { + //un-escape + s.replace(QLatin1String("<"), QLatin1String("<")); + s.replace(QLatin1String(">"), QLatin1String(">")); + s.replace(QLatin1String("&"), QLatin1String("&")); + } + resultList << s.trimmed(); + //qDebug() << s; + } + b.seek(0); + } + m_modelData << resultList; + } +} + + //TODO: do something smart while waiting for data to load // error handling (currently quite fragile) // profile doQuery and doSubquery @@ -64,6 +259,59 @@ QML_DEFINE_TYPE(QmlXmlListModel, XmlListModel); // support complex/nested objects? // how do we handle data updates (like rss feed -- usually items inserted at beginning) + +class QmlXmlListModelPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlXmlListModel) +public: + QmlXmlListModelPrivate() + : isClassComplete(false), size(-1), highestRole(Qt::UserRole) + , reply(0), queryId(-1), roleObjects(this) {} + + bool isClassComplete; + QString src; + QString query; + QString namespaces; + int size; + QList<int> roles; + QStringList roleNames; + int highestRole; + QNetworkReply *reply; + QmlXmlQuery qmlXmlQuery; + int queryId; + QmlXmlRoleList roleObjects; + QList<QList<QVariant> > data; +}; + + +void QmlXmlRoleList::append(XmlListModelRole *role) { + QmlConcreteList<XmlListModelRole *>::append(role); + model->roles << model->highestRole; + model->roleNames << role->name(); + ++model->highestRole; +} +//XXX clear, removeAt, and insert need to invalidate any cached data (in data table) as well +// (and the model should emit the appropriate signals) +void QmlXmlRoleList::clear() +{ + model->roles.clear(); + model->roleNames.clear(); + QmlConcreteList<XmlListModelRole *>::clear(); +} +void QmlXmlRoleList::removeAt(int i) +{ + model->roles.removeAt(i); + model->roleNames.removeAt(i); + QmlConcreteList<XmlListModelRole *>::removeAt(i); +} +void QmlXmlRoleList::insert(int i, XmlListModelRole *role) +{ + QmlConcreteList<XmlListModelRole *>::insert(i, role); + model->roles.insert(i, model->highestRole); + model->roleNames.insert(i, role->name()); + ++model->highestRole; +} + /*! \qmlclass XmlListModel \brief The XmlListModel class allows you to specify a model using XQuery. @@ -86,71 +334,17 @@ QML_DEFINE_TYPE(QmlXmlListModel, XmlListModel); \note The model is currently static, so the above is really just a snapshot of an RSS feed. */ -class QmlXmlListModelPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QmlXmlListModel) -public: - QmlXmlListModelPrivate() : isClassComplete(false), size(-1), highestRole(Qt::UserRole), reply(0), roleObjects(this) {} - - bool isClassComplete; - QString src; - QString query; - QString namespaces; - QList<int> roles; - QStringList roleNames; - mutable QList<QList<QVariant> > data; - int size; - int highestRole; - QNetworkReply *reply; - mutable QByteArray xml; - QString prefix; - - struct RoleList : public QmlConcreteList<XmlListModelRole *> - { - RoleList(QmlXmlListModelPrivate *p) - : model(p) {} - virtual void append(XmlListModelRole *role) { - QmlConcreteList<XmlListModelRole *>::append(role); - model->roles << model->highestRole; - model->roleNames << role->name(); - ++model->highestRole; - } - //XXX clear, removeAt, and insert need to invalidate any cached data (in data table) as well - // (and the model should emit the appropriate signals) - virtual void clear() - { - model->roles.clear(); - model->roleNames.clear(); - QmlConcreteList<XmlListModelRole *>::clear(); - } - virtual void removeAt(int i) - { - model->roles.removeAt(i); - model->roleNames.removeAt(i); - QmlConcreteList<XmlListModelRole *>::removeAt(i); - } - virtual void insert(int i, XmlListModelRole *role) - { - QmlConcreteList<XmlListModelRole *>::insert(i, role); - model->roles.insert(i, model->highestRole); - model->roleNames.insert(i, role->name()); - ++model->highestRole; - } - - QmlXmlListModelPrivate *model; - }; - - RoleList roleObjects; -}; - QmlXmlListModel::QmlXmlListModel(QObject *parent) : QListModelInterface(*(new QmlXmlListModelPrivate), parent) { Q_D(QmlXmlListModel); + connect(&d->qmlXmlQuery, SIGNAL(queryCompleted(int,int)), + this, SLOT(queryCompleted(int,int))); } QmlXmlListModel::~QmlXmlListModel() { + Q_D(QmlXmlListModel); } QmlList<XmlListModelRole *> *QmlXmlListModel::roleObjects() @@ -163,10 +357,6 @@ QHash<int,QVariant> QmlXmlListModel::data(int index, const QList<int> &roles) co { Q_D(const QmlXmlListModel); QHash<int, QVariant> rv; - - if (index > d->data.count() - 1) - doSubquery(index); - for (int i = 0; i < roles.size(); ++i) { int role = roles.at(i); int roleIndex = d->roles.indexOf(role); @@ -255,6 +445,9 @@ void QmlXmlListModel::reload() if (!d->isClassComplete) return; + d->qmlXmlQuery.abort(); + d->queryId = -1; + //clear existing data d->size = 0; int count = d->data.count(); @@ -288,98 +481,24 @@ void QmlXmlListModel::requestFinished() d->reply = 0; } else { QByteArray data = d->reply->readAll(); - doQuery(data); + d->queryId = d->qmlXmlQuery.doQuery(d->query, d->namespaces, data, &d->roleObjects); d->reply->deleteLater(); d->reply = 0; } } -void QmlXmlListModel::doQuery(QByteArray &rawData) +void QmlXmlListModel::queryCompleted(int id, int size) { Q_D(QmlXmlListModel); - QString r; - QXmlQuery query; - QBuffer rawBuffer(&rawData); - rawBuffer.open(QIODevice::ReadOnly); - query.bindVariable(QLatin1String("src"), &rawBuffer); - query.setQuery(d->namespaces + d->query); - query.evaluateTo(&r); - //qDebug() << r; - - //always need a single root element - QByteArray xml = "<dummy:items xmlns:dummy=\"http://qtsotware.com/dummy\">\n" + r.toUtf8() + "</dummy:items>"; - QBuffer b(&xml); - b.open(QIODevice::ReadOnly); - //qDebug() << xml; - - QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + d->namespaces; - QString prefix = QLatin1String("doc($inputDocument)/dummy:items") + - d->query.mid(d->query.lastIndexOf(QLatin1Char('/'))); - - //figure out how many items we are dealing with - int count = -1; - { - QXmlResultItems result; - QXmlQuery countquery; - countquery.bindVariable(QLatin1String("inputDocument"), &b); - countquery.setQuery(namespaces + QLatin1String("count(") + prefix + QLatin1String(")")); - countquery.evaluateTo(&result); - QXmlItem item(result.next()); - if (item.isAtomicValue()) - count = item.toAtomicValue().toInt(); - b.seek(0); - prefix += QLatin1String("[%1]/"); + if (id != d->queryId) + return; + d->size = size; + if (size > 0) { + d->data = d->qmlXmlQuery.modelData(); + emit itemsInserted(0, d->size); } - //qDebug() << count; - - QXmlQuery subquery; - subquery.bindVariable(QLatin1String("inputDocument"), &b); - d->prefix = namespaces + prefix; - d->xml = xml; - - d->size = count; - - if (count > 0) - emit itemsInserted(0, count); } -void QmlXmlListModel::doSubquery(int index) const -{ - Q_D(const QmlXmlListModel); - //qDebug() << "doSubQuery" << index; - QBuffer b(&d->xml); - b.open(QIODevice::ReadOnly); - - QXmlQuery subquery; - subquery.bindVariable(QLatin1String("inputDocument"), &b); - - //XXX should we use an array of objects or something else rather than a table? - for (int j = d->data.count(); j <= index; ++j) { - QList<QVariant> resultList; - for (int i = 0; i < d->roleObjects.size(); ++i) { - XmlListModelRole *role = d->roleObjects.at(i); - subquery.setQuery(d->prefix.arg(j+1) + role->query()); - if (role->isStringList()) { - QStringList data; - subquery.evaluateTo(&data); - resultList << QVariant(data); - //qDebug() << data; - } else { - QString s; - subquery.evaluateTo(&s); - if (role->isCData()) { - //un-escape - s.replace(QLatin1String("<"), QLatin1String("<")); - s.replace(QLatin1String(">"), QLatin1String(">")); - s.replace(QLatin1String("&"), QLatin1String("&")); - } - resultList << s.trimmed(); - //qDebug() << s; - } - b.seek(0); - } - d->data << resultList; - } -} +#include "qmlxmllistmodel.moc" QT_END_NAMESPACE diff --git a/src/declarative/extra/qmlxmllistmodel.h b/src/declarative/extra/qmlxmllistmodel.h index 9371448..f837040 100644 --- a/src/declarative/extra/qmlxmllistmodel.h +++ b/src/declarative/extra/qmlxmllistmodel.h @@ -120,12 +120,9 @@ public: public Q_SLOTS: void reload(); -protected: - void doQuery(QByteArray &rawData); - void doSubquery(int index) const; - private Q_SLOTS: void requestFinished(); + void queryCompleted(int,int); private: Q_DECLARE_PRIVATE(QmlXmlListModel) diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp index 876172d..c14408a 100644 --- a/src/declarative/fx/qfxgridview.cpp +++ b/src/declarative/fx/qfxgridview.cpp @@ -121,9 +121,9 @@ public: qreal rowPos() const { return (view->flow() == QFxGridView::LeftToRight ? item->y() : item->x()); } qreal colPos() const { return (view->flow() == QFxGridView::LeftToRight ? item->x() : item->y()); } qreal endRowPos() const { - return (view->flow() == QFxGridView::LeftToRight - ? item->y() + (item->height() > 0 ? item->height() : 1) - : item->x() + (item->width() > 0 ? item->width() : 1)) - 1; + return view->flow() == QFxGridView::LeftToRight + ? item->y() + view->cellHeight() - 1 + : item->x() + view->cellWidth() - 1; } void setPosition(qreal col, qreal row) { if (view->flow() == QFxGridView::LeftToRight) { @@ -149,7 +149,7 @@ public: QFxGridViewPrivate() : model(0), currentItem(0), tmpCurrent(0), flow(QFxGridView::LeftToRight) , visiblePos(0), visibleIndex(0) , currentIndex(-1) - , cellWidth(100), cellHeight(100), columns(1) + , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1) , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0) , keyPressed(false), ownModel(false), wrap(false), autoHighlight(true) @@ -157,13 +157,14 @@ public: void init(); void clear(); - FxGridItem *getItem(int modelIndex); FxGridItem *createItem(int modelIndex); void releaseItem(FxGridItem *item); void refill(qreal from, qreal to); void updateGrid(); void layout(bool removed=false); + void updateUnrequestedIndexes(); + void updateUnrequestedPositions(); void updateTrackedItem(); void createHighlight(); void updateHighlight(); @@ -290,6 +291,7 @@ public: QFxVisualItemModel *model; QVariant modelVariant; QList<FxGridItem*> visibleItems; + QHash<QFxItem*,int> unrequestedItems; FxGridItem *currentItem; QFxItem *tmpCurrent; QFxGridView::Flow flow; @@ -299,6 +301,7 @@ public: int cellWidth; int cellHeight; int columns; + int requestedIndex; QmlComponent *highlightComponent; FxGridItem *highlight; FxGridItem *trackedItem; @@ -330,29 +333,18 @@ void QFxGridViewPrivate::clear() visibleItems.clear(); visiblePos = 0; visibleIndex = 0; - if (currentItem) { - FxGridItem *tmpItem = currentItem; - currentItem = 0; - currentIndex = -1; - releaseItem(tmpItem); - } + releaseItem(currentItem); + currentItem = 0; + currentIndex = -1; createHighlight(); trackedItem = 0; } -FxGridItem *QFxGridViewPrivate::getItem(int modelIndex) -{ - if (currentItem && modelIndex == currentIndex) - return currentItem; - if (FxGridItem *listItem = visibleItem(modelIndex)) - return listItem; - return createItem(modelIndex); -} - FxGridItem *QFxGridViewPrivate::createItem(int modelIndex) { Q_Q(QFxGridView); // create object + requestedIndex = modelIndex; FxGridItem *listItem = 0; if (QFxItem *item = model->item(modelIndex, false)) { listItem = new FxGridItem(item, q); @@ -362,6 +354,7 @@ FxGridItem *QFxGridViewPrivate::createItem(int modelIndex) listItem->item->setZ(modelIndex + 1); listItem->item->setParent(q->viewport()); } + requestedIndex = 0; return listItem; } @@ -369,15 +362,18 @@ FxGridItem *QFxGridViewPrivate::createItem(int modelIndex) void QFxGridViewPrivate::releaseItem(FxGridItem *item) { Q_Q(QFxGridView); - if (item != currentItem) { - if (trackedItem == item) { - QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged())); - QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged())); - trackedItem = 0; - } - model->release(item->item); - delete item; + if (!item) + return; + if (trackedItem == item) { + QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged())); + QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged())); + trackedItem = 0; } + 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)); + } + delete item; } void QFxGridViewPrivate::refill(qreal from, qreal to) @@ -409,7 +405,7 @@ void QFxGridViewPrivate::refill(qreal from, qreal to) FxGridItem *item = 0; while (modelIndex < model->count() && rowPos <= to) { //qDebug() << "refill: append item" << modelIndex; - if (!(item = getItem(modelIndex))) + if (!(item = createItem(modelIndex))) break; item->setPosition(colPos, rowPos); visibleItems.append(item); @@ -432,7 +428,7 @@ void QFxGridViewPrivate::refill(qreal from, qreal to) } while (visibleIndex > 0 && rowPos + rowSize() - 1 >= from){ //qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos; - if (!(item = getItem(visibleIndex-1))) + if (!(item = createItem(visibleIndex-1))) break; --visibleIndex; item->setPosition(colPos, rowPos); @@ -518,6 +514,28 @@ void QFxGridViewPrivate::layout(bool removed) q->setViewportWidth(endPosition() - startPosition()); fixupX(); } + updateUnrequestedPositions(); +} + +void QFxGridViewPrivate::updateUnrequestedIndexes() +{ + Q_Q(QFxGridView); + QHash<QFxItem*,int>::iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) + *it = model->indexOf(it.key(), q); +} + +void QFxGridViewPrivate::updateUnrequestedPositions() +{ + QHash<QFxItem*,int>::const_iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) { + qDebug() << "pos of" << (*it) << colPosAt(*it) << rowPosAt(*it); + if (flow == QFxGridView::LeftToRight) { + it.key()->setPos(QPointF(colPosAt(*it), rowPosAt(*it))); + } else { + it.key()->setPos(QPointF(rowPosAt(*it), colPosAt(*it))); + } + } } void QFxGridViewPrivate::updateTrackedItem() @@ -606,11 +624,11 @@ void QFxGridViewPrivate::updateCurrent(int modelIndex) Q_Q(QFxGridView); if (!isValid() || modelIndex < 0 || modelIndex >= model->count()) { if (currentItem) { - FxGridItem *item = currentItem; + currentItem->attached->setIsCurrentItem(false); + releaseItem(currentItem); currentItem = 0; - currentIndex = 0; + currentIndex = -1; updateHighlight(); - releaseItem(item); emit q->currentIndexChanged(); } return; @@ -625,28 +643,21 @@ void QFxGridViewPrivate::updateCurrent(int modelIndex) delete tmpCurrent; tmpCurrent = 0; } - int oldCurrentIndex = currentIndex; FxGridItem *oldCurrentItem = currentItem; - currentIndex = -1; - currentItem = visibleItem(modelIndex); - if (!currentItem) { - currentItem = getItem(modelIndex); - if (currentItem) - currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex)); - } currentIndex = modelIndex; + currentItem = createItem(modelIndex); + qDebug() << "got current" << currentItem->item; fixCurrentVisibility = true; if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { + currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex)); currentItem->item->setFocus(true); currentItem->attached->setIsCurrentItem(true); } updateHighlight(); emit q->currentIndexChanged(); - // Release the old current item - if (oldCurrentItem && !visibleItem(oldCurrentIndex)) - releaseItem(oldCurrentItem); + releaseItem(oldCurrentItem); } //---------------------------------------------------------------------------- @@ -711,6 +722,8 @@ void QFxGridView::setModel(const QVariant &model) if (d->model) { disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); + disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + disconnect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); } d->clear(); d->modelVariant = model; @@ -736,6 +749,8 @@ void QFxGridView::setModel(const QVariant &model) d->updateCurrent(d->currentIndex); connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); + connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + connect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); refill(); emit countChanged(); } @@ -1182,7 +1197,7 @@ void QFxGridView::itemsInserted(int modelIndex, int count) d->visibleIndex += count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxGridItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index += count; } } @@ -1258,10 +1273,8 @@ void QFxGridView::itemsInserted(int modelIndex, int count) // Update the indexes of the following visible items. for (; index < d->visibleItems.count(); ++index) { FxGridItem *listItem = d->visibleItems.at(index); - if (listItem != d->currentItem) { - if (listItem->index != -1) - listItem->index += count; - } + if (listItem->index != -1) + listItem->index += count; } } // everything is in order now - emit add() signal @@ -1274,7 +1287,7 @@ void QFxGridView::itemsInserted(int modelIndex, int count) void QFxGridView::itemsRemoved(int modelIndex, int count) { Q_D(QFxGridView); - + qDebug() << "QFxGridView::itemsRemoved"; int index = d->mapFromModel(modelIndex); if (index == -1) { if (modelIndex + count - 1 < d->visibleIndex) { @@ -1282,7 +1295,7 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->visibleIndex -= count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxGridItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index -= count; } } @@ -1292,11 +1305,8 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem) { - FxGridItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + d->releaseItem(d->currentItem); + d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); } @@ -1305,6 +1315,8 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) return; } + qDebug() << "release gridview"; + // Remove the items from the visible list, skipping anything already marked for removal QList<FxGridItem*>::Iterator it = d->visibleItems.begin(); while (it != d->visibleItems.end()) { @@ -1314,8 +1326,7 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) ++it; } else if (item->index >= modelIndex + count) { // after removed items - if (item != d->currentItem) - item->index -= count; + item->index -= count; ++it; } else { // removed item @@ -1338,11 +1349,9 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem && !d->currentItem->attached->delayRemove()) { - FxGridItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + qDebug() << "release current" << d->currentItem; + d->releaseItem(d->currentItem); + qDebug() << "done"; d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); @@ -1385,6 +1394,29 @@ void QFxGridView::destroyRemoved() d->layout(); } +void QFxGridView::createdItem(int index, QFxItem *item) +{ + Q_D(QFxGridView); + item->setItemParent(this); + if (d->requestedIndex != index) { + qDebug() << "Added unrequested" << index; + item->setItemParent(this); + d->unrequestedItems.insert(item, index); + if (d->flow == QFxGridView::LeftToRight) { + item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index))); + } else { + item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index))); + } + } +} + +void QFxGridView::destroyingItem(QFxItem *item) +{ + Q_D(QFxGridView); + d->unrequestedItems.remove(item); +} + + void QFxGridView::refill() { Q_D(QFxGridView); diff --git a/src/declarative/fx/qfxgridview.h b/src/declarative/fx/qfxgridview.h index ff08831..99c7cff 100644 --- a/src/declarative/fx/qfxgridview.h +++ b/src/declarative/fx/qfxgridview.h @@ -131,6 +131,8 @@ private Q_SLOTS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void destroyRemoved(); + void createdItem(int index, QFxItem *item); + void destroyingItem(QFxItem *item); void sizeChange(); private: diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 46166e2..27f7ff1 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -171,15 +171,14 @@ public: QFxListViewPrivate() : model(0), currentItem(0), tmpCurrent(0), orient(Qt::Vertical) , visiblePos(0), visibleIndex(0) - , averageSize(100), currentIndex(-1), currItemMode(QFxListView::Free) - , snapPos(0), highlightComponent(0), highlight(0), trackedItem(0) + , averageSize(100), currentIndex(-1), requestedIndex(-1) + , currItemMode(QFxListView::Free), snapPos(0), highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0) , keyPressed(false), ownModel(false), wrap(false), autoHighlight(true) , fixCurrentVisibility(false) {} void init(); void clear(); - FxListItem *getItem(int modelIndex); FxListItem *createItem(int modelIndex); void releaseItem(FxListItem *item); @@ -333,6 +332,8 @@ public: void refill(qreal from, qreal to); void layout(); + void updateUnrequestedIndexes(); + void updateUnrequestedPositions(); void updateTrackedItem(); void createHighlight(); void updateHighlight(); @@ -347,6 +348,7 @@ public: QFxVisualItemModel *model; QVariant modelVariant; QList<FxListItem*> visibleItems; + QHash<QFxItem*,int> unrequestedItems; FxListItem *currentItem; QFxItem *tmpCurrent; Qt::Orientation orient; @@ -354,6 +356,7 @@ public: int visibleIndex; qreal averageSize; int currentIndex; + int requestedIndex; QFxListView::CurrentItemPositioning currItemMode; int snapPos; QmlComponent *highlightComponent; @@ -390,29 +393,18 @@ void QFxListViewPrivate::clear() visibleItems.clear(); visiblePos = 0; visibleIndex = 0; - if (currentItem) { - FxListItem *tmpItem = currentItem; - currentItem = 0; - currentIndex = -1; - releaseItem(tmpItem); - } + releaseItem(currentItem); + currentItem = 0; + currentIndex = -1; createHighlight(); trackedItem = 0; } -FxListItem *QFxListViewPrivate::getItem(int modelIndex) -{ - if (currentItem && modelIndex == currentIndex) - return currentItem; - if (FxListItem *listItem = visibleItem(modelIndex)) - return listItem; - return createItem(modelIndex); -} - FxListItem *QFxListViewPrivate::createItem(int modelIndex) { Q_Q(QFxListView); // create object + requestedIndex = modelIndex; FxListItem *listItem = 0; if (QFxItem *item = model->item(modelIndex, false)) { listItem = new FxListItem(item, q); @@ -438,6 +430,7 @@ FxListItem *QFxListViewPrivate::createItem(int modelIndex) else QObject::connect(listItem->item, SIGNAL(widthChanged()), q, SLOT(itemResized())); } + requestedIndex = -1; return listItem; } @@ -445,21 +438,24 @@ FxListItem *QFxListViewPrivate::createItem(int modelIndex) void QFxListViewPrivate::releaseItem(FxListItem *item) { Q_Q(QFxListView); - if (item != currentItem) { - if (orient == Qt::Vertical) - QObject::disconnect(item->item, SIGNAL(heightChanged()), q, SLOT(itemResized())); - else - QObject::disconnect(item->item, SIGNAL(widthChanged()), q, SLOT(itemResized())); - if (trackedItem == item) { - const char *notifier1 = orient == Qt::Vertical ? SIGNAL(topChanged()) : SIGNAL(leftChanged()); - const char *notifier2 = orient == Qt::Vertical ? SIGNAL(heightChanged()) : SIGNAL(widthChanged()); - QObject::disconnect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged())); - QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged())); - trackedItem = 0; - } - model->release(item->item); - delete item; + if (!item) + return; + if (orient == Qt::Vertical) + QObject::disconnect(item->item, SIGNAL(heightChanged()), q, SLOT(itemResized())); + else + QObject::disconnect(item->item, SIGNAL(widthChanged()), q, SLOT(itemResized())); + if (trackedItem == item) { + const char *notifier1 = orient == Qt::Vertical ? SIGNAL(topChanged()) : SIGNAL(leftChanged()); + const char *notifier2 = orient == Qt::Vertical ? SIGNAL(heightChanged()) : SIGNAL(widthChanged()); + QObject::disconnect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged())); + QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged())); + trackedItem = 0; } + 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)); + } + delete item; } void QFxListViewPrivate::refill(qreal from, qreal to) @@ -485,7 +481,7 @@ void QFxListViewPrivate::refill(qreal from, qreal to) int pos = itemEnd + 1; while (modelIndex < model->count() && pos <= to) { //qDebug() << "refill: append item" << modelIndex; - if (!(item = getItem(modelIndex))) + if (!(item = createItem(modelIndex))) break; item->setPosition(pos); pos += item->size(); @@ -495,7 +491,7 @@ void QFxListViewPrivate::refill(qreal from, qreal to) } while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > from) { //qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos; - if (!(item = getItem(visibleIndex-1))) + if (!(item = createItem(visibleIndex-1))) break; --visibleIndex; visiblePos -= item->size(); @@ -562,6 +558,29 @@ void QFxListViewPrivate::layout() fixupX(); q->setViewportWidth(endPosition() - startPosition()); } + updateUnrequestedPositions(); +} + +void QFxListViewPrivate::updateUnrequestedIndexes() +{ + Q_Q(QFxListView); + QHash<QFxItem*,int>::iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) + *it = model->indexOf(it.key(), q); +} + +void QFxListViewPrivate::updateUnrequestedPositions() +{ + QHash<QFxItem*,int>::const_iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) { + qDebug() << "pos of" << (*it) << positionAt(*it); + if (visibleItem(*it)) + continue; + if (orient == Qt::Vertical) + it.key()->setY(positionAt(*it)); + else + it.key()->setX(positionAt(*it)); + } } void QFxListViewPrivate::updateTrackedItem() @@ -695,13 +714,11 @@ void QFxListViewPrivate::updateCurrent(int modelIndex) Q_Q(QFxListView); if (!isValid() || modelIndex < 0 || modelIndex >= model->count()) { if (currentItem) { - FxListItem *item = currentItem; - int index = currentIndex; + currentItem->attached->setIsCurrentItem(false); + releaseItem(currentItem); currentItem = 0; - currentIndex = 0; + currentIndex = -1; updateHighlight(); - if (!visibleItem(index)) - releaseItem(item); emit q->currentIndexChanged(); } return; @@ -716,40 +733,28 @@ void QFxListViewPrivate::updateCurrent(int modelIndex) delete tmpCurrent; tmpCurrent = 0; } - int oldCurrentIndex = currentIndex; FxListItem *oldCurrentItem = currentItem; - currentIndex = -1; - currentItem = visibleItem(modelIndex); - if (!currentItem) { - currentItem = getItem(modelIndex); - if (currentItem) { - if (modelIndex == visibleIndex - 1) { - // We can calculate exact postion in this case - currentItem->setPosition(visibleItems.first()->position() - currentItem->size()); - } else { - // Create current item now and position as best we can. - // Its position will be corrected when it becomes visible. - currentItem->setPosition(positionAt(modelIndex)); - } - } - } currentIndex = modelIndex; + currentItem = createItem(modelIndex); fixCurrentVisibility = true; if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { + if (modelIndex == visibleIndex - 1) { + // We can calculate exact postion in this case + currentItem->setPosition(visibleItems.first()->position() - currentItem->size()); + } else { + // Create current item now and position as best we can. + // Its position will be corrected when it becomes visible. + currentItem->setPosition(positionAt(modelIndex)); + } currentItem->item->setFocus(true); currentItem->attached->setIsCurrentItem(true); } updateHighlight(); emit q->currentIndexChanged(); // Release the old current item - if (oldCurrentItem && !visibleItem(oldCurrentIndex)) { - if (!currentItem || oldCurrentItem->item == currentItem->item) - delete oldCurrentItem; - else - releaseItem(oldCurrentItem); - } + releaseItem(oldCurrentItem); } void QFxListViewPrivate::updateAverage() @@ -884,6 +889,8 @@ void QFxListView::setModel(const QVariant &model) if (d->model) { disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); + disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + disconnect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); } d->clear(); d->modelVariant = model; @@ -909,6 +916,8 @@ void QFxListView::setModel(const QVariant &model) d->updateCurrent(d->currentIndex); connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); + connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + connect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); refill(); emit countChanged(); } @@ -1417,6 +1426,7 @@ void QFxListView::itemResized() void QFxListView::itemsInserted(int modelIndex, int count) { Q_D(QFxListView); + d->updateUnrequestedIndexes(); if (!d->visibleItems.count() || d->model->count() <= 1) { d->layout(); d->updateCurrent(qMax(0, qMin(d->currentIndex, d->model->count()-1))); @@ -1437,7 +1447,7 @@ void QFxListView::itemsInserted(int modelIndex, int count) d->visibleIndex += count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxListItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index += count; } } @@ -1487,29 +1497,29 @@ void QFxListView::itemsInserted(int modelIndex, int count) // Update the indexes of the following visible items. for (; index < d->visibleItems.count(); ++index) { FxListItem *listItem = d->visibleItems.at(index); - if (listItem != d->currentItem) { - listItem->setPosition(listItem->position() + (pos - initialPos)); - if (listItem->index != -1) - listItem->index += count; - } + listItem->setPosition(listItem->position() + (pos - initialPos)); + if (listItem->index != -1) + listItem->index += count; } } // everything is in order now - emit add() signal for (int j = 0; j < added.count(); ++j) added.at(j)->attached->emitAdd(); + d->updateUnrequestedPositions(); emit countChanged(); } void QFxListView::itemsRemoved(int modelIndex, int count) { Q_D(QFxListView); + d->updateUnrequestedIndexes(); if (!d->mapRangeFromModel(modelIndex, count)) { if (modelIndex + count - 1 < d->visibleIndex) { // Items removed before our visible items. d->visibleIndex -= count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxListItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index -= count; } } @@ -1519,11 +1529,8 @@ void QFxListView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem) { - FxListItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + d->releaseItem(d->currentItem); + d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); } @@ -1541,8 +1548,7 @@ void QFxListView::itemsRemoved(int modelIndex, int count) ++it; } else if (item->index >= modelIndex + count) { // after removed items - if (item != d->currentItem) - item->index -= count; + item->index -= count; ++it; } else { // removed item @@ -1565,11 +1571,7 @@ void QFxListView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem && !d->currentItem->attached->delayRemove()) { - FxListItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + d->releaseItem(d->currentItem); d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); @@ -1618,6 +1620,25 @@ void QFxListView::destroyRemoved() d->layout(); } +void QFxListView::createdItem(int index, QFxItem *item) +{ + Q_D(QFxListView); + if (d->requestedIndex != index) { + item->setItemParent(viewport()); + d->unrequestedItems.insert(item, index); + if (d->orient == Qt::Vertical) + item->setY(d->positionAt(index)); + else + item->setX(d->positionAt(index)); + } +} + +void QFxListView::destroyingItem(QFxItem *item) +{ + Q_D(QFxListView); + d->unrequestedItems.remove(item); +} + QObject *QFxListView::qmlAttachedProperties(QObject *obj) { return QFxListViewAttached::properties(obj); diff --git a/src/declarative/fx/qfxlistview.h b/src/declarative/fx/qfxlistview.h index 6bf2b54..87a851b 100644 --- a/src/declarative/fx/qfxlistview.h +++ b/src/declarative/fx/qfxlistview.h @@ -141,6 +141,8 @@ private Q_SLOTS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void destroyRemoved(); + void createdItem(int index, QFxItem *item); + void destroyingItem(QFxItem *item); }; QML_DECLARE_TYPE(QFxListView); diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp index b7215cf..b1c78e9 100644 --- a/src/declarative/fx/qfxpathview.cpp +++ b/src/declarative/fx/qfxpathview.cpp @@ -159,7 +159,7 @@ void QFxPathView::setModel(const QVariant &model) if (d->model) { disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); - disconnect(d->model, SIGNAL(itemCreated(int, QFxItem*)), this, SLOT(itemCreated(int,QFxItem*))); + disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); for (int i=0; i<d->items.count(); i++){ QFxItem *p = d->items[i]; d->model->release(p); @@ -186,7 +186,7 @@ void QFxPathView::setModel(const QVariant &model) if (d->model) { connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); - connect(d->model, SIGNAL(itemCreated(int, QFxItem*)), this, SLOT(itemCreated(int,QFxItem*))); + connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); } d->firstIndex = 0; d->pathOffset = 0; @@ -559,9 +559,10 @@ bool QFxPathView::mouseFilter(QGraphicsSceneMouseEvent *e) void QFxPathViewPrivate::regenerate() { Q_Q(QFxPathView); + qDebug() << "relaease all pathview"; for (int i=0; i<items.count(); i++){ QFxItem *p = items[i]; - model->release(p); + releaseItem(p); } items.clear(); @@ -634,7 +635,7 @@ void QFxPathView::refill() while(wrapIndex-- >= 0){ QFxItem* p = d->items.takeFirst(); d->updateItem(p, 0.0); - d->model->release(p); + d->releaseItem(p); d->firstIndex++; d->firstIndex %= d->model->count(); int index = (d->firstIndex + d->items.count())%d->model->count(); @@ -647,7 +648,7 @@ void QFxPathView::refill() while(wrapIndex++ < d->items.count()-1){ QFxItem* p = d->items.takeLast(); d->updateItem(p, 1.0); - d->model->release(p); + d->releaseItem(p); d->firstIndex--; if (d->firstIndex < 0) d->firstIndex = d->model->count() - 1; @@ -698,6 +699,7 @@ void QFxPathView::itemsInserted(int modelIndex, int count) void QFxPathView::itemsRemoved(int modelIndex, int count) { + qDebug() << "QFxPathView::itemsRemoved"; //XXX support animated removal Q_D(QFxPathView); if (!d->isValid()) @@ -733,7 +735,7 @@ void QFxPathView::itemsRemoved(int modelIndex, int count) d->moveOffset.setValue(targetOffset); } -void QFxPathView::itemCreated(int index, QFxItem *item) +void QFxPathView::createdItem(int index, QFxItem *item) { Q_D(QFxPathView); if (d->requestedIndex != index) { diff --git a/src/declarative/fx/qfxpathview.h b/src/declarative/fx/qfxpathview.h index 32e03b8..33db566 100644 --- a/src/declarative/fx/qfxpathview.h +++ b/src/declarative/fx/qfxpathview.h @@ -115,7 +115,7 @@ private Q_SLOTS: void ticked(); void itemsInserted(int index, int count); void itemsRemoved(int index, int count); - void itemCreated(int index, QFxItem *item); + void createdItem(int index, QFxItem *item); void destroyingItem(QFxItem *item); protected: diff --git a/src/declarative/fx/qfxpathview_p.h b/src/declarative/fx/qfxpathview_p.h index 358daf6..b5c5ba2 100644 --- a/src/declarative/fx/qfxpathview_p.h +++ b/src/declarative/fx/qfxpathview_p.h @@ -101,6 +101,9 @@ public: requestedIndex = -1; return item; } + void releaseItem(QFxItem *item) { + model->release(item); + } bool isValid() const { return model && model->count() > 0 && model->delegate() && path; diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp index 533917e..c631d33 100644 --- a/src/declarative/fx/qfxvisualitemmodel.cpp +++ b/src/declarative/fx/qfxvisualitemmodel.cpp @@ -73,9 +73,53 @@ public: QList<int> m_roles; QHash<int,QString> m_roleNames; - QHash<int, QObject *> m_cache; + struct ObjectRef { + ObjectRef(QObject *object=0) : obj(object), ref(1) {} + QObject *obj; + int ref; + }; + class Cache : public QHash<int, ObjectRef> { + public: + QObject *getItem(int index) { + QObject *item = 0; + QHash<int,ObjectRef>::iterator it = find(index); + if (it != end()) { + (*it).ref++; + item = (*it).obj; + qDebug() << "ref" << item << (*it).ref; + } + return item; + } + QObject *item(int index) { + QObject *item = 0; + QHash<int, ObjectRef>::const_iterator it = find(index); + if (it != end()) + item = (*it).obj; + return item; + } + void insertItem(int index, QObject *obj) { + insert(index, ObjectRef(obj)); + } + bool releaseItem(QObject *obj) { + QHash<int, ObjectRef>::iterator it = begin(); + for (; it != end(); ++it) { + ObjectRef &objRef = *it; + if (objRef.obj == obj) { + if (--objRef.ref == 0) { + erase(it); + qDebug() << "released item" << obj << "item count" << count(); + return true; + } + qDebug() << "not releasing" << obj << "ref" << objRef.ref; + break; + } + } + return false; + } + }; + + Cache m_cache; QHash<QObject *, QmlPackage*> m_packaged; - QHash<QmlPackage*, int> m_packageRef; QFxVisualItemModelParts *m_parts; friend class QFxVisualItemParts; @@ -337,8 +381,8 @@ void QFxVisualItemModel::setModel(const QVariant &model) this, SIGNAL(itemsRemoved(int,int))); QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); - QObject::disconnect(d->m_visualItemModel, SIGNAL(packageCreated(int,QmlPackage*)), - this, SLOT(_q_packageCreated(int,QmlPackage*))); + QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QmlPackage*)), + this, SLOT(_q_createdPackage(int,QmlPackage*))); QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)), this, SLOT(_q_destroyingPackage(QmlPackage*))); d->m_visualItemModel = 0; @@ -390,8 +434,8 @@ void QFxVisualItemModel::setModel(const QVariant &model) this, SIGNAL(itemsRemoved(int,int))); QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); - QObject::connect(d->m_visualItemModel, SIGNAL(packageCreated(int,QmlPackage*)), - this, SLOT(_q_packageCreated(int,QmlPackage*))); + QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QmlPackage*)), + this, SLOT(_q_createdPackage(int,QmlPackage*))); QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)), this, SLOT(_q_destroyingPackage(QmlPackage*))); return; @@ -445,41 +489,39 @@ QFxItem *QFxVisualItemModel::item(int index, bool complete) return item(index, QByteArray(), complete); } -void QFxVisualItemModel::release(QFxItem *item) +/* + Returns ReleaseStatus flags. +*/ +QFxVisualItemModel::ReleaseFlags QFxVisualItemModel::release(QFxItem *item) { Q_D(QFxVisualItemModel); - if (d->m_visualItemModel) { - d->m_visualItemModel->release(item); - return; - } - item->setItemParent(0); - QObject *obj = item; + if (d->m_visualItemModel) + return d->m_visualItemModel->release(item); + ReleaseFlags stat = 0; + QObject *obj = item; bool inPackage = false; - if (QmlPackage *package = d->m_packaged.value(item)) { - static_cast<QObject*>(item)->setParent(package); - d->m_packaged.remove(item); - //XXX Inefficient - for (QHash<QObject *, QmlPackage *>::Iterator iter = d->m_packaged.begin(); - iter != d->m_packaged.end(); ++iter) { - if (*iter == package) - return; - } + + QHash<QObject*,QmlPackage*>::iterator it = d->m_packaged.find(item); + if (it != d->m_packaged.end()) { + QmlPackage *package = *it; + d->m_packaged.erase(it); + if (d->m_packaged.contains(item)) + stat |= Referenced; inPackage = true; obj = package; // fall through and delete } - //XXX Inefficient - for (QHash<int, QObject *>::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ++iter) { - if (*iter == obj) { - if (inPackage) - emit destroyingPackage(qobject_cast<QmlPackage*>(obj)); - delete obj; - d->m_cache.erase(iter); - return; - } + if (d->m_cache.releaseItem(obj)) { + if (inPackage) + emit destroyingPackage(qobject_cast<QmlPackage*>(obj)); + stat |= Destroyed; + delete obj; + } else if (!inPackage) { + stat |= Referenced; } + + return stat; } QObject *QFxVisualItemModel::parts() @@ -499,10 +541,8 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp if (d->modelCount() <= 0 || !d->m_delegate) return 0; - QObject *nobj = 0; - if (d->m_cache.contains(index)) { - nobj = d->m_cache[index]; - } else { + QObject *nobj = d->m_cache.getItem(index); + if (!nobj) { QmlContext *ccontext = d->m_context; if (!ccontext) ccontext = qmlContext(this); QmlContext *ctxt = new QmlContext(ccontext); @@ -515,8 +555,9 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp if (nobj) { ctxt->setParent(nobj); data->setParent(nobj); - - d->m_cache.insert(index, nobj); + d->m_cache.insertItem(index, nobj); + if (QmlPackage *package = qobject_cast<QmlPackage *>(nobj)) + emit createdPackage(index, package); } else { delete data; delete ctxt; @@ -529,8 +570,7 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp if (package) { QObject *o = package->part(QLatin1String(viewId)); item = qobject_cast<QFxItem *>(o); - d->m_packaged[o] = package; - emit packageCreated(index, package); + d->m_packaged.insertMulti(item, package); } } @@ -558,8 +598,8 @@ QVariant QFxVisualItemModel::evaluate(int index, const QString &expression, QObj return QVariant(); QVariant value; - if (d->m_cache.contains(index)) { - QObject *nobj = d->m_cache[index]; + QObject *nobj = d->m_cache.item(index); + if (nobj) { QFxItem *item = qobject_cast<QFxItem *>(nobj); if (item) { QmlExpression e(qmlContext(item), expression, objectContext); @@ -582,6 +622,16 @@ QVariant QFxVisualItemModel::evaluate(int index, const QString &expression, QObj return value; } +int QFxVisualItemModel::indexOf(QFxItem *item, QObject *objectContext) const +{ + QmlExpression e(qmlContext(item), "index", objectContext); + e.setTrackChange(false); + QVariant value = e.value(); + if (value.isValid()) + return value.toInt(); + return -1; +} + void QFxVisualItemModel::_q_itemsChanged(int index, int count, const QList<int> &roles) { @@ -589,9 +639,7 @@ void QFxVisualItemModel::_q_itemsChanged(int index, int count, // XXX - highly inefficient for (int ii = index; ii < index + count; ++ii) { - if (d->m_cache.contains(ii)) { - - QObject *item = d->m_cache[ii]; + if (QObject *item = d->m_cache.item(ii)) { QFxVisualItemModelData *data = d->data(item); for (int prop = 0; prop < data->count(); ++prop) { @@ -615,18 +663,18 @@ void QFxVisualItemModel::_q_itemsInserted(int index, int count) { Q_D(QFxVisualItemModel); // XXX - highly inefficient - QHash<int, QObject *> items; - for (QHash<int, QObject *>::Iterator iter = d->m_cache.begin(); + QHash<int,QFxVisualItemModelPrivate::ObjectRef> items; + for (QHash<int,QFxVisualItemModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { if (iter.key() >= index) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; int index = iter.key() + count; iter = d->m_cache.erase(iter); - items.insert(index, item); + items.insert(index, objRef); - QFxVisualItemModelData *data = d->data(item); + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(index); } else { ++iter; @@ -641,21 +689,21 @@ void QFxVisualItemModel::_q_itemsRemoved(int index, int count) { Q_D(QFxVisualItemModel); // XXX - highly inefficient - QHash<int, QObject *> items; - for (QHash<int, QObject *>::Iterator iter = d->m_cache.begin(); + QHash<int, QFxVisualItemModelPrivate::ObjectRef> items; + for (QHash<int, QFxVisualItemModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { if (iter.key() >= index && iter.key() < index + count) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; iter = d->m_cache.erase(iter); - items.insertMulti(-1, item); //XXX perhaps better to maintain separately - QFxVisualItemModelData *data = d->data(item); + items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(-1); } else if (iter.key() >= index + count) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; int index = iter.key() - count; iter = d->m_cache.erase(iter); - items.insert(index, item); - QFxVisualItemModelData *data = d->data(item); + items.insert(index, objRef); + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(index); } else { ++iter; @@ -670,18 +718,18 @@ void QFxVisualItemModel::_q_itemsMoved(int from, int to, int count) { Q_D(QFxVisualItemModel); // XXX - highly inefficient - QHash<int, QObject *> items; - for (QHash<int, QObject *>::Iterator iter = d->m_cache.begin(); + QHash<int,QFxVisualItemModelPrivate::ObjectRef> items; + for (QHash<int,QFxVisualItemModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { if (iter.key() >= from && iter.key() < from + count) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; int index = iter.key() - from + to; iter = d->m_cache.erase(iter); - items.insert(index, item); + items.insert(index, objRef); - QFxVisualItemModelData *data = d->data(item); + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(index); } else { ++iter; @@ -708,10 +756,10 @@ void QFxVisualItemModel::_q_dataChanged(const QModelIndex &begin, const QModelIn _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); } -void QFxVisualItemModel::_q_packageCreated(int index, QmlPackage *package) +void QFxVisualItemModel::_q_createdPackage(int index, QmlPackage *package) { Q_D(QFxVisualItemModel); - emit itemCreated(index, qobject_cast<QFxItem*>(package->part(d->m_part))); + emit createdItem(index, qobject_cast<QFxItem*>(package->part(d->m_part))); } void QFxVisualItemModel::_q_destroyingPackage(QmlPackage *package) diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h index 586d837..622065c 100644 --- a/src/declarative/fx/qfxvisualitemmodel.h +++ b/src/declarative/fx/qfxvisualitemmodel.h @@ -86,21 +86,26 @@ public: QString part() const; void setPart(const QString &); + enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 }; + Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag) + int count() const; QFxItem *item(int index, bool complete=true); QFxItem *item(int index, const QByteArray &, bool complete=true); - void release(QFxItem *item); + ReleaseFlags release(QFxItem *item); void completeItem(); QVariant evaluate(int index, const QString &expression, QObject *objectContext); + int indexOf(QFxItem *item, QObject *objectContext) const; + QObject *parts(); Q_SIGNALS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); - void itemCreated(int index, QFxItem *item); - void packageCreated(int index, QmlPackage *package); + void createdItem(int index, QFxItem *item); + void createdPackage(int index, QmlPackage *package); void destroyingItem(QFxItem *item); void destroyingPackage(QmlPackage *package); @@ -112,7 +117,7 @@ private Q_SLOTS: void _q_rowsInserted(const QModelIndex &,int,int); void _q_rowsRemoved(const QModelIndex &,int,int); void _q_dataChanged(const QModelIndex&,const QModelIndex&); - void _q_packageCreated(int index, QmlPackage *package); + void _q_createdPackage(int index, QmlPackage *package); void _q_destroyingPackage(QmlPackage *package); private: diff --git a/src/declarative/util/qmlpackage.cpp b/src/declarative/util/qmlpackage.cpp index aa7ed38..bfad44c 100644 --- a/src/declarative/util/qmlpackage.cpp +++ b/src/declarative/util/qmlpackage.cpp @@ -98,6 +98,11 @@ QmlPackage::QmlPackage(QObject *parent) QmlPackage::~QmlPackage() { + Q_D(QmlPackage); + for (int ii = 0; ii < d->dataList.count(); ++ii) { + QObject *obj = d->dataList.at(ii); + delete obj; + } } QmlList<QObject *> *QmlPackage::data() |