1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51/*
52 treemodel.cpp
53
54 Provides a simple tree model to show how to create and use hierarchical
55 models.
56*/
57
58#include "treemodel.h"
59#include "treeitem.h"
60
61#include <QStringList>
62
63//! [0]
64TreeModel::TreeModel(const QString &data, QObject *parent)
65 : QAbstractItemModel(parent)
66{
67 rootItem = new TreeItem({tr("Title"), tr("Summary")});
68 setupModelData(data.split('\n'), rootItem);
69}
70//! [0]
71
72//! [1]
73TreeModel::~TreeModel()
74{
75 delete rootItem;
76}
77//! [1]
78
79//! [2]
80int TreeModel::columnCount(const QModelIndex &parent) const
81{
82 if (parent.isValid())
83 return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
84 return rootItem->columnCount();
85}
86//! [2]
87
88//! [3]
89QVariant TreeModel::data(const QModelIndex &index, int role) const
90{
91 if (!index.isValid())
92 return QVariant();
93
94 if (role != Qt::DisplayRole)
95 return QVariant();
96
97 TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
98
99 return item->data(index.column());
100}
101//! [3]
102
103//! [4]
104Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
105{
106 if (!index.isValid())
107 return Qt::NoItemFlags;
108
109 return QAbstractItemModel::flags(index);
110}
111//! [4]
112
113//! [5]
114QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
115 int role) const
116{
117 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
118 return rootItem->data(section);
119
120 return QVariant();
121}
122//! [5]
123
124//! [6]
125QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
126{
127 if (!hasIndex(row, column, parent))
128 return QModelIndex();
129
130 TreeItem *parentItem;
131
132 if (!parent.isValid())
133 parentItem = rootItem;
134 else
135 parentItem = static_cast<TreeItem*>(parent.internalPointer());
136
137 TreeItem *childItem = parentItem->child(row);
138 if (childItem)
139 return createIndex(row, column, childItem);
140 return QModelIndex();
141}
142//! [6]
143
144//! [7]
145QModelIndex TreeModel::parent(const QModelIndex &index) const
146{
147 if (!index.isValid())
148 return QModelIndex();
149
150 TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
151 TreeItem *parentItem = childItem->parentItem();
152
153 if (parentItem == rootItem)
154 return QModelIndex();
155
156 return createIndex(parentItem->row(), 0, parentItem);
157}
158//! [7]
159
160//! [8]
161int TreeModel::rowCount(const QModelIndex &parent) const
162{
163 TreeItem *parentItem;
164 if (parent.column() > 0)
165 return 0;
166
167 if (!parent.isValid())
168 parentItem = rootItem;
169 else
170 parentItem = static_cast<TreeItem*>(parent.internalPointer());
171
172 return parentItem->childCount();
173}
174//! [8]
175
176void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
177{
178 QList<TreeItem *> parents;
179 QList<int> indentations;
180 parents << parent;
181 indentations << 0;
182
183 int number = 0;
184
185 while (number < lines.count()) {
186 int position = 0;
187 while (position < lines[number].length()) {
188 if (lines[number].at(position) != ' ')
189 break;
190 position++;
191 }
192
193 const QString lineData = lines[number].mid(position).trimmed();
194
195 if (!lineData.isEmpty()) {
196 // Read the column data from the rest of the line.
197 const QStringList columnStrings =
198 lineData.split(QLatin1Char('\t'), Qt::SkipEmptyParts);
199 QList<QVariant> columnData;
200 columnData.reserve(columnStrings.count());
201 for (const QString &columnString : columnStrings)
202 columnData << columnString;
203
204 if (position > indentations.last()) {
205 // The last child of the current parent is now the new parent
206 // unless the current parent has no children.
207
208 if (parents.last()->childCount() > 0) {
209 parents << parents.last()->child(parents.last()->childCount()-1);
210 indentations << position;
211 }
212 } else {
213 while (position < indentations.last() && parents.count() > 0) {
214 parents.pop_back();
215 indentations.pop_back();
216 }
217 }
218
219 // Append a new item to the current parent's list of children.
220 parents.last()->appendChild(new TreeItem(columnData, parents.last()));
221 }
222 ++number;
223 }
224}
225