summaryrefslogtreecommitdiffstats
path: root/src/imports/jsondb-listmodel/jsondb-listmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports/jsondb-listmodel/jsondb-listmodel.cpp')
-rw-r--r--src/imports/jsondb-listmodel/jsondb-listmodel.cpp1263
1 files changed, 0 insertions, 1263 deletions
diff --git a/src/imports/jsondb-listmodel/jsondb-listmodel.cpp b/src/imports/jsondb-listmodel/jsondb-listmodel.cpp
deleted file mode 100644
index 1daa3e0..0000000
--- a/src/imports/jsondb-listmodel/jsondb-listmodel.cpp
+++ /dev/null
@@ -1,1263 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "jsondb-listmodel.h"
-#include "jsondb-listmodel_p.h"
-#include "private/jsondb-strings_p.h"
-
-#include <QJSEngine>
-#include <QJSValueIterator>
-
-
-#undef DEBUG_LIST_MODEL
-
-#ifdef DEBUG_LIST_MODEL
-#define DEBUG() qDebug() << Q_FUNC_INFO
-#else
-#define DEBUG() if (0) qDebug() << QString("%1:%2").arg(__FUNCTION__).arg(__LINE__)
-#endif
-
-
-JsonDbListModelPrivate::JsonDbListModelPrivate(JsonDbListModel *q)
- : q_ptr(q)
- , chunkSize(40)
- , lowWaterMark(10)
- , maxCacheSize(0) // unlimited cache
- , totalRowCount(0)
- , cacheStart(0)
- , cacheEnd(0)
- , newChunkOffset(0)
- , totalCountRequestId(-1)
- , lastFetchedIndex(-1)
- , requestInProgress(false)
- , componentComplete(false)
- , resetModel(true)
- , updateRecieved(false)
- , totalRowCountRecieved(false)
- , state(None)
- , jsonDbConnection(JsonDbConnection::instance())
-{
-}
-
-void JsonDbListModelPrivate::init()
-{
- Q_Q(JsonDbListModel);
- q->connect(&jsonDb, SIGNAL(response(int,QVariant)),
- q, SLOT(_q_jsonDbResponse(int,QVariant)),
- Qt::QueuedConnection);
- q->connect(&jsonDb, SIGNAL(error(int,int,QString)),
- q, SLOT(_q_jsonDbErrorResponse(int,int,QString)),
- Qt::QueuedConnection);
- q->connect(&jsonDb, SIGNAL(notified(QString,QVariant,QString)),
- q, SLOT(_q_jsonDbNotified(QString,QVariant,QString)),
- Qt::QueuedConnection);
- q->connect(q, SIGNAL(needAnotherChunk(int)), q, SLOT(_q_requestAnotherChunk(int)), Qt::QueuedConnection);
-}
-
-JsonDbListModelPrivate::~JsonDbListModelPrivate()
-{
- // Why do we need to do this while destroying the object
- if (!notifyUuid.isEmpty()) {
- QVariantMap notificationObject;
- notificationObject.insert("_uuid", notifyUuid);
- jsonDb.remove(notificationObject);
- }
-}
-
-void JsonDbListModelPrivate::clearCache(int newStart)
-{
- cacheStart = newStart;
- cacheEnd = newStart;
- objectUuids.clear();
- objectSortValues.clear();
- data.clear();
- cachedUuids.clear();
- lastFetchedItem.clear();
- lastFetchedIndex = -1;
-}
-
-int JsonDbListModelPrivate::makeSpaceFor(int count, int insertAt)
-{
- int itemsToRemove = itemsInCache() + count - maxCacheSize;
- // Check for unlimited cache
- if (maxCacheSize <= 0)
- itemsToRemove = 0;
- int index = 0;
- int newCacheStart = insertAt;
- int newCacheEnd = newCacheStart + count;
- if (newCacheStart == cacheEnd) {
- // adding elements in the end.
- } else if (newCacheEnd == cacheStart) {
- // adding elements in the beginning.
- index = itemsInCache() - itemsToRemove;
- } else if (newCacheStart >= cacheStart && newCacheEnd <= cacheEnd) {
- // adding elements within the cached elements
- // don't remove any, we should ignore duplicates.
- return 0;
- } else if (newCacheStart <= cacheStart && newCacheEnd >= cacheEnd) {
- // new cache will include the current one, so skip it
- return 0;
- } else if (newCacheEnd < cacheStart || newCacheStart > cacheEnd) {
- // we need to invalidate the cache, we only store elements in sequence.
- itemsToRemove = itemsInCache();
- clearCache(insertAt);
- return itemsToRemove;
- } else if (newCacheEnd < cacheEnd) {
- // adding items in the beginning, with overlap.
- itemsToRemove -= (newCacheEnd - cacheStart);
- index = itemsInCache() - itemsToRemove;
- } else if (newCacheStart > cacheStart) {
- // adding items towards the end, with overlap
- itemsToRemove -= (cacheEnd - newCacheStart);
- }
- if (itemsToRemove <= 0)
- return 0;
- for (int i = 0; i < itemsToRemove; i++) {
- const QString &uuid = cachedUuids.at(i+index);
- Q_ASSERT(objectSortValues.contains(uuid));
- const JsonDbSortKey &key = objectSortValues.value(uuid);
- Q_ASSERT(objectUuids.contains(key, uuid));
- objectUuids.remove(key, uuid);
- objectSortValues.remove(uuid);
- data.remove(uuid);
- }
- QList<QString>::iterator first = cachedUuids.begin()+index;
- QList<QString>::iterator last = first+itemsToRemove;
- cachedUuids.erase(first, last);
-
- if (index > 0)
- cacheEnd -= itemsToRemove;
- else
- cacheStart += itemsToRemove;
- return itemsToRemove;
-}
-
-JsonDbSortKey JsonDbListModelPrivate::sortKey(const QVariantMap &object)
-{
- return JsonDbSortKey(object, orderDirections, orderPaths);
-}
-
-// removes an item from the cache
-void JsonDbListModelPrivate::removeItem(int index)
-{
- if (cachedUuids.size() <= index) {
- qWarning() << "removeItem index not in cache";
- return;
- }
-
- const QString &uuid = cachedUuids[index];
- const JsonDbSortKey &key = objectSortValues.value(uuid);
- objectUuids.remove(key, uuid);
- objectSortValues.remove(uuid);
- data.remove(uuid);
- cachedUuids.removeAt(index);
- cacheEnd = qMax(cacheStart, cacheEnd-1);
-}
-
-// finds the object position within the cache limits
-int JsonDbListModelPrivate::findSortedPosition(const QString& uuid)
-{
- int pos = 0;
- QMap<JsonDbSortKey,QString>::const_iterator it;
- QMap<JsonDbSortKey,QString>::const_iterator end = objectUuids.end();
- for (it = objectUuids.begin(); it != end; it++, pos++) {
- if (it.value() == uuid)
- return pos;
- }
- // uuid not found in objectUuids
- return -1;
-}
-
-// insert item notification handler
-void JsonDbListModelPrivate::insertItem(const QVariantMap &item, bool emitSignals)
-{
- Q_Q(JsonDbListModel);
- Q_UNUSED(item);
-
- lastFetchedItem.clear();
- lastFetchedIndex = -1;
- clearCache(cacheStart);
- totalRowCount++;
- if (emitSignals) {
- // When a new item is added, the position of the item is not known
- // to the model. We will clear the cache and notify that an item
- // is added at the end + all data is changed.
- QModelIndex parent;
- q->beginInsertRows(parent, totalRowCount-1, totalRowCount-1);
- q->endInsertRows();
- emit q->countChanged();
- emit q->rowCountChanged();
- QModelIndex start = q->createIndex(0,0);
- QModelIndex end = q->createIndex(totalRowCount-1, 0);
- emit q->dataChanged(start, end);
- }
-}
-
-// deleteitem notification handler
-void JsonDbListModelPrivate::deleteItem(const QVariantMap &item, bool emitSignals)
-{
- Q_Q(JsonDbListModel);
-
- lastFetchedItem.clear();
- lastFetchedIndex = -1;
- const QString &uuid = item.value("_uuid", QString()).toString();
- int index = cachedUuids.indexOf(uuid);
- if (index != -1) {
- // When item is in the cache emit signals using the exact position.
- QModelIndex parent;
- if (emitSignals)
- q->beginRemoveRows(parent, cacheStart+index, cacheStart+index);
- removeItem(index);
- totalRowCount = qMax(0, totalRowCount -1);
- if (emitSignals) {
- q->endRemoveRows();
- emit q->countChanged();
- emit q->rowCountChanged();
- }
- } else {
- // Model dosen't know the position from where the item is deleted.
- // We will clear the cache and notify that an item is removed
- // from the end + all data is changed.
- QModelIndex parent;
- if (!totalRowCount)
- emitSignals = false;
- if (emitSignals)
- q->beginRemoveRows(parent, totalRowCount-1, totalRowCount-1);
- clearCache(cacheStart);
- totalRowCount = qMax(0, totalRowCount -1);
- if (emitSignals) {
- q->endRemoveRows();
- emit q->countChanged();
- emit q->rowCountChanged();
- QModelIndex start = q->createIndex(0,0);
- QModelIndex end = q->createIndex((totalRowCount ? totalRowCount-1 :0), 0);
- emit q->dataChanged(start, end);
- }
- }
-}
-
-// updateitem notification handler
-void JsonDbListModelPrivate::updateItem(const QVariantMap &item)
-{
- Q_Q(JsonDbListModel);
- lastFetchedItem.clear();
- lastFetchedIndex = -1;
- const QString &uuid = item.value("_uuid").toString();
- // if item is currently in cache.
- if (objectSortValues.contains(uuid)) {
- int currentIndex = findSortedPosition(uuid);
- deleteItem(item, false);
- insertItem(item, false);
- int newIndex = findSortedPosition(uuid);
- if (currentIndex == newIndex) {
- // emit signal for the changed item.
- QModelIndex modelIndex = q->createIndex(newIndex, 0);
- emit q->dataChanged(modelIndex, modelIndex);
- return;
- }
- }
- // We are not sure about the position of the updated item,
- // clear the cache and notify that all data is changed.
- clearCache(cacheStart);
- QModelIndex start = q->createIndex(0,0);
- QModelIndex end = q->createIndex((totalRowCount ? totalRowCount-1 :0), 0);
- emit q->dataChanged(start, end);
-}
-
-void JsonDbListModelPrivate::_q_requestAnotherChunk(int offset)
-{
- if (requestInProgress || query.isEmpty())
- return;
- int maxItemsToFetch = chunkSize;
- if (offset < 0) {
- maxItemsToFetch += offset;
- offset = 0;
- }
- newChunkOffset = offset;
- if (newChunkOffset >= cacheStart && newChunkOffset < cacheEnd)
- newChunkOffset = cacheEnd;
- // now fetch more
- QVariantMap request;
- request.insert(JsonDbString::kQueryStr, query);
- request.insert("offset", newChunkOffset);
- request.insert("limit", maxItemsToFetch);
- resetModel = false;
- requestIds.insert(jsonDb.find(request));
- requestInProgress = true;
-}
-
-void JsonDbListModelPrivate::fetchChunkSynchronous(int offset)
-{
- // Ignore previous reqests
- if (requestInProgress) {
- requestIds.clear();
- }
- Q_ASSERT(!query.isEmpty());
- int maxItemsToFetch = chunkSize;
- if (offset < 0) {
- maxItemsToFetch += offset;
- offset = 0;
- }
- newChunkOffset = offset;
- if (newChunkOffset >= cacheStart && newChunkOffset < cacheEnd)
- newChunkOffset = cacheEnd;
- // now fetch more
- QVariantMap request;
- request.insert(JsonDbString::kQueryStr, query);
- request.insert("offset", newChunkOffset);
- request.insert("limit", maxItemsToFetch);
- resetModel = false;
- requestInProgress = true;
- QVariantMap v = jsonDbConnection->sync(JsonDbConnection::makeQueryRequest(query, newChunkOffset, maxItemsToFetch)).toMap();
- requestInProgress = false;
- updateCache(v);
-}
-
-void JsonDbListModelPrivate::populateModel()
-{
- Q_Q(JsonDbListModel);
- clearCache();
- updateRecieved = false;
- totalRowCountRecieved = false;
- totalRowCount = 0;
- // Request the total count
- QVariantMap requestCount;
- QString countQuery = query+"[count]";
- requestCount.insert(JsonDbString::kQueryStr, countQuery);
-
- totalCountRequestId = jsonDb.find(requestCount);
-
- QVariantMap requestQuery;
- //Request at least 2 chunks of data
- requestQuery.insert(JsonDbString::kQueryStr, query);
- requestQuery.insert("offset", newChunkOffset);
- int itemsToGet = chunkSize*2;
- if (maxCacheSize)
- itemsToGet = qMin(itemsToGet, maxCacheSize);
- requestQuery.insert("limit",itemsToGet);
- resetModel = true;
- requestIds.insert(jsonDb.find(requestQuery));
- requestInProgress = true;
- state = JsonDbListModelPrivate::Querying;
- emit q->stateChanged();
-}
-
-QVariantMap JsonDbListModelPrivate::getItem(int index, bool handleCacheMiss, bool &cacheMiss)
-{
- QVariantMap item;
- if (index < 0 || index >= totalRowCount)
- return item;
- if (index < cacheStart || index >= cacheEnd) {
- DEBUG()<<"Index "<< index<<"Out of Range, fetch more...."<<cacheStart<<cacheEnd;
- // clear and fetch new set of items
- if (handleCacheMiss) {
- // clearing the cache is done by makeSpaceFor()
- fetchChunkSynchronous(qMax(index-(chunkSize/2), 0));
- } else {
- cacheMiss = true;
- return item;
- }
- }
-
- if (cachedUuids.size() <= (index - cacheStart)) {
- qWarning() << "Could not get Item";
- return item;
- }
- QString uuid = cachedUuids[index - cacheStart];
- item = data.value(uuid);
- if ((lowWaterMark > 0) && (data.size() < totalRowCount)) {
- if ((cacheEnd - index) < lowWaterMark) {
- _q_requestAnotherChunk(cacheEnd);
- } else if (cacheStart && (index - cacheStart) < lowWaterMark) {
- _q_requestAnotherChunk(qMax(cacheStart-chunkSize, 0));
- }
- }
- cacheMiss = false;
- lastFetchedItem = item;
- lastFetchedIndex = index;
- return item;
-}
-
-QVariantMap JsonDbListModelPrivate::getItem(const QModelIndex &modelIndex, int role,
- bool handleCacheMiss, bool &cacheMiss)
-{
- Q_UNUSED(role);
- return getItem(modelIndex.row(), handleCacheMiss, cacheMiss);
-}
-
-static QVariant lookupProperty(QVariantMap object, const QStringList &path)
-{
- if (!path.size()) {
- return QVariant();
- }
- QVariantMap emptyMap;
- QVariantList emptyList;
- QVariantList objectList;
- for (int i = 0; i < path.size() - 1; i++) {
- const QString &key = path.at(i);
- // this part of the property is a list
- if (!objectList.isEmpty()) {
- bool ok = false;
- int index = key.toInt(&ok);
- if (ok && (index >= 0) && (objectList.count() > index)) {
- if (objectList.at(index).type() == QVariant::List) {
- objectList = objectList.at(index).toList();
- object = emptyMap;
- } else {
- object = objectList.at(index).toMap();
- objectList = emptyList;
- }
- continue;
- }
- }
- // this part is a map
- if (object.contains(key)) {
- if (object.value(key).type() == QVariant::List) {
- objectList = object.value(key).toList();
- object = emptyMap;
- } else {
- object = object.value(key).toMap();
- objectList = emptyList;
- }
- } else {
- return QVariant();
- }
- }
- const QString &key = path.last();
- // get the last part from the list
- if (!objectList.isEmpty()) {
- bool ok = false;
- int index = key.toInt(&ok);
- if (ok && (index >= 0) && (objectList.count() > index)) {
- return objectList.at(index);
- }
- }
- // if the last part is in a map
- return object.value(key);
-}
-
-static QVariantMap updateProperty(QVariantMap item, const QStringList &propertyChain, QVariant value)
-{
- if (propertyChain.size() < 1) {
- qCritical() << "updateProperty" << "empty property chain" << item;
- } else if (propertyChain.size() == 1) {
- item.insert(propertyChain[0], value.toString());
- } else {
- QString property = propertyChain[0];
- QVariant newChild = updateProperty(item.value(property).toMap(), propertyChain.mid(1), value);
- item.insert(property, newChild);
- }
- return item;
-}
-
-/*!
- \qmlmodule QtAddOn.JsonDb 1.0
-
- QML interface to Json Database.
-*/
-
-/*!
- \qmltype JsonDbListModel
- \instantiates JsonDbListModel
- \ingroup qml-working-with-data
- \inqmlmodule QtAddOn.JsonDb 1.0
- \inherits ListModel
- \since 1.0
- \brief Provides a ListModel displaying data items matching a query.
-
- The JsonDbListModel provides a ListModel usable with views such as
- ListView or GridView displaying data items matching a query.
-
- \code
- JsonDbListModel {
- id: contactsModel
- query: "[?_type=\"Contact\"]"
- roleNames: ["firstName", "lastName", "phoneNumber"]
- }
- ListView {
- model: contactsModel
- Row {
- spacing: 10
- Text {
- text: firstName + " " + lastName
- }
- Text {
- text: phoneNumber
- }
- }
- }
- \endcode
-*/
-
-/*!
- \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::rowCount
-
- Returns the number of rows in the model.
-*/
-
-/*!
- \qmlproperty string QtAddOn.JsonDb::JsonDbListModel::query
-
- Returns the model's query.
-*/
-
-JsonDbListModel::JsonDbListModel(QObject *parent)
- : QAbstractListModel(parent), d_ptr(new JsonDbListModelPrivate(this))
-{
- Q_D(JsonDbListModel);
- d->init();
-}
-
-JsonDbListModel::~JsonDbListModel()
-{
-}
-
-void JsonDbListModel::classBegin()
-{
-}
-
-void JsonDbListModel::componentComplete()
-{
- Q_D(JsonDbListModel);
- d->componentComplete = true;
- if (!d->query.isEmpty()) {
- d->populateModel();
- }
-}
-
-void JsonDbListModelPrivate::createOrUpdateNotification()
-{
- if (!notifyUuid.isEmpty()) {
- QVariantMap notificationObject;
- notificationObject.insert("_uuid", notifyUuid);
- jsonDb.remove(notificationObject);
- notifyUuid.clear();
- }
-
- const JsonDbClient::NotifyTypes actions = JsonDbClient::NotifyCreate | JsonDbClient::NotifyUpdate | JsonDbClient::NotifyRemove;
- notificationObjectRequestIds.insert(jsonDb.notify(actions, query));
- DEBUG() << notificationObjectRequestIds;
-}
-
-/*!
- \qmlmethod QtAddOn.JsonDb::JsonDbListModel::sectionIndex(section, successCallback, errorCallback)
- */
-int JsonDbListModel::sectionIndex(const QString &section,
- const QJSValue &successCallback,
- const QJSValue &errorCallback)
-{
- Q_D(JsonDbListModel);
- // Find the count of items "< section"
- QString sectionCountQueryLT = d->queryWithoutSort+"[?"+d->orderProperties[0]+"<\""+section+"\"][count]";
- QVariantMap request;
- request.insert(JsonDbString::kQueryStr, sectionCountQueryLT);
- int id = d->jsonDb.find(request);
- // Register any valid callbacks
- CallbackInfo info;
- if (successCallback.isCallable()
- || errorCallback.isCallable()) {
- info.successCallback = successCallback;
- info.errorCallback = errorCallback;
- d->sectionIndexRequestIds.insert(id, info);
- }
- return id;
-}
-
-/*!
- \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::count
-
- Returns the number of items in the model.
-*/
-int JsonDbListModel::count() const
-{
- Q_D(const JsonDbListModel);
- return d->totalRowCount;
-}
-
-QModelIndex JsonDbListModel::index(int row, int , const QModelIndex &) const
-{
- return createIndex(row, 0);
-}
-
-int JsonDbListModel::rowCount(const QModelIndex &) const
-{
- Q_D(const JsonDbListModel);
- return d->totalRowCount;
-}
-
-QVariant JsonDbListModel::data(const QModelIndex &modelIndex, int role) const
-{
- Q_D(const JsonDbListModel);
- QVariantMap item;
- if (!(d->lastFetchedIndex == modelIndex.row()) || (d->lastFetchedIndex == -1)) {
- JsonDbListModel * pThis = const_cast<JsonDbListModel *>(this);
- bool cacheMiss = false;
- item = pThis->d_func()->getItem(modelIndex, role, true, cacheMiss);
- } else {
- item = d->lastFetchedItem;
- }
-
- QVariant result;
- QStringList property = d->properties[role];
- result = lookupProperty(item, property);
-
- return result;
-}
-
-QHash<int, QByteArray> JsonDbListModel::roleNames() const
-{
- Q_D(const JsonDbListModel);
- return d->roleNames;
-}
-
-void JsonDbListModel::set(int index, const QJSValue& valuemap,
- const QJSValue &successCallback,
- const QJSValue &errorCallback)
-{
- Q_D(JsonDbListModel);
- d->set(index, valuemap, successCallback, errorCallback);
-}
-
-void JsonDbListModelPrivate::set(int index, const QJSValue& valuemap,
- const QJSValue &successCallback,
- const QJSValue &errorCallback)
-{
- Q_Q(JsonDbListModel);
- if (!valuemap.isObject() || valuemap.isArray()) {
- qDebug() << q->tr("set: value is not an object");
- return;
- }
- // supports only changing an exixting item.
- if (index >= totalRowCount || index < 0) {
- qDebug() << q->tr("set: index %1 out of range").arg(index);
- return;
- }
-
- bool cacheMiss = false;
- QVariantMap item = getItem(index, false, cacheMiss);
- if (cacheMiss) {
- fetchChunkSynchronous(qMax(index-(chunkSize/2), 0));
- //TODO, do some error checking.
- item = getItem(index, false, cacheMiss);
- if (cacheMiss)
- DEBUG() << "Could not fetch item at index : %1" << index;
- }
-
- QJSValueIterator it(valuemap);
- while (it.hasNext()) {
- it.next();
- QString name = it.name();
- QVariant v = it.value().toVariant();
- int role = q->roleFromString(name);
- if (role == -1) {
- qDebug() << q->tr("set: property %1 invalid").arg(name);
- continue;
- }
- item = updateProperty(item, properties[role], v);
- }
-
- lastFetchedItem.clear();
- lastFetchedIndex = -1;
- // Item will be updated through the update notification
- CallbackInfo info;
- info.index = index;
- int id = jsonDb.update(item); // possibly change to variantToQson(item)..
- // Register any valid callbacks
- if (successCallback.isCallable()
- || errorCallback.isCallable()) {
- info.successCallback = successCallback;
- info.errorCallback = errorCallback;
- updateRequestIds.insert(id, info);
- }
-}
-
-void JsonDbListModel::setProperty(int index, const QString& property, const QVariant& value,
- const QJSValue &successCallback,
- const QJSValue &errorCallback)
-{
- Q_D(JsonDbListModel);
- d->setProperty(index, property, value, successCallback, errorCallback);
-}
-
-void JsonDbListModelPrivate::setProperty(int index, const QString& property, const QVariant& value,
- const QJSValue &successCallback,
- const QJSValue &errorCallback)
-{
- Q_Q(JsonDbListModel);
- // supports only changing an exixting item.
- if (index >= totalRowCount || index < 0) {
- qDebug() << q->tr("set: index %1 out of range").arg(index);
- return;
- }
-
- bool cacheMiss = false;
- QVariantMap item = getItem(index, false, cacheMiss);
- if (cacheMiss) {
- fetchChunkSynchronous(qMax(index-(chunkSize/2), 0));
- //TODO, do some error checking.
- item = getItem(index, false, cacheMiss);
- if (cacheMiss)
- DEBUG() << "Could not fetch item with index : " << index;
- }
-
- int role = q->roleFromString(property);
- if (role == -1) {
- qDebug() << q->tr("set: property %1 invalid").arg(property);
- return;
- }
- item = updateProperty(item, properties[role], value);
-
- lastFetchedItem.clear();
- lastFetchedIndex = -1;
-
- int id = jsonDb.update(item); // possibly change to variantToQson(item)..
- // Register any valid callbacks
- if (successCallback.isCallable()
- || errorCallback.isCallable()) {
-
- // Item will be updated through the update notification
- CallbackInfo info;
- info.index = index;
- info.successCallback = successCallback;
- info.errorCallback = errorCallback;
- updateRequestIds.insert(id, info);
- }
-}
-
-void JsonDbListModel::fetchMore(const QModelIndex &)
-{
- DEBUG() << endl;
-}
-
-bool JsonDbListModel::canFetchMore(const QModelIndex &) const
-{
- DEBUG() << endl;
- return false;
-}
-
-void JsonDbListModel::setQuery(const QString &newQuery)
-{
- Q_D(JsonDbListModel);
-
- const QString oldQuery = d->query;
- d->query = newQuery;
- d->state = JsonDbListModelPrivate::Querying;
- emit stateChanged();
- if (oldQuery != newQuery) {
- d->findSortOrder();
- }
-
- if (!d->componentComplete)
- return;
-
- d->populateModel();
-}
-
-/*!
- \qmlproperty string QtAddOn.JsonDb::JsonDbListModel::query
-
- Returns the query used by the model to fetch items from the database.
-
- In the following example, the \a JsonDbListModel would contain all the objects with \a _type contains the value \a "CONTACT"
-
- \qml
- JsonDbListModel {
- id: listModel
- query: "[?_type=\"CONTACT\"]"
- }
- \endqml
-
-*/
-QString JsonDbListModel::query() const
-{
- Q_D(const JsonDbListModel);
- return d->query;
-}
-
-void JsonDbListModel::setLimit(int newLimit)
-{
- Q_D(JsonDbListModel);
- d->maxCacheSize = newLimit;
-}
-
-/*!
- \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::limit
-
- The number of items to be cached.
-*/
-int JsonDbListModel::limit() const
-{
- Q_D(const JsonDbListModel);
- return d->maxCacheSize;
-}
-
-void JsonDbListModel::setChunkSize(int newChunkSize)
-{
- Q_D(JsonDbListModel);
- d->chunkSize = newChunkSize;
-}
-
-/*!
- \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::chunkSize
-
- The number of items to fetch at a time from the database.
-
- The model uses a heuristic to fetch only as many items as needed by
- the view. Each time it requests items it fetches \a chunkSize items.
-*/
-int JsonDbListModel::chunkSize() const
-{
- Q_D(const JsonDbListModel);
- return d->chunkSize;
-}
-
-void JsonDbListModel::setLowWaterMark(int newLowWaterMark)
-{
- Q_D(JsonDbListModel);
- d->lowWaterMark = newLowWaterMark;
-}
-
-/*!
- \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::lowWaterMark
-
- Controls when to fetch more items from the database.
-
- JsonDbListModel fetch \a chunkSize more items when the associated
- view requests an item within \a lowWaterMark from the end of the
- items previously fetched.
-*/
-int JsonDbListModel::lowWaterMark() const
-{
- Q_D(const JsonDbListModel);
- return d->lowWaterMark;
-}
-
-
-/*!
- \qmlproperty ListOrObject QtAddOn.JsonDb::JsonDbListModel::roleNames
-
- Controls which properties to expose from the objects matching the query.
-
- Setting \a roleNames to a list of strings causes the model to fetch
- those properties of the objects and expose them as roles to the
- delegate for each item viewed.
-
- \code
- JsonDbListModel {
- query: "[?_type=\"MyType\"]"
- roleNames: ['a', 'b']
- }
- ListView {
- model: listModel
- Text {
- text: a + ":" + b
- }
- \endcode
-
- Setting \a roleNames to a dictionary remaps properties in the object
- to the specified roles in the model.
-
- In the following example, role \a a would yield the value of
- property \a aLongName in the objects. Role \a liftedProperty would
- yield the value of \a o.nested.property for each matching object \a
- o in the database.
-
- \code
- function makeRoleNames() {
- return { 'a': 'aLongName', 'liftedProperty': 'nested.property' };
- }
- JsonDbListModel {
- id: listModel
- query: "[?_type=\"MyType\"]"
- roleNames: makeRoleNames()
- }
- ListView {
- model: listModel
- Text {
- text: a + " " + liftedProperty
- }
- }
- \endcode
-*/
-QVariant JsonDbListModel::scriptableRoleNames() const
-{
- Q_D(const JsonDbListModel);
-
- DEBUG() << d->roleMap;
- return d->roleMap;
-}
-
-QString removeArrayOperator(QString propertyName)
-{
- propertyName.replace(QLatin1Char('['), QLatin1Char('.'));
- propertyName.remove(QLatin1Char(']'));
- return propertyName;
-}
-
-void JsonDbListModel::setScriptableRoleNames(const QVariant &vroles)
-{
- Q_D(JsonDbListModel);
- d->properties.clear();
- d->roleNames.clear();
- if (vroles.type() == QVariant::Map) {
- QVariantMap roles = vroles.toMap();
- d->roleMap = roles;
- int i = 0;
- for (QVariantMap::const_iterator it = roles.begin(); it != roles.end(); ++it) {
- d->roleNames.insert(i, it.key().toLatin1());
- d->properties.insert(i, removeArrayOperator(it.value().toString()).split('.'));
- i++;
- }
- } else {
- QVariantList roleList = vroles.toList();
- d->roleMap.clear();
- for (int i = 0; i < roleList.size(); i++) {
- QString role = roleList[i].toString();
- d->roleMap[role] = role;
- d->roleNames.insert(i, role.toLatin1());
- d->properties.insert(i, removeArrayOperator(role).split('.'));
- }
- }
- DEBUG() << d->roleNames;
-}
-
-QString JsonDbListModel::state() const
-{
- Q_D(const JsonDbListModel);
- switch (d->state) {
- case JsonDbListModelPrivate::None:
- return QString("None");
- case JsonDbListModelPrivate::Querying:
- return QString("Querying");
- case JsonDbListModelPrivate::Ready:
- return QString("Ready");
- default:
- return QString("Error");
- }
-}
-
-QString JsonDbListModel::toString(int role) const
-{
- Q_D(const JsonDbListModel);
- if (d->roleNames.contains(role))
- return QString::fromLatin1(d->roleNames.value(role));
- else
- return QString();
-}
-
-int JsonDbListModel::roleFromString(const QString &roleName) const
-{
- Q_D(const JsonDbListModel);
- return d->roleNames.key(roleName.toLatin1(), -1);
-}
-
-void JsonDbListModelPrivate::updateCache(const QVariantMap &v)
-{
- Q_Q(JsonDbListModel);
- QVariantMap m = v;
- if (m.contains("data")) {
- QVariantList items = m.value("data").toList();
- int size = items.size();
- int sizeAdded = 0;
- if (size) {
- DEBUG()<<"OLD Cache Start"<<cacheStart<<"Cache End:"<<cacheEnd;
- if (resetModel)
- q->beginResetModel();
- makeSpaceFor(size, newChunkOffset);
- bool appendToCache = (newChunkOffset >= cacheEnd) ? true : false;
- int insertAt = appendToCache ? itemsInCache() : 0;
- DEBUG()<<"INSERT AT :"<<insertAt<<"Elements Retrieved:"<<size<<"ChunkOffset:"<<newChunkOffset<<appendToCache << itemsInCache();
- DEBUG()<<"Cache Start"<<cacheStart<<"Cache End:"<<cacheEnd<<"Total Rows = "<<totalRowCount;
- // Add the new result to cache.
- for (int i = 0; i < size; i++) {
- QVariantMap item = items.value(i).toMap();
- const QString &uuid = item.value(JsonDbString::kUuidStr).toString();
- if (objectSortValues.contains(uuid)){
- break;
- }
- JsonDbSortKey key = sortKey(item);
- objectUuids.insert(key, uuid);
- objectSortValues.insert(uuid, key);
- data[uuid] = item;
- cachedUuids.insert(insertAt++, uuid);
- sizeAdded++;
- }
- DEBUG()<<"sizeAdded:"<<sizeAdded;
- // Update the cache limits
- if (!itemsInCache()) {
- cacheStart = newChunkOffset;
- cacheEnd = cacheStart + sizeAdded;
- } else if (appendToCache) {
- cacheEnd += sizeAdded;
- } else {
- cacheStart = qMax(0, cacheStart-sizeAdded);
- }
- Q_ASSERT(cachedUuids.count() == data.count());
- }
- if (resetModel && totalRowCountRecieved)
- resetModelFinished();
- else
- updateRecieved = true;
- }
-}
-
-void JsonDbListModelPrivate::_q_jsonDbResponse(int id, const QVariant &v)
-{
- QVariantMap m = v.toMap();
- if (requestIds.contains(id)) {
- requestIds.remove(id);
- requestInProgress = false;
- updateCache(m);
- } else if (totalCountRequestId == id) {
- QVariantList items = m.value("data").toList();
- m = items.value(0).toMap();
- totalRowCount = m.value("count").toInt();
- totalRowCountRecieved = true;
- if (updateRecieved)
- resetModelFinished();
- } else if (notificationObjectRequestIds.contains(id)) {
- notificationObjectRequestIds.remove(id);
- notifyUuid = m.value(JsonDbString::kUuidStr).toString();
- } else if (updateRequestIds.constFind(id) != updateRequestIds.constEnd()) {
- CallbackInfo info = updateRequestIds.value(id);
- if (info.successCallback.isCallable()) {
- QJSValueList args;
- QJSValue scriptResult = info.successCallback.engine()->toScriptValue(id);
- args << scriptResult;
- scriptResult = info.successCallback.engine()->toScriptValue(info.index);
- args << scriptResult;
- info.successCallback.call(args);
- }
- updateRequestIds.remove(id);
- } else if (sectionIndexRequestIds.constFind(id) != sectionIndexRequestIds.constEnd()) {
- CallbackInfo info = sectionIndexRequestIds.value(id);
- if (info.successCallback.isCallable()) {
- QVariantList items = m.value("data").toList();
- m = items.value(0).toMap();
- QJSValueList args;
- QJSValue scriptResult = info.successCallback.engine()->toScriptValue(id);
- args << scriptResult;
- scriptResult = info.successCallback.engine()->toScriptValue(m.value("count").toInt());
- args << scriptResult;
- info.successCallback.call(args);
- }
- sectionIndexRequestIds.remove(id);
- }
-}
-
-void JsonDbListModelPrivate::resetModelFinished()
-{
- Q_Q(JsonDbListModel);
- q->endResetModel();
- emit q->countChanged();
- emit q->rowCountChanged();
- state = Ready;
- emit q->stateChanged();
- resetModel = false;
- pendingNotifications.clear();
- createOrUpdateNotification();
-}
-
-bool operator<(const QVariant& a, const QVariant& b)
-{
- if ((a.type() == QVariant::Int) && (b.type() == QVariant::Int))
- return a.toInt() < b.toInt();
- else if ((a.type() == QVariant::Double) && (b.type() == QVariant::Double))
- return a.toFloat() < b.toFloat();
- return (QString::compare( a.toString(), b.toString(), Qt::CaseInsensitive ) < 0);
-}
-
-bool operator>(const QVariant& a, const QVariant& b) { return b < a; }
-
-bool JsonDbListModelPrivate::findSortOrder()
-{
- QRegExp orderMatch("\\[([/\\\\[\\]])[ ]*([^\\[\\]]+)[ ]*\\]");
- orderDirections.clear();
- orderProperties.clear();
- orderPaths.clear();
- int matchIndex = 0, firstMatch = -1;
- DEBUG() << query;
- while ((matchIndex = orderMatch.indexIn(query, matchIndex)) >= 0) {
- orderDirections << orderMatch.cap(1);
- orderProperties << orderMatch.cap(2);
- orderPaths << orderMatch.cap(2).split('.');
- DEBUG() << matchIndex;
- if (firstMatch == -1)
- firstMatch = matchIndex;
- matchIndex += orderMatch.matchedLength();
- }
- queryWithoutSort = query.mid(0,firstMatch);
- if (orderPaths.isEmpty()) {
- orderDirections << "/";
- orderProperties << "_uuid";
- orderPaths << orderProperties[0].split('.');
- }
- DEBUG() << orderDirections << orderProperties << orderPaths;
- return true;
-}
-
-void JsonDbListModelPrivate::_q_jsonDbNotified(const QString& currentNotifyUuid, const QVariant &v, const QString &action)
-{
- QVariantMap item = v.toMap();
- if (currentNotifyUuid != notifyUuid) {
- return;
- }
- if (resetModel) {
- // we have not received the first chunk, wait for it before processing notifications
- NotifyItem pending;
- pending.notifyUuid = currentNotifyUuid;
- pending.item = item;
- pending.action = action;
- pendingNotifications.append(pending);
- return;
- }
- if (action == JsonDbString::kCreateStr) {
- insertItem(item);
- return ;
- } else if (action == JsonDbString::kRemoveStr) {
- deleteItem(item);
- return ;
- } else if (action == JsonDbString::kUpdateStr) {
- updateItem(item);
- return ;
- }
-
-}
-
-void JsonDbListModelPrivate::_q_jsonDbErrorResponse(int id, int code, const QString &message)
-{
- if (requestIds.contains(id)) {
- requestIds.remove(id);
- qWarning() << QString("JsonDb error: %1 %2").arg(code).arg(message);
- } else if (updateRequestIds.constFind(id) != updateRequestIds.constEnd()) {
- CallbackInfo info = updateRequestIds.value(id);
- if (info.errorCallback.isCallable()) {
- QJSValueList args;
- args << info.errorCallback.engine()->toScriptValue(id);
- args << info.errorCallback.engine()->toScriptValue(info.index);
- args << info.errorCallback.engine()->toScriptValue(code);
- args << info.errorCallback.engine()->toScriptValue(message);
- info.errorCallback.call(args);
- }
- updateRequestIds.remove(id);
- }
-}
-
-void JsonDbListModelPrivate::_q_jsonDbErrorResponse(int code, const QString &message)
-{
- qWarning() << QString("JsonDb error: %1 %2").arg(code).arg(message);
-}
-
-/*!
- \qmlmethod QVariant JsonDbListModel::get(int idx, const QString &property) const
- \since 1.0
-*/
-QVariant JsonDbListModel::get(int idx, const QString &property) const
-{
- int role = roleFromString(property);
- if (role >= 0)
- return data(index(idx, 0), role);
- else
- return QVariant();
-}
-
-
-class JsonDbSortKeyPrivate : public QSharedData {
-public:
- JsonDbSortKeyPrivate(QStringList directions, QVariantList keys) : mDirections(directions), mKeys(keys) {}
- const QStringList &directions() const { return mDirections; }
- const QVariantList &keys() const { return mKeys; }
-private:
- QStringList mDirections;
- QVariantList mKeys;
- JsonDbSortKeyPrivate(const JsonDbSortKeyPrivate&);
-};
-
-JsonDbSortKey::JsonDbSortKey()
-{
-}
-
-JsonDbSortKey::JsonDbSortKey(const QVariantMap &object, const QStringList &directions, const QList<QStringList> &paths)
-{
- QVariantList keys;
- for (int i = 0; i < paths.size(); i++)
- keys.append(lookupProperty(object, paths[i]));
- d = new JsonDbSortKeyPrivate(directions, keys);
-}
-
-JsonDbSortKey::JsonDbSortKey(const JsonDbSortKey&other)
- : d(other.d)
-{
-}
-
-const QVariantList &JsonDbSortKey::keys() const { return d->keys(); }
-const QStringList &JsonDbSortKey::directions() const { return d->directions(); }
-
-QString JsonDbSortKey::toString() const
-{
- QStringList result;
- for (int i = 0; i < d->keys().size(); i++) {
- result.append(QString("%1%2")
- .arg(d->directions()[i])
- .arg(d->keys()[i].toString()));
- }
- return result.join(", ");
-}
-
-bool operator <(const JsonDbSortKey &a, const JsonDbSortKey &b)
-{
- const QVariantList &akeys = a.keys();
- const QVariantList &bkeys = b.keys();
- const QStringList &adirs = a.directions();
- for (int i = 0; i < akeys.size(); i++) {
- const QVariant &akey = akeys[i];
- const QVariant &bkey = bkeys[i];
- if (akey != bkey) {
- if (adirs[i] == "/")
- return akey < bkey;
- else
- return akey > bkey;
- }
- }
- return false;
-}
-
-#include "moc_jsondb-listmodel.cpp"