summaryrefslogtreecommitdiffstats
path: root/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp')
-rw-r--r--src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp1155
1 files changed, 1155 insertions, 0 deletions
diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp
new file mode 100644
index 0000000..2fc143d
--- /dev/null
+++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp
@@ -0,0 +1,1155 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qmlgraphicsvisualitemmodel_p.h"
+
+#include "qmlgraphicsitem.h"
+
+#include <qmlcontext.h>
+#include <qmlengine.h>
+#include <qmlexpression.h>
+#include <qmlpackage_p.h>
+#include <qmlopenmetaobject_p.h>
+#include <qmllistaccessor_p.h>
+#include <qmlinfo.h>
+#include <qmldeclarativedata_p.h>
+#include <qmlpropertycache_p.h>
+#include <qmlguard_p.h>
+
+#include <qlistmodelinterface_p.h>
+#include <qhash.h>
+#include <qlist.h>
+#include <qmetaobjectbuilder_p.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QML_DECLARE_TYPE(QListModelInterface)
+
+QT_BEGIN_NAMESPACE
+
+class QmlGraphicsVisualItemModelAttached : public QObject
+{
+ Q_OBJECT
+
+public:
+ QmlGraphicsVisualItemModelAttached(QObject *parent)
+ : QObject(parent), m_index(0) {}
+ ~QmlGraphicsVisualItemModelAttached() {
+ attachedProperties.remove(parent());
+ }
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const { return m_index; }
+ void setIndex(int idx) {
+ if (m_index != idx) {
+ m_index = idx;
+ emit indexChanged();
+ }
+ }
+
+ static QmlGraphicsVisualItemModelAttached *properties(QObject *obj) {
+ QmlGraphicsVisualItemModelAttached *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QmlGraphicsVisualItemModelAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+ }
+
+Q_SIGNALS:
+ void indexChanged();
+
+public:
+ int m_index;
+
+ static QHash<QObject*, QmlGraphicsVisualItemModelAttached*> attachedProperties;
+};
+
+QHash<QObject*, QmlGraphicsVisualItemModelAttached*> QmlGraphicsVisualItemModelAttached::attachedProperties;
+
+
+class QmlGraphicsVisualItemModelPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlGraphicsVisualItemModel)
+public:
+ QmlGraphicsVisualItemModelPrivate() : QObjectPrivate(), children(this) {}
+
+ struct ItemList : public QmlConcreteList<QmlGraphicsItem *>
+ {
+ ItemList(QmlGraphicsVisualItemModelPrivate *m) : QmlConcreteList<QmlGraphicsItem *>(), model(m) {}
+
+ void append(QmlGraphicsItem *item);
+
+ QmlGraphicsVisualItemModelPrivate *model;
+ };
+
+ void itemAppended() {
+ Q_Q(QmlGraphicsVisualItemModel);
+ QmlGraphicsVisualItemModelAttached *attached = QmlGraphicsVisualItemModelAttached::properties(children.last());
+ attached->setIndex(children.count()-1);
+ emit q->itemsInserted(children.count()-1, 1);
+ emit q->countChanged();
+ }
+
+ void emitChildrenChanged() {
+ Q_Q(QmlGraphicsVisualItemModel);
+ emit q->childrenChanged();
+ }
+ ItemList children;
+};
+
+
+/*!
+ \qmlclass VisualItemModel QmlGraphicsVisualItemModel
+ \brief The VisualItemModel allows items to be provided to a view.
+
+ The children of the VisualItemModel are provided in a model which
+ can be used in a view. Note that no delegate should be
+ provided to a view since the VisualItemModel contains the
+ visual delegate (items).
+
+ An item can determine its index within the
+ model via the VisualItemModel.index attached property.
+
+ The example below places three colored rectangles in a ListView.
+ \code
+ Item {
+ VisualItemModel {
+ id: itemModel
+ Rectangle { height: 30; width: 80; color: "red" }
+ Rectangle { height: 30; width: 80; color: "green" }
+ Rectangle { height: 30; width: 80; color: "blue" }
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: itemModel
+ }
+ }
+ \endcode
+*/
+QmlGraphicsVisualItemModel::QmlGraphicsVisualItemModel()
+ : QmlGraphicsVisualModel(*(new QmlGraphicsVisualItemModelPrivate))
+{
+}
+
+QmlList<QmlGraphicsItem *> *QmlGraphicsVisualItemModel::children()
+{
+ Q_D(QmlGraphicsVisualItemModel);
+ return &(d->children);
+}
+
+/*!
+ \qmlproperty int VisualItemModel::count
+
+ The number of items in the model. This property is readonly.
+*/
+int QmlGraphicsVisualItemModel::count() const
+{
+ Q_D(const QmlGraphicsVisualItemModel);
+ return d->children.count();
+}
+
+bool QmlGraphicsVisualItemModel::isValid() const
+{
+ return true;
+}
+
+QmlGraphicsItem *QmlGraphicsVisualItemModel::item(int index, bool)
+{
+ Q_D(QmlGraphicsVisualItemModel);
+ return d->children.at(index);
+}
+
+QmlGraphicsVisualModel::ReleaseFlags QmlGraphicsVisualItemModel::release(QmlGraphicsItem *)
+{
+ // Nothing to do
+ return 0;
+}
+
+void QmlGraphicsVisualItemModel::completeItem()
+{
+ // Nothing to do
+}
+
+QString QmlGraphicsVisualItemModel::stringValue(int index, const QString &name)
+{
+ Q_D(QmlGraphicsVisualItemModel);
+ if (index < 0 || index >= d->children.count())
+ return QString();
+ return QmlEngine::contextForObject(d->children.at(index))->contextProperty(name).toString();
+}
+
+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));
+ QmlExpression e(ctxt, expression, objectContext);
+ e.setTrackChange(false);
+ QVariant value = e.value();
+ delete ctxt;
+ return value;
+}
+
+int QmlGraphicsVisualItemModel::indexOf(QmlGraphicsItem *item, QObject *) const
+{
+ Q_D(const QmlGraphicsVisualItemModel);
+ return d->children.indexOf(item);
+}
+
+void QmlGraphicsVisualItemModelPrivate::ItemList::append(QmlGraphicsItem *item)
+{
+ QmlConcreteList<QmlGraphicsItem*>::append(item);
+ item->QObject::setParent(model->q_ptr);
+ model->itemAppended();
+
+ model->emitChildrenChanged();
+}
+
+QmlGraphicsVisualItemModelAttached *QmlGraphicsVisualItemModel::qmlAttachedProperties(QObject *obj)
+{
+ return QmlGraphicsVisualItemModelAttached::properties(obj);
+}
+
+//============================================================================
+
+class VDMDelegateDataType : public QmlOpenMetaObjectType
+{
+public:
+ VDMDelegateDataType(const QMetaObject *base, QmlEngine *engine) : QmlOpenMetaObjectType(base, engine) {}
+
+ void propertyCreated(int, QMetaPropertyBuilder &prop) {
+ prop.setWritable(false);
+ }
+};
+
+class QmlGraphicsVisualDataModelParts;
+class QmlGraphicsVisualDataModelData;
+class QmlGraphicsVisualDataModelPrivate : public QObjectPrivate
+{
+public:
+ QmlGraphicsVisualDataModelPrivate(QmlContext *);
+
+ static QmlGraphicsVisualDataModelPrivate *get(QmlGraphicsVisualDataModel *m) {
+ return static_cast<QmlGraphicsVisualDataModelPrivate *>(QObjectPrivate::get(m));
+ }
+
+ QmlGuard<QListModelInterface> m_listModelInterface;
+ QmlGuard<QAbstractItemModel> m_abstractItemModel;
+ QmlGuard<QmlGraphicsVisualDataModel> m_visualItemModel;
+ QString m_part;
+
+ QmlComponent *m_delegate;
+ QmlContext *m_context;
+ QList<int> m_roles;
+ QHash<QByteArray,int> m_roleNames;
+ void ensureRoles() {
+ if (m_roleNames.isEmpty()) {
+ if (m_listModelInterface) {
+ m_roles = m_listModelInterface->roles();
+ for (int ii = 0; ii < m_roles.count(); ++ii)
+ m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii));
+ if (m_roles.count() == 1)
+ m_roleNames.insert("modelData", m_roles.at(0));
+ } else if (m_abstractItemModel) {
+ for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin();
+ it != m_abstractItemModel->roleNames().end(); ++it) {
+ m_roles.append(it.key());
+ m_roleNames.insert(*it, it.key());
+ }
+ if (m_roles.count() == 1)
+ m_roleNames.insert("modelData", m_roles.at(0));
+ } else if (m_listAccessor) {
+ m_roleNames.insert("modelData", 0);
+ if (m_listAccessor->type() == QmlListAccessor::Instance) {
+ if (QObject *object = m_listAccessor->at(0).value<QObject*>()) {
+ int count = object->metaObject()->propertyCount();
+ for (int ii = 1; ii < count; ++ii) {
+ const QMetaProperty &prop = object->metaObject()->property(ii);
+ m_roleNames.insert(prop.name(), 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void createMetaData() {
+ if (!m_metaDataCreated) {
+ ensureRoles();
+ QHash<QByteArray, int>::const_iterator it = m_roleNames.begin();
+ while (it != m_roleNames.end()) {
+ m_delegateDataType->createProperty(it.key());
+ ++it;
+ }
+ m_metaDataCreated = true;
+ }
+ }
+
+ 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;
+ }
+ 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);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+ };
+
+ int modelCount() const {
+ if (m_visualItemModel)
+ return m_visualItemModel->count();
+ if (m_listModelInterface)
+ return m_listModelInterface->count();
+ if (m_abstractItemModel)
+ return m_abstractItemModel->rowCount();
+ if (m_listAccessor)
+ return m_listAccessor->count();
+ return 0;
+ }
+
+ Cache m_cache;
+ QHash<QObject *, QmlPackage*> m_packaged;
+
+ QmlGraphicsVisualDataModelParts *m_parts;
+ friend class QmlGraphicsVisualItemParts;
+
+ VDMDelegateDataType *m_delegateDataType;
+ friend class QmlGraphicsVisualDataModelData;
+ bool m_metaDataCreated;
+ bool m_metaDataCacheable;
+
+ QmlGraphicsVisualDataModelData *data(QObject *item);
+
+ QVariant m_modelVariant;
+ QmlListAccessor *m_listAccessor;
+};
+
+class QmlGraphicsVisualDataModelDataMetaObject : public QmlOpenMetaObject
+{
+public:
+ QmlGraphicsVisualDataModelDataMetaObject(QObject *parent, QmlOpenMetaObjectType *type)
+ : QmlOpenMetaObject(parent, type) {}
+
+ virtual QVariant initialValue(int);
+ virtual int createProperty(const char *, const char *);
+
+private:
+ friend class QmlGraphicsVisualDataModelData;
+ QHash<int,int> roleToProp;
+};
+
+class QmlGraphicsVisualDataModelData : public QObject
+{
+Q_OBJECT
+public:
+ QmlGraphicsVisualDataModelData(int index, QmlGraphicsVisualDataModel *model);
+ ~QmlGraphicsVisualDataModelData();
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const;
+ void setIndex(int index);
+
+ int propForRole(int) const;
+ void setValue(int, const QVariant &);
+
+Q_SIGNALS:
+ void indexChanged();
+
+private:
+ friend class QmlGraphicsVisualDataModelDataMetaObject;
+ int m_index;
+ QmlGuard<QmlGraphicsVisualDataModel> m_model;
+ QmlGraphicsVisualDataModelDataMetaObject *m_meta;
+};
+
+int QmlGraphicsVisualDataModelData::propForRole(int id) const
+{
+ QHash<int,int>::const_iterator it = m_meta->roleToProp.find(id);
+ if (it != m_meta->roleToProp.end())
+ return m_meta->roleToProp[id];
+ return -1;
+}
+
+void QmlGraphicsVisualDataModelData::setValue(int id, const QVariant &val)
+{
+ m_meta->setValue(id, val);
+}
+
+int QmlGraphicsVisualDataModelDataMetaObject::createProperty(const char *name, const char *type)
+{
+ QmlGraphicsVisualDataModelData *data =
+ static_cast<QmlGraphicsVisualDataModelData *>(object());
+
+ if (!data->m_model)
+ return -1;
+
+ QmlGraphicsVisualDataModelPrivate *model = QmlGraphicsVisualDataModelPrivate::get(data->m_model);
+
+ if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
+ if (model->m_listAccessor->type() == QmlListAccessor::QmlList
+ || model->m_listAccessor->type() == QmlListAccessor::QListPtr) {
+ model->ensureRoles();
+ QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>();
+ if (object && object->property(name).isValid())
+ return QmlOpenMetaObject::createProperty(name, type);
+ }
+ }
+ return -1;
+}
+
+QVariant QmlGraphicsVisualDataModelDataMetaObject::initialValue(int propId)
+{
+ QmlGraphicsVisualDataModelData *data =
+ static_cast<QmlGraphicsVisualDataModelData *>(object());
+
+ Q_ASSERT(data->m_model);
+ QmlGraphicsVisualDataModelPrivate *model = QmlGraphicsVisualDataModelPrivate::get(data->m_model);
+
+ QByteArray propName = name(propId);
+ if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
+ if (propName == "modelData") {
+ if (model->m_listAccessor->type() == QmlListAccessor::Instance) {
+ QObject *object = model->m_listAccessor->at(0).value<QObject*>();
+ return object->metaObject()->property(1).read(object); // the first property after objectName
+ }
+ return model->m_listAccessor->at(data->m_index);
+ } else {
+ // return any property of a single object instance.
+ QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>();
+ return object->property(propName);
+ }
+ } else if (model->m_listModelInterface) {
+ model->ensureRoles();
+ QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
+ if (it != model->m_roleNames.end()) {
+ roleToProp.insert(*it, propId);
+ QVariant value = model->m_listModelInterface->data(data->m_index, *it);
+ return value;
+ } else if (model->m_roles.count() == 1 && propName == "modelData") {
+ //for compatability with other lists, assign modelData if there is only a single role
+ roleToProp.insert(model->m_roles.first(), propId);
+ QVariant value = model->m_listModelInterface->data(data->m_index, model->m_roles.first());
+ return value;
+ }
+ } else if (model->m_abstractItemModel) {
+ model->ensureRoles();
+ QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
+ if (it != model->m_roleNames.end()) {
+ roleToProp.insert(*it, propId);
+ QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0);
+ return model->m_abstractItemModel->data(index, *it);
+ }
+ }
+ Q_ASSERT(!"Can never be reached");
+ return QVariant();
+}
+
+QmlGraphicsVisualDataModelData::QmlGraphicsVisualDataModelData(int index,
+ QmlGraphicsVisualDataModel *model)
+: m_index(index), m_model(model),
+m_meta(new QmlGraphicsVisualDataModelDataMetaObject(this, QmlGraphicsVisualDataModelPrivate::get(model)->m_delegateDataType))
+{
+ QmlGraphicsVisualDataModelPrivate *modelPriv = QmlGraphicsVisualDataModelPrivate::get(model);
+ if (modelPriv->m_metaDataCacheable) {
+ if (!modelPriv->m_metaDataCreated)
+ modelPriv->createMetaData();
+ m_meta->setCached(true);
+ }
+}
+
+QmlGraphicsVisualDataModelData::~QmlGraphicsVisualDataModelData()
+{
+}
+
+int QmlGraphicsVisualDataModelData::index() const
+{
+ return m_index;
+}
+
+// This is internal only - it should not be set from qml
+void QmlGraphicsVisualDataModelData::setIndex(int index)
+{
+ m_index = index;
+ emit indexChanged();
+}
+
+//---------------------------------------------------------------------------
+
+class QmlGraphicsVisualDataModelPartsMetaObject : public QmlOpenMetaObject
+{
+public:
+ QmlGraphicsVisualDataModelPartsMetaObject(QObject *parent)
+ : QmlOpenMetaObject(parent) {}
+
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual QVariant initialValue(int);
+};
+
+class QmlGraphicsVisualDataModelParts : public QObject
+{
+Q_OBJECT
+public:
+ QmlGraphicsVisualDataModelParts(QmlGraphicsVisualDataModel *parent);
+
+private:
+ friend class QmlGraphicsVisualDataModelPartsMetaObject;
+ QmlGraphicsVisualDataModel *model;
+};
+
+void QmlGraphicsVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+}
+
+QVariant QmlGraphicsVisualDataModelPartsMetaObject::initialValue(int id)
+{
+ QmlGraphicsVisualDataModel *m = new QmlGraphicsVisualDataModel;
+ m->setParent(object());
+ m->setPart(QString::fromUtf8(name(id)));
+ m->setModel(QVariant::fromValue(static_cast<QmlGraphicsVisualDataModelParts *>(object())->model));
+
+ QVariant var = QVariant::fromValue((QObject *)m);
+ return var;
+}
+
+QmlGraphicsVisualDataModelParts::QmlGraphicsVisualDataModelParts(QmlGraphicsVisualDataModel *parent)
+: QObject(parent), model(parent)
+{
+ new QmlGraphicsVisualDataModelPartsMetaObject(this);
+}
+
+QmlGraphicsVisualDataModelPrivate::QmlGraphicsVisualDataModelPrivate(QmlContext *ctxt)
+: m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0)
+, m_context(ctxt), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false)
+, m_metaDataCacheable(false), m_listAccessor(0)
+{
+}
+
+QmlGraphicsVisualDataModelData *QmlGraphicsVisualDataModelPrivate::data(QObject *item)
+{
+ QmlGraphicsVisualDataModelData *dataItem =
+ item->findChild<QmlGraphicsVisualDataModelData *>();
+ Q_ASSERT(dataItem);
+ return dataItem;
+}
+
+//---------------------------------------------------------------------------
+
+QmlGraphicsVisualDataModel::QmlGraphicsVisualDataModel()
+: QmlGraphicsVisualModel(*(new QmlGraphicsVisualDataModelPrivate(0)))
+{
+}
+
+QmlGraphicsVisualDataModel::QmlGraphicsVisualDataModel(QmlContext *ctxt)
+: QmlGraphicsVisualModel(*(new QmlGraphicsVisualDataModelPrivate(ctxt)))
+{
+}
+
+QmlGraphicsVisualDataModel::~QmlGraphicsVisualDataModel()
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_listAccessor)
+ delete d->m_listAccessor;
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+}
+
+QVariant QmlGraphicsVisualDataModel::model() const
+{
+ Q_D(const QmlGraphicsVisualDataModel);
+ return d->m_modelVariant;
+}
+
+void QmlGraphicsVisualDataModel::setModel(const QVariant &model)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ delete d->m_listAccessor;
+ d->m_listAccessor = 0;
+ d->m_modelVariant = model;
+ if (d->m_listModelInterface) {
+ // Assume caller has released all items.
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_listModelInterface = 0;
+ } else if (d->m_abstractItemModel) {
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsInserted(const QModelIndex &,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsRemoved(const QModelIndex &,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)),
+ this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)),
+ this, SLOT(_q_rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)));
+ } else if (d->m_visualItemModel) {
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ 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(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;
+ }
+
+ d->m_roles.clear();
+ d->m_roleNames.clear();
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+ d->m_metaDataCreated = 0;
+ d->m_metaDataCacheable = false;
+ d->m_delegateDataType = new VDMDelegateDataType(&QmlGraphicsVisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this));
+
+ QObject *object = qvariant_cast<QObject *>(model);
+ if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_metaDataCacheable = true;
+ if (d->m_delegate && d->m_listModelInterface->count())
+ emit itemsInserted(0, d->m_listModelInterface->count());
+ return;
+ } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsInserted(const QModelIndex &,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsRemoved(const QModelIndex &,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)),
+ this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)),
+ this, SLOT(_q_rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)));
+ d->m_metaDataCacheable = true;
+ return;
+ }
+ if ((d->m_visualItemModel = qvariant_cast<QmlGraphicsVisualDataModel *>(model))) {
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ 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(createdPackage(int,QmlPackage*)),
+ this, SLOT(_q_createdPackage(int,QmlPackage*)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)),
+ this, SLOT(_q_destroyingPackage(QmlPackage*)));
+ return;
+ }
+ d->m_listAccessor = new QmlListAccessor;
+ d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this));
+ if (d->m_listAccessor->type() != QmlListAccessor::QmlList && d->m_listAccessor->type() != QmlListAccessor::QListPtr)
+ d->m_metaDataCacheable = true;
+ if (d->m_delegate && d->modelCount()) {
+ emit itemsInserted(0, d->modelCount());
+ emit countChanged();
+ }
+}
+
+QmlComponent *QmlGraphicsVisualDataModel::delegate() const
+{
+ Q_D(const QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->delegate();
+ return d->m_delegate;
+}
+
+void QmlGraphicsVisualDataModel::setDelegate(QmlComponent *delegate)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ bool wasValid = d->m_delegate != 0;
+ d->m_delegate = delegate;
+ if (!wasValid && d->modelCount() && d->m_delegate) {
+ emit itemsInserted(0, d->modelCount());
+ emit countChanged();
+ }
+ if (wasValid && !d->m_delegate && d->modelCount()) {
+ emit itemsRemoved(0, d->modelCount());
+ emit countChanged();
+ }
+}
+
+QString QmlGraphicsVisualDataModel::part() const
+{
+ Q_D(const QmlGraphicsVisualDataModel);
+ return d->m_part;
+}
+
+void QmlGraphicsVisualDataModel::setPart(const QString &part)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ d->m_part = part;
+}
+
+int QmlGraphicsVisualDataModel::count() const
+{
+ Q_D(const QmlGraphicsVisualDataModel);
+ return d->modelCount();
+}
+
+QmlGraphicsItem *QmlGraphicsVisualDataModel::item(int index, bool complete)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete);
+ return item(index, QByteArray(), complete);
+}
+
+/*
+ Returns ReleaseStatus flags.
+*/
+QmlGraphicsVisualDataModel::ReleaseFlags QmlGraphicsVisualDataModel::release(QmlGraphicsItem *item)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->release(item);
+
+ ReleaseFlags stat = 0;
+ QObject *obj = item;
+ bool inPackage = false;
+
+ 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
+ }
+
+ if (d->m_cache.releaseItem(obj)) {
+ if (inPackage) {
+ emit destroyingPackage(qobject_cast<QmlPackage*>(obj));
+ } else {
+ item->setVisible(false);
+ static_cast<QGraphicsItem*>(item)->setParentItem(0);
+ }
+ stat |= Destroyed;
+ obj->deleteLater();
+ } else if (!inPackage) {
+ stat |= Referenced;
+ }
+
+ return stat;
+}
+
+QObject *QmlGraphicsVisualDataModel::parts()
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (!d->m_parts)
+ d->m_parts = new QmlGraphicsVisualDataModelParts(this);
+ return d->m_parts;
+}
+
+QmlGraphicsItem *QmlGraphicsVisualDataModel::item(int index, const QByteArray &viewId, bool complete)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, viewId, complete);
+
+ if (d->modelCount() <= 0 || !d->m_delegate)
+ return 0;
+
+ QObject *nobj = d->m_cache.getItem(index);
+ if (!nobj) {
+ QmlContext *ccontext = d->m_context;
+ if (!ccontext) ccontext = qmlContext(this);
+ QmlContext *ctxt = new QmlContext(ccontext);
+ QmlGraphicsVisualDataModelData *data = new QmlGraphicsVisualDataModelData(index, this);
+ ctxt->setContextProperty(QLatin1String("model"), data);
+ ctxt->addDefaultObject(data);
+ nobj = d->m_delegate->beginCreate(ctxt);
+ if (complete)
+ d->m_delegate->completeCreate();
+ if (nobj) {
+ ctxt->setParent(nobj);
+ data->setParent(nobj);
+ d->m_cache.insertItem(index, nobj);
+ if (QmlPackage *package = qobject_cast<QmlPackage *>(nobj))
+ emit createdPackage(index, package);
+ } else {
+ delete data;
+ delete ctxt;
+ qWarning() << d->m_delegate->errors();
+ }
+ }
+ QmlGraphicsItem *item = qobject_cast<QmlGraphicsItem *>(nobj);
+ if (!item) {
+ QmlPackage *package = qobject_cast<QmlPackage *>(nobj);
+ if (package) {
+ QObject *o = package->part(QString::fromUtf8(viewId));
+ item = qobject_cast<QmlGraphicsItem *>(o);
+ if (item)
+ d->m_packaged.insertMulti(item, package);
+ }
+ }
+ if (!item) {
+ d->m_cache.releaseItem(nobj);
+ qmlInfo(d->m_delegate) << QmlGraphicsVisualDataModel::tr("Delegate component must be Item type.");
+ }
+
+ return item;
+}
+
+void QmlGraphicsVisualDataModel::completeItem()
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel) {
+ d->m_visualItemModel->completeItem();
+ return;
+ }
+
+ d->m_delegate->completeCreate();
+}
+
+QString QmlGraphicsVisualDataModel::stringValue(int index, const QString &name)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->stringValue(index, name);
+
+ if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
+ return QString();
+
+ QString val;
+ QObject *data = 0;
+ bool tempData = false;
+
+ if (QObject *nobj = d->m_cache.item(index))
+ data = d->data(nobj);
+ if (!data) {
+ data = new QmlGraphicsVisualDataModelData(index, this);
+ tempData = true;
+ }
+
+ QmlDeclarativeData *ddata = QmlDeclarativeData::get(data);
+ if (ddata && ddata->propertyCache) {
+ QmlPropertyCache::Data *prop = ddata->propertyCache->property(name);
+ if (prop) {
+ if (prop->propType == QVariant::String) {
+ void *args[] = { &val, 0 };
+ QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
+ } else if (prop->propType == qMetaTypeId<QVariant>()) {
+ QVariant v;
+ void *args[] = { &v, 0 };
+ QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
+ val = v.toString();
+ }
+ } else {
+ val = data->property(name.toUtf8()).toString();
+ }
+ } else {
+ val = data->property(name.toUtf8()).toString();
+ }
+
+ if (tempData)
+ delete data;
+
+ return val;
+}
+
+QVariant QmlGraphicsVisualDataModel::evaluate(int index, const QString &expression, QObject *objectContext)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->evaluate(index, expression, objectContext);
+
+ if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
+ return QVariant();
+
+ QVariant value;
+ QObject *nobj = d->m_cache.item(index);
+ if (nobj) {
+ QmlGraphicsItem *item = qobject_cast<QmlGraphicsItem *>(nobj);
+ if (item) {
+ QmlExpression e(qmlContext(item), expression, objectContext);
+ e.setTrackChange(false);
+ value = e.value();
+ }
+ } 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);
+ QmlExpression e(ctxt, expression, objectContext);
+ e.setTrackChange(false);
+ value = e.value();
+ delete data;
+ delete ctxt;
+ }
+
+ return value;
+}
+
+int QmlGraphicsVisualDataModel::indexOf(QmlGraphicsItem *item, QObject *) const
+{
+ QVariant val = QmlEngine::contextForObject(item)->contextProperty(QLatin1String("index"));
+ return val.toInt();
+ return -1;
+}
+
+void QmlGraphicsVisualDataModel::_q_itemsChanged(int index, int count,
+ const QList<int> &roles)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ // XXX - highly inefficient
+ for (int ii = index; ii < index + count; ++ii) {
+
+ if (QObject *item = d->m_cache.item(ii)) {
+ QmlGraphicsVisualDataModelData *data = d->data(item);
+
+ for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) {
+ int role = roles.at(roleIdx);
+ int propId = data->propForRole(role);
+ if (propId != -1) {
+ if (d->m_listModelInterface) {
+ data->setValue(propId, d->m_listModelInterface->data(ii, QList<int>() << role).value(role));
+ } else if (d->m_abstractItemModel) {
+ QModelIndex index = d->m_abstractItemModel->index(ii, 0);
+ data->setValue(propId, d->m_abstractItemModel->data(index, role));
+ }
+ }
+ }
+ }
+ }
+}
+
+void QmlGraphicsVisualDataModel::_q_itemsInserted(int index, int count)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ // XXX - highly inefficient
+ QHash<int,QmlGraphicsVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QmlGraphicsVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= index) {
+ QmlGraphicsVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + count;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QmlGraphicsVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsInserted(index, count);
+ emit countChanged();
+}
+
+void QmlGraphicsVisualDataModel::_q_itemsRemoved(int index, int count)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ // XXX - highly inefficient
+ QHash<int, QmlGraphicsVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int, QmlGraphicsVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+ if (iter.key() >= index && iter.key() < index + count) {
+ QmlGraphicsVisualDataModelPrivate::ObjectRef objRef = *iter;
+ iter = d->m_cache.erase(iter);
+ items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
+ QmlGraphicsVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(-1);
+ } else if (iter.key() >= index + count) {
+ QmlGraphicsVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - count;
+ iter = d->m_cache.erase(iter);
+ items.insert(index, objRef);
+ QmlGraphicsVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+
+ d->m_cache.unite(items);
+ emit itemsRemoved(index, count);
+ emit countChanged();
+}
+
+void QmlGraphicsVisualDataModel::_q_itemsMoved(int from, int to, int count)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ // XXX - highly inefficient
+ QHash<int,QmlGraphicsVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QmlGraphicsVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= from && iter.key() < from + count) {
+ QmlGraphicsVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - from + to;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QmlGraphicsVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ for (QHash<int,QmlGraphicsVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ int diff = from > to ? count : -count;
+ if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) {
+ QmlGraphicsVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + diff;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QmlGraphicsVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsMoved(from, to, count);
+}
+
+void QmlGraphicsVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
+{
+ if (!parent.isValid())
+ _q_itemsInserted(begin, end - begin + 1);
+}
+
+void QmlGraphicsVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
+{
+ if (!parent.isValid())
+ _q_itemsRemoved(begin, end - begin + 1);
+}
+
+void QmlGraphicsVisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
+{
+ const int count = sourceEnd - sourceStart + 1;
+ if (!destinationParent.isValid() && !sourceParent.isValid()) {
+ _q_itemsMoved(sourceStart, destinationRow, count);
+ } else if (!sourceParent.isValid()) {
+ _q_itemsRemoved(sourceStart, count);
+ } else if (!destinationParent.isValid()) {
+ _q_itemsInserted(destinationRow, count);
+ }
+}
+
+void QmlGraphicsVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ if (!begin.parent().isValid())
+ _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
+}
+
+void QmlGraphicsVisualDataModel::_q_createdPackage(int index, QmlPackage *package)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ emit createdItem(index, qobject_cast<QmlGraphicsItem*>(package->part(d->m_part)));
+}
+
+void QmlGraphicsVisualDataModel::_q_destroyingPackage(QmlPackage *package)
+{
+ Q_D(QmlGraphicsVisualDataModel);
+ emit destroyingItem(qobject_cast<QmlGraphicsItem*>(package->part(d->m_part)));
+}
+
+QML_DEFINE_NOCREATE_TYPE(QmlGraphicsVisualModel);
+QML_DEFINE_TYPE(Qt,4,6,VisualItemModel,QmlGraphicsVisualItemModel)
+QML_DEFINE_TYPE(Qt,4,6,VisualDataModel,QmlGraphicsVisualDataModel)
+
+QT_END_NAMESPACE
+
+#include <qmlgraphicsvisualitemmodel.moc>