153
|
1 /****************************************************************************
|
|
2 **
|
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 ** Contact: Qt Software Information (qt-info@nokia.com)
|
|
5 **
|
|
6 ** This file is part of the examples of the Qt Toolkit.
|
|
7 **
|
|
8 ** $QT_BEGIN_LICENSE:LGPL$
|
|
9 ** Commercial Usage
|
|
10 ** Licensees holding valid Qt Commercial licenses may use this file in
|
|
11 ** accordance with the Qt Commercial License Agreement provided with the
|
|
12 ** Software or, alternatively, in accordance with the terms contained in
|
|
13 ** a written agreement between you and Nokia.
|
|
14 **
|
|
15 ** GNU Lesser General Public License Usage
|
|
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
17 ** General Public License version 2.1 as published by the Free Software
|
|
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
19 ** packaging of this file. Please review the following information to
|
|
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
22 **
|
|
23 ** In addition, as a special exception, Nokia gives you certain
|
|
24 ** additional rights. These rights are described in the Nokia Qt LGPL
|
|
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|
26 ** package.
|
|
27 **
|
|
28 ** GNU General Public License Usage
|
|
29 ** Alternatively, this file may be used under the terms of the GNU
|
|
30 ** General Public License version 3.0 as published by the Free Software
|
|
31 ** Foundation and appearing in the file LICENSE.GPL included in the
|
|
32 ** packaging of this file. Please review the following information to
|
|
33 ** ensure the GNU General Public License version 3.0 requirements will be
|
|
34 ** met: http://www.gnu.org/copyleft/gpl.html.
|
|
35 **
|
|
36 ** If you are unsure which license is appropriate for your use, please
|
|
37 ** contact the sales department at qt-sales@nokia.com.
|
|
38 ** $QT_END_LICENSE$
|
|
39 **
|
|
40 ****************************************************************************/
|
|
41 module treemodel;
|
|
42
|
|
43
|
|
44 import qt.core.QAbstractItemModel;
|
|
45 import qt.core.QModelIndex;
|
|
46 import qt.core.QVariant;
|
|
47
|
|
48 import treeitem;
|
|
49
|
|
50 import tango.core.Array : find;
|
|
51 import tango.text.Util : trim;
|
|
52
|
|
53
|
|
54 //replacement for QString.split
|
|
55 T[][] split(T)(T[] str, T[] match, bool keep_empty = true)
|
|
56 {
|
|
57 uint pos, start = 0;
|
|
58
|
|
59 T[][] values;
|
|
60 if(str.length == 0)
|
|
61 return values;
|
|
62
|
|
63 while(true)
|
|
64 {
|
|
65 pos = start + find(str[start..$], match);
|
|
66 if(keep_empty)
|
|
67 {
|
|
68 if((pos - start) >= 0)
|
|
69 values ~= str[start..pos];
|
|
70 }
|
|
71 else
|
|
72 {
|
|
73 if((pos - start) != 0)
|
|
74 values ~= str[start..pos];
|
|
75 }
|
|
76
|
|
77 if(pos == str.length)
|
|
78 break;
|
|
79
|
|
80 start = pos + 1;
|
|
81 }
|
|
82
|
|
83 return values;
|
|
84 }
|
|
85
|
|
86
|
|
87 class TreeModel : public QAbstractItemModel
|
|
88 {
|
|
89 public:
|
|
90
|
|
91 this(string[] headers, string data, QObject parent = null)
|
|
92 {
|
|
93 super(parent);
|
|
94 QVariant[] rootData;
|
|
95 foreach(string header; headers)
|
|
96 rootData ~= new QVariant(header);
|
|
97
|
|
98 rootItem = new TreeItem(rootData);
|
|
99 setupModelData(split(data, "\n"), rootItem);
|
|
100 }
|
|
101
|
|
102 ~this()
|
|
103 {
|
|
104 delete rootItem;
|
|
105 }
|
|
106
|
|
107 QVariant data(QModelIndex index, int role)
|
|
108 {
|
|
109 if (!index.isValid())
|
|
110 return new QVariant();
|
|
111
|
|
112 if (role != Qt.DisplayRole && role != Qt.EditRole)
|
|
113 return new QVariant();
|
|
114
|
|
115 TreeItem item = getItem(index);
|
|
116 return item.data(index.column());
|
|
117 }
|
|
118
|
|
119 QVariant headerData(int section, Qt.Orientation orientation, int role = Qt.DisplayRole)
|
|
120 {
|
|
121 if (orientation == Qt.Horizontal && role == Qt.DisplayRole)
|
|
122 return rootItem.data(section);
|
|
123
|
|
124 return new QVariant();
|
|
125 }
|
|
126
|
|
127 QModelIndex index(int row, int column, QModelIndex parent = QModelIndex())
|
|
128 {
|
|
129 if (parent.isValid() && parent.column() != 0)
|
|
130 return QModelIndex();
|
|
131
|
|
132 TreeItem parentItem = getItem(parent);
|
|
133
|
|
134 TreeItem childItem = parentItem.child(row);
|
|
135 if (childItem)
|
|
136 return createIndex(row, column, cast(void*) childItem);
|
|
137 else
|
|
138 return QModelIndex();
|
|
139 }
|
|
140
|
|
141 QModelIndex parent(QModelIndex index)
|
|
142 {
|
|
143 if (!index.isValid())
|
|
144 return QModelIndex();
|
|
145
|
|
146 TreeItem childItem = getItem(index);
|
|
147 TreeItem parentItem = childItem.parent();
|
|
148
|
|
149 if (parentItem == rootItem)
|
|
150 return QModelIndex();
|
|
151
|
|
152 return createIndex(parentItem.childNumber(), 0, cast(void*) parentItem);
|
|
153 }
|
|
154
|
|
155 int rowCount(QModelIndex parent = QModelIndex())
|
|
156 {
|
|
157 TreeItem parentItem = getItem(parent);
|
|
158 return parentItem.childCount();
|
|
159 }
|
|
160
|
|
161 int columnCount(QModelIndex parent = QModelIndex())
|
|
162 {
|
|
163 return rootItem.columnCount();
|
|
164 }
|
|
165
|
|
166 int flags(QModelIndex index)
|
|
167 {
|
|
168 if (!index.isValid())
|
|
169 return 0;
|
|
170
|
|
171 return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable;
|
|
172 }
|
|
173
|
|
174
|
|
175 bool setData(QModelIndex index, QVariant value, int role = Qt.EditRole)
|
|
176 {
|
|
177 if (role != Qt.EditRole)
|
|
178 return false;
|
|
179
|
|
180 TreeItem item = getItem(index);
|
|
181 bool result = item.setData(index.column(), value);
|
|
182
|
|
183 if (result)
|
|
184 dataChanged.emit(index, index);
|
|
185
|
|
186 return result;
|
|
187 }
|
|
188
|
|
189 bool setHeaderData(int section, Qt.Orientation orientation, QVariant value, int role = Qt.EditRole)
|
|
190 {
|
|
191 if (role != Qt.EditRole || orientation != Qt.Horizontal)
|
|
192 return false;
|
|
193
|
|
194 bool result = rootItem.setData(section, value);
|
|
195
|
|
196 if (result)
|
|
197 headerDataChanged.emit(orientation, section, section);
|
|
198
|
|
199 return result;
|
|
200 }
|
|
201
|
|
202 bool insertColumns(int position, int columns, QModelIndex parent = QModelIndex())
|
|
203 {
|
|
204 bool success;
|
|
205
|
|
206 beginInsertColumns(parent, position, position + columns - 1);
|
|
207 success = rootItem.insertColumns(position, columns);
|
|
208 endInsertColumns();
|
|
209
|
|
210 return success;
|
|
211 }
|
|
212
|
|
213
|
|
214 bool removeColumns(int position, int columns, QModelIndex parent = QModelIndex())
|
|
215 {
|
|
216 bool success;
|
|
217
|
|
218 beginRemoveColumns(parent, position, position + columns - 1);
|
|
219 success = rootItem.removeColumns(position, columns);
|
|
220 endRemoveColumns();
|
|
221
|
|
222 if (rootItem.columnCount() == 0)
|
|
223 removeRows(0, rowCount());
|
|
224
|
|
225 return success;
|
|
226 }
|
|
227
|
|
228
|
|
229 bool insertRows(int position, int rows, QModelIndex parent = QModelIndex())
|
|
230 {
|
|
231 TreeItem parentItem = getItem(parent);
|
|
232 bool success;
|
|
233
|
|
234 beginInsertRows(parent, position, position + rows - 1);
|
|
235 success = parentItem.insertChildren(position, rows, rootItem.columnCount());
|
|
236 endInsertRows();
|
|
237
|
|
238 return success;
|
|
239 }
|
|
240
|
|
241 bool removeRows(int position, int rows, QModelIndex parent = QModelIndex())
|
|
242 {
|
|
243 TreeItem parentItem = getItem(parent);
|
|
244 bool success = true;
|
|
245
|
|
246 beginRemoveRows(parent, position, position + rows - 1);
|
|
247 success = parentItem.removeChildren(position, rows);
|
|
248 endRemoveRows();
|
|
249
|
|
250 return success;
|
|
251 }
|
|
252
|
|
253 private:
|
|
254
|
|
255 void setupModelData(string[] lines, TreeItem parent)
|
|
256 {
|
|
257 TreeItem[] parents;
|
|
258 int[] indentations;
|
|
259 parents ~= parent;
|
|
260 indentations ~= 0;
|
|
261
|
|
262 int number = 0;
|
|
263
|
|
264 while (number < lines.length) {
|
|
265 int position = 0;
|
|
266 while (position < lines[number].length) {
|
|
267 if (lines[number][position] != ' ')
|
|
268 break;
|
|
269 position++;
|
|
270 }
|
|
271
|
|
272 string lineData = trim(lines[number][position..$]);
|
|
273
|
|
274 if (lineData.length) {
|
|
275 // Read the column data from the rest of the line.
|
|
276 string[] columnStrings = split(lineData, "\t", false);
|
|
277 QVariant[] columnData;
|
|
278 for (int column = 0; column < columnStrings.length; ++column)
|
|
279 columnData ~= new QVariant(columnStrings[column]);
|
|
280
|
|
281 if (position > indentations[$-1]) {
|
|
282 // The last child of the current parent is now the new parent
|
|
283 // unless the current parent has no children.
|
|
284
|
|
285 if (parents[$-1].childCount() > 0) {
|
|
286 parents ~= parents[$-1].child(parents[$-1].childCount()-1);
|
|
287 indentations ~= position;
|
|
288 }
|
|
289 } else {
|
|
290 while (position < indentations[$-1] && parents.length > 0) {
|
|
291 parents = parents[0..$-1];
|
|
292 indentations = indentations[0..$-1];
|
|
293 }
|
|
294 }
|
|
295
|
|
296 // Append a new item to the current parent's list of children.
|
|
297 parent = parents[$-1];
|
|
298 parent.insertChildren(parent.childCount(), 1, rootItem.columnCount());
|
|
299 for (int column = 0; column < columnData.length; ++column)
|
|
300 parent.child(parent.childCount() - 1).setData(column, columnData[column]);
|
|
301 }
|
|
302
|
|
303 number++;
|
|
304 }
|
|
305 }
|
|
306
|
|
307 TreeItem getItem(QModelIndex index)
|
|
308 {
|
|
309 if (index.isValid()) {
|
|
310 TreeItem item = cast(TreeItem) index.internalPointer();
|
|
311 if (item) return item;
|
|
312 }
|
|
313 return rootItem;
|
|
314 }
|
|
315
|
|
316 TreeItem rootItem;
|
|
317 }
|