/* * The MIT License (MIT) * * Copyright (c) 2011 SCHUTZ Sacha * Copyright (c) 2020 Kali Kaneko * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include "qjsonmodel.h" std::mutex mtx; QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent) { mParent = parent; } QJsonTreeItem::~QJsonTreeItem() { qDeleteAll(mChilds); } void QJsonTreeItem::appendChild(QJsonTreeItem *item) { mChilds.append(item); } QJsonTreeItem *QJsonTreeItem::child(int row) { return mChilds.value(row); } QJsonTreeItem *QJsonTreeItem::parent() { return mParent; } int QJsonTreeItem::childCount() const { return mChilds.count(); } int QJsonTreeItem::row() const { if (mParent) return mParent->mChilds.indexOf(const_cast(this)); return 0; } void QJsonTreeItem::setKey(const QString &key) { mKey = key; } void QJsonTreeItem::setValue(const QString &value) { mValue = value; } void QJsonTreeItem::setType(const QJsonValue::Type &type) { mType = type; } QString QJsonTreeItem::key() const { return mKey; } QString QJsonTreeItem::value() const { return mValue; } QJsonValue::Type QJsonTreeItem::type() const { return mType; } QJsonTreeItem* QJsonTreeItem::load(const QJsonValue& value, QJsonTreeItem* parent) { QJsonTreeItem * rootItem = new QJsonTreeItem(parent); rootItem->setKey("root"); if ( value.isObject()) { //Get all QJsonValue childs for (QString key : value.toObject().keys()){ QJsonValue v = value.toObject().value(key); QJsonTreeItem * child = load(v,rootItem); child->setKey(key); child->setType(v.type()); rootItem->appendChild(child); } } else if ( value.isArray()) { //Get all QJsonValue childs int index = 0; for (QJsonValue v : value.toArray()){ QJsonTreeItem * child = load(v,rootItem); child->setKey(QString::number(index)); child->setType(v.type()); rootItem->appendChild(child); ++index; } } else { rootItem->setValue(value.toVariant().toString()); rootItem->setType(value.type()); } return rootItem; } //========================================================================= QJsonModel::QJsonModel(QObject *parent) : QAbstractItemModel(parent) , mRootItem{new QJsonTreeItem} { mHeaders.append("key"); mHeaders.append("value"); } QJsonModel::QJsonModel(const QString& fileName, QObject *parent) : QAbstractItemModel(parent) , mRootItem{new QJsonTreeItem} { mHeaders.append("key"); mHeaders.append("value"); load(fileName); } QJsonModel::QJsonModel(QIODevice * device, QObject *parent) : QAbstractItemModel(parent) , mRootItem{new QJsonTreeItem} { mHeaders.append("key"); mHeaders.append("value"); load(device); } QJsonModel::QJsonModel(const QByteArray& json, QObject *parent) : QAbstractItemModel(parent) , mRootItem{new QJsonTreeItem} { mHeaders.append("key"); mHeaders.append("value"); loadJson(json); } QJsonModel::~QJsonModel() { delete mRootItem; } bool QJsonModel::load(const QString &fileName) { QFile file(fileName); bool success = false; if (file.open(QIODevice::ReadOnly)) { success = load(&file); file.close(); } else success = false; return success; } bool QJsonModel::load(QIODevice *device) { return loadJson(device->readAll()); } bool QJsonModel::loadJson(const QByteArray &json) { mtx.lock(); auto const& jdoc = QJsonDocument::fromJson(json); bool ok = false; if (!jdoc.isNull()) { beginResetModel(); delete mRootItem; if (jdoc.isArray()) { mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.array())); mRootItem->setType(QJsonValue::Array); } else { mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.object())); mRootItem->setType(QJsonValue::Object); } endResetModel(); emit dataChanged(QModelIndex(), QModelIndex(), {}); ok = true; } if (!ok) { qDebug()<(index.internalPointer()); switch (role) { case Roles::KeyRole: return item->key(); case Roles::ValueRole: return item->value(); case Qt::DisplayRole: { if (index.column() == 0) return QString("%1").arg(item->key()); else if (index.column() == 1) return QString("%1").arg(item->value()); else return QString(""); } case Qt::EditRole: { if (index.column() == 1) return QString("%1").arg(item->value()); else return QString(""); } default: return QVariant(); } return QVariant(); } bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int role) { int col = index.column(); if (Qt::EditRole == role) { if (col == 1) { QJsonTreeItem *item = static_cast(index.internalPointer()); item->setValue(value.toString()); emit dataChanged(index, index, {Qt::EditRole}); return true; } } return false; } QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { return mHeaders.value(section); } else return QVariant(); } QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); QJsonTreeItem *parentItem; if (!parent.isValid()) parentItem = mRootItem; else parentItem = static_cast(parent.internalPointer()); QJsonTreeItem *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex QJsonModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); QJsonTreeItem *childItem = static_cast(index.internalPointer()); QJsonTreeItem *parentItem = childItem->parent(); if (parentItem == mRootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } int QJsonModel::rowCount(const QModelIndex &parent) const { QJsonTreeItem *parentItem; if (parent.column() > 0) return 0; if (!parent.isValid()) parentItem = mRootItem; else parentItem = static_cast(parent.internalPointer()); return parentItem->childCount(); } int QJsonModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 2; } Qt::ItemFlags QJsonModel::flags(const QModelIndex &index) const { int col = index.column(); auto item = static_cast(index.internalPointer()); auto isArray = QJsonValue::Array == item->type(); auto isObject = QJsonValue::Object == item->type(); if ((col == 1) && !(isArray || isObject)) { return Qt::ItemIsEditable | QAbstractItemModel::flags(index); } else { return QAbstractItemModel::flags(index); } } QJsonDocument QJsonModel::json() const { mtx.lock(); auto v = genJson(mRootItem); QJsonDocument doc; if (v.isObject()) { doc = QJsonDocument(v.toObject()); } else { doc = QJsonDocument(v.toArray()); } mtx.unlock(); return doc; } QJsonValue QJsonModel::genJson(QJsonTreeItem * item) const { auto type = item->type(); int nchild = item->childCount(); if (QJsonValue::Object == type) { QJsonObject jo; for (int i = 0; i < nchild; ++i) { auto ch = item->child(i); auto key = ch->key(); jo.insert(key, genJson(ch)); } return jo; } else if (QJsonValue::Array == type) { QJsonArray arr; for (int i = 0; i < nchild; ++i) { auto ch = item->child(i); arr.append(genJson(ch)); } return arr; } else { QJsonValue va(item->value()); return va; } } QHash QJsonModel::roleNames() const { QHash roles; roles[Roles::KeyRole] = "key"; roles[Roles::ValueRole] = "value"; return roles; } QByteArray QJsonModel::getJson() { return ((QJsonDocument)(this->json())).toJson(); }