source: branches/vendor/trolltech/qt/current/tools/qconfig/featuretreemodel.cpp @ 2

Last change on this file since 2 was 2, checked in by Dmitry A. Kuminov, 12 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 12.8 KB
Line 
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 tools applications 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
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
Note: See TracBrowser for help on using the repository browser.