File indexing completed on 2024-05-12 17:15:12

0001 /*
0002    Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LGPL.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 
0019    Alternatively, this file is available under the Mozilla Public License
0020    Version 1.1.  You may obtain a copy of the License at
0021    http://www.mozilla.org/MPL/
0022 */
0023 
0024 #include "argumentsmodel.h"
0025 
0026 #include "message.h"
0027 #include "arguments.h"
0028 
0029 #include <QStandardItemModel>
0030 
0031 static void addKeyValue(QStandardItem *parent, const char *k, bool isEmpty, const QVariant &v)
0032 {
0033     QStandardItem *key = new QStandardItem(QLatin1String(k));
0034     QStandardItem *value = new QStandardItem;
0035     value->setData(isEmpty ? QLatin1String("<nil>") : v, Qt::DisplayRole);
0036     parent->appendRow(QList<QStandardItem *>() << key << value);
0037 }
0038 
0039 // when isEmpty, str is an invalid pointer. getting the pointer is safe, only dereferencing is not.
0040 static void addKeyValue(QStandardItem *parent, const char *k, bool isEmpty, const char *str)
0041 {
0042     addKeyValue(parent, k, isEmpty, isEmpty ? QVariant() : QString::fromUtf8(str));
0043 }
0044 
0045 static QStandardItem *ascend(QStandardItem *parent, QStandardItemModel *model)
0046 {
0047     // the parent of a top-level item is null, not model->invisibleRootItem()...
0048     QStandardItem *newParent = parent->parent();
0049     return newParent ? newParent : model->invisibleRootItem();
0050 }
0051 
0052 static QStandardItem *descend(QStandardItem *parent, const QString &name)
0053 {
0054     QStandardItem *newParent = new QStandardItem(name);
0055     parent->appendRow(newParent);
0056     return newParent;
0057 }
0058 
0059 static QStandardItemModel *withFaultyData(QStandardItemModel *model)
0060 {
0061     model->removeRows(0, model->rowCount());
0062     model->appendRow(new QStandardItem(QLatin1String("bad data!")));
0063     return model;
0064 }
0065 
0066 static QStandardItemModel *withEmptyData(QStandardItemModel *model)
0067 {
0068     model->removeRows(0, model->rowCount());
0069     model->appendRow(new QStandardItem(QLatin1String("<no arguments>")));
0070     return model;
0071 }
0072 
0073 QAbstractItemModel* createArgumentsModel(Message *message)
0074 {
0075     QStandardItemModel *model = new QStandardItemModel();
0076     QStringList headerLabels = QStringList() << QLatin1String("Type") << QLatin1String("Value");
0077     model->setHorizontalHeaderLabels(headerLabels);
0078 
0079     if (!message) {
0080         return withEmptyData(model);
0081     }
0082 
0083     QStandardItem *parent = model->invisibleRootItem();
0084 
0085     Arguments::Reader reader(message->arguments());
0086     if (!reader.isValid()) {
0087         return withFaultyData(model);
0088     }
0089 
0090     bool isDone = false;
0091     // Cache it, don't call Reader::isInsideEmptyArray() on every data element.
0092     bool inEmptyArray = false;
0093 
0094     while (!isDone) {
0095         switch(reader.state()) {
0096         case Arguments::Finished:
0097             isDone = true;
0098             break;
0099         case Arguments::BeginStruct:
0100             reader.beginStruct();
0101             parent = descend(parent, "Struct");
0102             break;
0103         case Arguments::EndStruct:
0104             reader.endStruct();
0105             parent = ascend(parent, model);
0106             break;
0107         case Arguments::BeginVariant:
0108             reader.beginVariant();
0109             parent = descend(parent, "Variant");
0110             break;
0111         case Arguments::EndVariant:
0112             reader.endVariant();
0113             parent = ascend(parent, model);
0114             break;
0115         case Arguments::BeginArray: {
0116             inEmptyArray = !reader.beginArray(Arguments::Reader::ReadTypesOnlyIfEmpty);
0117             parent = descend(parent, inEmptyArray ? "Array (no elements, showing just types)" : "Array");
0118             break; }
0119         case Arguments::EndArray:
0120             reader.endArray();
0121             inEmptyArray = reader.isInsideEmptyArray();
0122             parent = ascend(parent, model);
0123             break;
0124         case Arguments::BeginDict: {
0125             inEmptyArray = !reader.beginDict(Arguments::Reader::ReadTypesOnlyIfEmpty);
0126             parent = descend(parent, inEmptyArray ? "Dict (no elements, showing just types)" : "Dict");
0127             break; }
0128         case Arguments::EndDict:
0129             reader.endDict();
0130             inEmptyArray = reader.isInsideEmptyArray();
0131             parent = ascend(parent, model);
0132             break;
0133         case Arguments::Byte:
0134             addKeyValue(parent, "byte", inEmptyArray, reader.readByte());
0135             break;
0136         case Arguments::Boolean:
0137             addKeyValue(parent, "boolean", inEmptyArray, reader.readBoolean());
0138             break;
0139         case Arguments::Int16:
0140             addKeyValue(parent, "int16", inEmptyArray, reader.readInt16());
0141             break;
0142         case Arguments::Uint16:
0143             addKeyValue(parent, "uint16", inEmptyArray, reader.readUint16());
0144             break;
0145         case Arguments::Int32:
0146             addKeyValue(parent, "int32", inEmptyArray, reader.readInt32());
0147             break;
0148         case Arguments::Uint32:
0149             addKeyValue(parent, "uint32", inEmptyArray, reader.readUint32());
0150             break;
0151         case Arguments::Int64:
0152             addKeyValue(parent, "int64", inEmptyArray, reader.readInt64());
0153             break;
0154         case Arguments::Uint64:
0155             addKeyValue(parent, "uint64", inEmptyArray, reader.readUint64());
0156             break;
0157         case Arguments::Double:
0158             addKeyValue(parent, "double", inEmptyArray, reader.readDouble());
0159             break;
0160         case Arguments::String:
0161             addKeyValue(parent, "string", inEmptyArray, reader.readString().ptr);
0162             break;
0163         case Arguments::ObjectPath:
0164             addKeyValue(parent, "object path", inEmptyArray, reader.readObjectPath().ptr);
0165             break;
0166         case Arguments::Signature:
0167             addKeyValue(parent, "type signature", inEmptyArray, reader.readSignature().ptr);
0168             break;
0169         case Arguments::UnixFd:
0170             addKeyValue(parent, "file descriptor", inEmptyArray, reader.readUnixFd());
0171             break;
0172         case Arguments::InvalidData:
0173         case Arguments::NeedMoreData:
0174         default:
0175             return withFaultyData(model);
0176             break;
0177         }
0178     }
0179 
0180     if (!model->rowCount()) {
0181         return withEmptyData(model);
0182     }
0183     return model;
0184 }