Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "featuretreemodel.h"
43#include "feature.h"
44#include <QPalette>
45#include <QColor>
46#include <QApplication>
47#include <QtDebug>
48
49QT_BEGIN_NAMESPACE
50
51class Node
52{
53public:
54 Node(Feature *f, Node *p = 0) : feature(f), parent(p) {}
55 ~Node();
56 Node* find(const Feature *child) const;
57 bool contains(const Feature *child) const { return find(child) != 0; }
58 bool insert(Node *n);
59
60 Feature *feature;
61 Node *parent;
62 QList<Node*> children; // maybe convert to Map to get keys sorted
63};
64
65Node::~Node()
66{
67 while (!children.isEmpty())
68 delete children.takeFirst();
69}
70
71Node* Node::find(const Feature *f) const
72{
73 if (this->feature == f)
74 return const_cast<Node*>(this);
75
76 foreach (Node *n, children)
77 if (Node *m = n->find(f))
78 return m;
79
80 return 0;
81}
82
83static bool nodePtrLessThan(const Node *n1, const Node *n2)
84{
85 return (n1->feature->key() < n2->feature->key());
86}
87
88/*
89 Try insert \a n into the tree with this node as root.
90 n is inserted as a child if it has a dependency to this node.
91 Returns true if child is inserted into the tree, false otherwise.
92*/
93bool Node::insert(Node *n)
94{
95 Feature *f = const_cast<Feature*>(n->feature);
96 if (feature->supports().contains(f)) {
97 children.append(n);
98 qSort(children.begin(), children.end(), nodePtrLessThan);
99 n->parent = this;
100 return true;
101 }
102 foreach (Node *child, children)
103 if (child->insert(n))
104 return true;
105 return false;
106}
107
108static bool isSection(const QModelIndex &index)
109{
110 return index.isValid() && (index.internalId() == 0);
111}
112
113FeatureTreeModel::FeatureTreeModel(QObject *parent)
114 : QAbstractItemModel(parent)
115{
116}
117
118FeatureTreeModel::~FeatureTreeModel()
119{
120 foreach (QString section, sections.keys())
121 while (!sections[section].isEmpty())
122 delete sections[section].takeFirst();
123}
124
125/*
126 Returns true if the model already contains \a in \a section, false otherwise.
127*/
128bool FeatureTreeModel::contains(const QString &section, const Feature *f) const
129{
130 return (find(section, f) != 0);
131}
132
133Node* FeatureTreeModel::find(const QString &section, const Feature *f) const
134{
135 QList<Node*> roots = sections[section];
136 foreach (Node *root, roots)
137 if (Node *n = root->find(f))
138 return n;
139 return 0;
140}
141
142/*
143 Add new \a feature to the tree.
144 When all feature is added, buildTree() must be called to build the
145 dependency tree.
146*/
147void FeatureTreeModel::addFeature(Feature *feature)
148{
149 const QString section = feature->section();
150 Q_ASSERT(!contains(section, feature));
151
152 connect(feature, SIGNAL(changed()), this, SLOT(featureChanged()));
153
154 Node *node = new Node(feature, 0);
155
156 // try insert any toplevel nodes as child of this one
157 foreach (Node *n, sections[section])
158 if (node->insert(n))
159 sections[section].removeAll(n);
160
161 // try insert this node as a child of any existing node
162 foreach (Node *n, sections[section])
163 if (n->insert(node)) {
164 emit layoutChanged();
165 return;
166 }
167
168 // not a child, insert as a toplevel node
169 sections[section].append(node);
170 qSort(sections[section].begin(), sections[section].end(), nodePtrLessThan);
171 emit layoutChanged();
172}
173
174QModelIndex FeatureTreeModel::createIndex(int row, int column,
175 const QModelIndex &parent,
176 const Node *node) const
177{
178 QModelIndex index = QAbstractItemModel::createIndex(row, column,
179 (void*)node);
180 if (parent.isValid())
181 parentMap[index] = parent;
182 if (node)
183 featureIndexMap[node->feature] = index;
184 return index;
185}
186
187QModelIndex FeatureTreeModel::index(int row, int column,
188 const QModelIndex &parent) const
189{
190 if (!parent.isValid()) { // index is a section
191 if (row < sections.size() && column == 0)
192 return QAbstractItemModel::createIndex(row, column, 0);
193 return QModelIndex();
194 }
195
196 if (isSection(parent)) { // index is a toplevel feature
197 const int parentRow = parent.row();
198 if (parentRow < sections.size()) {
199 QString section = sections.keys().at(parentRow);
200 QList<Node*> nodes = sections[section];
201 if (row < nodes.size() && column < 2)
202 return createIndex(row, column, parent, nodes.at(row));
203 }
204 return QModelIndex();
205 }
206
207 // parent is a feature
208 Node *parentNode = static_cast<Node*>(parent.internalPointer());
209 QList<Node*> children = parentNode->children;
210 if (row < children.size() && column < 2)
211 return createIndex(row, column, parent, children.at(row));
212
213 return QModelIndex();
214}
215
216QModelIndex FeatureTreeModel::index(const QModelIndex &parent,
217 const Feature *feature) const
218{
219 const int rows = rowCount(parent);
220 for (int i = 0; i < rows; ++i) {
221 QModelIndex child = index(i, 0, parent);
222 Node *node = static_cast<Node*>(child.internalPointer());
223 if (node && node->feature == feature)
224 return child;
225 QModelIndex childSearch = index(child, feature);
226 if (childSearch.isValid())
227 return childSearch;
228 }
229 return QModelIndex();
230}
231
232QModelIndex FeatureTreeModel::index(const Feature *feature) const
233{
234 if (featureIndexMap.contains(feature))
235 return featureIndexMap.value(feature);
236
237 // exhaustive search
238 int sectionRow = sections.keys().indexOf(feature->section());
239 QModelIndex sectionIndex = index(sectionRow, 0, QModelIndex());
240
241 return index(sectionIndex, feature);
242}
243
244QModelIndex FeatureTreeModel::parent(const QModelIndex &index) const
245{
246 if (!index.isValid())
247 return QModelIndex();
248
249 if (parentMap.contains(index))
250 return parentMap.value(index);
251 return QModelIndex();
252}
253
254int FeatureTreeModel::rowCount(const QModelIndex &parent) const
255{
256 if (!parent.isValid())
257 return sections.size();
258
259 if (isSection(parent)) {
260 const QString section = sections.keys().at(parent.row());
261 return sections[section].size();
262 }
263
264 const Node *node = static_cast<Node*>(parent.internalPointer());
265 return node->children.size();
266}
267
268int FeatureTreeModel::columnCount(const QModelIndex &parent) const
269{
270#if 0
271 if (!parent.isValid())
272 return 0;
273
274 if (isSection(parent))
275 return 1;
276#endif
277 Q_UNUSED(parent);
278 return 2; // Feature: [key, name]
279}
280
281QVariant FeatureTreeModel::data(const QModelIndex &index, int role) const
282{
283 if (!index.isValid())
284 return QVariant();
285
286 const Node *node = static_cast<Node*>(index.internalPointer());
287
288 switch (role) {
289 case Qt::DisplayRole: {
290 if (node == 0) // index is a section
291 return sections.keys().at(index.row());
292 if (index.column() == 0)
293 return node->feature->key();
294 Q_ASSERT(index.column() == 1);
295 return node->feature->title();
296 }
297 case Qt::CheckStateRole: {
298 if (node && index.column() == 0)
299 return (node->feature->enabled() ?
300 Qt::Checked : Qt::Unchecked);
301 break;
302 }
303 case Qt::TextColorRole: {
304 if (node && index.column() == 0) // feature key
305 if (node->feature->selectable())
306 return QApplication::palette().color(QPalette::Link);
307 break;
308 }
309 case Qt::TextAlignmentRole:
310 case Qt::BackgroundColorRole:
311 case Qt::FontRole:
312 case Qt::ToolTipRole: // TODO
313 case Qt::StatusTipRole: // TODO
314 case Qt::WhatsThisRole: // TODO
315 case Qt::DecorationRole:
316 case Qt::EditRole:
317 default:
318 break;
319 }
320 return QVariant();
321}
322
323bool FeatureTreeModel::setData(const QModelIndex &index,
324 const QVariant &value, int role)
325{
326 if (!index.isValid())
327 return false;
328
329 Node *node = static_cast<Node*>(index.internalPointer());
330 if (!node)
331 return false;
332
333 if (role == Qt::CheckStateRole) {
334 Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
335 if (state == Qt::Checked)
336 node->feature->setEnabled(true);
337 else if (state == Qt::Unchecked)
338 node->feature->setEnabled(false);
339 emit dataChanged(index, index);
340 return true;
341 }
342 return false;
343}
344
345Qt::ItemFlags FeatureTreeModel::flags(const QModelIndex &index) const
346{
347 if (!index.isValid() || index.internalPointer() == 0)
348 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
349
350 const Node *node = static_cast<Node*>(index.internalPointer());
351 const Feature *feature = node->feature;
352 Qt::ItemFlags flags = Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
353
354 if (feature->selectable())
355 flags |= Qt::ItemIsEnabled;
356
357 return flags;
358}
359
360QVariant FeatureTreeModel::headerData(int section, Qt::Orientation orientation,
361 int role) const
362{
363 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
364 if (section == 0)
365 return QString("Id");
366 else if (section == 1)
367 return QString("Name");
368 }
369
370 return QVariant();
371}
372
373Feature* FeatureTreeModel::getFeature(const QModelIndex &index) const
374{
375 if (!index.isValid())
376 return 0;
377 if (isSection(index))
378 return 0;
379 Node *node = static_cast<Node*>(index.internalPointer());
380 return const_cast<Feature*>(node->feature);
381}
382
383void FeatureTreeModel::featureChanged()
384{
385 Feature *feature = qobject_cast<Feature*>(sender());
386 if (feature) {
387 QModelIndex featureIndex = index(feature);
388 emit dataChanged(featureIndex, featureIndex);
389 } else {
390 emit layoutChanged();
391 }
392}
393
394void FeatureTreeModel::readConfig(QTextStream &stream)
395{
396 static QRegExp regexp("\\s*#\\s*define\\s+QT_NO_(\\S+)\\s*");
397
398 while (!stream.atEnd()) {
399 QString line = stream.readLine();
400 if (regexp.exactMatch(line)) {
401 Feature *f = Feature::getInstance(regexp.cap(1));
402 f->setEnabled(false);
403 }
404 }
405}
406/*
407 Search for all disabled child features of \a parent.
408 Returns a list of feature keys for the disabled items.
409*/
410QStringList FeatureTreeModel::findDisabled(const QModelIndex &parent) const
411{
412 QStringList stringList;
413
414 const int rows = rowCount(parent);
415 for (int i = 0; i < rows; ++i) {
416 QModelIndex child = index(i, 0, parent);
417 Node *node = static_cast<Node*>(child.internalPointer());
418 if (node && node->feature && !node->feature->enabled())
419 stringList << node->feature->key();
420 stringList << findDisabled(child);
421 }
422 return stringList;
423}
424
425void FeatureTreeModel::writeConfig(QTextStream &stream) const
426{
427 const int sectionCount = rowCount(QModelIndex());
428
429 for (int i = 0; i < sectionCount; ++i) {
430 QModelIndex section = index(i, 0, QModelIndex());
431 QStringList disabled = findDisabled(section);
432 if (disabled.size() > 0) {
433 stream << '\n' << "/* " << sections.keys().at(i) << " */" << '\n';
434 foreach (QString feature, disabled)
435 stream << "#ifndef QT_NO_" << feature << '\n'
436 << "# define QT_NO_" << feature << '\n'
437 << "#endif" << '\n';
438 }
439 }
440}
441
442void FeatureTreeModel::clear()
443{
444 Feature::clear();
445 sections.clear();
446 parentMap.clear();
447 featureIndexMap.clear();
448 emit layoutChanged();
449}
450
451QT_END_NAMESPACE
452

Warning: That file was not part of the compilation database. It may have many parsing errors.