Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
ObjectModel: add API for dynamic changes
Following the ListModel API:
- object get(index)
- append(object)
- insert(int index, object)
- move(int from, int to, int n)
- remove(int index, int n)

[ChangeLog][QtQml][ObjectModel] Added get(), append(), insert(), move()
and remove() methods.

Change-Id: I592e55b7c4c933a1100191bf5a9405944b347172
Reviewed-by: Alan Alpert <aalpert@blackberry.com>
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
  • Loading branch information
J-P Nurmi committed Jun 10, 2015
1 parent f12c072 commit eb7db59
Show file tree
Hide file tree
Showing 11 changed files with 620 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/qml/types/qqmlmodelsmodule.cpp
Expand Up @@ -48,6 +48,7 @@ void QQmlModelsModule::defineModule()
qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");

qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
}
Expand Down
204 changes: 189 additions & 15 deletions src/qml/types/qqmlobjectmodel.cpp
Expand Up @@ -36,10 +36,12 @@
#include <QtCore/qcoreapplication.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlinfo.h>

#include <private/qqmlchangeset_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qobject_p.h>
#include <private/qpodvector_p.h>

#include <QtCore/qhash.h>
#include <QtCore/qlist.h>
Expand Down Expand Up @@ -67,9 +69,8 @@ class QQmlObjectModelPrivate : public QObjectPrivate
QQmlObjectModelPrivate() : QObjectPrivate() {}

static void children_append(QQmlListProperty<QObject> *prop, QObject *item) {
static_cast<QQmlObjectModelPrivate *>(prop->data)->children.append(Item(item));
static_cast<QQmlObjectModelPrivate *>(prop->data)->itemAppended();
static_cast<QQmlObjectModelPrivate *>(prop->data)->emitChildrenChanged();
int index = static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count();
static_cast<QQmlObjectModelPrivate *>(prop->data)->insert(index, item);
}

static int children_count(QQmlListProperty<QObject> *prop) {
Expand All @@ -81,33 +82,77 @@ class QQmlObjectModelPrivate : public QObjectPrivate
}

static void children_clear(QQmlListProperty<QObject> *prop) {
static_cast<QQmlObjectModelPrivate *>(prop->data)->itemCleared(static_cast<QQmlObjectModelPrivate *>(prop->data)->children);
static_cast<QQmlObjectModelPrivate *>(prop->data)->children.clear();
static_cast<QQmlObjectModelPrivate *>(prop->data)->emitChildrenChanged();
static_cast<QQmlObjectModelPrivate *>(prop->data)->clear();
}

void itemAppended() {
void insert(int index, QObject *item) {
Q_Q(QQmlObjectModel);
QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.last().item);
attached->setIndex(children.count()-1);
children.insert(index, Item(item));
for (int i = index; i < children.count(); ++i) {
QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
attached->setIndex(i);
}
QQmlChangeSet changeSet;
changeSet.insert(children.count() - 1, 1);
changeSet.insert(index, 1);
emit q->modelUpdated(changeSet, false);
emit q->countChanged();
emit q->childrenChanged();
}

void itemCleared(const QList<Item> &children) {
void move(int from, int to, int n) {
Q_Q(QQmlObjectModel);
foreach (const Item &child, children)
emit q->destroyingItem(child.item);
emit q->countChanged();
if (from > to) {
// Only move forwards - flip if backwards moving
int tfrom = from;
int tto = to;
from = tto;
to = tto+n;
n = tfrom-tto;
}

QPODVector<QQmlObjectModelPrivate::Item, 4> store;
for (int i = 0; i < to - from; ++i)
store.append(children[from + n + i]);
for (int i = 0; i < n; ++i)
store.append(children[from + i]);

for (int i = 0; i < store.count(); ++i) {
children[from + i] = store[i];
QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(from + i).item);
attached->setIndex(from + i);
}

QQmlChangeSet changeSet;
changeSet.move(from, to, n, -1);
emit q->modelUpdated(changeSet, false);
emit q->childrenChanged();
}

void emitChildrenChanged() {
void remove(int index, int n) {
Q_Q(QQmlObjectModel);
for (int i = index; i < index + n; ++i) {
QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
attached->setIndex(-1);
}
children.erase(children.begin() + index, children.begin() + index + n);
for (int i = index; i < children.count(); ++i) {
QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
attached->setIndex(i);
}
QQmlChangeSet changeSet;
changeSet.remove(index, n);
emit q->modelUpdated(changeSet, false);
emit q->countChanged();
emit q->childrenChanged();
}

void clear() {
Q_Q(QQmlObjectModel);
foreach (const Item &child, children)
emit q->destroyingItem(child.item);
remove(0, children.count());
}

int indexOf(QObject *item) const {
for (int i = 0; i < children.count(); ++i)
if (children.at(i).item == item)
Expand Down Expand Up @@ -258,4 +303,133 @@ QQmlObjectModelAttached *QQmlObjectModel::qmlAttachedProperties(QObject *obj)
return QQmlObjectModelAttached::properties(obj);
}

/*!
\qmlmethod object QtQml.Models::ObjectModel::get(int index)
\since 5.6
Returns the item at \a index in the model. This allows the item
to be accessed or modified from JavaScript:
\code
Component.onCompleted: {
objectModel.append(objectComponent.createObject())
console.log(objectModel.get(0).objectName);
objectModel.get(0).objectName = "first";
}
\endcode
The \a index must be an element in the list.
\sa append()
*/
QObject *QQmlObjectModel::get(int index) const
{
Q_D(const QQmlObjectModel);
if (index < 0 || index >= d->children.count())
return 0;
return d->children.at(index).item;
}

/*!
\qmlmethod QtQml.Models::ObjectModel::append(object item)
\since 5.6
Appends a new item to the end of the model.
\code
objectModel.append(objectComponent.createObject())
\endcode
\sa insert(), remove()
*/
void QQmlObjectModel::append(QObject *object)
{
Q_D(QQmlObjectModel);
d->insert(count(), object);
}

/*!
\qmlmethod QtQml.Models::ObjectModel::insert(int index, object item)
\since 5.6
Inserts a new item to the model at position \a index.
\code
objectModel.insert(2, objectComponent.createObject())
\endcode
The \a index must be to an existing item in the list, or one past
the end of the list (equivalent to append).
\sa append(), remove()
*/
void QQmlObjectModel::insert(int index, QObject *object)
{
Q_D(QQmlObjectModel);
if (index < 0 || index > count()) {
qmlInfo(this) << tr("insert: index %1 out of range").arg(index);
return;
}
d->insert(index, object);
}

/*!
\qmlmethod QtQml.Models::ObjectModel::move(int from, int to, int n = 1)
\since 5.6
Moves \a n items \a from one position \a to another.
The from and to ranges must exist; for example, to move the first 3 items
to the end of the model:
\code
objectModel.move(0, objectModel.count - 3, 3)
\endcode
\sa append()
*/
void QQmlObjectModel::move(int from, int to, int n)
{
Q_D(QQmlObjectModel);
if (n <= 0 || from == to)
return;
if (from < 0 || to < 0 || from + n > count() || to + n > count()) {
qmlInfo(this) << tr("move: out of range");
return;
}
d->move(from, to, n);
}

/*!
\qmlmethod QtQml.Models::ObjectModel::remove(int index, int n = 1)
\since 5.6
Removes the items at \a index from the model.
\sa clear()
*/
void QQmlObjectModel::remove(int index, int n)
{
Q_D(QQmlObjectModel);
if (index < 0 || n <= 0 || index + n > count()) {
qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count());
return;
}
d->remove(index, n);
}

/*!
\qmlmethod QtQml.Models::ObjectModel::clear()
\since 5.6
Clears all items from the model.
\sa append(), remove()
*/
void QQmlObjectModel::clear()
{
Q_D(QQmlObjectModel);
d->clear();
}

QT_END_NAMESPACE
11 changes: 10 additions & 1 deletion src/qml/types/qqmlobjectmodel_p.h
Expand Up @@ -107,6 +107,15 @@ class Q_QML_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel

static QQmlObjectModelAttached *qmlAttachedProperties(QObject *obj);

Q_REVISION(3) Q_INVOKABLE QObject *get(int index) const;
Q_REVISION(3) Q_INVOKABLE void append(QObject *object);
Q_REVISION(3) Q_INVOKABLE void insert(int index, QObject *object);
Q_REVISION(3) Q_INVOKABLE void move(int from, int to, int n = 1);
Q_REVISION(3) Q_INVOKABLE void remove(int index, int n = 1);

public Q_SLOTS:
Q_REVISION(3) void clear();

Q_SIGNALS:
void childrenChanged();

Expand All @@ -120,7 +129,7 @@ class QQmlObjectModelAttached : public QObject

public:
QQmlObjectModelAttached(QObject *parent)
: QObject(parent), m_index(0) {}
: QObject(parent), m_index(-1) {}
~QQmlObjectModelAttached() {
attachedProperties.remove(parent());
}
Expand Down
3 changes: 2 additions & 1 deletion tests/auto/qml/qml.pro
Expand Up @@ -59,7 +59,8 @@ PRIVATETESTS += \
qqmlenginecleanup \
v4misc \
qqmltranslation \
qqmlimport
qqmlimport \
qqmlobjectmodel

qtHaveModule(widgets) {
PUBLICTESTS += \
Expand Down
10 changes: 10 additions & 0 deletions tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro
@@ -0,0 +1,10 @@
CONFIG += testcase
TARGET = tst_qqmlobjectmodel
osx:CONFIG -= app_bundle

SOURCES += tst_qqmlobjectmodel.cpp

CONFIG += parallel_test

QT += qml testlib
QT += core-private qml-private

0 comments on commit eb7db59

Please sign in to comment.