tools/qconfig/featuretreemodel.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    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 
       
    49 QT_BEGIN_NAMESPACE
       
    50 
       
    51 class Node
       
    52 {
       
    53 public:
       
    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 
       
    65 Node::~Node()
       
    66 {
       
    67     while (!children.isEmpty())
       
    68         delete children.takeFirst();
       
    69 }
       
    70 
       
    71 Node* 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 
       
    83 static 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 */
       
    93 bool 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 
       
   108 static bool isSection(const QModelIndex &index)
       
   109 {
       
   110     return index.isValid() && (index.internalId() == 0);
       
   111 }
       
   112 
       
   113 FeatureTreeModel::FeatureTreeModel(QObject *parent)
       
   114     : QAbstractItemModel(parent)
       
   115 {
       
   116 }
       
   117 
       
   118 FeatureTreeModel::~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 */
       
   128 bool FeatureTreeModel::contains(const QString &section, const Feature *f) const
       
   129 {
       
   130     return (find(section, f) != 0);
       
   131 }
       
   132 
       
   133 Node* 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 */
       
   147 void 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 
       
   174 QModelIndex 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 
       
   187 QModelIndex 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 
       
   216 QModelIndex 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 
       
   232 QModelIndex 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 
       
   244 QModelIndex 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 
       
   254 int 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 
       
   268 int 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 
       
   281 QVariant 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 
       
   323 bool 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 
       
   345 Qt::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 
       
   360 QVariant 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 
       
   373 Feature* 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 
       
   383 void 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 
       
   394 void 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 */
       
   410 QStringList 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 
       
   425 void 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 
       
   442 void FeatureTreeModel::clear()
       
   443 {
       
   444     Feature::clear();
       
   445     sections.clear();
       
   446     parentMap.clear();
       
   447     featureIndexMap.clear();
       
   448     emit layoutChanged();
       
   449 }
       
   450 
       
   451 QT_END_NAMESPACE