diff options
author | Andras Becsi <andras.becsi@digia.com> | 2013-04-30 15:28:42 +0200 |
---|---|---|
committer | Andras Becsi <andras.becsi@digia.com> | 2013-04-30 17:49:14 +0200 |
commit | 16403616e3f98fafd3a1644dbfd71131b0bd39ca (patch) | |
tree | 549bbd7ac99ee286449212c21046a4ba2e28a012 | |
parent | 5b99ccbc02dc8f9022de0645657f983455b6e7be (diff) | |
download | qtenginio-16403616e3f98fafd3a1644dbfd71131b0bd39ca.tar.gz |
Add append, remove, setData and setValue to EnginioModel
and fix the initialization issue of EnginioClient.
Later we need to improve the abstraction for EnginioModel
and EnginioClient, this is just to make the examples work
by bringing the model to feature parity with the prototype.
-rw-r--r-- | src/enginio_client/enginioclient.h | 1 | ||||
-rw-r--r-- | src/enginio_client/enginiomodel.cpp | 116 | ||||
-rw-r--r-- | src/enginio_client/enginiomodel.h | 5 | ||||
-rw-r--r-- | src/enginio_plugin/enginio_plugin.pro | 2 | ||||
-rw-r--r-- | src/enginio_plugin/enginioplugin.cpp | 7 | ||||
-rw-r--r-- | src/enginio_plugin/enginioqmlclient.cpp | 5 | ||||
-rw-r--r-- | src/enginio_plugin/enginioqmlclient.h | 7 | ||||
-rw-r--r-- | src/enginio_plugin/enginioqmlmodel.cpp | 54 | ||||
-rw-r--r-- | src/enginio_plugin/enginioqmlmodel.h | 64 |
9 files changed, 256 insertions, 5 deletions
diff --git a/src/enginio_client/enginioclient.h b/src/enginio_client/enginioclient.h index 9004f2c..d6e95df 100644 --- a/src/enginio_client/enginioclient.h +++ b/src/enginio_client/enginioclient.h @@ -95,6 +95,7 @@ public: signals: void sessionAuthenticated() const; void sessionTerminated() const; + void clientInitialized() const; void backendIdChanged(const QString &backendId); void backendSecretChanged(const QString &backendSecret); void finished(EnginioReply *reply); diff --git a/src/enginio_client/enginiomodel.cpp b/src/enginio_client/enginiomodel.cpp index 416c98c..405412e 100644 --- a/src/enginio_client/enginiomodel.cpp +++ b/src/enginio_client/enginiomodel.cpp @@ -52,8 +52,13 @@ class EnginioModelPrivate { const static int FullModelReset; mutable QMap<const EnginioReply*, QPair<int /*row*/, QJsonObject> > _dataChanged; + QSet<int> _rowsToSync; + + enum { + InvalidRole = -1, + SyncedRole = Qt::UserRole + 1 + }; - const static int SyncedRole = Qt::UserRole + 1; QHash<int, QString> _roles; QJsonArray _data; // TODO replace by a sparse array, and add laziness @@ -127,6 +132,7 @@ public: _enginio = const_cast<EnginioClient*>(enginio); if (_enginio) { _connections.append(QObject::connect(_enginio, &EnginioClient::finished, FinishedRequest(this))); + _connections.append(QObject::connect(_enginio, &EnginioClient::clientInitialized, QueryChanged(this))); _connections.append(QObject::connect(_enginio, &QObject::destroyed, EnginioDestroyed(this))); } emit q->enginioChanged(_enginio); @@ -137,6 +143,35 @@ public: return _query; } + void append(const QJsonObject &value) + { + QJsonObject object(value); + object["objectType"] = _query["objectType"]; // TODO think about it, it means that not all queries are valid + q->beginInsertRows(QModelIndex(), _data.count(), _data.count()); + const EnginioReply* id = _enginio->create(object, _area); + _data.append(value); + const int row = _data.count() - 1; + _rowsToSync.insert(row); + _dataChanged.insert(id, qMakePair(row, object)); + q->endInsertRows(); + } + + void remove(int row) + { + QJsonObject oldObject = _data.at(row).toObject(); + const EnginioReply* id = _enginio->remove(oldObject, _area); + _dataChanged.insert(id, qMakePair(row, oldObject)); + emit q->dataChanged(q->index(row), q->index(row) , QVector<int>{SyncedRole,}); + } + + void setValue(int row, const QVariant &value, const QString &role) + { + int key = _roles.key(role, InvalidRole); + if (key != InvalidRole) { + setData(row, value, key); + } + } + void setQuery(const QJsonObject &query) { _query = query; @@ -169,16 +204,62 @@ public: { QPair<int, QJsonObject> requestInfo = _dataChanged.take(response); int row = requestInfo.first; + _rowsToSync.remove(row); if (row == FullModelReset) { q->beginResetModel(); + _rowsToSync.clear(); _data = response->data()[QStringLiteral("results")].toArray(); syncRoles(); q->endResetModel(); } else { // TODO update, insert and remove + Q_ASSERT(row < _data.count()); + // update or insert data + QJsonObject currentValue = _data.at(row).toObject(); + QJsonObject oldValue = requestInfo.second; + QJsonObject newValue(response->data()); + + if (response->errorCode() != QNetworkReply::NoError) { + _data.replace(row, oldValue); // FIXME do we have to do more here? + return; + } + + if (newValue.isEmpty()) { + qDebug() << "Removing"; + q->beginRemoveRows(QModelIndex(), row, row); + _data.removeAt(row); + q->endRemoveRows(); + } else { + _data.replace(row, newValue); + if (_data.count() == 1) { + q->beginResetModel(); + syncRoles(); + q->endResetModel(); + } else { + emit q->dataChanged(q->index(row), q->index(row)); + } + } } } + bool setData(const int row, const QVariant &value, int role) + { + if (role > SyncedRole) { + _rowsToSync.insert(row); + QJsonObject oldObject = _data.at(row).toObject(); + QJsonObject newObject = oldObject; + newObject[_roles.value(role)] = QJsonValue::fromVariant(value); + const EnginioReply* id = _enginio->update(newObject, _area); + _dataChanged.insert(id, qMakePair(row, oldObject)); + _data.replace(row, newObject); + emit q->dataChanged(q->index(row), q->index(row)); + return true; + } + + Q_UNIMPLEMENTED(); + return false; + } + void syncRoles() { // estimate new roles: @@ -211,6 +292,9 @@ public: QVariant data(unsigned row, int role) { + if (role == SyncedRole) + return !_rowsToSync.contains(row); + const QJsonValue value = _data.at(row); const QJsonObject object = value.toObject(); if (role > Qt::UserRole && !object.isEmpty()) @@ -263,6 +347,28 @@ void EnginioModel::setArea(const int area) return; d->setArea(area); } + +void EnginioModel::append(const QJsonObject &value) +{ + d->append(value); +} + +void EnginioModel::remove(int row) +{ + if (row >= d->rowCount()) + return; + + d->remove(row); +} + +void EnginioModel::setValue(int row, const QVariant &value, const QString &role) +{ + if (row >= d->rowCount()) // TODO remove as soon as we have a sparse array. + return; + + d->setValue(row, value, role); +} + void EnginioModel::execute() { d->execute(); @@ -287,6 +393,14 @@ int EnginioModel::rowCount(const QModelIndex &parent) const return d->rowCount(); } +bool EnginioModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.row() >= d->rowCount()) // TODO remove as soon as we have a sparse array. + return false; + + return d->setData(index.row(), value, role); +} + QHash<int, QByteArray> EnginioModel::roleNames() const { return d->roleNames(); diff --git a/src/enginio_client/enginiomodel.h b/src/enginio_client/enginiomodel.h index 3bd36e0..eb8d46b 100644 --- a/src/enginio_client/enginiomodel.h +++ b/src/enginio_client/enginiomodel.h @@ -66,6 +66,11 @@ public: virtual Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; + + Q_INVOKABLE void append(const QJsonObject &value); + Q_INVOKABLE void remove(int row); + Q_INVOKABLE void setValue(int row, const QVariant &value, const QString &role); protected: virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE; diff --git a/src/enginio_plugin/enginio_plugin.pro b/src/enginio_plugin/enginio_plugin.pro index 96a8de7..7f63ec8 100644 --- a/src/enginio_plugin/enginio_plugin.pro +++ b/src/enginio_plugin/enginio_plugin.pro @@ -5,6 +5,7 @@ QT += qml quick enginio SOURCES += \ enginioqmlclient.cpp \ + enginioqmlmodel.cpp \ enginioplugin.cpp \ enginioqmlobjectmodel.cpp \ enginioqmlqueryoperation.cpp \ @@ -15,6 +16,7 @@ SOURCES += \ HEADERS += \ enginioqmlclient.h \ + enginioqmlmodel.h \ enginioplugin.h \ enginioqmlobjectmodel.h \ enginioqmlqueryoperation.h \ diff --git a/src/enginio_plugin/enginioplugin.cpp b/src/enginio_plugin/enginioplugin.cpp index 178d2f3..644e0a8 100644 --- a/src/enginio_plugin/enginioplugin.cpp +++ b/src/enginio_plugin/enginioplugin.cpp @@ -39,6 +39,7 @@ #include "enginioplugin.h" #include "enginioqmlacloperation.h" #include "enginioqmlclient.h" +#include "enginioqmlmodel.h" #include "enginioqmlfileoperation.h" #include "enginioqmlidentityauthoperation.h" #include "enginioqmlobjectmodel.h" @@ -150,10 +151,10 @@ void EnginioPlugin::initializeEngine(QQmlEngine *engine, const char *uri) void EnginioPlugin::registerTypes(const char *uri) { - // @uri io.engin + // @uri Enginio qmlRegisterType<EnginioQmlClient>(uri, 1, 0, "Client"); - qmlRegisterType<EnginioClient>(uri, 1, 0, "Enginio"); - qmlRegisterType<EnginioModel>(uri, 1, 0, "EnginioModel"); + qmlRegisterType<EnginioQmlClient>(uri, 1, 0, "Enginio"); + qmlRegisterType<EnginioQmlModel>(uri, 1, 0, "EnginioModel"); qmlRegisterType<EnginioReply>(uri, 1, 0, "EnginioReply"); qmlRegisterType<EnginioQmlObjectModel>(uri, 1, 0, "ObjectModel"); qmlRegisterType<EnginioQmlObjectOperation>(uri, 1, 0, "ObjectOperation"); diff --git a/src/enginio_plugin/enginioqmlclient.cpp b/src/enginio_plugin/enginioqmlclient.cpp index dde91b3..1b4a42f 100644 --- a/src/enginio_plugin/enginioqmlclient.cpp +++ b/src/enginio_plugin/enginioqmlclient.cpp @@ -95,6 +95,11 @@ EnginioQmlClient::EnginioQmlClient(const QString &backendId, { } +void EnginioQmlClient::componentComplete() +{ + emit clientInitialized(); +} + QString EnginioQmlClient::apiUrlAsString() const { return apiUrl().toString(); diff --git a/src/enginio_plugin/enginioqmlclient.h b/src/enginio_plugin/enginioqmlclient.h index 384b2a5..78a9082 100644 --- a/src/enginio_plugin/enginioqmlclient.h +++ b/src/enginio_plugin/enginioqmlclient.h @@ -39,6 +39,7 @@ #define ENGINIOQMLCLIENT_H #include "enginioclient.h" +#include <QQmlParserStatus> class EnginioQmlAclOperation; class EnginioQmlIdentityAuthOperation; @@ -46,10 +47,11 @@ class EnginioQmlObjectModel; class EnginioQmlObjectOperation; class EnginioQmlQueryOperation; -class EnginioQmlClient : public EnginioClient +class EnginioQmlClient : public EnginioClient, public QQmlParserStatus { Q_OBJECT Q_DISABLE_COPY(EnginioQmlClient) + Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QString apiUrl READ apiUrlAsString WRITE setApiUrlFromString) Q_PROPERTY(QString sessionToken READ sessionToken) @@ -67,6 +69,9 @@ public: EnginioQmlObjectModel *model = 0); Q_INVOKABLE EnginioQmlIdentityAuthOperation * createIdentityAuthOperation(); Q_INVOKABLE EnginioQmlAclOperation * createAclOperation(); + + virtual void classBegin() { } + virtual void componentComplete(); }; #endif // ENGINIOQMLCLIENT_H diff --git a/src/enginio_plugin/enginioqmlmodel.cpp b/src/enginio_plugin/enginioqmlmodel.cpp new file mode 100644 index 0000000..4a11f3f --- /dev/null +++ b/src/enginio_plugin/enginioqmlmodel.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://qt.digia.com/contact-us +** +** This file is part of the Enginio Qt Client Library. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +****************************************************************************/ + +#include "enginioqmlmodel.h" + +EnginioQmlModel::EnginioQmlModel(QObject *parent) + : EnginioModel(parent) +{ + connect(this, SIGNAL(enginioChanged(const EnginioClient*)), SIGNAL(enginioChanged())); +} + +EnginioQmlClient *EnginioQmlModel::enginio() const +{ + return qobject_cast<EnginioQmlClient*>(EnginioModel::enginio()); +} + +void EnginioQmlModel::setEnginio(const EnginioQmlClient *enginio) +{ + EnginioModel::setEnginio(enginio); +} diff --git a/src/enginio_plugin/enginioqmlmodel.h b/src/enginio_plugin/enginioqmlmodel.h new file mode 100644 index 0000000..1040d88 --- /dev/null +++ b/src/enginio_plugin/enginioqmlmodel.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://qt.digia.com/contact-us +** +** This file is part of the Enginio Qt Client Library. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +****************************************************************************/ + +#ifndef ENGINIOQMLMODEL_H +#define ENGINIOQMLMODEL_H + +#include "enginiomodel.h" +#include "enginioqmlclient.h" + +class EnginioQmlModel : public EnginioModel +{ + // FIXME: Dirty hack. Revise this! + Q_OBJECT + Q_DISABLE_COPY(EnginioQmlModel) + +signals: + void enginioChanged(); + +public: + // TODO: Downcast does not work in QML (when assigning EnginioQmlClient to a property that expects EnginioClient) + // thus we need to find a proper abstraction instead and this has to be removed. + Q_PROPERTY(EnginioQmlClient *enginio READ enginio WRITE setEnginio NOTIFY enginioChanged) + + EnginioQmlClient *enginio() const; + void setEnginio(const EnginioQmlClient *enginio); + + EnginioQmlModel(QObject *parent = 0); +}; + +#endif // ENGINIOQMLOBJECTMODEL_H |