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 }