summaryrefslogtreecommitdiffstats
path: root/src/qconfig/featuretreemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qconfig/featuretreemodel.cpp')
-rw-r--r--src/qconfig/featuretreemodel.cpp451
1 files changed, 451 insertions, 0 deletions
diff --git a/src/qconfig/featuretreemodel.cpp b/src/qconfig/featuretreemodel.cpp
new file mode 100644
index 000000000..b67e1b540
--- /dev/null
+++ b/src/qconfig/featuretreemodel.cpp
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "featuretreemodel.h"
+#include "feature.h"
+#include <QPalette>
+#include <QColor>
+#include <QApplication>
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+class Node
+{
+public:
+ Node(Feature *f, Node *p = 0) : feature(f), parent(p) {}
+ ~Node();
+ Node* find(const Feature *child) const;
+ bool contains(const Feature *child) const { return find(child) != 0; }
+ bool insert(Node *n);
+
+ Feature *feature;
+ Node *parent;
+ QList<Node*> children; // maybe convert to Map to get keys sorted
+};
+
+Node::~Node()
+{
+ while (!children.isEmpty())
+ delete children.takeFirst();
+}
+
+Node* Node::find(const Feature *f) const
+{
+ if (this->feature == f)
+ return const_cast<Node*>(this);
+
+ foreach (Node *n, children)
+ if (Node *m = n->find(f))
+ return m;
+
+ return 0;
+}
+
+static bool nodePtrLessThan(const Node *n1, const Node *n2)
+{
+ return (n1->feature->key() < n2->feature->key());
+}
+
+/*
+ Try insert \a n into the tree with this node as root.
+ n is inserted as a child if it has a dependency to this node.
+ Returns true if child is inserted into the tree, false otherwise.
+*/
+bool Node::insert(Node *n)
+{
+ Feature *f = const_cast<Feature*>(n->feature);
+ if (feature->supports().contains(f)) {
+ children.append(n);
+ qSort(children.begin(), children.end(), nodePtrLessThan);
+ n->parent = this;
+ return true;
+ }
+ foreach (Node *child, children)
+ if (child->insert(n))
+ return true;
+ return false;
+}
+
+static bool isSection(const QModelIndex &index)
+{
+ return index.isValid() && (index.internalId() == 0);
+}
+
+FeatureTreeModel::FeatureTreeModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+}
+
+FeatureTreeModel::~FeatureTreeModel()
+{
+ foreach (QString section, sections.keys())
+ while (!sections[section].isEmpty())
+ delete sections[section].takeFirst();
+}
+
+/*
+ Returns true if the model already contains \a in \a section, false otherwise.
+*/
+bool FeatureTreeModel::contains(const QString &section, const Feature *f) const
+{
+ return (find(section, f) != 0);
+}
+
+Node* FeatureTreeModel::find(const QString &section, const Feature *f) const
+{
+ QList<Node*> roots = sections[section];
+ foreach (Node *root, roots)
+ if (Node *n = root->find(f))
+ return n;
+ return 0;
+}
+
+/*
+ Add new \a feature to the tree.
+ When all feature is added, buildTree() must be called to build the
+ dependency tree.
+*/
+void FeatureTreeModel::addFeature(Feature *feature)
+{
+ const QString section = feature->section();
+ Q_ASSERT(!contains(section, feature));
+
+ connect(feature, SIGNAL(changed()), this, SLOT(featureChanged()));
+
+ Node *node = new Node(feature, 0);
+
+ // try insert any toplevel nodes as child of this one
+ foreach (Node *n, sections[section])
+ if (node->insert(n))
+ sections[section].removeAll(n);
+
+ // try insert this node as a child of any existing node
+ foreach (Node *n, sections[section])
+ if (n->insert(node)) {
+ emit layoutChanged();
+ return;
+ }
+
+ // not a child, insert as a toplevel node
+ sections[section].append(node);
+ qSort(sections[section].begin(), sections[section].end(), nodePtrLessThan);
+ emit layoutChanged();
+}
+
+QModelIndex FeatureTreeModel::createIndex(int row, int column,
+ const QModelIndex &parent,
+ const Node *node) const
+{
+ QModelIndex index = QAbstractItemModel::createIndex(row, column,
+ (void*)node);
+ if (parent.isValid())
+ parentMap[index] = parent;
+ if (node)
+ featureIndexMap[node->feature] = index;
+ return index;
+}
+
+QModelIndex FeatureTreeModel::index(int row, int column,
+ const QModelIndex &parent) const
+{
+ if (!parent.isValid()) { // index is a section
+ if (row < sections.size() && column == 0)
+ return QAbstractItemModel::createIndex(row, column, 0);
+ return QModelIndex();
+ }
+
+ if (isSection(parent)) { // index is a toplevel feature
+ const int parentRow = parent.row();
+ if (parentRow < sections.size()) {
+ QString section = sections.keys().at(parentRow);
+ QList<Node*> nodes = sections[section];
+ if (row < nodes.size() && column < 2)
+ return createIndex(row, column, parent, nodes.at(row));
+ }
+ return QModelIndex();
+ }
+
+ // parent is a feature
+ Node *parentNode = static_cast<Node*>(parent.internalPointer());
+ QList<Node*> children = parentNode->children;
+ if (row < children.size() && column < 2)
+ return createIndex(row, column, parent, children.at(row));
+
+ return QModelIndex();
+}
+
+QModelIndex FeatureTreeModel::index(const QModelIndex &parent,
+ const Feature *feature) const
+{
+ const int rows = rowCount(parent);
+ for (int i = 0; i < rows; ++i) {
+ QModelIndex child = index(i, 0, parent);
+ Node *node = static_cast<Node*>(child.internalPointer());
+ if (node && node->feature == feature)
+ return child;
+ QModelIndex childSearch = index(child, feature);
+ if (childSearch.isValid())
+ return childSearch;
+ }
+ return QModelIndex();
+}
+
+QModelIndex FeatureTreeModel::index(const Feature *feature) const
+{
+ if (featureIndexMap.contains(feature))
+ return featureIndexMap.value(feature);
+
+ // exhaustive search
+ int sectionRow = sections.keys().indexOf(feature->section());
+ QModelIndex sectionIndex = index(sectionRow, 0, QModelIndex());
+
+ return index(sectionIndex, feature);
+}
+
+QModelIndex FeatureTreeModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ if (parentMap.contains(index))
+ return parentMap.value(index);
+ return QModelIndex();
+}
+
+int FeatureTreeModel::rowCount(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return sections.size();
+
+ if (isSection(parent)) {
+ const QString section = sections.keys().at(parent.row());
+ return sections[section].size();
+ }
+
+ const Node *node = static_cast<Node*>(parent.internalPointer());
+ return node->children.size();
+}
+
+int FeatureTreeModel::columnCount(const QModelIndex &parent) const
+{
+#if 0
+ if (!parent.isValid())
+ return 0;
+
+ if (isSection(parent))
+ return 1;
+#endif
+ Q_UNUSED(parent);
+ return 2; // Feature: [key, name]
+}
+
+QVariant FeatureTreeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ const Node *node = static_cast<Node*>(index.internalPointer());
+
+ switch (role) {
+ case Qt::DisplayRole: {
+ if (node == 0) // index is a section
+ return sections.keys().at(index.row());
+ if (index.column() == 0)
+ return node->feature->key();
+ Q_ASSERT(index.column() == 1);
+ return node->feature->title();
+ }
+ case Qt::CheckStateRole: {
+ if (node && index.column() == 0)
+ return (node->feature->enabled() ?
+ Qt::Checked : Qt::Unchecked);
+ break;
+ }
+ case Qt::TextColorRole: {
+ if (node && index.column() == 0) // feature key
+ if (node->feature->selectable())
+ return QApplication::palette().color(QPalette::Link);
+ break;
+ }
+ case Qt::TextAlignmentRole:
+ case Qt::BackgroundColorRole:
+ case Qt::FontRole:
+ case Qt::ToolTipRole: // TODO
+ case Qt::StatusTipRole: // TODO
+ case Qt::WhatsThisRole: // TODO
+ case Qt::DecorationRole:
+ case Qt::EditRole:
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+bool FeatureTreeModel::setData(const QModelIndex &index,
+ const QVariant &value, int role)
+{
+ if (!index.isValid())
+ return false;
+
+ Node *node = static_cast<Node*>(index.internalPointer());
+ if (!node)
+ return false;
+
+ if (role == Qt::CheckStateRole) {
+ Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
+ if (state == Qt::Checked)
+ node->feature->setEnabled(true);
+ else if (state == Qt::Unchecked)
+ node->feature->setEnabled(false);
+ emit dataChanged(index, index);
+ return true;
+ }
+ return false;
+}
+
+Qt::ItemFlags FeatureTreeModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid() || index.internalPointer() == 0)
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ const Node *node = static_cast<Node*>(index.internalPointer());
+ const Feature *feature = node->feature;
+ Qt::ItemFlags flags = Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
+
+ if (feature->selectable())
+ flags |= Qt::ItemIsEnabled;
+
+ return flags;
+}
+
+QVariant FeatureTreeModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ if (section == 0)
+ return QString("Id");
+ else if (section == 1)
+ return QString("Name");
+ }
+
+ return QVariant();
+}
+
+Feature* FeatureTreeModel::getFeature(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ if (isSection(index))
+ return 0;
+ Node *node = static_cast<Node*>(index.internalPointer());
+ return const_cast<Feature*>(node->feature);
+}
+
+void FeatureTreeModel::featureChanged()
+{
+ Feature *feature = qobject_cast<Feature*>(sender());
+ if (feature) {
+ QModelIndex featureIndex = index(feature);
+ emit dataChanged(featureIndex, featureIndex);
+ } else {
+ emit layoutChanged();
+ }
+}
+
+void FeatureTreeModel::readConfig(QTextStream &stream)
+{
+ static QRegExp regexp("\\s*#\\s*define\\s+QT_NO_(\\S+)\\s*");
+
+ while (!stream.atEnd()) {
+ QString line = stream.readLine();
+ if (regexp.exactMatch(line)) {
+ Feature *f = Feature::getInstance(regexp.cap(1));
+ f->setEnabled(false);
+ }
+ }
+}
+/*
+ Search for all disabled child features of \a parent.
+ Returns a list of feature keys for the disabled items.
+*/
+QStringList FeatureTreeModel::findDisabled(const QModelIndex &parent) const
+{
+ QStringList stringList;
+
+ const int rows = rowCount(parent);
+ for (int i = 0; i < rows; ++i) {
+ QModelIndex child = index(i, 0, parent);
+ Node *node = static_cast<Node*>(child.internalPointer());
+ if (node && node->feature && !node->feature->enabled())
+ stringList << node->feature->key();
+ stringList << findDisabled(child);
+ }
+ return stringList;
+}
+
+void FeatureTreeModel::writeConfig(QTextStream &stream) const
+{
+ const int sectionCount = rowCount(QModelIndex());
+
+ for (int i = 0; i < sectionCount; ++i) {
+ QModelIndex section = index(i, 0, QModelIndex());
+ QStringList disabled = findDisabled(section);
+ if (disabled.size() > 0) {
+ stream << '\n' << "/* " << sections.keys().at(i) << " */" << '\n';
+ foreach (QString feature, disabled)
+ stream << "#ifndef QT_NO_" << feature << '\n'
+ << "# define QT_NO_" << feature << '\n'
+ << "#endif" << '\n';
+ }
+ }
+}
+
+void FeatureTreeModel::clear()
+{
+ Feature::clear();
+ sections.clear();
+ parentMap.clear();
+ featureIndexMap.clear();
+ emit layoutChanged();
+}
+
+QT_END_NAMESPACE