JsonTreeModel Implementation  v0.1.0
A Qt tree model for visualizing and manipulating a JSON document.
jsontreemodel.h
Go to the documentation of this file.
1 /*\
2  * Copyright (c) 2018 Sze Howe Koh
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 \*/
8 
9 #ifndef JSONTREEMODEL_H
10 #define JSONTREEMODEL_H
11 
12 #include <QAbstractItemModel>
13 #include <QJsonObject>
14 #include <QJsonArray>
15 
16 //=================================
17 // JsonTreeModelNode and subclasses
18 //=================================
19 /*
20  If only we could get a QJsonValueRef to a nested item,
21  we wouldn't need such "heavy" node classes...
22 */
23 /*
24  TODO: Support user-defined Structure and Scalar column names
25  TODO: Support user-defined icons for different datatypes in Structure column???
26  TODO: Support user-defined font for Array indices in Structure column???
27 */
29 {
30 public:
31  enum Type {
35  };
36 
38  virtual ~JsonTreeModelNode() {}
39 
40  inline JsonTreeModelNode* parent() const
41  { return m_parent; }
42 
44  { Q_ASSERT(parent->type() != Scalar); m_parent = parent; }
45 
46  virtual Type type() const = 0;
47  virtual QJsonValue value() const = 0;
48 
49 private:
50  // NOTE: Only JsonTreeModelListNode can be a parent, but I don't want to introduce a dependency to a subclass
51  JsonTreeModelNode* m_parent;
52 };
53 
55 {
56 public:
58 
59  QJsonValue value() const override
60  { return m_value; }
61 
62  void setValue(const QJsonValue& value)
63  { m_value = value; }
64 
65  Type type() const override
66  { return Scalar; }
67 
68 private:
69  QJsonValue m_value;
70 };
71 
73 {
74 public:
76  JsonTreeModelListNode(const QJsonArray& array, JsonTreeModelNode* parent);
77 
79  {
80  // TODO: Tell parent to remove this child from its list? Only if we do partial deletions
81  qDeleteAll(m_childList);
82  }
83 
84  inline JsonTreeModelNode* childAt(int i) const
85  { return m_childList[i]; }
86 
87  inline int childCount() const
88  { return m_childList.count(); }
89 
90  inline int childPosition(JsonTreeModelNode* child) const
91  { return m_childPositions.value(child, -1); }
92 
93  Type type() const override
94  { return Array; }
95 
96  QJsonValue value() const override;
97 
98 protected:
99  void registerChild(JsonTreeModelNode* child);
100  void deregisterChild(JsonTreeModelNode* child);
101 
102 private:
103  QVector<JsonTreeModelNode*> m_childList;
104  QMap<JsonTreeModelNode*, int> m_childPositions;
105 };
106 
108 {
109 public:
110  JsonTreeModelNamedListNode(const QJsonObject& object, JsonTreeModelNode* parent);
111 
112  inline QString childListNodeName(JsonTreeModelNode* child) const
113  { return m_childListNodeNames[child]; }
114 
115  inline int namedScalarCount() const
116  { return m_namedScalarMap.size(); }
117 
118  inline QJsonValue namedScalarValue(const QString& name) const
119  { return m_namedScalarMap[name]; }
120 
121  inline void setNamedScalarValue(const QString& name, const QJsonValue& value)
122  {
123  Q_ASSERT(value.type() != QJsonValue::Undefined && value.type() != QJsonValue::Array && value.type() != QJsonValue::Object);
124  m_namedScalarMap[name] = value;
125  }
126 
127  Type type() const override
128  { return Object; }
129 
130  QJsonValue value() const override;
131 
132 private:
133  // TODO: Use JsonTreeModelListNode::childPosition() for indexing; not need for map with m_childListNodeNames
134  QMap<JsonTreeModelNode*, QString> m_childListNodeNames;
135  QMap<QString, QJsonValue> m_namedScalarMap;
136 };
137 
139 {
140 public:
142 
143  QJsonValue value() const override
144  { return childAt(0)->value(); } // ASSUMPTION: A wrapper node will always have exactly 1 child JsonTreeModelNamedListNode
145 };
146 
147 
148 //=================================
149 // JsonTreeModel itself
150 //=================================
151 class JsonTreeModel : public QAbstractItemModel
152 {
153  Q_OBJECT
154 
155 public:
156  // TODO: Add flag to sort the keys, or leave them in the order of discovery
158  {
162  };
163 
164  explicit JsonTreeModel(QObject* parent = nullptr);
165  ~JsonTreeModel() override { delete m_rootNode; }
166 
167  // Header:
168  QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
169 
170  // Basic functionality:
171  QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
172  QModelIndex parent(const QModelIndex& index) const override;
173 
174  int rowCount(const QModelIndex& parent = QModelIndex()) const override;
175  int columnCount(const QModelIndex& parent = QModelIndex()) const override;
176 
177  QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
178 
179  // Editable:
180  bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
181  Qt::ItemFlags flags(const QModelIndex& index) const override;
182 
183  // API specific to JsonTreeModel:
184  void setJson(const QJsonArray& array, ScalarColumnSearchMode searchMode = QuickSearch);
185  void setJson(const QJsonObject& object, ScalarColumnSearchMode searchMode = QuickSearch);
186  QJsonValue json(const QModelIndex& index = QModelIndex()) const;
187 
188  // TODO: Decide if the json()/setJson() API should be symmetrical or not
189 
190  void setScalarColumns(const QStringList& columns);
191  QStringList scalarColumns() const { return m_headers.mid(2); }
192 
193 private:
194  bool isEditable(const QModelIndex& index) const;
195 
196  JsonTreeModelListNode* m_rootNode;
197  QStringList m_headers;
198 };
199 
200 #endif // JSONTREEMODEL_H
The JsonTreeModel class provides a data model for a JSON document.
Definition: jsontreemodel.h:151
QJsonValue json(const QModelIndex &index=QModelIndex()) const
Returns the JSON value under the given index.
Definition: jsontreemodel.cpp:805
int namedScalarCount() const
Returns the number of scalar elements within this node.
Definition: jsontreemodel.h:115
JsonTreeModelNode(JsonTreeModelNode *parent)
Constructs a new node with the given parent.
Definition: jsontreemodel.h:37
QJsonValue value() const override
Returns the JSON object represented by this node.
Definition: jsontreemodel.cpp:305
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Returns data under the given index for the specified role.
Definition: jsontreemodel.cpp:602
int childPosition(JsonTreeModelNode *child) const
Returns index number of the specified child, or -1 if the child does not belong to this node...
Definition: jsontreemodel.h:90
JsonTreeModelNode * parent() const
Returns this node&#39;s parent.
Definition: jsontreemodel.h:40
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows under the given parent.
Definition: jsontreemodel.cpp:558
ScalarColumnSearchMode
This enum controls how setJson() updates the model&#39;s column headers.
Definition: jsontreemodel.h:157
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Definition: jsontreemodel.cpp:491
Definition: jsontreemodel.h:159
~JsonTreeModel() override
Destroys the JsonTreeModel and frees its memory.
Definition: jsontreemodel.h:165
The JsonTreeModelWrapperNode class wraps a top-level JsonTreeModelNamedListNode, to allow its scalar ...
Definition: jsontreemodel.h:138
Type type() const override
Returns JsonTreeModelNode::Scalar.
Definition: jsontreemodel.h:65
QModelIndex parent(const QModelIndex &index) const override
Definition: jsontreemodel.cpp:529
~JsonTreeModelListNode() override
Definition: jsontreemodel.h:78
QJsonValue value() const override
Returns the JSON structure (array or object) represented by this node.
Definition: jsontreemodel.cpp:179
JsonTreeModelNode * childAt(int i) const
Returns the child node at index i.
Definition: jsontreemodel.h:84
Type
This enum describes the type of data represented by a JsonTreeModelNode.
Definition: jsontreemodel.h:31
Definition: jsontreemodel.h:160
JsonTreeModelScalarNode(const QJsonValue &value, JsonTreeModelNode *parent)
Constructs a node under the specified parent to represent the specified scalar value.
Definition: jsontreemodel.cpp:73
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition: jsontreemodel.cpp:727
void setValue(const QJsonValue &value)
Replaces the value represented by this node.
Definition: jsontreemodel.h:62
QJsonValue value() const override
Returns the scalar JSON value represented by this node.
Definition: jsontreemodel.h:59
JsonTreeModelNamedListNode(const QJsonObject &object, JsonTreeModelNode *parent)
Constructs a node under the specified parent to represent the specified JSON object.
Definition: jsontreemodel.cpp:236
void setNamedScalarValue(const QString &name, const QJsonValue &value)
Adds or updates a scalar element of the JSON object represented by this node.
Definition: jsontreemodel.h:121
void setJson(const QJsonArray &array, ScalarColumnSearchMode searchMode=QuickSearch)
Sets the whole model&#39;s internal data structure to the given JSON array.
Definition: jsontreemodel.cpp:846
QString childListNodeName(JsonTreeModelNode *child) const
Definition: jsontreemodel.h:112
virtual QJsonValue value() const =0
Returns the JSON value represented by this node and its children (if any).
JsonTreeModelNamedListNode represents a JSON object.
Definition: jsontreemodel.h:107
virtual Type type() const =0
Type type() const override
Returns JsonTreeModelNode::Array.
Definition: jsontreemodel.h:93
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Definition: jsontreemodel.cpp:660
Represents scalar JSON values (nulls, Booleans, numbers, and strings).
Definition: jsontreemodel.h:32
int childCount() const
Returns the number of child nodes under this row.
Definition: jsontreemodel.h:87
QStringList scalarColumns() const
Returns the names of the JSON objects&#39; scalar members that are shown by the model.
Definition: jsontreemodel.h:191
JsonTreeModelScalarNode is the most basic element of a JsonTreeModel&#39;s internal data.
Definition: jsontreemodel.h:54
JsonTreeModel(QObject *parent=nullptr)
Constructs an empty JsonTreeModel with the given parent.
Definition: jsontreemodel.cpp:474
JsonTreeModelListNode represents a JSON structure (namely an array or an object) and provides the bac...
Definition: jsontreemodel.h:72
void registerChild(JsonTreeModelNode *child)
Puts the child node under this node&#39;s hierarchy.
Definition: jsontreemodel.cpp:193
void deregisterChild(JsonTreeModelNode *child)
Removes the child node from this node&#39;s hierarchy.
Definition: jsontreemodel.cpp:206
QJsonValue value() const override
Returns the JSON object represented by the wrapped node.
Definition: jsontreemodel.h:143
virtual ~JsonTreeModelNode()
Frees the memory held by this node and its children.
Definition: jsontreemodel.h:38
void setScalarColumns(const QStringList &columns)
Sets the JSON objects&#39; scalar members that are shown by the model.
Definition: jsontreemodel.cpp:918
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: jsontreemodel.cpp:505
JsonTreeModelNode is the base class for the internal data structure behind JsonTreeModel.
Definition: jsontreemodel.h:28
Definition: jsontreemodel.h:161
Represents JSON objects.
Definition: jsontreemodel.h:33
QJsonValue namedScalarValue(const QString &name) const
Returns the scalar element in this node which has the given name.
Definition: jsontreemodel.h:118
JsonTreeModelWrapperNode(JsonTreeModelNamedListNode *realNode)
Constructs a wrapper for realNode and takes ownership of it.
Definition: jsontreemodel.cpp:326
Represents JSON arrays.
Definition: jsontreemodel.h:34
void setParent(JsonTreeModelNode *parent)
Makes this node a child of parent.
Definition: jsontreemodel.h:43
Type type() const override
Returns JsonTreeModelNode::Object.
Definition: jsontreemodel.h:127
JsonTreeModelListNode(JsonTreeModelNode *parent)
Constructs an empty JsonTreeModelListNode under the specified parent.
Definition: jsontreemodel.h:75
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns in the model.
Definition: jsontreemodel.cpp:580