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