Merge branch 'master' into refactor
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativevisualitemmodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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 <QtDeclarative/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                 for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin();
295                         it != m_abstractItemModel->roleNames().end(); ++it) {
296                     m_roles.append(it.key());
297                     m_roleNames.insert(*it, it.key());
298                 }
299                 if (m_roles.count())
300                     m_roleNames.insert("hasModelChildren", -1);
301             } else if (m_listAccessor) {
302                 m_roleNames.insert("modelData", 0);
303                 if (m_listAccessor->type() == QDeclarative1ListAccessor::Instance) {
304                     if (QObject *object = m_listAccessor->at(0).value<QObject*>()) {
305                         int count = object->metaObject()->propertyCount();
306                         for (int ii = 1; ii < count; ++ii) {
307                             const QMetaProperty &prop = object->metaObject()->property(ii);
308                             m_roleNames.insert(prop.name(), 0);
309                         }
310                     }
311                 }
312             }
313         }
314     }
315
316     QHash<int,int> m_roleToPropId;
317     int m_modelDataPropId;
318     void createMetaData() {
319         if (!m_metaDataCreated) {
320             ensureRoles();
321             if (m_roleNames.count()) {
322                 QHash<QByteArray, int>::const_iterator it = m_roleNames.begin();
323                 while (it != m_roleNames.end()) {
324                     int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset();
325                     m_roleToPropId.insert(*it, propId);
326                     ++it;
327                 }
328                 // Add modelData property
329                 if (m_roles.count() == 1)
330                     m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset();
331                 m_metaDataCreated = true;
332             }
333         }
334     }
335
336     struct ObjectRef {
337         ObjectRef(QObject *object=0) : obj(object), ref(1) {}
338         QObject *obj;
339         int ref;
340     };
341     class Cache : public QHash<int, ObjectRef> {
342     public:
343         QObject *getItem(int index) {
344             QObject *item = 0;
345             QHash<int,ObjectRef>::iterator it = find(index);
346             if (it != end()) {
347                 (*it).ref++;
348                 item = (*it).obj;
349             }
350             return item;
351         }
352         QObject *item(int index) {
353             QObject *item = 0;
354             QHash<int, ObjectRef>::const_iterator it = find(index);
355             if (it != end())
356                 item = (*it).obj;
357             return item;
358         }
359         void insertItem(int index, QObject *obj) {
360             insert(index, ObjectRef(obj));
361         }
362         bool releaseItem(QObject *obj) {
363             QHash<int, ObjectRef>::iterator it = begin();
364             for (; it != end(); ++it) {
365                 ObjectRef &objRef = *it;
366                 if (objRef.obj == obj) {
367                     if (--objRef.ref == 0) {
368                         erase(it);
369                         return true;
370                     }
371                     break;
372                 }
373             }
374             return false;
375         }
376     };
377
378     int modelCount() const {
379         if (m_visualItemModel)
380             return m_visualItemModel->count();
381         if (m_listModelInterface)
382             return m_listModelInterface->count();
383         if (m_abstractItemModel)
384             return m_abstractItemModel->rowCount(m_root);
385         if (m_listAccessor)
386             return m_listAccessor->count();
387         return 0;
388     }
389
390     Cache m_cache;
391     QHash<QObject *, QDeclarative1Package*> m_packaged;
392
393     QDeclarative1VisualDataModelParts *m_parts;
394     friend class QDeclarative1VisualItemParts;
395
396     VDMDelegateDataType *m_delegateDataType;
397     friend class QDeclarative1VisualDataModelData;
398     bool m_metaDataCreated : 1;
399     bool m_metaDataCacheable : 1;
400     bool m_delegateValidated : 1;
401     bool m_completePending : 1;
402
403     QDeclarative1VisualDataModelData *data(QObject *item);
404
405     QVariant m_modelVariant;
406     QDeclarative1ListAccessor *m_listAccessor;
407
408     QModelIndex m_root;
409     QList<QByteArray> watchedRoles;
410     QList<int> watchedRoleIds;
411 };
412
413 class QDeclarative1VisualDataModelDataMetaObject : public QDeclarative1OpenMetaObject
414 {
415 public:
416     QDeclarative1VisualDataModelDataMetaObject(QObject *parent, QDeclarative1OpenMetaObjectType *type)
417     : QDeclarative1OpenMetaObject(parent, type) {}
418
419     virtual QVariant initialValue(int);
420     virtual int createProperty(const char *, const char *);
421
422 private:
423     friend class QDeclarative1VisualDataModelData;
424 };
425
426 class QDeclarative1VisualDataModelData : public QObject
427 {
428 Q_OBJECT
429 public:
430     QDeclarative1VisualDataModelData(int index, QDeclarative1VisualDataModel *model);
431     ~QDeclarative1VisualDataModelData();
432
433     Q_PROPERTY(int index READ index NOTIFY indexChanged)
434     int index() const;
435     void setIndex(int index);
436
437     int propForRole(int) const;
438     int modelDataPropertyId() const {
439         QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(m_model);
440         return model->m_modelDataPropId;
441     }
442
443     void setValue(int, const QVariant &);
444     bool hasValue(int id) const {
445         return m_meta->hasValue(id);
446     }
447
448     void ensureProperties();
449
450 Q_SIGNALS:
451     void indexChanged();
452
453 private:
454     friend class QDeclarative1VisualDataModelDataMetaObject;
455     int m_index;
456     QDeclarativeGuard<QDeclarative1VisualDataModel> m_model;
457     QDeclarative1VisualDataModelDataMetaObject *m_meta;
458 };
459
460 int QDeclarative1VisualDataModelData::propForRole(int id) const
461 {
462     QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(m_model);
463     QHash<int,int>::const_iterator it = model->m_roleToPropId.find(id);
464     if (it != model->m_roleToPropId.end())
465         return *it;
466
467     return -1;
468 }
469
470 void QDeclarative1VisualDataModelData::setValue(int id, const QVariant &val)
471 {
472     m_meta->setValue(id, val);
473 }
474
475 int QDeclarative1VisualDataModelDataMetaObject::createProperty(const char *name, const char *type)
476 {
477     QDeclarative1VisualDataModelData *data =
478         static_cast<QDeclarative1VisualDataModelData *>(object());
479
480     if (!data->m_model)
481         return -1;
482
483     QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(data->m_model);
484     if (data->m_index < 0 || data->m_index >= model->modelCount())
485         return -1;
486
487     if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
488         if (model->m_listAccessor->type() == QDeclarative1ListAccessor::ListProperty) {
489             model->ensureRoles();
490             if (qstrcmp(name,"modelData") == 0)
491                 return QDeclarative1OpenMetaObject::createProperty(name, type);
492         }
493     }
494     return -1;
495 }
496
497 QVariant QDeclarative1VisualDataModelDataMetaObject::initialValue(int propId)
498 {
499     QDeclarative1VisualDataModelData *data =
500         static_cast<QDeclarative1VisualDataModelData *>(object());
501
502     Q_ASSERT(data->m_model);
503     QDeclarative1VisualDataModelPrivate *model = QDeclarative1VisualDataModelPrivate::get(data->m_model);
504
505     QByteArray propName = name(propId);
506     if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
507         if (propName == "modelData") {
508             if (model->m_listAccessor->type() == QDeclarative1ListAccessor::Instance) {
509                 QObject *object = model->m_listAccessor->at(0).value<QObject*>();
510                 return object->metaObject()->property(1).read(object); // the first property after objectName
511             }
512             return model->m_listAccessor->at(data->m_index);
513         } else {
514             // return any property of a single object instance.
515             QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>();
516             return object->property(propName);
517         }
518     } else if (model->m_listModelInterface) {
519         model->ensureRoles();
520         QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
521         if (it != model->m_roleNames.end()) {
522             QVariant value = model->m_listModelInterface->data(data->m_index, *it);
523             return value;
524         } else if (model->m_roles.count() == 1 && propName == "modelData") {
525             //for compatibility with other lists, assign modelData if there is only a single role
526             QVariant value = model->m_listModelInterface->data(data->m_index, model->m_roles.first());
527             return value;
528         }
529     } else if (model->m_abstractItemModel) {
530         model->ensureRoles();
531         QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root);
532         if (propName == "hasModelChildren") {
533             return model->m_abstractItemModel->hasChildren(index);
534         } else {
535             QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
536             if (it != model->m_roleNames.end()) {
537                 return model->m_abstractItemModel->data(index, *it);
538             } else if (model->m_roles.count() == 1 && propName == "modelData") {
539                 //for compatibility with other lists, assign modelData if there is only a single role
540                 return model->m_abstractItemModel->data(index, model->m_roles.first());
541             }
542         }
543     }
544     Q_ASSERT(!"Can never be reached");
545     return QVariant();
546 }
547
548 QDeclarative1VisualDataModelData::QDeclarative1VisualDataModelData(int index,
549                                                QDeclarative1VisualDataModel *model)
550 : m_index(index), m_model(model),
551 m_meta(new QDeclarative1VisualDataModelDataMetaObject(this, QDeclarative1VisualDataModelPrivate::get(model)->m_delegateDataType))
552 {
553     ensureProperties();
554 }
555
556 QDeclarative1VisualDataModelData::~QDeclarative1VisualDataModelData()
557 {
558 }
559
560 void QDeclarative1VisualDataModelData::ensureProperties()
561 {
562     QDeclarative1VisualDataModelPrivate *modelPriv = QDeclarative1VisualDataModelPrivate::get(m_model);
563     if (modelPriv->m_metaDataCacheable) {
564         if (!modelPriv->m_metaDataCreated)
565             modelPriv->createMetaData();
566         if (modelPriv->m_metaDataCreated)
567             m_meta->setCached(true);
568     }
569 }
570
571 int QDeclarative1VisualDataModelData::index() const
572 {
573     return m_index;
574 }
575
576 // This is internal only - it should not be set from qml
577 void QDeclarative1VisualDataModelData::setIndex(int index)
578 {
579     m_index = index;
580     emit indexChanged();
581 }
582
583 //---------------------------------------------------------------------------
584
585 class QDeclarative1VisualDataModelPartsMetaObject : public QDeclarative1OpenMetaObject
586 {
587 public:
588     QDeclarative1VisualDataModelPartsMetaObject(QObject *parent)
589     : QDeclarative1OpenMetaObject(parent) {}
590
591     virtual void propertyCreated(int, QMetaPropertyBuilder &);
592     virtual QVariant initialValue(int);
593 };
594
595 class QDeclarative1VisualDataModelParts : public QObject
596 {
597 Q_OBJECT
598 public:
599     QDeclarative1VisualDataModelParts(QDeclarative1VisualDataModel *parent);
600
601 private:
602     friend class QDeclarative1VisualDataModelPartsMetaObject;
603     QDeclarative1VisualDataModel *model;
604 };
605
606 void QDeclarative1VisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
607 {
608     prop.setWritable(false);
609 }
610
611 QVariant QDeclarative1VisualDataModelPartsMetaObject::initialValue(int id)
612 {
613     QDeclarative1VisualDataModel *m = new QDeclarative1VisualDataModel;
614     m->setParent(object());
615     m->setPart(QString::fromUtf8(name(id)));
616     m->setModel(QVariant::fromValue(static_cast<QDeclarative1VisualDataModelParts *>(object())->model));
617
618     QVariant var = QVariant::fromValue((QObject *)m);
619     return var;
620 }
621
622 QDeclarative1VisualDataModelParts::QDeclarative1VisualDataModelParts(QDeclarative1VisualDataModel *parent)
623 : QObject(parent), model(parent)
624 {
625     new QDeclarative1VisualDataModelPartsMetaObject(this);
626 }
627
628 QDeclarative1VisualDataModelPrivate::QDeclarative1VisualDataModelPrivate(QDeclarativeContext *ctxt)
629 : m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0)
630 , m_context(ctxt), m_modelDataPropId(-1), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false)
631 , m_metaDataCacheable(false), m_delegateValidated(false), m_completePending(false), m_listAccessor(0)
632 {
633 }
634
635 QDeclarative1VisualDataModelData *QDeclarative1VisualDataModelPrivate::data(QObject *item)
636 {
637     QDeclarative1VisualDataModelData *dataItem =
638         item->findChild<QDeclarative1VisualDataModelData *>();
639     Q_ASSERT(dataItem);
640     return dataItem;
641 }
642
643 //---------------------------------------------------------------------------
644
645 /*!
646     \qmlclass VisualDataModel QDeclarative1VisualDataModel
647     \inqmlmodule QtQuick 1
648     \ingroup qml-working-with-data
649     \brief The VisualDataModel encapsulates a model and delegate
650
651     A VisualDataModel encapsulates a model and the delegate that will
652     be instantiated for items in the model.
653
654     It is usually not necessary to create VisualDataModel elements.
655     However, it can be useful for manipulating and accessing the \l modelIndex 
656     when a QAbstractItemModel subclass is used as the 
657     model. Also, VisualDataModel is used together with \l Package to 
658     provide delegates to multiple views.
659
660     The example below illustrates using a VisualDataModel with a ListView.
661
662     \snippet doc/src/snippets/declarative/visualdatamodel.qml 0
663 */
664
665 QDeclarative1VisualDataModel::QDeclarative1VisualDataModel()
666 : QDeclarative1VisualModel(*(new QDeclarative1VisualDataModelPrivate(0)))
667 {
668 }
669
670 QDeclarative1VisualDataModel::QDeclarative1VisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
671 : QDeclarative1VisualModel(*(new QDeclarative1VisualDataModelPrivate(ctxt)), parent)
672 {
673 }
674
675 QDeclarative1VisualDataModel::~QDeclarative1VisualDataModel()
676 {
677     Q_D(QDeclarative1VisualDataModel);
678     if (d->m_listAccessor)
679         delete d->m_listAccessor;
680     if (d->m_delegateDataType)
681         d->m_delegateDataType->release();
682 }
683
684 /*!
685     \qmlproperty model QtQuick1::VisualDataModel::model
686     This property holds the model providing data for the VisualDataModel.
687
688     The model provides a set of data that is used to create the items
689     for a view.  For large or dynamic datasets the model is usually
690     provided by a C++ model object.  The C++ model object must be a \l
691     {QAbstractItemModel} subclass or a simple list.
692
693     Models can also be created directly in QML, using a \l{ListModel} or
694     \l{XmlListModel}.
695
696     \sa {qmlmodels}{Data Models}
697 */
698 QVariant QDeclarative1VisualDataModel::model() const
699 {
700     Q_D(const QDeclarative1VisualDataModel);
701     return d->m_modelVariant;
702 }
703
704 void QDeclarative1VisualDataModel::setModel(const QVariant &model)
705 {
706     Q_D(QDeclarative1VisualDataModel);
707     delete d->m_listAccessor;
708     d->m_listAccessor = 0;
709     d->m_modelVariant = model;
710     if (d->m_listModelInterface) {
711         // Assume caller has released all items.
712         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
713                 this, SLOT(_q_itemsChanged(int,int,QList<int>)));
714         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
715                 this, SLOT(_q_itemsInserted(int,int)));
716         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
717                 this, SLOT(_q_itemsRemoved(int,int)));
718         QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
719                 this, SLOT(_q_itemsMoved(int,int,int)));
720         d->m_listModelInterface = 0;
721     } else if (d->m_abstractItemModel) {
722         QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
723                             this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
724         QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
725                             this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
726         QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
727                             this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
728         QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
729                             this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
730         QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
731         QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
732         d->m_abstractItemModel = 0;
733     } else if (d->m_visualItemModel) {
734         QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
735                          this, SIGNAL(itemsInserted(int,int)));
736         QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
737                          this, SIGNAL(itemsRemoved(int,int)));
738         QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
739                          this, SIGNAL(itemsMoved(int,int,int)));
740         QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarative1Package*)),
741                          this, SLOT(_q_createdPackage(int,QDeclarative1Package*)));
742         QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarative1Package*)),
743                          this, SLOT(_q_destroyingPackage(QDeclarative1Package*)));
744         d->m_visualItemModel = 0;
745     }
746
747     d->m_roles.clear();
748     d->m_roleNames.clear();
749     if (d->m_delegateDataType)
750         d->m_delegateDataType->release();
751     d->m_metaDataCreated = 0;
752     d->m_metaDataCacheable = false;
753     d->m_delegateDataType = new VDMDelegateDataType(&QDeclarative1VisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this));
754
755     QObject *object = qvariant_cast<QObject *>(model);
756     if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
757         QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
758                          this, SLOT(_q_itemsChanged(int,int,QList<int>)));
759         QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
760                          this, SLOT(_q_itemsInserted(int,int)));
761         QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
762                          this, SLOT(_q_itemsRemoved(int,int)));
763         QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
764                          this, SLOT(_q_itemsMoved(int,int,int)));
765         d->m_metaDataCacheable = true;
766         if (d->m_delegate && d->m_listModelInterface->count())
767             emit itemsInserted(0, d->m_listModelInterface->count());
768         return;
769     } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
770         QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
771                             this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
772         QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
773                             this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
774         QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
775                             this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
776         QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
777                             this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
778         QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
779         QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
780         d->m_metaDataCacheable = true;
781         if (d->m_abstractItemModel->canFetchMore(d->m_root))
782             d->m_abstractItemModel->fetchMore(d->m_root);
783         return;
784     }
785     if ((d->m_visualItemModel = qvariant_cast<QDeclarative1VisualDataModel *>(model))) {
786         QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
787                          this, SIGNAL(itemsInserted(int,int)));
788         QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
789                          this, SIGNAL(itemsRemoved(int,int)));
790         QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
791                          this, SIGNAL(itemsMoved(int,int,int)));
792         QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarative1Package*)),
793                          this, SLOT(_q_createdPackage(int,QDeclarative1Package*)));
794         QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarative1Package*)),
795                          this, SLOT(_q_destroyingPackage(QDeclarative1Package*)));
796         return;
797     }
798     d->m_listAccessor = new QDeclarative1ListAccessor;
799     d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this));
800     if (d->m_listAccessor->type() != QDeclarative1ListAccessor::ListProperty)
801         d->m_metaDataCacheable = true;
802     if (d->m_delegate && d->modelCount()) {
803         emit itemsInserted(0, d->modelCount());
804         emit countChanged();
805     }
806 }
807
808 /*!
809     \qmlproperty Component QtQuick1::VisualDataModel::delegate
810
811     The delegate provides a template defining each item instantiated by a view.
812     The index is exposed as an accessible \c index property.  Properties of the
813     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
814 */
815 QDeclarativeComponent *QDeclarative1VisualDataModel::delegate() const
816 {
817     Q_D(const QDeclarative1VisualDataModel);
818     if (d->m_visualItemModel)
819         return d->m_visualItemModel->delegate();
820     return d->m_delegate;
821 }
822
823 void QDeclarative1VisualDataModel::setDelegate(QDeclarativeComponent *delegate)
824 {
825     Q_D(QDeclarative1VisualDataModel);
826     bool wasValid = d->m_delegate != 0;
827     d->m_delegate = delegate;
828     d->m_delegateValidated = false;
829     if (!wasValid && d->modelCount() && d->m_delegate) {
830         emit itemsInserted(0, d->modelCount());
831         emit countChanged();
832     }
833     if (wasValid && !d->m_delegate && d->modelCount()) {
834         emit itemsRemoved(0, d->modelCount());
835         emit countChanged();
836     }
837 }
838
839 /*!
840     \qmlproperty QModelIndex QtQuick1::VisualDataModel::rootIndex
841
842     QAbstractItemModel provides a hierarchical tree of data, whereas
843     QML only operates on list data.  \c rootIndex allows the children of
844     any node in a QAbstractItemModel to be provided by this model.
845
846     This property only affects models of type QAbstractItemModel that
847     are hierarchical (e.g, a tree model). 
848
849     For example, here is a simple interactive file system browser.
850     When a directory name is clicked, the view's \c rootIndex is set to the
851     QModelIndex node of the clicked directory, thus updating the view to show
852     the new directory's contents.
853
854     \c main.cpp:
855     \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/main.cpp 0
856    
857     \c view.qml:
858     \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/view.qml 0
859
860     If the \l model is a QAbstractItemModel subclass, the delegate can also
861     reference a \c hasModelChildren property (optionally qualified by a
862     \e model. prefix) that indicates whether the delegate's model item has 
863     any child nodes.
864
865
866     \sa modelIndex(), parentModelIndex()
867 */
868 QVariant QDeclarative1VisualDataModel::rootIndex() const
869 {
870     Q_D(const QDeclarative1VisualDataModel);
871     return QVariant::fromValue(d->m_root);
872 }
873
874 void QDeclarative1VisualDataModel::setRootIndex(const QVariant &root)
875 {
876     Q_D(QDeclarative1VisualDataModel);
877     QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
878     if (d->m_root != modelIndex) {
879         int oldCount = d->modelCount();
880         d->m_root = modelIndex;
881         if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex))
882             d->m_abstractItemModel->fetchMore(modelIndex);
883         int newCount = d->modelCount();
884         if (d->m_delegate && oldCount)
885             emit itemsRemoved(0, oldCount);
886         if (d->m_delegate && newCount)
887             emit itemsInserted(0, newCount);
888         if (newCount != oldCount)
889             emit countChanged();
890         emit rootIndexChanged();
891     }
892 }
893
894
895 /*!
896     \qmlmethod QModelIndex QtQuick1::VisualDataModel::modelIndex(int index)
897
898     QAbstractItemModel provides a hierarchical tree of data, whereas
899     QML only operates on list data.  This function assists in using
900     tree models in QML.
901
902     Returns a QModelIndex for the specified index.
903     This value can be assigned to rootIndex.
904
905     \sa rootIndex
906 */
907 QVariant QDeclarative1VisualDataModel::modelIndex(int idx) const
908 {
909     Q_D(const QDeclarative1VisualDataModel);
910     if (d->m_abstractItemModel)
911         return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root));
912     return QVariant::fromValue(QModelIndex());
913 }
914
915 /*!
916     \qmlmethod QModelIndex QtQuick1::VisualDataModel::parentModelIndex()
917
918     QAbstractItemModel provides a hierarchical tree of data, whereas
919     QML only operates on list data.  This function assists in using
920     tree models in QML.
921
922     Returns a QModelIndex for the parent of the current rootIndex.
923     This value can be assigned to rootIndex.
924
925     \sa rootIndex
926 */
927 QVariant QDeclarative1VisualDataModel::parentModelIndex() const
928 {
929     Q_D(const QDeclarative1VisualDataModel);
930     if (d->m_abstractItemModel)
931         return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root));
932     return QVariant::fromValue(QModelIndex());
933 }
934
935 QString QDeclarative1VisualDataModel::part() const
936 {
937     Q_D(const QDeclarative1VisualDataModel);
938     return d->m_part;
939 }
940
941 void QDeclarative1VisualDataModel::setPart(const QString &part)
942 {
943     Q_D(QDeclarative1VisualDataModel);
944     d->m_part = part;
945 }
946
947 int QDeclarative1VisualDataModel::count() const
948 {
949     Q_D(const QDeclarative1VisualDataModel);
950     if (d->m_visualItemModel)
951         return d->m_visualItemModel->count();
952     if (!d->m_delegate)
953         return 0;
954     return d->modelCount();
955 }
956
957 QDeclarativeItem *QDeclarative1VisualDataModel::item(int index, bool complete)
958 {
959     Q_D(QDeclarative1VisualDataModel);
960     if (d->m_visualItemModel)
961         return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete);
962     return item(index, QByteArray(), complete);
963 }
964
965 /*
966   Returns ReleaseStatus flags.
967 */
968 QDeclarative1VisualDataModel::ReleaseFlags QDeclarative1VisualDataModel::release(QDeclarativeItem *item)
969 {
970     Q_D(QDeclarative1VisualDataModel);
971     if (d->m_visualItemModel)
972         return d->m_visualItemModel->release(item);
973
974     ReleaseFlags stat = 0;
975     QObject *obj = item;
976     bool inPackage = false;
977
978     QHash<QObject*,QDeclarative1Package*>::iterator it = d->m_packaged.find(item);
979     if (it != d->m_packaged.end()) {
980         QDeclarative1Package *package = *it;
981         d->m_packaged.erase(it);
982         if (d->m_packaged.contains(item))
983             stat |= Referenced;
984         inPackage = true;
985         obj = package; // fall through and delete
986     }
987
988     if (d->m_cache.releaseItem(obj)) {
989         // Remove any bindings to avoid warnings due to parent change.
990         QObjectPrivate *p = QObjectPrivate::get(obj);
991         Q_ASSERT(p->declarativeData);
992         QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData);
993         if (d->ownContext && d->context)
994             d->context->clearContext();
995
996         if (inPackage) {
997             emit destroyingPackage(qobject_cast<QDeclarative1Package*>(obj));
998         } else {
999             if (item->scene())
1000                 item->scene()->removeItem(item);
1001         }
1002         stat |= Destroyed;
1003         obj->deleteLater();
1004     } else if (!inPackage) {
1005         stat |= Referenced;
1006     }
1007
1008     return stat;
1009 }
1010
1011 /*!
1012     \qmlproperty object QtQuick1::VisualDataModel::parts
1013
1014     The \a parts property selects a VisualDataModel which creates
1015     delegates from the part named.  This is used in conjunction with
1016     the \l Package element.
1017
1018     For example, the code below selects a model which creates
1019     delegates named \e list from a \l Package:
1020
1021     \code
1022     VisualDataModel {
1023         id: visualModel
1024         delegate: Package {
1025             Item { Package.name: "list" }
1026         }
1027         model: myModel
1028     }
1029
1030     ListView {
1031         width: 200; height:200
1032         model: visualModel.parts.list
1033     }
1034     \endcode
1035
1036     \sa Package
1037 */
1038 QObject *QDeclarative1VisualDataModel::parts()
1039 {
1040     Q_D(QDeclarative1VisualDataModel);
1041     if (!d->m_parts)
1042         d->m_parts = new QDeclarative1VisualDataModelParts(this);
1043     return d->m_parts;
1044 }
1045
1046 QDeclarativeItem *QDeclarative1VisualDataModel::item(int index, const QByteArray &viewId, bool complete)
1047 {
1048     Q_D(QDeclarative1VisualDataModel);
1049     if (d->m_visualItemModel)
1050         return d->m_visualItemModel->item(index, viewId, complete);
1051
1052     if (d->modelCount() <= 0 || !d->m_delegate)
1053         return 0;
1054     QObject *nobj = d->m_cache.getItem(index);
1055     bool needComplete = false;
1056     if (!nobj) {
1057         QDeclarativeContext *ccontext = d->m_context;
1058         if (!ccontext) ccontext = qmlContext(this);
1059         QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext);
1060         QDeclarative1VisualDataModelData *data = new QDeclarative1VisualDataModelData(index, this);
1061         if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor
1062             && d->m_listAccessor->type() == QDeclarative1ListAccessor::ListProperty) {
1063             ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject*>());
1064             ctxt = new QDeclarativeContext(ctxt, ctxt);
1065         }
1066         ctxt->setContextProperty(QLatin1String("model"), data);
1067         ctxt->setContextObject(data);
1068         d->m_completePending = false;
1069         nobj = d->m_delegate->beginCreate(ctxt);
1070         if (complete) {
1071             d->m_delegate->completeCreate();
1072         } else {
1073             d->m_completePending = true;
1074             needComplete = true;
1075         }
1076         if (nobj) {
1077             QDeclarative_setParent_noEvent(ctxt, nobj);
1078             QDeclarative_setParent_noEvent(data, nobj);
1079             d->m_cache.insertItem(index, nobj);
1080             if (QDeclarative1Package *package = qobject_cast<QDeclarative1Package *>(nobj))
1081                 emit createdPackage(index, package);
1082         } else {
1083             delete data;
1084             delete ctxt;
1085             qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate";
1086         }
1087     }
1088     QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(nobj);
1089     if (!item) {
1090         QDeclarative1Package *package = qobject_cast<QDeclarative1Package *>(nobj);
1091         if (package) {
1092             QObject *o = package->part(QString::fromUtf8(viewId));
1093             item = qobject_cast<QDeclarativeItem *>(o);
1094             if (item)
1095                 d->m_packaged.insertMulti(item, package);
1096         }
1097     }
1098     if (!item) {
1099         if (needComplete)
1100             d->m_delegate->completeCreate();
1101         d->m_cache.releaseItem(nobj);
1102         if (!d->m_delegateValidated) {
1103             qmlInfo(d->m_delegate) << QDeclarative1VisualDataModel::tr("Delegate component must be Item type.");
1104             d->m_delegateValidated = true;
1105         }
1106     }
1107     if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
1108         d->m_abstractItemModel->fetchMore(d->m_root);
1109
1110     return item;
1111 }
1112
1113 bool QDeclarative1VisualDataModel::completePending() const
1114 {
1115     Q_D(const QDeclarative1VisualDataModel);
1116     if (d->m_visualItemModel)
1117         return d->m_visualItemModel->completePending();
1118     return d->m_completePending;
1119 }
1120
1121 void QDeclarative1VisualDataModel::completeItem()
1122 {
1123     Q_D(QDeclarative1VisualDataModel);
1124     if (d->m_visualItemModel) {
1125         d->m_visualItemModel->completeItem();
1126         return;
1127     }
1128
1129     d->m_delegate->completeCreate();
1130     d->m_completePending = false;
1131 }
1132
1133 QString QDeclarative1VisualDataModel::stringValue(int index, const QString &name)
1134 {
1135     Q_D(QDeclarative1VisualDataModel);
1136     if (d->m_visualItemModel)
1137         return d->m_visualItemModel->stringValue(index, name);
1138
1139     if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) {
1140         if (QObject *object = d->m_listAccessor->at(index).value<QObject*>())
1141             return object->property(name.toUtf8()).toString();
1142     }
1143
1144     if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
1145         return QString();
1146
1147     QString val;
1148     QObject *data = 0;
1149     bool tempData = false;
1150
1151     if (QObject *nobj = d->m_cache.item(index))
1152         data = d->data(nobj);
1153     if (!data) {
1154         data = new QDeclarative1VisualDataModelData(index, this);
1155         tempData = true;
1156     }
1157
1158     QDeclarativeData *ddata = QDeclarativeData::get(data);
1159     if (ddata && ddata->propertyCache) {
1160         QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name);
1161         if (prop) {
1162             if (prop->propType == QVariant::String) {
1163                 void *args[] = { &val, 0 };
1164                 QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
1165             } else if (prop->propType == qMetaTypeId<QVariant>()) {
1166                 QVariant v;
1167                 void *args[] = { &v, 0 };
1168                 QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
1169                 val = v.toString();
1170             }
1171         } else {
1172             val = data->property(name.toUtf8()).toString();
1173         }
1174     } else {
1175         val = data->property(name.toUtf8()).toString();
1176     }
1177
1178     if (tempData)
1179         delete data;
1180
1181     return val;
1182 }
1183
1184 int QDeclarative1VisualDataModel::indexOf(QDeclarativeItem *item, QObject *) const
1185 {
1186     QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index"));
1187         return val.toInt();
1188     return -1;
1189 }
1190
1191 void QDeclarative1VisualDataModel::setWatchedRoles(QList<QByteArray> roles)
1192 {
1193     Q_D(QDeclarative1VisualDataModel);
1194     d->watchedRoles = roles;
1195     d->watchedRoleIds.clear();
1196 }
1197
1198 void QDeclarative1VisualDataModel::_q_itemsChanged(int index, int count,
1199                                          const QList<int> &roles)
1200 {
1201     Q_D(QDeclarative1VisualDataModel);
1202     bool changed = false;
1203     if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) {
1204         foreach (QByteArray r, d->watchedRoles) {
1205             if (d->m_roleNames.contains(r))
1206                 d->watchedRoleIds << d->m_roleNames.value(r);
1207         }
1208     }
1209
1210     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin();
1211         iter != d->m_cache.end(); ++iter) {
1212         const int idx = iter.key();
1213
1214         if (idx >= index && idx < index+count) {
1215             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1216             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1217             for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) {
1218                 int role = roles.at(roleIdx);
1219                 if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role))
1220                     changed = true;
1221                 int propId = data->propForRole(role);
1222                 if (propId != -1) {
1223                     if (data->hasValue(propId)) {
1224                         if (d->m_listModelInterface) {
1225                             data->setValue(propId, d->m_listModelInterface->data(idx, role));
1226                         } else if (d->m_abstractItemModel) {
1227                             QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
1228                             data->setValue(propId, d->m_abstractItemModel->data(index, role));
1229                         }
1230                     }
1231                 } else {
1232                     QString roleName;
1233                     if (d->m_listModelInterface)
1234                         roleName = d->m_listModelInterface->toString(role);
1235                     else if (d->m_abstractItemModel)
1236                         roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role));
1237                     qmlInfo(this) << "Changing role not present in item: " << roleName;
1238                 }
1239             }
1240             if (d->m_roles.count() == 1) {
1241                 // Handle the modelData role we add if there is just one role.
1242                 int propId = data->modelDataPropertyId();
1243                 if (data->hasValue(propId)) {
1244                     int role = d->m_roles.at(0);
1245                     if (d->m_listModelInterface) {
1246                         data->setValue(propId, d->m_listModelInterface->data(idx, role));
1247                     } else if (d->m_abstractItemModel) {
1248                         QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
1249                         data->setValue(propId, d->m_abstractItemModel->data(index, role));
1250                     }
1251                 }
1252             }
1253         }
1254     }
1255     if (changed)
1256         emit itemsChanged(index, count);
1257 }
1258
1259 void QDeclarative1VisualDataModel::_q_itemsInserted(int index, int count)
1260 {
1261     Q_D(QDeclarative1VisualDataModel);
1262     if (!count)
1263         return;
1264     // XXX - highly inefficient
1265     QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef> items;
1266     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1267         iter != d->m_cache.end(); ) {
1268
1269         if (iter.key() >= index) {
1270             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1271             int index = iter.key() + count;
1272             iter = d->m_cache.erase(iter);
1273
1274             items.insert(index, objRef);
1275
1276             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1277             data->setIndex(index);
1278         } else {
1279             ++iter;
1280         }
1281     }
1282     d->m_cache.unite(items);
1283
1284     emit itemsInserted(index, count);
1285     emit countChanged();
1286 }
1287
1288 void QDeclarative1VisualDataModel::_q_itemsRemoved(int index, int count)
1289 {
1290     Q_D(QDeclarative1VisualDataModel);
1291     if (!count)
1292         return;
1293     // XXX - highly inefficient
1294     QHash<int, QDeclarative1VisualDataModelPrivate::ObjectRef> items;
1295     for (QHash<int, QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1296         iter != d->m_cache.end(); ) {
1297         if (iter.key() >= index && iter.key() < index + count) {
1298             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1299             iter = d->m_cache.erase(iter);
1300             items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
1301             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1302             data->setIndex(-1);
1303         } else if (iter.key() >= index + count) {
1304             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1305             int index = iter.key() - count;
1306             iter = d->m_cache.erase(iter);
1307             items.insert(index, objRef);
1308             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1309             data->setIndex(index);
1310         } else {
1311             ++iter;
1312         }
1313     }
1314
1315     d->m_cache.unite(items);
1316     emit itemsRemoved(index, count);
1317     emit countChanged();
1318 }
1319
1320 void QDeclarative1VisualDataModel::_q_itemsMoved(int from, int to, int count)
1321 {
1322     Q_D(QDeclarative1VisualDataModel);
1323     // XXX - highly inefficient
1324     QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef> items;
1325     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1326         iter != d->m_cache.end(); ) {
1327
1328         if (iter.key() >= from && iter.key() < from + count) {
1329             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1330             int index = iter.key() - from + to;
1331             iter = d->m_cache.erase(iter);
1332
1333             items.insert(index, objRef);
1334
1335             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1336             data->setIndex(index);
1337         } else {
1338             ++iter;
1339         }
1340     }
1341     for (QHash<int,QDeclarative1VisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
1342         iter != d->m_cache.end(); ) {
1343
1344         int diff = from > to ? count : -count;
1345         if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) {
1346             QDeclarative1VisualDataModelPrivate::ObjectRef objRef = *iter;
1347             int index = iter.key() + diff;
1348             iter = d->m_cache.erase(iter);
1349
1350             items.insert(index, objRef);
1351
1352             QDeclarative1VisualDataModelData *data = d->data(objRef.obj);
1353             data->setIndex(index);
1354         } else {
1355             ++iter;
1356         }
1357     }
1358     d->m_cache.unite(items);
1359
1360     emit itemsMoved(from, to, count);
1361 }
1362
1363 void QDeclarative1VisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1364 {
1365     Q_D(QDeclarative1VisualDataModel);
1366     if (parent == d->m_root)
1367         _q_itemsInserted(begin, end - begin + 1);
1368 }
1369
1370 void QDeclarative1VisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1371 {
1372     Q_D(QDeclarative1VisualDataModel);
1373     if (parent == d->m_root)
1374         _q_itemsRemoved(begin, end - begin + 1);
1375 }
1376
1377 void QDeclarative1VisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
1378 {
1379     Q_D(QDeclarative1VisualDataModel);
1380     const int count = sourceEnd - sourceStart + 1;
1381     if (destinationParent == d->m_root && sourceParent == d->m_root) {
1382         _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-1, count);
1383     } else if (sourceParent == d->m_root) {
1384         _q_itemsRemoved(sourceStart, count);
1385     } else if (destinationParent == d->m_root) {
1386         _q_itemsInserted(destinationRow, count);
1387     }
1388 }
1389
1390 void QDeclarative1VisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1391 {
1392     Q_D(QDeclarative1VisualDataModel);
1393     if (begin.parent() == d->m_root)
1394         _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
1395 }
1396
1397 void QDeclarative1VisualDataModel::_q_layoutChanged()
1398 {
1399     Q_D(QDeclarative1VisualDataModel);
1400     _q_itemsChanged(0, count(), d->m_roles);
1401 }
1402
1403 void QDeclarative1VisualDataModel::_q_modelReset()
1404 {
1405     Q_D(QDeclarative1VisualDataModel);
1406     d->m_root = QModelIndex();
1407     emit modelReset();
1408     emit rootIndexChanged();
1409     if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
1410         d->m_abstractItemModel->fetchMore(d->m_root);
1411 }
1412
1413 void QDeclarative1VisualDataModel::_q_createdPackage(int index, QDeclarative1Package *package)
1414 {
1415     Q_D(QDeclarative1VisualDataModel);
1416     emit createdItem(index, qobject_cast<QDeclarativeItem*>(package->part(d->m_part)));
1417 }
1418
1419 void QDeclarative1VisualDataModel::_q_destroyingPackage(QDeclarative1Package *package)
1420 {
1421     Q_D(QDeclarative1VisualDataModel);
1422     emit destroyingItem(qobject_cast<QDeclarativeItem*>(package->part(d->m_part)));
1423 }
1424
1425
1426
1427 QT_END_NAMESPACE
1428
1429 QML_DECLARE_TYPE(QListModelInterface)
1430
1431 #include <qdeclarativevisualitemmodel.moc>