"Fossies" - the Fresh Open Source Software Archive

Member "labplot-2.8.2/src/backend/datasources/filters/QJsonModel.cpp" (24 Feb 2021, 10198 Bytes) of package /linux/privat/labplot-2.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "QJsonModel.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.1_vs_2.8.2.

    1 /*
    2  * The MIT License (MIT)
    3  *
    4  * Copyright (c) 2011 SCHUTZ Sacha
    5  * Copyright (C) 2020 Alexander Semke (alexander.semke@web.de)
    6  *
    7  * Permission is hereby granted, free of charge, to any person obtaining a copy
    8  * of this software and associated documentation files (the "Software"), to deal
    9  * in the Software without restriction, including without limitation the rights
   10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11  * copies of the Software, and to permit persons to whom the Software is
   12  * furnished to do so, subject to the following conditions:
   13  *
   14  * The above copyright notice and this permission notice shall be included in all
   15  * copies or substantial portions of the Software.
   16  *
   17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   23  * SOFTWARE.
   24  */
   25 
   26 #include "QJsonModel.h"
   27 #include "backend/lib/trace.h"
   28 
   29 #include <QFile>
   30 #include <QMessageBox>
   31 #include <QPainter>
   32 
   33 #include <KLocalizedString>
   34 
   35 QJsonTreeItem::QJsonTreeItem(QJsonTreeItem* parent) : mParent(parent) {}
   36 
   37 QJsonTreeItem::~QJsonTreeItem() {
   38     qDeleteAll(mChildren);
   39 }
   40 
   41 void QJsonTreeItem::appendChild(QJsonTreeItem* item) {
   42     mChildren.append(item);
   43 }
   44 
   45 void QJsonTreeItem::reserve(int size) {
   46     mChildren.reserve(size);
   47 }
   48 
   49 QJsonTreeItem* QJsonTreeItem::child(int row) {
   50     return mChildren.value(row);
   51 }
   52 
   53 QJsonTreeItem* QJsonTreeItem::parent() {
   54     return mParent;
   55 }
   56 
   57 int QJsonTreeItem::childCount() const {
   58     return mChildren.count();
   59 }
   60 
   61 int QJsonTreeItem::row() const {
   62     if (mParent)
   63         return mParent->mChildren.indexOf(const_cast<QJsonTreeItem*>(this));
   64 
   65     return 0;
   66 }
   67 
   68 void QJsonTreeItem::setKey(const QString& key) {
   69     mKey = key;
   70 }
   71 
   72 void QJsonTreeItem::setValue(const QString& value) {
   73     mValue = value;
   74 }
   75 
   76 void QJsonTreeItem::setType(const QJsonValue::Type type) {
   77     mType = type;
   78 }
   79 
   80 void QJsonTreeItem::setSize(int size) {
   81     mSize = size;
   82 }
   83 
   84 const QString& QJsonTreeItem::key() const {
   85     return mKey;
   86 }
   87 
   88 const QString& QJsonTreeItem::value() const {
   89     return mValue;
   90 }
   91 
   92 QJsonValue::Type QJsonTreeItem::type() const {
   93     return mType;
   94 }
   95 
   96 int QJsonTreeItem::size() const {
   97     return mSize;
   98 }
   99 
  100 QJsonTreeItem* QJsonTreeItem::load(const QJsonValue& value, QJsonTreeItem* parent) {
  101     auto* rootItem = new QJsonTreeItem(parent);
  102 //  rootItem->setKey("root");
  103 
  104     if (value.isObject()) {
  105         const auto& object = value.toObject();
  106 
  107         //determine the size
  108         rootItem->setSize(QJsonDocument(object).toJson(QJsonDocument::Compact).size());
  109 
  110         //read all children
  111         for (const QString& key : object.keys()) {
  112             const QJsonValue& v = object.value(key);
  113             QJsonTreeItem* child = load(v,rootItem);
  114             child->setKey(key);
  115             child->setType(v.type());
  116             rootItem->appendChild(child);
  117         }
  118     } else if (value.isArray()) {
  119         const auto& array = value.toArray();
  120         rootItem->setSize(QJsonDocument(array).toJson(QJsonDocument::Compact).size());
  121 
  122         int index = 0;
  123         rootItem->reserve(array.count());
  124         for (const QJsonValue& v : array) {
  125             QJsonTreeItem* child = load(v, rootItem);
  126             child->setKey(QString::number(index));
  127             child->setType(v.type());
  128             rootItem->appendChild(child);
  129             ++index;
  130         }
  131     } else {
  132         const QString& str = value.toVariant().toString();
  133         rootItem->setValue(str);
  134         rootItem->setType(value.type());
  135         rootItem->setSize(str.length());
  136     }
  137 
  138     return rootItem;
  139 }
  140 
  141 //=========================================================================
  142 
  143 QJsonModel::QJsonModel(QObject* parent) : QAbstractItemModel(parent),
  144     mHeadItem(new QJsonTreeItem),
  145     mRootItem(new QJsonTreeItem(mHeadItem)) {
  146 
  147     mHeadItem->appendChild(mRootItem);
  148     mHeaders.append(i18n("Key"));
  149     mHeaders.append(i18n("Value"));
  150     mHeaders.append(i18n("Size in Bytes"));
  151 
  152     //icons
  153     QPainter painter;
  154     QPixmap pix(64, 64);
  155 
  156     QFont font;
  157     font.setPixelSize(60);
  158 
  159     const QColor& color = qApp->palette().color(QPalette::Text);
  160     painter.setPen(QPen(color));
  161 
  162     //draw the icon for JSON array
  163     pix.fill(QColor(Qt::transparent));
  164     painter.begin(&pix);
  165     painter.setFont(font);
  166     painter.drawText(pix.rect(), Qt::AlignCenter, QLatin1String("[ ]"));
  167     painter.end();
  168     mArrayIcon = QIcon(pix);
  169 
  170     //draw the icon for JSON object
  171     pix.fill(QColor(Qt::transparent));
  172     painter.begin(&pix);
  173     painter.setFont(font);
  174     painter.drawText(pix.rect(), Qt::AlignCenter, QLatin1String("{ }"));
  175     painter.end();
  176     mObjectIcon = QIcon(pix);
  177 }
  178 
  179 QJsonModel::~QJsonModel() {
  180     //delete mRootItem;
  181     delete mHeadItem;
  182 }
  183 
  184 void QJsonModel::clear() {
  185     beginResetModel();
  186     delete mHeadItem;
  187     mHeadItem = new QJsonTreeItem;
  188     mRootItem = new QJsonTreeItem(mHeadItem);
  189     mHeadItem->appendChild(mRootItem);
  190     endResetModel();
  191 }
  192 
  193 bool QJsonModel::load(const QString& fileName) {
  194     QFile file(fileName);
  195     bool success = false;
  196     if (file.open(QIODevice::ReadOnly)) {
  197         success = load(&file);
  198         file.close();
  199     } else
  200         success = false;
  201 
  202     return success;
  203 }
  204 
  205 bool QJsonModel::load(QIODevice* device) {
  206     return loadJson(device->readAll());
  207 }
  208 
  209 bool QJsonModel::loadJson(const QByteArray& json) {
  210     QJsonParseError error;
  211 
  212     const QJsonDocument& doc = QJsonDocument::fromJson(json, &error);
  213     if (error.error == QJsonParseError::NoError)
  214         return loadJson(doc);
  215     else {
  216         QMessageBox::critical(nullptr, i18n("Failed to load JSON document"),
  217                               i18n("Failed to load JSON document. Error: %1.", error.errorString()));
  218         return false;
  219     }
  220 
  221 }
  222 
  223 bool QJsonModel::loadJson(const QJsonDocument& jdoc) {
  224     PERFTRACE("load json document into the model");
  225     if (!jdoc.isNull()) {
  226         beginResetModel();
  227         delete mHeadItem;
  228 
  229         mHeadItem = new QJsonTreeItem;
  230 
  231         if (jdoc.isArray()) {
  232             {
  233             PERFTRACE("load json tree items");
  234             mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.array()), mHeadItem);
  235             }
  236             mRootItem->setType(QJsonValue::Array);
  237 
  238         } else {
  239             mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.object()), mHeadItem);
  240             mRootItem->setType(QJsonValue::Object);
  241         }
  242 
  243         mHeadItem->appendChild(mRootItem);
  244 
  245         endResetModel();
  246         return true;
  247     }
  248 
  249     return false;
  250 }
  251 
  252 QVariant QJsonModel::data(const QModelIndex& index, int role) const {
  253     if (!index.isValid())
  254         return QVariant();
  255 
  256     auto* item = static_cast<QJsonTreeItem*>(index.internalPointer());
  257 
  258     if (role == Qt::DisplayRole) {
  259         if (index.column() == 0)
  260             return item->key();
  261         else if (index.column() == 1) {
  262             //in case the value is very long, cut it so the preview tree tree view doesnt' explode
  263             if (item->value().length() > 200)
  264                 return item->value().left(200) + QLatin1String(" ...");
  265             else
  266                 return item->value();
  267         } else {
  268             if (item->size() != 0)
  269                 return QString::number(item->size());
  270             else
  271                 return QString();
  272         }
  273     } else if (Qt::EditRole == role) {
  274         if (index.column() == 1)
  275             return item->value();
  276     } else if (role == Qt::DecorationRole) {
  277         if (index.column() == 0) {
  278             if (item->type() == QJsonValue::Array)
  279                 return mArrayIcon;
  280             else if (item->type() == QJsonValue::Object)
  281                 return mObjectIcon;
  282         }
  283     }
  284 
  285     return QVariant();
  286 }
  287 
  288 bool QJsonModel::setData(const QModelIndex& index, const QVariant& value, int role) {
  289     if (Qt::EditRole == role) {
  290         if (index.column() == 1) {
  291             auto* item = static_cast<QJsonTreeItem*>(index.internalPointer());
  292             item->setValue(value.toString());
  293             emit dataChanged(index, index, {Qt::EditRole});
  294             return true;
  295         }
  296     }
  297 
  298     return false;
  299 }
  300 
  301 QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const {
  302     if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
  303         return mHeaders.value(section);
  304 
  305     return QVariant();
  306 }
  307 
  308 QModelIndex QJsonModel::index(int row, int column, const QModelIndex& parent) const {
  309     if (!hasIndex(row, column, parent))
  310         return QModelIndex{};
  311 
  312     QJsonTreeItem* parentItem;
  313 
  314     if (!parent.isValid())
  315         parentItem = mHeadItem;
  316     else
  317         parentItem = static_cast<QJsonTreeItem*>(parent.internalPointer());
  318 
  319     QJsonTreeItem* childItem = parentItem->child(row);
  320     if (childItem)
  321         return createIndex(row, column, childItem);
  322 
  323     return QModelIndex{};
  324 }
  325 
  326 QModelIndex QJsonModel::parent(const QModelIndex& index) const {
  327     if (!index.isValid())
  328         return QModelIndex{};
  329 
  330     auto* childItem = static_cast<QJsonTreeItem*>(index.internalPointer());
  331     QJsonTreeItem* parentItem = childItem->parent();
  332 
  333     if (parentItem == mHeadItem)
  334         return QModelIndex{};
  335 
  336     return createIndex(parentItem->row(), 0, parentItem);
  337 }
  338 
  339 int QJsonModel::rowCount(const QModelIndex& parent) const {
  340     QJsonTreeItem* parentItem;
  341     if (parent.column() > 0)
  342         return 0;
  343 
  344     if (!parent.isValid())
  345         parentItem = mHeadItem;
  346     else
  347         parentItem = static_cast<QJsonTreeItem*>(parent.internalPointer());
  348 
  349     return parentItem->childCount();
  350 }
  351 
  352 int QJsonModel::columnCount(const QModelIndex& parent) const {
  353     Q_UNUSED(parent)
  354     return 3;
  355 }
  356 
  357 Qt::ItemFlags QJsonModel::flags(const QModelIndex& index) const {
  358     if (index.column() == 1)
  359         return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
  360     else
  361         return QAbstractItemModel::flags(index);
  362 }
  363 /*
  364 QJsonDocument QJsonModel::json() const {
  365     auto v = genJson(mRootItem);
  366     QJsonDocument doc;
  367 
  368     if (v.isObject())
  369         doc = QJsonDocument(v.toObject());
  370     else
  371         doc = QJsonDocument(v.toArray());
  372 
  373     return doc;
  374 }
  375 */
  376 QJsonValue QJsonModel::genJson(QJsonTreeItem* item) const {
  377     auto type = item->type();
  378     const int nchild = item->childCount();
  379 
  380     if (QJsonValue::Object == type) {
  381         QJsonObject jo;
  382         for (int i = 0; i < nchild; ++i) {
  383             auto ch = item->child(i);
  384             auto key = ch->key();
  385             jo.insert(key, genJson(ch));
  386         }
  387         return  jo;
  388     } else if (QJsonValue::Array == type) {
  389         QJsonArray arr;
  390         for (int i = 0; i < nchild; ++i) {
  391             auto ch = item->child(i);
  392             arr.append(genJson(ch));
  393         }
  394         return arr;
  395     } else {
  396         QJsonValue va(item->value());
  397         return va;
  398     }
  399 
  400 }
  401 
  402 QJsonDocument QJsonModel::genJsonByIndex(const QModelIndex& index) const {
  403     if (!index.isValid())
  404         return QJsonDocument();
  405 
  406     auto* item = static_cast<QJsonTreeItem*>(index.internalPointer());
  407     return QJsonDocument::fromVariant(genJson(item).toVariant());
  408 }