beb303efc0ff49900295d19822f6678e5f891fd5
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativevisualitemmodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtQuick1/private/qdeclarativevisualitemmodel_p.h"
43
44 #include "QtQuick1/qdeclarativeitem.h"
45
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/private/qdeclarativecontext_p.h>
48 #include <QtDeclarative/qdeclarativeengine.h>
49 #include <QtDeclarative/qdeclarativeexpression.h>
50 #include <QtQuick1/private/qdeclarativepackage_p.h>
51 #include <QtQuick1/private/qdeclarativeopenmetaobject_p.h>
52 #include <QtQuick1/private/qdeclarativelistaccessor_p.h>
53 #include <QtDeclarative/qdeclarativeinfo.h>
54 #include <QtDeclarative/private/qdeclarativedata_p.h>
55 #include <QtDeclarative/private/qdeclarativepropertycache_p.h>
56 #include <QtDeclarative/private/qdeclarativeguard_p.h>
57 #include <QtDeclarative/private/qdeclarativeglobal_p.h>
58
59 #include <qgraphicsscene.h>
60 #include <QtDeclarative/private/qlistmodelinterface_p.h>
61 #include <qhash.h>
62 #include <qlist.h>
63 #include <private/qmetaobjectbuilder_p.h>
64 #include <QtCore/qdebug.h>
65
66 #include <private/qobject_p.h>
67
68 QT_BEGIN_NAMESPACE
69
70
71
72 QHash<QObject*, QDeclarative1VisualItemModelAttached*> QDeclarative1VisualItemModelAttached::attachedProperties;
73
74
75 class QDeclarative1VisualItemModelPrivate : public QObjectPrivate
76 {
77     Q_DECLARE_PUBLIC(QDeclarative1VisualItemModel)
78 public:
79     QDeclarative1VisualItemModelPrivate() : QObjectPrivate() {}
80
81     static void children_append(QDeclarativeListProperty<QDeclarativeItem> *prop, QDeclarativeItem *item) {
82         QDeclarative_setParent_noEvent(item, prop->object);
83         static_cast<QDeclarative1VisualItemModelPrivate *>(prop->data)->children.append(Item(item));
84         static_cast<QDeclarative1VisualItemModelPrivate *>(prop->data)->itemAppended();
85         static_cast<QDeclarative1VisualItemModelPrivate *>(prop->data)->emitChildrenChanged();
86     }
87
88     static int children_count(QDeclarativeListProperty<QDeclarativeItem> *prop) {
89         return static_cast<QDeclarative1VisualItemModelPrivate *>(prop->data)->children.count();
90     }
91
92     static QDeclarativeItem *children_at(QDeclarativeListProperty<QDeclarativeItem> *prop, int index) {
93         return static_cast<QDeclarative1VisualItemModelPrivate *>(prop->data)->children.at(index).item;
94     }
95
96     void itemAppended() {
97         Q_Q(QDeclarative1VisualItemModel);
98         QDeclarative1VisualItemModelAttached *attached = QDeclarative1VisualItemModelAttached::properties(children.last().item);
99         attached->setIndex(children.count()-1);
100         emit q->itemsInserted(children.count()-1, 1);
101         emit q->countChanged();
102     }
103
104     void emitChildrenChanged() {
105         Q_Q(QDeclarative1VisualItemModel);
106         emit q->childrenChanged();
107     }
108
109     int indexOf(QDeclarativeItem *item) const {
110         for (int i = 0; i < children.count(); ++i)
111             if (children.at(i).item == item)
112                 return i;
113         return -1;
114     }
115
116     class Item {
117     public:
118         Item(QDeclarativeItem *i) : item(i), ref(0) {}
119
120         void addRef() { ++ref; }
121         bool deref() { return --ref == 0; }
122
123         QDeclarativeItem *item;
124         int ref;
125     };
126
127     QList<Item> children;
128 };
129
130
131 /*!
132     \qmlclass VisualItemModel QDeclarative1VisualItemModel
133     \inqmlmodule QtQuick 1
134     \ingroup qml-working-with-data
135   \since QtQuick 1.0
136     \brief The VisualItemModel allows items to be provided to a view.
137
138     A VisualItemModel contains the visual items to be used in a view.
139     When a VisualItemModel is used in a view, the view does not require
140     a delegate since the VisualItemModel already contains the visual
141     delegate (items).
142
143     An item can determine its index within the
144     model via the \l{VisualItemModel::index}{index} attached property.
145
146     The example below places three colored rectangles in a ListView.
147     \code
148     import QtQuick 1.0
149
150     Rectangle {
151         VisualItemModel {
152             id: itemModel
153             Rectangle { height: 30; width: 80; color: "red" }
154             Rectangle { height: 30; width: 80; color: "green" }
155             Rectangle { height: 30; width: 80; color: "blue" }
156         }
157
158         ListView {
159             anchors.fill: parent
160             model: itemModel
161         }
162     }
163     \endcode
164
165     \image visualitemmodel.png
166
167     \sa {declarative/modelviews/visualitemmodel}{VisualItemModel example}
168 */
169 QDeclarative1VisualItemModel::QDeclarative1VisualItemModel(QObject *parent)
170     : QDeclarative1VisualModel(*(new QDeclarative1VisualItemModelPrivate), parent)
171 {
172 }
173
174 /*!
175     \qmlattachedproperty int VisualItemModel::index
176     This attached property holds the index of this delegate's item within the model.
177
178     It is attached to each instance of the delegate.
179 */
180
181 QDeclarativeListProperty<QDeclarativeItem> QDeclarative1VisualItemModel::children()
182 {
183     Q_D(QDeclarative1VisualItemModel);
184     return QDeclarativeListProperty<QDeclarativeItem>(this, d, d->children_append,
185                                                       d->children_count, d->children_at);
186 }
187
188 /*!
189     \qmlproperty int QtQuick1::VisualItemModel::count
190
191     The number of items in the model.  This property is readonly.
192 */
193 int QDeclarative1VisualItemModel::count() const
194 {
195     Q_D(const QDeclarative1VisualItemModel);
196     return d->children.count();
197 }
198
199 bool QDeclarative1VisualItemModel::isValid() const
200 {
201     return true;
202 }
203
204 QDeclarativeItem *QDeclarative1VisualItemModel::item(int index, bool)
205 {
206     Q_D(QDeclarative1VisualItemModel);
207     QDeclarative1VisualItemModelPrivate::Item &item = d->children[index];
208     item.addRef();
209     return item.item;
210 }
211
212 QDeclarative1VisualModel::ReleaseFlags QDeclarative1VisualItemModel::release(QDeclarativeItem *item)
213 {
214     Q_D(QDeclarative1VisualItemModel);
215     int idx = d->indexOf(item);
216     if (idx >= 0) {
217         if (d->children[idx].deref()) {
218             if (item->scene())
219                 item->scene()->removeItem(item);
220             QDeclarative_setParent_noEvent(item, this);
221         }
222     }
223     return 0;
224 }
225
226 bool QDeclarative1VisualItemModel::completePending() const
227 {
228     return false;
229 }
230
231 void QDeclarative1VisualItemModel::completeItem()
232 {
233     // Nothing to do
234 }
235
236 QString QDeclarative1VisualItemModel::stringValue(int index, const QString &name)
237 {
238     Q_D(QDeclarative1VisualItemModel);
239     if (index < 0 || index >= d->children.count())
240         return QString();
241     return QDeclarativeEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString();
242 }
243
244 int QDeclarative1VisualItemModel::indexOf(QDeclarativeItem *item, QObject *) const
245 {
246     Q_D(const QDeclarative1VisualItemModel);
247     return d->indexOf(item);
248 }
249
250 QDeclarative1VisualItemModelAttached *QDeclarative1VisualItemModel::qmlAttachedProperties(QObject *obj)
251 {
252     return QDeclarative1VisualItemModelAttached::properties(obj);
253 }
254
255 //============================================================================
256
257 class VDMDelegateDataType : public QDeclarative1OpenMetaObjectType
258 {
259 public:
260     VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarative1OpenMetaObjectType(base, engine) {}
261
262     void propertyCreated(int, QMetaPropertyBuilder &prop) {
263         prop.setWritable(false);
264     }
265 };
266
267 class QDeclarative1VisualDataModelParts;
268 class QDeclarative1VisualDataModelData;
269 class QDeclarative1VisualDataModelPrivate : public QObjectPrivate
270 {
271 public:
272     QDeclarative1VisualDataModelPrivate(QDeclarativeContext *);
273
274     static QDeclarative1VisualDataModelPrivate *get(QDeclarative1VisualDataModel *m) {
275         return static_cast<QDeclarative1VisualDataModelPrivate *>(QObjectPrivate::get(m));
276     }
277
278     QDeclarativeGuard<QListModelInterface> m_listModelInterface;
279     QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel;
280     QDeclarativeGuard<QDeclarative1VisualDataModel> m_visualItemModel;
281     QString m_part;
282
283     QDeclarativeComponent *m_delegate;
284     QDeclarativeGuard<QDeclarativeContext> m_context;
285     QList<int> m_roles;
286     QHash<QByteArray,int> m_roleNames;
287     void ensureRoles() {
288         if (m_roleNames.isEmpty()) {
289             if (m_listModelInterface) {
290                 m_roles = m_listModelInterface->roles();
291                 for (int ii = 0; ii < m_roles.count(); ++ii)
292                     m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii));
293             } else if (m_abstractItemModel) {
294                 QHash<int,QByteArray> roles = m_abstractItemModel->roleNames();
295                 for (QHash<int,QByteArray>::const_iterator it = roles.begin();
296                         it != roles.end(); ++it) {
297                     m_roles.append(it.key());
298                     m_roleNames.insert(*it, it.key());
299                 }
300                 if (m_roles.count())
301                     m_roleNames.insert("hasModelChildren", -1);
302             } else if (m_listAccessor) {
303                 m_roleNames.insert("modelData", 0);
304                 if (m_listAccessor->type() == QDeclarative1ListAccessor::Instance) {
305                     if (QObject *object = m_listAccessor->at(0).value<QObject*>()) {
306                         int count = object->metaObject()->propertyCount();
307                         for (int ii = 1; ii < count; ++ii) {
308                             const QMetaProperty &prop = object->metaObject()->property(ii);
309                             m_roleNames.insert(prop.name(), 0);
310                         }
311                     }
312                 }
313             }
314         }
315     }
316
317     QHash<int,int> m_roleToPropId;
318     int m_modelDataPropId;
319     void createMetaData() {
320         if (!m_metaDataCreated) {
321             ensureRoles();
322             if (m_roleNames.count()) {
323                 QHash<QByteArray, int>::const_iterator it = m_roleNames.begin();
324                 while (it != m_roleNames.end()) {
325                     int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset();
326                     m_roleToPropId.insert(*it, propId);
327                     ++it;
328                 }
329                 // Add modelData property
330                 if (m_roles.count() == 1)
331                     m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset();
332                 m_metaDataCreated = true;
333             }
334         }
335     }
336
337     struct ObjectRef {
338         ObjectRef(QObject *object=0) : obj(object), ref(1) {}
339         QObject *obj;
340         int ref;
341     };
342     class Cache : public QHash<int, ObjectRef> {
343     public:
344         QObject *getItem(int index) {
345             QObject *item = 0;
346             QHash<int,ObjectRef>::iterator it = find(index);
347             if (it != end()) {
348                 (*it).ref++;
349                 item = (*it).obj;
350             }
351             return item;
352         }
353         QObject *item(int index) {
354             QObject *item = 0;
355             QHash<int, ObjectRef>::const_iterator it = find(index);
356             if (it != end())
357                 item = (*it).obj;
358             return item;
359         }
360         void insertItem(int index, QObject *obj) {
361             insert(index, ObjectRef(obj));
362         }
363         bool releaseItem(QObject *obj) {
364             QHash<int, ObjectRef>::iterator it = begin();
365             for (; it != end(); ++it) {
366                 ObjectRef &objRef = *it;
367                 if (objRef.obj == obj) {
368                     if (--objRef.ref == 0) {
369                         erase(it);
370                         return true;
371                     }
372                     break;
373                 }
374             }
375             return false;
376         }
377     };
378
379     int modelCount() const {
380         if (m_visualItemModel)
381             return m_visualItemModel->count();
382         if (m_listModelInterface)
383             return m_listModelInterface->count();
384         if (m_abstractItemModel)
385             return m_abstractItemModel->rowCount(m_root);
386         if (m_listAccessor)
387             return m_listAccessor->count();
388         return 0;
389     }
390
391     Cache m_cache;
392     QHash<QObject *, QDeclarative1Package*> m_packaged;
393
394     QDeclarative1VisualDataModelParts *m_parts;
395     friend class QDeclarative1VisualItemParts;
396
397     VDMDelegateDataType *m_delegateDataType;
398     friend class QDeclarative1VisualDataModelData;
399     bool m_metaDataCreated : 1;
400     bool m_metaDataCacheable : 1;
401     bool m_delegateValidated : 1;
402     bool m_completePending : 1;
403
404     QDeclarative1VisualDataModelData *data(QObject *item);
405
406     QVariant m_modelVariant;
407     QDeclarative1ListAccessor *m_listAccessor;
408
409     QModelIndex m_root;
410     QList<QByteArray> watchedRoles;
411     QList<int> watchedRoleIds;
412 };
413
414 class QDeclarative1VisualDataModelDataMetaObject : public QDeclarative1OpenMetaObject
415 {
416 public:
417     QDeclarative1VisualDataModelDataMetaObject(QObject *parent, QDeclarative1OpenMetaObjectType *type)
418     : QDeclarative1OpenMetaObject(parent, type) {}
419
420     virtual QVariant initialValue(int);
421     virtual int createProperty(const char *, const char *);
422
423 private:
424     friend class QDeclarative1VisualDataModelData;
425 };
426
427 class QDeclarative1VisualDataModelData : public QObject
428 {
429 Q_OBJECT
430 public:
431     QDeclarative1VisualDataModelData(int index, QDeclarative1VisualDataModel *model);
432     ~QDeclarative1VisualDataModelData();
433
434     Q_PROPERTY(int index READ index NOTIFY indexChanged)
435     int index() const;
436     void setIndex(int index);
437
438     int propForRole(int) const;
439     int modelDataPropertyId() const {
440         QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(m_model);
441         return model->m_modelDataPropId;
442     }
443
444     void setValue(int, const QVariant &);
445     bool hasValue(int id) const {
446         return m_meta->hasValue(id);
447     }
448
449     void ensureProperties();
450
451 Q_SIGNALS:
452     void indexChanged();
453
454 private:
455     friend class QDeclarative1VisualDataModelDataMetaObject;
456     int m_index;
457     QDeclarativeGuard<QDeclarative1VisualDataModel> m_model;
458     QDeclarative1VisualDataModelDataMetaObject *m_meta;
459 };
460
461 int QDeclarative1VisualDataModelData::propForRole(int id) const
462 {
463     QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(m_model);
464     QHash<int,int>::const_iterator it = model->m_roleToPropId.find(id);
465     if (it != model->m_roleToPropId.end())
466         return *it;
467
468     return -1;
469 }
470
471 void QDeclarative1VisualDataModelData::setValue(int id, const QVariant &val)
472 {
473     m_meta->setValue(id, val);
474 }
475
476 int QDeclarative1VisualDataModelDataMetaObject::createProperty(const char *name, const char *type)
477 {
478     QDeclarative1VisualDataModelData *data =
479         static_cast<QDeclarative1VisualDataModelData *>(object());
480
481     if (!data->m_model)
482         return -1;
483
484     QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(data->m_model);
485     if (data->m_index < 0 || data->m_index >= model->modelCount())
486         return -1;
487
488     if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
489         if (model->m_listAccessor->type() == QDeclarative1ListAccessor::ListProperty) {
490             model->ensureRoles();
491             if (qstrcmp(name,"modelData") == 0)
492                 return QDeclarative1OpenMetaObject::createProperty(name, type);
493         }
494     }
495     return -1;
496 }
497
498 QVariant QDeclarative1VisualDataModelDataMetaObject::initialValue(int propId)
499 {
500     QDeclarative1VisualDataModelData *data =
501         static_cast<QDeclarative1VisualDataModelData *>(object());
502
503     Q_ASSERT(data->m_model);
504     QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(data->m_model);
505
506     QByteArray propName = name(propId);
507     if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
508         if (propName == "modelData") {
509             if (model->m_listAccessor->type() == QDeclarative1ListAccessor::Instance) {
510                 QObject *object = model->m_listAccessor->at(0).value<QObject*>();
511                 return object->metaObject()->property(1).read(object); // the first property after objectName
512             }
513             return model->m_listAccessor->at(data->m_index);
514         } else {
515             // return any property of a single object instance.
516             QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>();
517             return object->property(propName);
518         }
519     } else if (model->m_listModelInterface) {
520         model->ensureRoles();
521         QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
522         if (it != model->m_roleNames.end()) {
523             QVariant value = model->m_listModelInterface->data(data->m_index, *it);
524             return value;
525         } else if (model->m_roles.count() == 1 && propName == "modelData") {
526             //for compatibility with other lists, assign modelData if there is only a single role
527             QVariant value = model->m_listModelInterface->data(data->m_index, model->m_roles.first());
528             return value;
529         }
530     } else if (model->m_abstractItemModel) {
531         model->ensureRoles();
532         QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root);
533         if (propName == "hasModelChildren") {
534             return model->m_abstractItemModel->hasChildren(index);
535         } else {
536             QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
537             if (it != model->m_roleNames.end()) {
538                 return model->m_abstractItemModel->data(index, *it);
539             } else if (model->m_roles.count() == 1 && propName == "modelData") {
540                 //for compatibility with other lists, assign modelData if there is only a single role
541                 return model->m_abstractItemModel->data(index, model->m_roles.first());
542             }
543         }
544     }
545     Q_ASSERT(!"Can never be reached");
546     return QVariant();
547 }
548
549 QDeclarative1VisualDataModelData::QDeclarative1VisualDataModelData(int index,
550                                                QDeclarative1VisualDataModel *model)
551 : m_index(index), m_model(model),
552 m_meta(new QDeclarative1VisualDataModelDataMetaObject(this, QDeclarative1VisualDataModelPrivate::get(model)->m_delegateDataType))
553 {
554     ensureProperties();
555 }
556
557 QDeclarative1VisualDataModelData::~QDeclarative1VisualDataModelData()
558 {
559 }
560
561 void QDeclarative1VisualDataModelData::ensureProperties()
562 {
563     QDeclarative1VisualDataModelPrivate *modelPriv = QDeclarative1VisualDataModelPrivate::get(m_model);
564     if (modelPriv->m_metaDataCacheable) {
565         if (!modelPriv->m_metaDataCreated)
566             modelPriv->createMetaData();
567         if (modelPriv->m_metaDataCreated)
568             m_meta->setCached(true);
569     }
570 }
571
572 int QDeclarative1VisualDataModelData::index() const
573 {
574     return m_index;
575 }
576
577 // This is internal only - it should not be set from qml
578 void QDeclarative1VisualDataModelData::setIndex(int index)
579 {
580     m_index = index;
581     emit indexChanged();
582 }
583
584 //---------------------------------------------------------------------------
585
586 class QDeclarative1VisualDataModelPartsMetaObject : public QDeclarative1OpenMetaObject
587 {
588 public:
589     QDeclarative1VisualDataModelPartsMetaObject(QObject *parent)
590     : QDeclarative1OpenMetaObject(parent) {}
591
592     virtual void propertyCreated(int, QMetaPropertyBuilder &);
593     virtual QVariant initialValue(int);
594 };
595
596 class QDeclarative1VisualDataModelParts : public QObject
597 {
598 Q_OBJECT
599 public:
600     QDeclarative1VisualDataModelParts(QDeclarative1VisualDataModel *parent);
601
602 private:
603     friend class QDeclarative1VisualDataModelPartsMetaObject;
604     QDeclarative1VisualDataModel *model;
605 };
606
607 void QDeclarative1VisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
608 {
609     prop.setWritable(false);
610 }
611
612 QVariant QDeclarative1VisualDataModelPartsMetaObject::initialValue(int id)
613 {
614     QDeclarative1VisualDataModel *m = new QDeclarative1VisualDataModel;
615     m->setParent(object());
616     m->setPart(QString::fromUtf8(name(id)));
617     m->setModel(QVariant::fromValue(static_cast<QDeclarative1VisualDataModelParts *>(object())->model));
618
619     QVariant var = QVariant::fromValue((QObject *)m);
620     return var;
621 }
622
623 QDeclarative1VisualDataModelParts::QDeclarative1VisualDataModelParts(QDeclarative1VisualDataModel *parent)
624 : QObject(parent), model(parent)
625 {
626     new QDeclarative1VisualDataModelPartsMetaObject(this);
627 }
628
629 QDeclarative1VisualDataModelPrivate::QDeclarative1VisualDataModelPrivate(QDeclarativeContext *ctxt)
630 : m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0)
631 , m_context(ctxt), m_modelDataPropId(-1), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false)
632 , m_metaDataCacheable(false), m_delegateValidated(false), m_completePending(false), m_listAccessor(0)
633 {
634 }
635
636 QDeclarative1VisualDataModelData *QDeclarative1VisualDataModelPrivate::data(QObject *item)
637 {
638     QDeclarative1VisualDataModelData *dataItem =
639         item->findChild<QDeclarative1VisualDataModelData *>();
640     Q_ASSERT(dataItem);
641     return dataItem;
642 }
643
644 //---------------------------------------------------------------------------
645
646 /*!
647     \qmlclass VisualDataModel QDeclarative1VisualDataModel
648     \inqmlmodule QtQuick 1
649     \ingroup qml-working-with-data
650     \brief The VisualDataModel encapsulates a model and delegate
651
652     A VisualDataModel encapsulates a model and the delegate that will
653     be instantiated for items in the model.
654
655     It is usually not necessary to create VisualDataModel elements.
656     However, it can be useful for manipulating and accessing the \l modelIndex 
657     when a QAbstractItemModel subclass is used as the 
658     model. Also, VisualDataModel is used together with \l Package to 
659     provide delegates to multiple views.
660
661     The example below illustrates using a VisualDataModel with a ListView.
662
663     \snippet doc/src/snippets/qtquick1/visualdatamodel.qml 0
664 */
665
666 QDeclarative1VisualDataModel::QDeclarative1VisualDataModel()
667 : QDeclarative1VisualModel(*(new QDeclarative1VisualDataModelPrivate(0)))
668 {
669 }
670
671 QDeclarative1VisualDataModel::QDeclarative1VisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
672 : QDeclarative1VisualModel(*(new QDeclarative1VisualDataModelPrivate(ctxt)), parent)
673 {
674 }
675
676 QDeclarative1VisualDataModel::~QDeclarative1VisualDataModel()
677 {
678     Q_D(QDeclarative1VisualDataModel);
679     if (d->m_listAccessor)
680         delete d->m_listAccessor;
681     if (d->m_delegateDataType)
682         d->m_delegateDataType->release();
683 }
684
685 /*!
686     \qmlproperty model QtQuick1::VisualDataModel::model
687     This property holds the model providing data for the VisualDataModel.
688
689     The model provides a set of data that is used to create the items
690     for a view.  For large or dynamic datasets the model is usually
691     provided by a C++ model object.  The C++ model object must be a \l
692     {QAbstractItemModel} subclass or a simple list.
693
694     Models can also be created directly in QML, using a \l{ListModel} or
695     \l{XmlListModel}.
696
697     \sa {qmlmodels}{Data Models}
698 */
699 QVariant QDeclarative1VisualDataModel::model() const
700 {
701     Q_D(const QDeclarative1VisualDataModel);
702     return d->m_modelVariant;
703 }
704
705 void QDeclarative1VisualDataModel::setModel(const QVariant &model)
706 {
707     Q_D(QDeclarative1VisualDataModel);
708     delete d->m_listAccessor;
709     d->m_listAccessor = 0;
710     d->m_modelVariant = model;
711     if (d->m_listModelInterface) {
712         // Assume caller has released all items.
713         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
714                 this, SLOT(_q_itemsChanged(int,int,QList<int>)));
715         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
716                 this, SLOT(_q_itemsInserted(int,int)));
717         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
718                 this, SLOT(_q_itemsRemoved(int,int)));
719         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
720                 this, SLOT(_q_itemsMoved(int,int,int)));
721         d->m_listModelInterface = 0;
722     } else if (d->m_abstractItemModel) {
723         QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
724                             this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
725         QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
726                             this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
727         QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
728                             this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
729         QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
730                             this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
731         QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
732         QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
733         d->m_abstractItemModel = 0;
734     } else if (d->m_visualItemModel) {
735         QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
736                          this, SIGNAL(itemsInserted(int,int)));
737         QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
738                          this, SIGNAL(itemsRemoved(int,int)));
739         QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
740                          this, SIGNAL(itemsMoved(int,int,int)));
741         QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarative1Package*)),
742                          this, SLOT(_q_createdPackage(int,QDeclarative1Package*)));
743         QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarative1Package*)),
744                          this, SLOT(_q_destroyingPackage(QDeclarative1Package*)));
745         d->m_visualItemModel = 0;
746     }
747
748     d->m_roles.clear();
749     d->m_roleNames.clear();
750     if (d->m_delegateDataType)
751         d->m_delegateDataType->release();
752     d->m_metaDataCreated = 0;
753     d->m_metaDataCacheable = false;
754     d->m_delegateDataType = new VDMDelegateDataType(&QDeclarative1VisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this));
755
756     QObject *object = qvariant_cast<QObject *>(model);
757     if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
758         QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
759                          this, SLOT(_q_itemsChanged(int,int,QList<int>)));
760         QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
761                          this, SLOT(_q_itemsInserted(int,int)));
762         QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
763                          this, SLOT(_q_itemsRemoved(int,int)));
764         QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
765                          this, SLOT(_q_itemsMoved(int,int,int)));
766         d->m_metaDataCacheable = true;
767         if (d->m_delegate && d->m_listModelInterface->count())
768             emit itemsInserted(0, d->m_listModelInterface->count());
769         return;
770     } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
771         QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
772                             this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
773         QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
774                             this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
775         QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
776                             this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
777         QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
778                             this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
779         QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
780         QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
781         d->m_metaDataCacheable = true;
782         if (d->m_abstractItemModel->canFetchMore(d->m_root))
783             d->m_abstractItemModel->fetchMore(d->m_root);
784         return;
785     }
786     if ((d->m_visualItemModel = qvariant_cast<QDeclarative1VisualDataModel *>(model))) {
787         QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
788                          this, SIGNAL(itemsInserted(int,int)));
789         QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
790                          this, SIGNAL(itemsRemoved(int,int)));
791         QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
792                          this, SIGNAL(itemsMoved(int,int,int)));
793         QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarative1Package*)),
794                          this, SLOT(_q_createdPackage(int,QDeclarative1Package*)));
795         QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarative1Package*)),
796                          this, SLOT(_q_destroyingPackage(QDeclarative1Package*)));
797         return;
798     }
799     d->m_listAccessor = new QDeclarative1ListAccessor;
800     d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this));
801     if (d->m_listAccessor->type() != QDeclarative1ListAccessor::ListProperty)
802         d->m_metaDataCacheable = true;
803     if (d->m_delegate && d->modelCount()) {
804         emit itemsInserted(0, d->modelCount());
805         emit countChanged();
806     }
807 }
808
809 /*!
810     \qmlproperty Component QtQuick1::VisualDataModel::delegate
811
812     The delegate provides a template defining each item instantiated by a view.
813     The index is exposed as an accessible \c index property.  Properties of the
814     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
815 */
816 QDeclarativeComponent *QDeclarative1VisualDataModel::delegate() const
817 {
818     Q_D(const QDeclarative1VisualDataModel);
819     if (d->m_visualItemModel)
820         return d->m_visualItemModel->delegate();
821     return d->m_delegate;
822 }
823
824 void QDeclarative1VisualDataModel::setDelegate(QDeclarativeComponent *delegate)
825 {
826     Q_D(QDeclarative1VisualDataModel);
827     bool wasValid = d->m_delegate != 0;
828     d->m_delegate = delegate;
829     d->m_delegateValidated = false;
830     if (!wasValid && d->modelCount() && d->m_delegate) {
831         emit itemsInserted(0, d->modelCount());
832         emit countChanged();
833     }
834     if (wasValid && !d->m_delegate && d->modelCount()) {
835         emit itemsRemoved(0, d->modelCount());
836         emit countChanged();
837     }
838 }
839
840 /*!
841     \qmlproperty QModelIndex QtQuick1::VisualDataModel::rootIndex
842
843     QAbstractItemModel provides a hierarchical tree of data, whereas
844     QML only operates on list data.  \c rootIndex allows the children of
845     any node in a QAbstractItemModel to be provided by this model.
846
847     This property only affects models of type QAbstractItemModel that
848     are hierarchical (e.g, a tree model). 
849
850     For example, here is a simple interactive file system browser.
851     When a directory name is clicked, the view's \c rootIndex is set to the
852     QModelIndex node of the clicked directory, thus updating the view to show
853     the new directory's contents.
854
855     \c main.cpp:
856     \snippet doc/src/snippets/qtquick1/visualdatamodel_rootindex/main.cpp 0
857    
858     \c view.qml:
859     \snippet doc/src/snippets/qtquick1/visualdatamodel_rootindex/view.qml 0
860
861     If the \l model is a QAbstractItemModel subclass, the delegate can also
862     reference a \c hasModelChildren property (optionally qualified by a
863     \e model. prefix) that indicates whether the delegate's model item has 
864     any child nodes.
865
866
867     \sa modelIndex(), parentModelIndex()
868 */
869 QVariant QDeclarative1VisualDataModel::rootIndex() const
870 {
871     Q_D(const QDeclarative1VisualDataModel);
872     return QVariant::fromValue(d->m_root);
873 }
874
875 void QDeclarative1VisualDataModel::setRootIndex(const QVariant &root)
876 {
877     Q_D(QDeclarative1VisualDataModel);
878     QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
879     if (d->m_root != modelIndex) {
880         int oldCount = d->modelCount();
881         d->m_root = modelIndex;
882         if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex))
883             d->m_abstractItemModel->fetchMore(modelIndex);
884         int newCount = d->modelCount();
885         if (d->m_delegate && oldCount)
886             emit itemsRemoved(0, oldCount);
887         if (d->m_delegate && newCount)
888             emit itemsInserted(0, newCount);
889         if (newCount != oldCount)
890             emit countChanged();
891         emit rootIndexChanged();
892     }
893 }
894
895
896 /*!
897     \qmlmethod QModelIndex QtQuick1::VisualDataModel::modelIndex(int index)
898
899     QAbstractItemModel provides a hierarchical tree of data, whereas
900     QML only operates on list data.  This function assists in using
901     tree models in QML.
902
903     Returns a QModelIndex for the specified index.
904     This value can be assigned to rootIndex.
905
906     \sa rootIndex
907 */
908 QVariant QDeclarative1VisualDataModel::modelIndex(int idx) const
909 {
910     Q_D(const QDeclarative1VisualDataModel);
911     if (d->m_abstractItemModel)
912         return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root));
913     return QVariant::fromValue(QModelIndex());
914 }
915
916 /*!
917     \qmlmethod QModelIndex QtQuick1::VisualDataModel::parentModelIndex()
918
919     QAbstractItemModel provides a hierarchical tree of data, whereas
920     QML only operates on list data.  This function assists in using
921     tree models in QML.
922
923     Returns a QModelIndex for the parent of the current rootIndex.
924     This value can be assigned to rootIndex.
925
926     \sa rootIndex
927 */
928 QVariant QDeclarative1VisualDataModel::parentModelIndex() const
929 {
930     Q_D(const QDeclarative1VisualDataModel);
931     if (d->m_abstractItemModel)
932         return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root));
933     return QVariant::fromValue(QModelIndex());
934 }
935
936 QString QDeclarative1VisualDataModel::part() const
937 {
938     Q_D(const QDeclarative1VisualDataModel);
939     return d->m_part;
940 }
941
942 void QDeclarative1VisualDataModel::setPart(const QString &part)
943 {
944     Q_D(QDeclarative1VisualDataModel);
945     d->m_part = part;
946 }
947
948 int QDeclarative1VisualDataModel::count() const
949 {
950     Q_D(const QDeclarative1VisualDataModel);
951     if (d->m_visualItemModel)
952         return d->m_visualItemModel->count();
953     if (!d->m_delegate)
954         return 0;
955     return d->modelCount();
956 }
957
958 QDeclarativeItem *QDeclarative1VisualDataModel::item(int index, bool complete)
959 {
960     Q_D(QDeclarative1VisualDataModel);
961     if (d->m_visualItemModel)
962         return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete);
963     return item(index, QByteArray(), complete);
964 }
965
966 /*
967   Returns ReleaseStatus flags.
968 */
969 QDeclarative1VisualDataModel::ReleaseFlags QDeclarative1VisualDataModel::release(QDeclarativeItem *item)
970 {
971     Q_D(QDeclarative1VisualDataModel);
972     if (d->m_visualItemModel)
973         return d->m_visualItemModel->release(item);
974
975     ReleaseFlags stat = 0;
976     QObject *obj = item;
977     bool inPackage = false;
978
979     QHash<QObject*,QDeclarative1Package*>::iterator it = d->m_packaged.find(item);
980     if (it != d->m_packaged.end()) {
981         QDeclarative1Package *package = *it;
982         d->m_packaged.erase(it);
983         if (d->m_packaged.contains(item))
984             stat |= Referenced;
985         inPackage = true;
986         obj = package; // fall through and delete
987     }
988
989     if (d->m_cache.releaseItem(obj)) {
990         // Remove any bindings to avoid warnings due to parent change.
991         QObjectPrivate *p = QObjectPrivate::get(obj);
992         Q_ASSERT(p->declarativeData);
993         QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData);
994         if (d->ownContext && d->context)
995             d->context->clearContext();
996
997         if (inPackage) {
998             emit destroyingPackage(qobject_cast<QDeclarative1Package*>(obj));
999         } else {
1000             if (item->scene())
1001                 item->scene()->removeItem(item);
1002         }
1003         stat |= Destroyed;
1004         obj->deleteLater();
1005     } else if (!inPackage) {
1006         stat |= Referenced;
1007     }
1008
1009     return stat;
1010 }
1011
1012 /*!
1013     \qmlproperty object QtQuick1::VisualDataModel::parts
1014
1015     The \a parts property selects a VisualDataModel which creates
1016     delegates from the part named.  This is used in conjunction with
1017     the \l Package element.
1018
1019     For example, the code below selects a model which creates
1020     delegates named \e list from a \l Package:
1021
1022     \code
1023     VisualDataModel {
1024         id: visualModel
1025         delegate: Package {
1026             Item { Package.name: "list" }
1027         }
1028         model: myModel
1029     }
1030
1031     ListView {
1032         width: 200; height:200
1033         model: visualModel.parts.list
1034     }
1035     \endcode
1036
1037     \sa Package
1038 */
1039 QObject *QDeclarative1VisualDataModel::parts()
1040 {
1041     Q_D(QDeclarative1VisualDataModel);
1042     if (!d->m_parts)
1043         d->m_parts = new QDeclarative1VisualDataModelParts(this);
1044     return d->m_parts;
1045 }
1046
1047 QDeclarativeItem *QDeclarative1VisualDataModel::item(int index, const QByteArray &viewId, bool complete)
1048 {
1049     Q_D(QDeclarative1VisualDataModel);
1050     if (d->m_visualItemModel)
1051         return d->m_visualItemModel->item(index, viewId, complete);
1052
1053     if (d->modelCount() <= 0 || !d->m_delegate)
1054         return 0;
1055     QObject *nobj = d->m_cache.getItem(index);
1056     bool needComplete = false;
1057     if (!nobj) {
1058         QDeclarativeContext *ccontext = d->m_context;
1059         if (!ccontext) ccontext = qmlContext(this);
1060         QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext);
1061         QDeclarative1VisualDataModelData *data = new QDeclarative1VisualDataModelData(index, this);
1062         if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor
1063             && d->m_listAccessor->type() == QDeclarative1ListAccessor::ListProperty) {
1064             ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject*>());
1065             ctxt = new QDeclarativeContext(ctxt, ctxt);
1066         }
1067         ctxt->setContextProperty(QLatin1String("model"), data);
1068         ctxt->setContextObject(data);
1069         d->m_completePending = false;
1070         nobj = d->m_delegate->beginCreate(ctxt);
1071         if (complete) {
1072             d->m_delegate->completeCreate();
1073         } else {
1074             d->m_completePending = true;
1075             needComplete = true;
1076         }
1077         if (nobj) {
1078             QDeclarative_setParent_noEvent(ctxt, nobj);
1079             QDeclarative_setParent_noEvent(data, nobj);
1080             d->m_cache.insertItem(index, nobj);
1081             if (QDeclarative1Package *package = qobject_cast<QDeclarative1Package *>(nobj))
1082                 emit createdPackage(index, package);
1083         } else {
1084             delete data;
1085             delete ctxt;
1086             qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate";
1087         }
1088     }
1089     QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(nobj);
1090     if (!item) {
1091         QDeclarative1Package *package = qobject_cast<QDeclarative1Package *>(nobj);
1092         if (package) {
1093             QObject *o = package->part(QString::fromUtf8(viewId));
1094             item = qobject_cast<QDeclarativeItem *>(o);
1095             if (item)
1096                 d->m_packaged.insertMulti(item, package);
1097         }
1098     }
1099     if (!item) {
1100         if (needComplete)
1101             d->m_delegate->completeCreate();
1102         d->m_cache.releaseItem(nobj);
1103         if (!d->m_delegateValidated) {
1104             qmlInfo(d->m_delegate) << QDeclarative1VisualDataModel::tr("Delegate component must be Item type.");
1105             d->m_delegateValidated = true;
1106         }
1107     }
1108     if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
1109         d->m_abstractItemModel->fetchMore(d->m_root);
1110
1111     return item;
1112 }
1113
1114 bool QDeclarative1VisualDataModel::completePending() const
1115 {
1116     Q_D(const QDeclarative1VisualDataModel);
1117     if (d->m_visualItemModel)
1118         return d->m_visualItemModel->completePending();
1119     return d->m_completePending;
1120 }
1121
1122 void QDeclarative1VisualDataModel::completeItem()
1123 {
1124     Q_D(QDeclarative1VisualDataModel);
1125     if (d->m_visualItemModel) {
1126         d->m_visualItemModel->completeItem();
1127         return;
1128     }
1129
1130     d->m_delegate->completeCreate();
1131     d->m_completePending = false;
1132 }
1133
1134 QString QDeclarative1VisualDataModel::stringValue(int index, const QString &name)
1135 {
1136     Q_D(QDeclarative1VisualDataModel);
1137     if (d->m_visualItemModel)
1138         return d->m_visualItemModel->stringValue(index, name);
1139
1140     if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) {
1141         if (QObject *object = d->m_listAccessor->at(index).value<QObject*>())
1142             return object->property(name.toUtf8()).toString();
1143     }
1144
1145     if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
1146         return QString();
1147
1148     QString val;
1149     QObject *data = 0;
1150     bool tempData = false;
1151
1152     if (QObject *nobj = d->m_cache.item(index))
1153         data = d->data(nobj);
1154     if (!data) {
1155         data = new QDeclarative1VisualDataModelData(index, this);
1156         tempData = true;
1157     }
1158
1159     QDeclarativeData *ddata = QDeclarativeData::get(data);
1160     if (ddata && ddata->propertyCache) {
1161         QDeclarativePropertyData *prop = ddata->propertyCache->property(name);
1162         if (prop) {
1163             if (prop->propType == QVariant::String) {
1164                 void *args[] = { &val, 0 };
1165                 QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
1166             } else if (prop->propType == qMetaTypeId<QVariant>()) {
1167                 QVariant v;
1168                 void *args[] = { &v, 0 };
1169                 QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
1170                 val = v.toString();
1171             }
1172         } else {
1173             val = data->property(name.toUtf8()).toString();
1174         }
1175     } else {
1176         val = data->property(name.toUtf8()).toString();
1177     }
1178
1179     if (tempData)
1180         delete data;
1181
1182     return val;
1183 }
1184
1185 int QDeclarative1VisualDataModel::indexOf(QDeclarativeItem *item, QObject *) const
1186 {
1187     QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index"));
1188         return val.toInt();
1189     return -1;
1190 }
1191
1192 void QDeclarative1VisualDataModel::setWatchedRoles(QList<QByteArray> roles)
1193 {
1194     Q_D(QDeclarative1VisualDataModel);
1195     d->watchedRoles = roles;
1196     d->watchedRoleIds.clear();
1197 }
1198
1199 void QDeclarative1VisualDataModel::_q_itemsChanged(int index, int count,
1200                                          const QList<int> &roles)
1201 {
1202     Q_D(QDeclarative1VisualDataModel);
1203     bool changed = false;
1204     if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) {
1205         foreach (QByteArray r, d->watchedRoles) {
1206             if (d->m_roleNames.contains(r))
1207                 d->watchedRoleIds << d->m_roleNames.value(r);
1208         }
1209     }
1210
1211     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin();
1212         iter != d->m_cache.end(); ++iter) {
1213         const int idx = iter.key();
1214
1215         if (idx >= index && idx < index+count) {
1216             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1217             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1218             for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) {
1219                 int role = roles.at(roleIdx);
1220                 if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role))
1221                     changed = true;
1222                 int propId = data->propForRole(role);
1223                 if (propId != -1) {
1224                     if (data->hasValue(propId)) {
1225                         if (d->m_listModelInterface) {
1226                             data->setValue(propId, d->m_listModelInterface->data(idx, role));
1227                         } else if (d->m_abstractItemModel) {
1228                             QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
1229                             data->setValue(propId, d->m_abstractItemModel->data(index, role));
1230                         }
1231                     }
1232                 } else {
1233                     QString roleName;
1234                     if (d->m_listModelInterface)
1235                         roleName = d->m_listModelInterface->toString(role);
1236                     else if (d->m_abstractItemModel)
1237                         roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role));
1238                     qmlInfo(this) << "Changing role not present in item: " << roleName;
1239                 }
1240             }
1241             if (d->m_roles.count() == 1) {
1242                 // Handle the modelData role we add if there is just one role.
1243                 int propId = data->modelDataPropertyId();
1244                 if (data->hasValue(propId)) {
1245                     int role = d->m_roles.at(0);
1246                     if (d->m_listModelInterface) {
1247                         data->setValue(propId, d->m_listModelInterface->data(idx, role));
1248                     } else if (d->m_abstractItemModel) {
1249                         QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
1250                         data->setValue(propId, d->m_abstractItemModel->data(index, role));
1251                     }
1252                 }
1253             }
1254         }
1255     }
1256     if (changed)
1257         emit itemsChanged(index, count);
1258 }
1259
1260 void QDeclarative1VisualDataModel::_q_itemsInserted(int index, int count)
1261 {
1262     Q_D(QDeclarative1VisualDataModel);
1263     if (!count)
1264         return;
1265     // XXX - highly inefficient
1266     QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef> items;
1267     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1268         iter != d->m_cache.end(); ) {
1269
1270         if (iter.key() >= index) {
1271             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1272             int index = iter.key() + count;
1273             iter = d->m_cache.erase(iter);
1274
1275             items.insert(index, objRef);
1276
1277             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1278             data->setIndex(index);
1279         } else {
1280             ++iter;
1281         }
1282     }
1283     d->m_cache.unite(items);
1284
1285     emit itemsInserted(index, count);
1286     emit countChanged();
1287 }
1288
1289 void QDeclarative1VisualDataModel::_q_itemsRemoved(int index, int count)
1290 {
1291     Q_D(QDeclarative1VisualDataModel);
1292     if (!count)
1293         return;
1294     // XXX - highly inefficient
1295     QHash<int, QDeclarative1VisualDataModelPrivate::ObjectRef> items;
1296     for (QHash<int, QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1297         iter != d->m_cache.end(); ) {
1298         if (iter.key() >= index && iter.key() < index + count) {
1299             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1300             iter = d->m_cache.erase(iter);
1301             items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
1302             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1303             data->setIndex(-1);
1304         } else if (iter.key() >= index + count) {
1305             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1306             int index = iter.key() - count;
1307             iter = d->m_cache.erase(iter);
1308             items.insert(index, objRef);
1309             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1310             data->setIndex(index);
1311         } else {
1312             ++iter;
1313         }
1314     }
1315
1316     d->m_cache.unite(items);
1317     emit itemsRemoved(index, count);
1318     emit countChanged();
1319 }
1320
1321 void QDeclarative1VisualDataModel::_q_itemsMoved(int from, int to, int count)
1322 {
1323     Q_D(QDeclarative1VisualDataModel);
1324     // XXX - highly inefficient
1325     QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef> items;
1326     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1327         iter != d->m_cache.end(); ) {
1328
1329         if (iter.key() >= from && iter.key() < from + count) {
1330             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1331             int index = iter.key() - from + to;
1332             iter = d->m_cache.erase(iter);
1333
1334             items.insert(index, objRef);
1335
1336             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1337             data->setIndex(index);
1338         } else {
1339             ++iter;
1340         }
1341     }
1342     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1343         iter != d->m_cache.end(); ) {
1344
1345         int diff = from > to ? count : -count;
1346         if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) {
1347             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1348             int index = iter.key() + diff;
1349             iter = d->m_cache.erase(iter);
1350
1351             items.insert(index, objRef);
1352
1353             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1354             data->setIndex(index);
1355         } else {
1356             ++iter;
1357         }
1358     }
1359     d->m_cache.unite(items);
1360
1361     emit itemsMoved(from, to, count);
1362 }
1363
1364 void QDeclarative1VisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1365 {
1366     Q_D(QDeclarative1VisualDataModel);
1367     if (parent == d->m_root)
1368         _q_itemsInserted(begin, end - begin + 1);
1369 }
1370
1371 void QDeclarative1VisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1372 {
1373     Q_D(QDeclarative1VisualDataModel);
1374     if (parent == d->m_root)
1375         _q_itemsRemoved(begin, end - begin + 1);
1376 }
1377
1378 void QDeclarative1VisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
1379 {
1380     Q_D(QDeclarative1VisualDataModel);
1381     const int count = sourceEnd - sourceStart + 1;
1382     if (destinationParent == d->m_root && sourceParent == d->m_root) {
1383         _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-count, count);
1384     } else if (sourceParent == d->m_root) {
1385         _q_itemsRemoved(sourceStart, count);
1386     } else if (destinationParent == d->m_root) {
1387         _q_itemsInserted(destinationRow, count);
1388     }
1389 }
1390
1391 void QDeclarative1VisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1392 {
1393     Q_D(QDeclarative1VisualDataModel);
1394     if (begin.parent() == d->m_root)
1395         _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
1396 }
1397
1398 void QDeclarative1VisualDataModel::_q_layoutChanged()
1399 {
1400     Q_D(QDeclarative1VisualDataModel);
1401     _q_itemsChanged(0, count(), d->m_roles);
1402 }
1403
1404 void QDeclarative1VisualDataModel::_q_modelReset()
1405 {
1406     Q_D(QDeclarative1VisualDataModel);
1407     d->m_root = QModelIndex();
1408     emit modelReset();
1409     emit rootIndexChanged();
1410     if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
1411         d->m_abstractItemModel->fetchMore(d->m_root);
1412 }
1413
1414 void QDeclarative1VisualDataModel::_q_createdPackage(int index, QDeclarative1Package *package)
1415 {
1416     Q_D(QDeclarative1VisualDataModel);
1417     emit createdItem(index, qobject_cast<QDeclarativeItem*>(package->part(d->m_part)));
1418 }
1419
1420 void QDeclarative1VisualDataModel::_q_destroyingPackage(QDeclarative1Package *package)
1421 {
1422     Q_D(QDeclarative1VisualDataModel);
1423     emit destroyingItem(qobject_cast<QDeclarativeItem*>(package->part(d->m_part)));
1424 }
1425
1426
1427
1428 QT_END_NAMESPACE
1429
1430 QML_DECLARE_TYPE(QListModelInterface)
1431
1432 #include <qdeclarativevisualitemmodel.moc>