OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / projectexplorer / projectmodels.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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 **
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, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "projectmodels.h"
35
36 #include "project.h"
37 #include "projectexplorerconstants.h"
38 #include "projectnodes.h"
39 #include "projectexplorer.h"
40
41 #include <coreplugin/fileiconprovider.h>
42 #include <utils/qtcassert.h>
43
44 #include <QtCore/QDebug>
45 #include <QtCore/QFileInfo>
46
47 #include <QtGui/QFont>
48 #include <QtGui/QIcon>
49
50 using namespace ProjectExplorer;
51 using namespace ProjectExplorer::Internal;
52 using Core::FileIconProvider;
53
54 namespace {
55
56 // sorting helper function
57
58 int fileNameCompare(const QString &a, const QString &b)
59 {
60     int result = a.compare(b, Qt::CaseInsensitive);
61     if (result != 0)
62         return result;
63     return a.compare(b, Qt::CaseSensitive);
64 }
65
66 bool sortNodes(Node *n1, Node *n2)
67 {
68     // Ordering is: project files, project, folder, file
69
70     const NodeType n1Type = n1->nodeType();
71     const NodeType n2Type = n2->nodeType();
72
73     // project files
74     FileNode *file1 = qobject_cast<FileNode*>(n1);
75     FileNode *file2 = qobject_cast<FileNode*>(n2);
76     if (file1 && file1->fileType() == ProjectFileType) {
77         if (file2 && file2->fileType() == ProjectFileType) {
78             const QString fileName1 = QFileInfo(file1->path()).fileName();
79             const QString fileName2 = QFileInfo(file2->path()).fileName();
80
81             int result = fileNameCompare(fileName1, fileName2);
82             if (result != 0)
83                 return result < 0;
84             else
85                 return file1 < file2;
86         } else {
87             return true; // project file is before everything else
88         }
89     } else {
90         if (file2 && file2->fileType() == ProjectFileType) {
91             return false;
92         }
93     }
94
95     // projects
96     if (n1Type == ProjectNodeType) {
97         if (n2Type == ProjectNodeType) {
98             ProjectNode *project1 = static_cast<ProjectNode*>(n1);
99             ProjectNode *project2 = static_cast<ProjectNode*>(n2);
100
101             int result = fileNameCompare(project1->displayName(), project2->displayName());
102             if (result != 0)
103                 return result < 0;
104             else
105                 return project1 < project2; // sort by pointer value
106         } else {
107            return true; // project is before folder & file
108        }
109     }
110     if (n2Type == ProjectNodeType)
111         return false;
112
113     if (n1Type == FolderNodeType) {
114         if (n2Type == FolderNodeType) {
115             FolderNode *folder1 = static_cast<FolderNode*>(n1);
116             FolderNode *folder2 = static_cast<FolderNode*>(n2);
117
118             int result = fileNameCompare(folder1->path(), folder2->path());
119             if (result != 0)
120                 return result < 0;
121             else
122                 return folder1 < folder2;
123         } else {
124             return true; // folder is before file
125         }
126     }
127     if (n2Type == FolderNodeType)
128         return false;
129
130     // must be file nodes
131     {
132         const QString filePath1 = n1->path();
133         const QString filePath2 = n2->path();
134
135         const QString fileName1 = QFileInfo(filePath1).fileName();
136         const QString fileName2 = QFileInfo(filePath2).fileName();
137
138         int result = fileNameCompare(fileName1, fileName2);
139         if (result != 0) {
140             return result < 0; // sort by filename
141         } else {
142             result = fileNameCompare(filePath1, filePath2);
143             if (result != 0) {
144                 return result < 0; // sort by filepath
145             } else {
146                 return n1 < n2; // sort by pointer value
147             }
148         }
149     }
150     return false;
151 }
152
153 } // namespace anon
154
155 FlatModel::FlatModel(SessionNode *rootNode, QObject *parent)
156         : QAbstractItemModel(parent),
157           m_filterProjects(false),
158           m_filterGeneratedFiles(true),
159           m_rootNode(rootNode),
160           m_startupProject(0),
161           m_parentFolderForChange(0)
162 {
163     NodesWatcher *watcher = new NodesWatcher(this);
164     m_rootNode->registerWatcher(watcher);
165
166     connect(watcher, SIGNAL(aboutToChangeHasBuildTargets(ProjectExplorer::ProjectNode*)),
167             this, SLOT(aboutToHasBuildTargetsChanged(ProjectExplorer::ProjectNode*)));
168
169     connect(watcher, SIGNAL(hasBuildTargetsChanged(ProjectExplorer::ProjectNode*)),
170             this, SLOT(hasBuildTargetsChanged(ProjectExplorer::ProjectNode*)));
171
172     connect(watcher, SIGNAL(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)),
173             this, SLOT(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)));
174     connect(watcher, SIGNAL(foldersAdded()),
175             this, SLOT(foldersAdded()));
176
177     connect(watcher, SIGNAL(foldersAboutToBeRemoved(FolderNode *, const QList<FolderNode*> &)),
178             this, SLOT(foldersAboutToBeRemoved(FolderNode *, const QList<FolderNode*> &)));
179     connect(watcher, SIGNAL(foldersRemoved()),
180             this, SLOT(foldersRemoved()));
181
182     connect(watcher, SIGNAL(filesAboutToBeAdded(FolderNode *,const QList<FileNode*> &)),
183             this, SLOT(filesAboutToBeAdded(FolderNode *, const QList<FileNode *> &)));
184     connect(watcher, SIGNAL(filesAdded()),
185             this, SLOT(filesAdded()));
186
187     connect(watcher, SIGNAL(filesAboutToBeRemoved(FolderNode *, const QList<FileNode*> &)),
188             this, SLOT(filesAboutToBeRemoved(FolderNode *, const QList<FileNode*> &)));
189     connect(watcher, SIGNAL(filesRemoved()),
190             this, SLOT(filesRemoved()));
191 }
192
193 QModelIndex FlatModel::index(int row, int column, const QModelIndex &parent) const
194 {
195     QModelIndex result;
196     if (!parent.isValid() && row == 0 && column == 0) { // session
197         result = createIndex(0, 0, m_rootNode);
198     } else if (parent.isValid() && column == 0) {
199         FolderNode *parentNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
200         Q_ASSERT(parentNode);
201         QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
202         if (it == m_childNodes.constEnd()) {
203             fetchMore(parentNode);
204             it = m_childNodes.constFind(parentNode);
205         }
206
207         if (row < it.value().size())
208             result = createIndex(row, 0, it.value().at(row));
209     }
210 //    qDebug() << "index of " << row << column << parent.data(Project::FilePathRole) << " is " << result.data(Project::FilePathRole);
211     return result;
212 }
213
214 QModelIndex FlatModel::parent(const QModelIndex &idx) const
215 {
216     QModelIndex parentIndex;
217     if (Node *node = nodeForIndex(idx)) {
218         FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
219         if (parentNode) {
220             FolderNode *grandParentNode = visibleFolderNode(parentNode->parentFolderNode());
221             if (grandParentNode) {
222                 QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(grandParentNode);
223                 if (it == m_childNodes.constEnd()) {
224                     fetchMore(grandParentNode);
225                     it = m_childNodes.constFind(grandParentNode);
226                 }
227                 Q_ASSERT(it != m_childNodes.constEnd());
228                 const int row = it.value().indexOf(parentNode);
229                 Q_ASSERT(row >= 0);
230                 parentIndex = createIndex(row, 0, parentNode);
231             } else {
232                 // top level node, parent is session
233                 parentIndex = index(0, 0, QModelIndex());
234             }
235         }
236     }
237
238 //    qDebug() << "parent of " << idx.data(Project::FilePathRole) << " is " << parentIndex.data(Project::FilePathRole);
239
240     return parentIndex;
241 }
242
243 QVariant FlatModel::data(const QModelIndex &index, int role) const
244 {
245     QVariant result;
246
247     if (Node *node = nodeForIndex(index)) {
248         FolderNode *folderNode = qobject_cast<FolderNode*>(node);
249         switch (role) {
250         case Qt::DisplayRole:
251         case Qt::EditRole: {
252             if (folderNode)
253                 result = folderNode->displayName();
254             else
255                 result = QFileInfo(node->path()).fileName(); //TODO cache that?
256             break;
257         }
258         case Qt::ToolTipRole: {
259             result = QDir::toNativeSeparators(node->path());
260             break;
261         }
262         case Qt::DecorationRole: {
263             if (folderNode)
264                 result = folderNode->icon();
265             else
266                 result = FileIconProvider::instance()->icon(QFileInfo(node->path()));
267             break;
268         }
269         case Qt::FontRole: {
270             QFont font;
271             if (node == m_startupProject)
272                 font.setBold(true);
273             result = font;
274             break;
275         }
276         case ProjectExplorer::Project::FilePathRole: {
277             result = node->path();
278             break;
279         }
280         }
281     }
282
283     return result;
284 }
285
286 Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
287 {
288     if (!index.isValid())
289         return 0;
290     // We claim that everything is editable
291     // That's slightly wrong
292     // We control the only view, and that one does the checks
293     return Qt::ItemIsSelectable|Qt::ItemIsEnabled | Qt::ItemIsEditable;
294 }
295
296 bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int role)
297 {
298     if (!index.isValid())
299         return false;
300     if (role != Qt::EditRole)
301         return false;
302
303     ProjectExplorerPlugin::instance()->renameFile(nodeForIndex(index), value.toString());
304     return true;
305 }
306
307 int FlatModel::rowCount(const QModelIndex &parent) const
308 {
309     int rows = 0;
310     if (!parent.isValid()) {
311         rows = 1;
312     } else {
313         FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
314         if (folderNode && m_childNodes.contains(folderNode))
315             rows = m_childNodes.value(folderNode).size();
316     }
317     return rows;
318 }
319
320 int FlatModel::columnCount(const QModelIndex &/*parent*/) const
321 {
322     return 1;
323 }
324
325 bool FlatModel::hasChildren(const QModelIndex &parent) const
326 {
327     if (!parent.isValid())
328         return true;
329
330     FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
331     if (!folderNode)
332         return false;
333
334     QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(folderNode);
335     if (it == m_childNodes.constEnd()) {
336         fetchMore(folderNode);
337         it = m_childNodes.constFind(folderNode);
338     }
339     return !it.value().isEmpty();
340 }
341
342 bool FlatModel::canFetchMore(const QModelIndex & parent) const
343 {
344     if (!parent.isValid()) {
345         return false;
346     } else {
347         if (FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent)))
348             return !m_childNodes.contains(folderNode);
349         else
350             return false;
351     }
352 }
353
354 void FlatModel::recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
355 {
356     foreach (FolderNode *folderNode, startNode->subFolderNodes()) {
357         if (folderNode && !blackList.contains(folderNode))
358             recursiveAddFolderNodesImpl(folderNode, list, blackList);
359     }
360 }
361
362 void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
363 {
364     if (!filter(startNode)) {
365         if (!blackList.contains(startNode))
366             list->append(startNode);
367     } else {
368         foreach (FolderNode *folderNode, startNode->subFolderNodes()) {
369             if (folderNode && !blackList.contains(folderNode))
370                 recursiveAddFolderNodesImpl(folderNode, list, blackList);
371         }
372     }
373 }
374
375 void FlatModel::recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
376 {
377     foreach (FolderNode *subFolderNode, startNode->subFolderNodes()) {
378         if (!blackList.contains(subFolderNode))
379             recursiveAddFileNodes(subFolderNode, list, blackList);
380     }
381     foreach (Node *node, startNode->fileNodes()) {
382         if (!blackList.contains(node) && !filter(node))
383             list->append(node);
384     }
385 }
386
387 QList<Node*> FlatModel::childNodes(FolderNode *parentNode, const QSet<Node*> &blackList) const
388 {
389     QList<Node*> nodeList;
390
391     if (parentNode->nodeType() == SessionNodeType) {
392         SessionNode *sessionNode = static_cast<SessionNode*>(parentNode);
393         QList<ProjectNode*> projectList = sessionNode->projectNodes();
394         for (int i = 0; i < projectList.size(); ++i) {
395             if (!blackList.contains(projectList.at(i)))
396                 nodeList << projectList.at(i);
397         }
398     } else {
399         recursiveAddFolderNodes(parentNode, &nodeList, blackList);
400         recursiveAddFileNodes(parentNode, &nodeList, blackList + nodeList.toSet());
401     }
402     qSort(nodeList.begin(), nodeList.end(), sortNodes);
403     return nodeList;
404 }
405
406 void FlatModel::fetchMore(FolderNode *folderNode) const
407 {
408     Q_ASSERT(folderNode);
409     Q_ASSERT(!m_childNodes.contains(folderNode));
410
411     QList<Node*> nodeList = childNodes(folderNode);
412     m_childNodes.insert(folderNode, nodeList);
413 }
414
415 void FlatModel::fetchMore(const QModelIndex &parent)
416 {
417     FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
418     Q_ASSERT(folderNode);
419
420     fetchMore(folderNode);
421 }
422
423 void FlatModel::setStartupProject(ProjectNode *projectNode)
424 {
425     if (m_startupProject != projectNode) {
426         QModelIndex oldIndex = (m_startupProject ? indexForNode(m_startupProject) : QModelIndex());
427         QModelIndex newIndex = (projectNode ? indexForNode(projectNode) : QModelIndex());
428         m_startupProject = projectNode;
429         if (oldIndex.isValid())
430             emit dataChanged(oldIndex, oldIndex);
431         if (newIndex.isValid())
432             emit dataChanged(newIndex, newIndex);
433     }
434 }
435
436 void FlatModel::reset()
437 {
438     m_childNodes.clear();
439     QAbstractItemModel::reset();
440 }
441
442 QModelIndex FlatModel::indexForNode(const Node *node_)
443 {
444     // We assume that we are only called for nodes that are represented
445
446     // we use non-const pointers internally
447     Node *node = const_cast<Node*>(node_);
448     if (!node)
449         return QModelIndex();
450
451     if (node == m_rootNode)
452         return createIndex(0, 0, m_rootNode);
453
454     FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
455
456     // Do we have the parent mapped?
457     QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
458     if (it == m_childNodes.constEnd()) {
459         fetchMore(parentNode);
460         it = m_childNodes.constFind(parentNode);
461     }
462     if (it != m_childNodes.constEnd()) {
463         const int row = it.value().indexOf(node);
464         if (row != -1)
465             return createIndex(row, 0, node);
466     }
467     return QModelIndex();
468 }
469
470 void FlatModel::setProjectFilterEnabled(bool filter)
471 {
472     if (filter == m_filterProjects)
473         return;
474     m_filterProjects = filter;
475     reset();
476 }
477
478 void FlatModel::setGeneratedFilesFilterEnabled(bool filter)
479 {
480     m_filterGeneratedFiles = filter;
481     reset();
482 }
483
484 bool FlatModel::projectFilterEnabled()
485 {
486     return m_filterProjects;
487 }
488
489 bool FlatModel::generatedFilesFilterEnabled()
490 {
491     return m_filterGeneratedFiles;
492 }
493
494 Node *FlatModel::nodeForIndex(const QModelIndex &index) const
495 {
496     if (index.isValid())
497         return (Node*)index.internalPointer();
498     return 0;
499 }
500
501 /*
502   Returns the first folder node in the ancestors
503   for the given node that is not filtered
504   out by the Flat Model.
505 */
506 FolderNode *FlatModel::visibleFolderNode(FolderNode *node) const
507 {
508     if (!node)
509         return 0;
510
511     for (FolderNode *folderNode = node;
512          folderNode;
513          folderNode = folderNode->parentFolderNode()) {
514         if (!filter(folderNode))
515             return folderNode;
516     }
517     return 0;
518 }
519
520 bool FlatModel::filter(Node *node) const
521 {
522     bool isHidden = false;
523     if (node->nodeType() == SessionNodeType) {
524         isHidden = false;
525     } else if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(node)) {
526         if (m_filterProjects && projectNode->parentFolderNode() != m_rootNode)
527             isHidden = !projectNode->hasBuildTargets();
528     } else if (node->nodeType() == FolderNodeType) {
529         if (m_filterProjects)
530             isHidden = true;
531     } else if (FileNode *fileNode = qobject_cast<FileNode*>(node)) {
532         if (m_filterGeneratedFiles)
533             isHidden = fileNode->isGenerated();
534     }
535     return isHidden;
536 }
537
538 bool isSorted(const QList<Node *> &nodes)
539 {
540     int size = nodes.size();
541     for (int i = 0; i < size -1; ++i) {
542         if (!sortNodes(nodes.at(i), nodes.at(i+1)))
543             return false;
544     }
545     return true;
546 }
547
548 /// slots and all the fun
549 void FlatModel::added(FolderNode* parentNode, const QList<Node*> &newNodeList)
550 {
551     QModelIndex parentIndex = indexForNode(parentNode);
552     // Old  list
553     QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
554     if (it == m_childNodes.constEnd())
555         return;
556     QList<Node *> oldNodeList = it.value();
557
558     // Compare lists and emit signals, and modify m_childNodes on the fly
559     QList<Node *>::const_iterator oldIter = oldNodeList.constBegin();
560     QList<Node *>::const_iterator newIter = newNodeList.constBegin();
561
562     Q_ASSERT(isSorted(oldNodeList));
563     Q_ASSERT(isSorted(newNodeList));
564
565     QSet<Node *> emptyDifference;
566     emptyDifference = oldNodeList.toSet();
567     emptyDifference.subtract(newNodeList.toSet());
568     if (!emptyDifference.isEmpty()) {
569         // This should not happen...
570         qDebug() << "FlatModel::added, old Node list should be subset of newNode list, found files in old list which were not part of new list";
571         foreach (Node *n, emptyDifference) {
572             qDebug()<<n->path();
573         }
574         Q_ASSERT(false);
575     }
576
577     // optimization, check for old list is empty
578     if (oldIter == oldNodeList.constEnd()) {
579         // New Node List is empty, nothing added which intrest us
580         if (newIter == newNodeList.constEnd())
581             return;
582         // So all we need to do is easy
583         beginInsertRows(parentIndex, 0, newNodeList.size() - 1);
584         m_childNodes.insert(parentNode, newNodeList);
585         endInsertRows();
586         return;
587     }
588
589     while (true) {
590         // Skip all that are the same
591         while (*oldIter == *newIter) {
592             ++oldIter;
593             ++newIter;
594             if (oldIter == oldNodeList.constEnd()) {
595                 // At end of oldNodeList, sweep up rest of newNodeList
596                 QList<Node *>::const_iterator startOfBlock = newIter;
597                 newIter = newNodeList.constEnd();
598                 int pos = oldIter - oldNodeList.constBegin();
599                 int count = newIter - startOfBlock;
600                 if (count > 0) {
601                     beginInsertRows(parentIndex, pos, pos+count-1);
602                     while (startOfBlock != newIter) {
603                         oldNodeList.insert(pos, *startOfBlock);
604                         ++pos;
605                         ++startOfBlock;
606                     }
607                     m_childNodes.insert(parentNode, oldNodeList);
608                     endInsertRows();
609                 }
610                 return; // Done with the lists, leave the function
611             }
612         }
613
614         QList<Node *>::const_iterator startOfBlock = newIter;
615         while (*oldIter != *newIter)
616             ++newIter;
617         // startOfBlock is the first that was diffrent
618         // newIter points to the new position of oldIter
619         // newIter - startOfBlock is number of new items
620         // oldIter is the position where those are...
621         int pos = oldIter - oldNodeList.constBegin();
622         int count = newIter - startOfBlock;
623         beginInsertRows(parentIndex, pos, pos + count - 1);
624         while (startOfBlock != newIter) {
625             oldNodeList.insert(pos, *startOfBlock);
626             ++pos;
627             ++startOfBlock;
628         }
629         m_childNodes.insert(parentNode, oldNodeList);
630         endInsertRows();
631         oldIter = oldNodeList.constBegin() + pos;
632     }
633 }
634
635 void FlatModel::removed(FolderNode* parentNode, const QList<Node*> &newNodeList)
636 {
637     QModelIndex parentIndex = indexForNode(parentNode);
638     // Old  list
639     QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
640     if (it == m_childNodes.constEnd())
641         return;
642
643     QList<Node *> oldNodeList = it.value();
644     // Compare lists and emit signals, and modify m_childNodes on the fly
645     QList<Node *>::const_iterator oldIter = oldNodeList.constBegin();
646     QList<Node *>::const_iterator newIter = newNodeList.constBegin();
647
648     Q_ASSERT(isSorted(oldNodeList));
649     Q_ASSERT(isSorted(newNodeList));
650
651     QSet<Node *> emptyDifference;
652     emptyDifference = newNodeList.toSet();
653     emptyDifference.subtract(oldNodeList.toSet());
654     if (!emptyDifference.isEmpty()) {
655         // This should not happen...
656         qDebug() << "FlatModel::removed, new Node list should be subset of oldNode list, found files in new list which were not part of old list";
657         foreach (Node *n, emptyDifference) {
658             qDebug()<<n->path();
659         }
660         Q_ASSERT(false);
661     }
662
663     // optimization, check for new list is empty
664     if (newIter == newNodeList.constEnd()) {
665         // New Node List is empty, everything removed
666         if (oldIter == oldNodeList.constEnd())
667             return;
668         // So all we need to do is easy
669         beginRemoveRows(parentIndex, 0, oldNodeList.size() - 1);
670         m_childNodes.insert(parentNode, newNodeList);
671         endRemoveRows();
672         return;
673     }
674
675     while (true) {
676         // Skip all that are the same
677         while (*oldIter == *newIter) {
678             ++oldIter;
679             ++newIter;
680             if (newIter == newNodeList.constEnd()) {
681                 // At end of newNodeList, sweep up rest of oldNodeList
682                 QList<Node *>::const_iterator startOfBlock = oldIter;
683                 oldIter = oldNodeList.constEnd();
684                 int pos = startOfBlock - oldNodeList.constBegin();
685                 int count = oldIter - startOfBlock;
686                 if (count > 0) {
687                     beginRemoveRows(parentIndex, pos, pos+count-1);
688                     while (startOfBlock != oldIter) {
689                         ++startOfBlock;
690                         oldNodeList.removeAt(pos);
691                     }
692
693                     m_childNodes.insert(parentNode, oldNodeList);
694                     endRemoveRows();
695                 }
696                 return; // Done with the lists, leave the function
697             }
698         }
699
700         QList<Node *>::const_iterator startOfBlock = oldIter;
701         while (*oldIter != *newIter)
702             ++oldIter;
703         // startOfBlock is the first that was diffrent
704         // oldIter points to the new position of newIter
705         // oldIter - startOfBlock is number of new items
706         // newIter is the position where those are...
707         int pos = startOfBlock - oldNodeList.constBegin();
708         int count = oldIter - startOfBlock;
709         beginRemoveRows(parentIndex, pos, pos + count - 1);
710         while (startOfBlock != oldIter) {
711             ++startOfBlock;
712             oldNodeList.removeAt(pos);
713         }
714         m_childNodes.insert(parentNode, oldNodeList);
715         endRemoveRows();
716         oldIter = oldNodeList.constBegin() + pos;
717     }
718 }
719
720 void FlatModel::aboutToHasBuildTargetsChanged(ProjectExplorer::ProjectNode* node)
721 {
722     if (!m_filterProjects)
723         return;
724     FolderNode *folder = visibleFolderNode(node->parentFolderNode());
725     QList<Node *> newNodeList = childNodes(folder, QSet<Node *>() << node);
726     removed(folder, newNodeList);
727
728     QList<Node *> staleFolders;
729     recursiveAddFolderNodesImpl(node, &staleFolders);
730     foreach (Node *n, staleFolders)
731         if (FolderNode *fn = qobject_cast<FolderNode *>(n))
732             m_childNodes.remove(fn);
733 }
734
735 void FlatModel::hasBuildTargetsChanged(ProjectExplorer::ProjectNode *node)
736 {
737     if (!m_filterProjects)
738         return;
739     // we are only interested if we filter
740     FolderNode *folder = visibleFolderNode(node->parentFolderNode());
741     QList<Node *> newNodeList = childNodes(folder);
742     added(folder, newNodeList);
743 }
744
745 void FlatModel::foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders)
746 {
747     Q_UNUSED(newFolders)
748     m_parentFolderForChange = parentFolder;
749 }
750
751 void FlatModel::foldersAdded()
752 {
753     // First found out what the folder is that we are adding the files to
754     FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange);
755
756     // Now get the new list for that folder
757     QList<Node *> newNodeList = childNodes(folderNode);
758
759     added(folderNode, newNodeList);
760 }
761
762 void FlatModel::foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders)
763 {
764     QSet<Node *> blackList;
765     foreach (FolderNode *node, staleFolders)
766         blackList.insert(node);
767
768     FolderNode *folderNode = visibleFolderNode(parentFolder);
769     QList<Node *> newNodeList = childNodes(folderNode, blackList);
770
771     removed(folderNode, newNodeList);
772     removeFromCache(staleFolders);
773 }
774
775 void FlatModel::removeFromCache(QList<FolderNode *> list)
776 {
777     foreach (FolderNode *fn, list) {
778         removeFromCache(fn->subFolderNodes());
779         m_childNodes.remove(fn);
780     }
781 }
782
783 void FlatModel::foldersRemoved()
784 {
785     // Do nothing
786 }
787
788 void FlatModel::filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles)
789 {
790     Q_UNUSED(newFiles)
791     m_parentFolderForChange = folder;
792 }
793
794 void FlatModel::filesAdded()
795 {
796     // First find out what the folder is that we are adding the files to
797     FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange);
798
799     // Now get the new List for that folder
800     QList<Node *> newNodeList = childNodes(folderNode);
801     added(folderNode, newNodeList);
802 }
803
804 void FlatModel::filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles)
805 {
806     // First found out what the folder (that is the project) is that we are adding the files to
807     FolderNode *folderNode = visibleFolderNode(folder);
808
809     QSet<Node *> blackList;
810     foreach(Node *node, staleFiles)
811         blackList.insert(node);
812
813     // Now get the new List for that folder
814     QList<Node *> newNodeList = childNodes(folderNode, blackList);
815     removed(folderNode, newNodeList);
816 }
817
818 void FlatModel::filesRemoved()
819 {
820     // Do nothing
821 }