ProjectExplorer: Make the FlatModel a Utils::TreeModel

The FlatModel is essentially a proxy model keeping expansion and
filter state per ProjectTree(View). Using a Utils::TreeModel makes
it fast enough to allow recreation of the proxy structure on
structural changes simplifying the parent/child logic significantly.

The {Session,Project,Folder,File}Node hierarchy still is still primary
information and shared by all views.

Change-Id: Ic08180a19bda37908280ff30e0737d188ed93e92
Reviewed-by: Robert Loehning <robert.loehning@qt.io>
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
hjk
2017-01-19 14:54:23 +01:00
parent 03a68a91bb
commit 3c743346b0
13 changed files with 236 additions and 1063 deletions

View File

@@ -249,13 +249,16 @@ public:
explicit TreeModel(QObject *parent = 0) : BaseTreeModel(new RootItem, parent) {} explicit TreeModel(QObject *parent = 0) : BaseTreeModel(new RootItem, parent) {}
explicit TreeModel(RootItem *root, QObject *parent = 0) : BaseTreeModel(root, parent) {} explicit TreeModel(RootItem *root, QObject *parent = 0) : BaseTreeModel(root, parent) {}
using BaseTreeModel::canFetchMore;
using BaseTreeModel::clear; using BaseTreeModel::clear;
using BaseTreeModel::columnCount; using BaseTreeModel::columnCount;
using BaseTreeModel::data; using BaseTreeModel::data;
using BaseTreeModel::destroyItem; using BaseTreeModel::destroyItem;
using BaseTreeModel::fetchMore;
using BaseTreeModel::hasChildren; using BaseTreeModel::hasChildren;
using BaseTreeModel::index; using BaseTreeModel::index;
using BaseTreeModel::indexForItem; using BaseTreeModel::indexForItem;
using BaseTreeModel::parent;
using BaseTreeModel::rowCount; using BaseTreeModel::rowCount;
using BaseTreeModel::setData; using BaseTreeModel::setData;
using BaseTreeModel::setHeader; using BaseTreeModel::setHeader;

View File

@@ -37,9 +37,15 @@ bool ExpandData::operator==(const ExpandData &other) const
return path == other.path && displayName == other.displayName; return path == other.path && displayName == other.displayName;
} }
QStringList ExpandData::toStringList() const ExpandData ExpandData::fromSettings(const QVariant &v)
{ {
return { path, displayName }; QStringList list = v.toStringList();
return list.size() == 2 ? ExpandData(list.at(0), list.at(1)) : ExpandData();
}
QVariant ExpandData::toSettings() const
{
return QVariant::fromValue(QStringList({ path, displayName }));
} }
int ProjectExplorer::Internal::qHash(const ExpandData &data) int ProjectExplorer::Internal::qHash(const ExpandData &data)

View File

@@ -38,7 +38,9 @@ public:
ExpandData() = default; ExpandData() = default;
ExpandData(const QString &path_, const QString &displayName_); ExpandData(const QString &path_, const QString &displayName_);
bool operator==(const ExpandData &other) const; bool operator==(const ExpandData &other) const;
QStringList toStringList() const;
static ExpandData fromSettings(const QVariant &v);
QVariant toSettings() const;
QString path; QString path;
QString displayName; QString displayName;

View File

@@ -29,6 +29,7 @@
#include "projectnodes.h" #include "projectnodes.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include "projecttree.h" #include "projecttree.h"
#include "session.h"
#include <coreplugin/fileiconprovider.h> #include <coreplugin/fileiconprovider.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -40,15 +41,13 @@
#include <QMimeData> #include <QMimeData>
#include <QLoggingCategory> #include <QLoggingCategory>
using namespace Utils;
namespace ProjectExplorer { namespace ProjectExplorer {
using namespace Internal; using namespace Internal;
namespace { static bool sortNodes(const Node *n1, const Node *n2)
// sorting helper function
bool sortNodes(Node *n1, Node *n2)
{ {
if (n1->priority() > n2->priority()) if (n1->priority() > n2->priority())
return true; return true;
@@ -66,78 +65,45 @@ bool sortNodes(Node *n1, Node *n2)
return n1 < n2; // sort by pointer value return n1 < n2; // sort by pointer value
} }
} // namespace anon static bool sortWrapperNodes(const WrapperNode *w1, const WrapperNode *w2)
FlatModel::FlatModel(SessionNode *rootNode, QObject *parent) : QAbstractItemModel(parent),
m_rootNode(rootNode)
{ {
return sortNodes(w1->m_node, w2->m_node);
}
FlatModel::FlatModel(QObject *parent)
: TreeModel<WrapperNode, WrapperNode>(new WrapperNode(SessionManager::sessionNode()), parent)
{
m_timer.setInterval(200);
connect(&m_timer, &QTimer::timeout, this, &FlatModel::doUpdate);
ProjectTree *tree = ProjectTree::instance(); ProjectTree *tree = ProjectTree::instance();
connect(tree, &ProjectTree::dataChanged, this, &FlatModel::update);
connect(tree, &ProjectTree::nodeUpdated, this, &FlatModel::nodeUpdated);
connect(tree, &ProjectTree::aboutToChangeShowInSimpleTree, SessionManager *sm = SessionManager::instance();
this, &FlatModel::aboutToShowInSimpleTreeChanged); connect(sm, &SessionManager::projectRemoved, this, &FlatModel::update);
connect(sm, &SessionManager::startupProjectChanged, this, &FlatModel::startupProjectChanged);
connect(tree, &ProjectTree::showInSimpleTreeChanged, connect(sm, &SessionManager::sessionLoaded, this, &FlatModel::loadExpandData);
this, &FlatModel::showInSimpleTreeChanged); connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData);
connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded);
connect(tree, &ProjectTree::foldersAboutToBeAdded,
this, &FlatModel::foldersAboutToBeAdded);
connect(tree, &ProjectTree::foldersAdded,
this, &FlatModel::foldersAdded);
connect(tree, &ProjectTree::foldersAboutToBeRemoved,
this, &FlatModel::foldersAboutToBeRemoved);
connect(tree, &ProjectTree::foldersRemoved,
this, &FlatModel::foldersRemoved);
connect(tree, &ProjectTree::filesAboutToBeAdded,
this, &FlatModel::filesAboutToBeAdded);
connect(tree, &ProjectTree::filesAdded,
this, &FlatModel::filesAdded);
connect(tree, &ProjectTree::filesAboutToBeRemoved,
this, &FlatModel::filesAboutToBeRemoved);
connect(tree, &ProjectTree::filesRemoved,
this, &FlatModel::filesRemoved);
connect(tree, &ProjectTree::nodeSortKeyAboutToChange,
this, &FlatModel::nodeSortKeyAboutToChange);
connect(tree, &ProjectTree::nodeSortKeyChanged,
this, &FlatModel::nodeSortKeyChanged);
connect(tree, &ProjectTree::nodeUpdated,
this, &FlatModel::nodeUpdated);
} }
QModelIndex FlatModel::index(int row, int column, const QModelIndex &parent) const void FlatModel::setView(QTreeView *view)
{ {
QModelIndex result; QTC_CHECK(!m_view);
if (!parent.isValid() && row == 0 && column == 0) { // session m_view = view;
result = createIndex(0, 0, m_rootNode); connect(m_view, &QTreeView::expanded, this, &FlatModel::onExpanded);
} else if (parent.isValid() && column == 0) { connect(m_view, &QTreeView::collapsed, this, &FlatModel::onCollapsed);
FolderNode *parentNode = nodeForIndex(parent)->asFolderNode();
Q_ASSERT(parentNode);
QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
if (it == m_childNodes.constEnd()) {
fetchMore(parentNode);
it = m_childNodes.constFind(parentNode);
}
if (row < it.value().size())
result = createIndex(row, 0, it.value().at(row));
}
// qDebug() << "index of " << row << column << parent.data(Project::FilePathRole) << " is " << result.data(Project::FilePathRole);
return result;
} }
QModelIndex FlatModel::parent(const QModelIndex &idx) const void FlatModel::startupProjectChanged(Project *project)
{ {
QModelIndex parentIndex; ProjectNode *projectNode = project ? project->rootProjectNode() : nullptr;
if (Node *node = nodeForIndex(idx)) { if (m_startupProject == projectNode)
FolderNode *parentNode = visibleFolderNode(node->parentFolderNode()); return;
if (parentNode) m_startupProject = projectNode;
return indexForNode(parentNode); layoutChanged();
}
return parentIndex;
} }
QVariant FlatModel::data(const QModelIndex &index, int role) const QVariant FlatModel::data(const QModelIndex &index, int role) const
@@ -149,7 +115,6 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
switch (role) { switch (role) {
case Qt::DisplayRole: { case Qt::DisplayRole: {
QString name = node->displayName(); QString name = node->displayName();
if (node->nodeType() == NodeType::Project if (node->nodeType() == NodeType::Project
&& node->parentFolderNode() && node->parentFolderNode()
&& node->parentFolderNode()->nodeType() == NodeType::Session) { && node->parentFolderNode()->nodeType() == NodeType::Session) {
@@ -207,7 +172,7 @@ Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
// We control the only view, and that one does the checks // We control the only view, and that one does the checks
Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled; Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled;
if (Node *node = nodeForIndex(index)) { if (Node *node = nodeForIndex(index)) {
if (node == m_rootNode) if (node->asSessionNode())
return 0; // no flags for session node... return 0; // no flags for session node...
if (!node->asProjectNode()) { if (!node->asProjectNode()) {
// either folder or file node // either folder or file node
@@ -235,142 +200,116 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
return true; return true;
} }
int FlatModel::rowCount(const QModelIndex &parent) const void FlatModel::update()
{ {
int rows = 0; m_timer.start(300);
if (!parent.isValid()) { }
rows = 1;
} else { void FlatModel::doUpdate()
FolderNode *folderNode = nodeForIndex(parent)->asFolderNode(); {
if (folderNode && m_childNodes.contains(folderNode)) m_timer.stop();
rows = m_childNodes.value(folderNode).size(); rebuildModel();
}
void FlatModel::rebuildModel()
{
QSet<Node *> seen;
rootItem()->removeChildren();
const QList<ProjectNode *> projectNodes = SessionManager::sessionNode()->projectNodes();
for (ProjectNode *projectNode : projectNodes) {
if (!seen.contains(projectNode))
addProjectNode(rootItem(), projectNode, &seen);
} }
return rows;
forAllItems([this](WrapperNode *node) {
const QString path = node->m_node->filePath().toString();
const QString displayName = node->m_node->displayName();
ExpandData ed(path, displayName);
if (m_toExpand.contains(ed))
m_view->expand(node->index());
});
} }
int FlatModel::columnCount(const QModelIndex &/*parent*/) const void FlatModel::onCollapsed(const QModelIndex &idx)
{ {
return 1; m_toExpand.remove(expandDataForNode(nodeForIndex(idx)));
} }
bool FlatModel::hasChildren(const QModelIndex &parent) const void FlatModel::onExpanded(const QModelIndex &idx)
{ {
if (!parent.isValid()) m_toExpand.insert(expandDataForNode(nodeForIndex(idx)));
return true; }
FolderNode *folderNode = nodeForIndex(parent)->asFolderNode(); ExpandData FlatModel::expandDataForNode(const Node *node) const
if (!folderNode) {
return false; QTC_ASSERT(node, return ExpandData());
const QString path = node->filePath().toString();
const QString displayName = node->displayName();
return ExpandData(path, displayName);
}
QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(folderNode); void FlatModel::handleProjectAdded(Project *project)
if (it == m_childNodes.constEnd()) { {
fetchMore(folderNode); Node *node = project->rootProjectNode();
it = m_childNodes.constFind(folderNode); m_toExpand.insert(expandDataForNode(node));
if (WrapperNode *wrapper = wrapperForNode(node)) {
wrapper->forFirstLevelChildren([this](WrapperNode *child) {
m_toExpand.insert(expandDataForNode(child->m_node));
});
} }
return !it.value().isEmpty(); doUpdate();
} }
bool FlatModel::canFetchMore(const QModelIndex & parent) const void FlatModel::loadExpandData()
{ {
if (!parent.isValid()) { const QList<QVariant> data = SessionManager::value("ProjectTree.ExpandData").value<QList<QVariant>>();
return false; m_toExpand = Utils::transform<QSet>(data, [](const QVariant &v) { return ExpandData::fromSettings(v); });
} else { m_toExpand.remove(ExpandData());
if (FolderNode *folderNode = nodeForIndex(parent)->asFolderNode()) }
return !m_childNodes.contains(folderNode);
else void FlatModel::saveExpandData()
return false; {
// TODO if there are multiple ProjectTreeWidgets, the last one saves the data
QList<QVariant> data = Utils::transform<QList>(m_toExpand, &ExpandData::toSettings);
SessionManager::setValue(QLatin1String("ProjectTree.ExpandData"), data);
}
void FlatModel::addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen)
{
seen->insert(projectNode);
auto node = new WrapperNode(projectNode);
parent->appendChild(node);
addFolderNode(node, projectNode, seen);
const QList<ProjectNode *> subProjectNodes = projectNode->projectNodes();
for (ProjectNode *subProjectNode : subProjectNodes) {
if (!seen->contains(subProjectNode))
addProjectNode(node, subProjectNode, seen);
} }
node->sortChildren(&sortWrapperNodes);
} }
void FlatModel::recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen)
{ {
foreach (FolderNode *folderNode, startNode->folderNodes()) { const QList<FolderNode *> subFolderNodes = folderNode->folderNodes();
if (folderNode && !blackList.contains(folderNode)) for (FolderNode *subFolderNode : subFolderNodes) {
recursiveAddFolderNodesImpl(folderNode, list, blackList); if (!filter(subFolderNode) && !seen->contains(subFolderNode)) {
} seen->insert(subFolderNode);
} auto node = new WrapperNode(subFolderNode);
parent->appendChild(node);
void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const addFolderNode(node, subFolderNode, seen);
{ node->sortChildren(&sortWrapperNodes);
if (!filter(startNode)) { } else {
if (!blackList.contains(startNode)) addFolderNode(parent, subFolderNode, seen);
list->append(startNode);
} else {
foreach (FolderNode *folderNode, startNode->folderNodes()) {
if (folderNode && !blackList.contains(folderNode))
recursiveAddFolderNodesImpl(folderNode, list, blackList);
} }
} }
} const QList<FileNode *> fileNodes = folderNode->fileNodes();
for (FileNode *fileNode : fileNodes) {
void FlatModel::recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const if (!filter(fileNode) && !seen->contains(fileNode)) {
{ seen->insert(fileNode);
foreach (FolderNode *subFolderNode, startNode->folderNodes()) { parent->appendChild(new WrapperNode(fileNode));
if (!blackList.contains(subFolderNode))
recursiveAddFileNodes(subFolderNode, list, blackList);
}
foreach (Node *node, startNode->fileNodes()) {
if (!blackList.contains(node) && !filter(node))
list->append(node);
}
}
QList<Node*> FlatModel::childNodes(FolderNode *parentNode, const QSet<Node*> &blackList) const
{
qCDebug(logger()) << " FlatModel::childNodes for " << parentNode->filePath();
QList<Node*> nodeList;
if (parentNode->nodeType() == NodeType::Session) {
auto sessionNode = static_cast<SessionNode*>(parentNode);
QList<ProjectNode*> projectList = sessionNode->projectNodes();
for (int i = 0; i < projectList.size(); ++i) {
if (!blackList.contains(projectList.at(i)))
nodeList << projectList.at(i);
} }
} else {
recursiveAddFolderNodes(parentNode, &nodeList, blackList);
recursiveAddFileNodes(parentNode, &nodeList, blackList + nodeList.toSet());
} }
Utils::sort(nodeList, sortNodes);
qCDebug(logger()) << " found" << nodeList.size() << "nodes";
return nodeList;
}
void FlatModel::fetchMore(FolderNode *folderNode) const
{
Q_ASSERT(folderNode);
Q_ASSERT(!m_childNodes.contains(folderNode));
QList<Node*> nodeList = childNodes(folderNode);
m_childNodes.insert(folderNode, nodeList);
}
void FlatModel::fetchMore(const QModelIndex &parent)
{
FolderNode *folderNode = nodeForIndex(parent)->asFolderNode();
Q_ASSERT(folderNode);
fetchMore(folderNode);
}
void FlatModel::setStartupProject(ProjectNode *projectNode)
{
if (m_startupProject != projectNode) {
QModelIndex oldIndex = (m_startupProject ? indexForNode(m_startupProject) : QModelIndex());
QModelIndex newIndex = (projectNode ? indexForNode(projectNode) : QModelIndex());
m_startupProject = projectNode;
if (oldIndex.isValid())
emit dataChanged(oldIndex, oldIndex);
if (newIndex.isValid())
emit dataChanged(newIndex, newIndex);
}
}
void FlatModel::reset()
{
beginResetModel();
m_childNodes.clear();
endResetModel();
} }
Qt::DropActions FlatModel::supportedDragActions() const Qt::DropActions FlatModel::supportedDragActions() const
@@ -395,32 +334,17 @@ QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const
return data; return data;
} }
QModelIndex FlatModel::indexForNode(const Node *node_) const WrapperNode *FlatModel::wrapperForNode(const Node *node) const
{ {
// We assume that we are only called for nodes that are represented return findNonRooItem([this, node](WrapperNode *item) {
return item->m_node == node;
});
}
// we use non-const pointers internally QModelIndex FlatModel::indexForNode(const Node *node) const
auto node = const_cast<Node*>(node_); {
if (!node) WrapperNode *wrapper = wrapperForNode(node);
return QModelIndex(); return wrapper ? indexForItem(wrapper) : QModelIndex();
if (node == m_rootNode)
return createIndex(0, 0, m_rootNode);
FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
// Do we have the parent mapped?
QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
if (it == m_childNodes.constEnd()) {
fetchMore(parentNode);
it = m_childNodes.constFind(parentNode);
}
if (it != m_childNodes.constEnd()) {
const int row = it.value().indexOf(node);
if (row != -1)
return createIndex(row, 0, node);
}
return QModelIndex();
} }
void FlatModel::setProjectFilterEnabled(bool filter) void FlatModel::setProjectFilterEnabled(bool filter)
@@ -428,13 +352,13 @@ void FlatModel::setProjectFilterEnabled(bool filter)
if (filter == m_filterProjects) if (filter == m_filterProjects)
return; return;
m_filterProjects = filter; m_filterProjects = filter;
reset(); rebuildModel();
} }
void FlatModel::setGeneratedFilesFilterEnabled(bool filter) void FlatModel::setGeneratedFilesFilterEnabled(bool filter)
{ {
m_filterGeneratedFiles = filter; m_filterGeneratedFiles = filter;
reset(); rebuildModel();
} }
bool FlatModel::projectFilterEnabled() bool FlatModel::projectFilterEnabled()
@@ -449,28 +373,8 @@ bool FlatModel::generatedFilesFilterEnabled()
Node *FlatModel::nodeForIndex(const QModelIndex &index) const Node *FlatModel::nodeForIndex(const QModelIndex &index) const
{ {
if (index.isValid()) WrapperNode *flatNode = itemForIndex(index);
return (Node*)index.internalPointer(); return flatNode ? flatNode->m_node : nullptr;
return nullptr;
}
/*
Returns the first folder node in the ancestors
for the given node that is not filtered
out by the Flat Model.
*/
FolderNode *FlatModel::visibleFolderNode(FolderNode *node) const
{
if (!node)
return nullptr;
for (FolderNode *folderNode = node;
folderNode;
folderNode = folderNode->parentFolderNode()) {
if (!filter(folderNode))
return folderNode;
}
return nullptr;
} }
bool FlatModel::filter(Node *node) const bool FlatModel::filter(Node *node) const
@@ -502,343 +406,9 @@ bool isSorted(const QList<Node *> &nodes)
return true; return true;
} }
/// slots and all the fun void FlatModel::nodeUpdated(Node *)
void FlatModel::added(FolderNode* parentNode, const QList<Node*> &newNodeList)
{ {
qCDebug(logger()) << "FlatModel::added" << parentNode->filePath() << newNodeList.size() << "nodes"; update();
QModelIndex parentIndex = indexForNode(parentNode);
// Old list
if (newNodeList.isEmpty()) {
qCDebug(logger()) << " newNodeList empty";
return;
}
QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
if (it == m_childNodes.constEnd()) {
if (!parentIndex.isValid()) {
qCDebug(logger()) << " parent not mapped returning";
return;
}
qCDebug(logger()) << " updated m_childNodes";
beginInsertRows(parentIndex, 0, newNodeList.size() - 1);
m_childNodes.insert(parentNode, newNodeList);
endInsertRows();
return;
}
QList<Node *> oldNodeList = it.value();
// Compare lists and emit signals, and modify m_childNodes on the fly
QList<Node *>::const_iterator oldIter = oldNodeList.constBegin();
QList<Node *>::const_iterator newIter = newNodeList.constBegin();
Q_ASSERT(isSorted(oldNodeList));
Q_ASSERT(isSorted(newNodeList));
QSet<Node *> emptyDifference;
emptyDifference = oldNodeList.toSet();
emptyDifference.subtract(newNodeList.toSet());
if (!emptyDifference.isEmpty()) {
// This should not happen...
qDebug() << "FlatModel::added, old Node list should be subset of newNode list, found files in old list which were not part of new list";
foreach (Node *n, emptyDifference)
qDebug()<<n->filePath();
Q_ASSERT(false);
}
// optimization, check for old list is empty
if (oldIter == oldNodeList.constEnd()) {
// New Node List is empty, nothing added which intrest us
if (newIter == newNodeList.constEnd())
return;
// So all we need to do is easy
beginInsertRows(parentIndex, 0, newNodeList.size() - 1);
m_childNodes.insert(parentNode, newNodeList);
endInsertRows();
qCDebug(logger()) << " updated m_childNodes";
return;
}
while (true) {
// Skip all that are the same
while (*oldIter == *newIter) {
++oldIter;
++newIter;
if (oldIter == oldNodeList.constEnd()) {
// At end of oldNodeList, sweep up rest of newNodeList
QList<Node *>::const_iterator startOfBlock = newIter;
newIter = newNodeList.constEnd();
int pos = oldIter - oldNodeList.constBegin();
int count = newIter - startOfBlock;
if (count > 0) {
beginInsertRows(parentIndex, pos, pos+count-1);
while (startOfBlock != newIter) {
oldNodeList.insert(pos, *startOfBlock);
++pos;
++startOfBlock;
}
m_childNodes.insert(parentNode, oldNodeList);
endInsertRows();
}
return; // Done with the lists, leave the function
}
}
QList<Node *>::const_iterator startOfBlock = newIter;
while (*oldIter != *newIter)
++newIter;
// startOfBlock is the first that was diffrent
// newIter points to the new position of oldIter
// newIter - startOfBlock is number of new items
// oldIter is the position where those are...
int pos = oldIter - oldNodeList.constBegin();
int count = newIter - startOfBlock;
beginInsertRows(parentIndex, pos, pos + count - 1);
while (startOfBlock != newIter) {
oldNodeList.insert(pos, *startOfBlock);
++pos;
++startOfBlock;
}
m_childNodes.insert(parentNode, oldNodeList);
endInsertRows();
oldIter = oldNodeList.constBegin() + pos;
}
qCDebug(logger()) << " updated m_childNodes";
}
void FlatModel::removed(FolderNode* parentNode, const QList<Node*> &newNodeList)
{
qCDebug(logger()) << "FlatModel::removed" << parentNode->filePath() << newNodeList.size() << "nodes";
QModelIndex parentIndex = indexForNode(parentNode);
// Old list
QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
if (it == m_childNodes.constEnd()) {
qCDebug(logger()) << " unmapped node";
return;
}
QList<Node *> oldNodeList = it.value();
// Compare lists and emit signals, and modify m_childNodes on the fly
QList<Node *>::const_iterator oldIter = oldNodeList.constBegin();
QList<Node *>::const_iterator newIter = newNodeList.constBegin();
Q_ASSERT(isSorted(newNodeList));
QSet<Node *> emptyDifference;
emptyDifference = newNodeList.toSet();
emptyDifference.subtract(oldNodeList.toSet());
if (!emptyDifference.isEmpty()) {
// This should not happen...
qDebug() << "FlatModel::removed, new Node list should be subset of oldNode list, found files in new list which were not part of old list";
foreach (Node *n, emptyDifference)
qDebug()<<n->filePath();
Q_ASSERT(false);
}
// optimization, check for new list is empty
if (newIter == newNodeList.constEnd()) {
// New Node List is empty, everything removed
if (oldIter == oldNodeList.constEnd())
return;
// So all we need to do is easy
beginRemoveRows(parentIndex, 0, oldNodeList.size() - 1);
m_childNodes.insert(parentNode, newNodeList);
endRemoveRows();
qCDebug(logger()) << " updated m_childNodes";
return;
}
while (true) {
// Skip all that are the same
while (*oldIter == *newIter) {
++oldIter;
++newIter;
if (newIter == newNodeList.constEnd()) {
// At end of newNodeList, sweep up rest of oldNodeList
QList<Node *>::const_iterator startOfBlock = oldIter;
oldIter = oldNodeList.constEnd();
int pos = startOfBlock - oldNodeList.constBegin();
int count = oldIter - startOfBlock;
if (count > 0) {
beginRemoveRows(parentIndex, pos, pos+count-1);
while (startOfBlock != oldIter) {
++startOfBlock;
oldNodeList.removeAt(pos);
}
m_childNodes.insert(parentNode, oldNodeList);
endRemoveRows();
}
return; // Done with the lists, leave the function
}
}
QList<Node *>::const_iterator startOfBlock = oldIter;
while (*oldIter != *newIter)
++oldIter;
// startOfBlock is the first that was diffrent
// oldIter points to the new position of newIter
// oldIter - startOfBlock is number of new items
// newIter is the position where those are...
int pos = startOfBlock - oldNodeList.constBegin();
int count = oldIter - startOfBlock;
beginRemoveRows(parentIndex, pos, pos + count - 1);
while (startOfBlock != oldIter) {
++startOfBlock;
oldNodeList.removeAt(pos);
}
m_childNodes.insert(parentNode, oldNodeList);
endRemoveRows();
oldIter = oldNodeList.constBegin() + pos;
}
qCDebug(logger()) << " updated m_childNodes";
}
void FlatModel::aboutToShowInSimpleTreeChanged(FolderNode* node)
{
if (!m_filterProjects)
return;
FolderNode *folder = visibleFolderNode(node->parentFolderNode());
QList<Node *> newNodeList = childNodes(folder, QSet<Node *>() << node);
removed(folder, newNodeList);
QList<Node *> staleFolders;
recursiveAddFolderNodesImpl(node, &staleFolders);
foreach (Node *n, staleFolders)
if (FolderNode *fn = n->asFolderNode())
m_childNodes.remove(fn);
}
void FlatModel::showInSimpleTreeChanged(FolderNode *node)
{
if (!m_filterProjects)
return;
// we are only interested if we filter
FolderNode *folder = visibleFolderNode(node->parentFolderNode());
QList<Node *> newNodeList = childNodes(folder);
added(folder, newNodeList);
}
void FlatModel::foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders)
{
qCDebug(logger()) << "FlatModel::foldersAboutToBeAdded";
Q_UNUSED(newFolders)
m_parentFolderForChange = parentFolder;
}
void FlatModel::foldersAdded()
{
// First found out what the folder is that we are adding the files to
FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange);
// Now get the new list for that folder
QList<Node *> newNodeList = childNodes(folderNode);
added(folderNode, newNodeList);
}
void FlatModel::foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders)
{
QSet<Node *> blackList;
foreach (FolderNode *node, staleFolders)
blackList.insert(node);
FolderNode *folderNode = visibleFolderNode(parentFolder);
QList<Node *> newNodeList = childNodes(folderNode, blackList);
removed(folderNode, newNodeList);
removeFromCache(staleFolders);
}
void FlatModel::removeFromCache(QList<FolderNode *> list)
{
foreach (FolderNode *fn, list) {
removeFromCache(fn->folderNodes());
m_childNodes.remove(fn);
}
}
void FlatModel::changedSortKey(FolderNode *folderNode, Node *node)
{
if (!m_childNodes.contains(folderNode))
return; // The directory was not yet mapped, so there is no need to sort it.
QList<Node *> nodes = m_childNodes.value(folderNode);
int oldIndex = nodes.indexOf(node);
nodes.removeAt(oldIndex);
QList<Node *>::iterator newPosIt = std::lower_bound(nodes.begin(), nodes.end(), node, sortNodes);
int newIndex = newPosIt - nodes.begin();
if (newIndex == oldIndex)
return;
nodes.insert(newPosIt, node);
QModelIndex parentIndex = indexForNode(folderNode);
if (newIndex > oldIndex)
++newIndex; // see QAbstractItemModel::beginMoveRows
beginMoveRows(parentIndex, oldIndex, oldIndex, parentIndex, newIndex);
m_childNodes[folderNode] = nodes;
endMoveRows();
}
void FlatModel::foldersRemoved()
{
// Do nothing
}
void FlatModel::filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles)
{
qCDebug(logger()) << "FlatModel::filesAboutToBeAdded";
Q_UNUSED(newFiles)
m_parentFolderForChange = folder;
}
void FlatModel::filesAdded()
{
// First find out what the folder is that we are adding the files to
FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange);
// Now get the new List for that folder
QList<Node *> newNodeList = childNodes(folderNode);
added(folderNode, newNodeList);
}
void FlatModel::filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles)
{
// First found out what the folder (that is the project) is that we are adding the files to
FolderNode *folderNode = visibleFolderNode(folder);
QSet<Node *> blackList;
foreach (Node *node, staleFiles)
blackList.insert(node);
// Now get the new List for that folder
QList<Node *> newNodeList = childNodes(folderNode, blackList);
removed(folderNode, newNodeList);
}
void FlatModel::filesRemoved()
{
// Do nothing
}
void FlatModel::nodeSortKeyAboutToChange(Node *node)
{
m_nodeForSortKeyChange = node;
}
void FlatModel::nodeSortKeyChanged()
{
FolderNode *folderNode = visibleFolderNode(m_nodeForSortKeyChange->parentFolderNode());
changedSortKey(folderNode, m_nodeForSortKeyChange);
}
void FlatModel::nodeUpdated(Node *node)
{
QModelIndex idx = indexForNode(node);
emit dataChanged(idx, idx);
} }
namespace Internal { namespace Internal {

View File

@@ -25,51 +25,53 @@
#pragma once #pragma once
#include <utils/fileutils.h> #include "expanddata.h"
#include "projectnodes.h"
#include <QAbstractItemModel> #include <utils/fileutils.h>
#include <utils/treemodel.h>
#include <QPointer>
#include <QSet> #include <QSet>
#include <QTimer>
#include <QTreeView>
namespace ProjectExplorer { namespace ProjectExplorer {
class Node; class Node;
class FileNode;
class FolderNode; class FolderNode;
class Project;
class ProjectNode; class ProjectNode;
class SessionNode;
namespace Internal { namespace Internal {
class FlatModel : public QAbstractItemModel class WrapperNode : public Utils::TypedTreeItem<WrapperNode>
{
public:
explicit WrapperNode(Node *node) : m_node(node) {}
QPointer<Node> m_node;
};
class FlatModel : public Utils::TreeModel<WrapperNode, WrapperNode>
{ {
Q_OBJECT Q_OBJECT
public: public:
FlatModel(SessionNode *rootNode, QObject *parent); FlatModel(QObject *parent);
void setView(QTreeView *view);
// QAbstractItemModel // QAbstractItemModel
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override; Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override; bool setData(const QModelIndex &index, const QVariant &value, int role) override;
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
int columnCount(const QModelIndex & parent = QModelIndex()) const override;
bool hasChildren(const QModelIndex & parent = QModelIndex()) const override;
bool canFetchMore(const QModelIndex & parent) const override;
void fetchMore(const QModelIndex & parent) override;
void reset();
Qt::DropActions supportedDragActions() const override; Qt::DropActions supportedDragActions() const override;
QStringList mimeTypes() const override; QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override; QMimeData *mimeData(const QModelIndexList &indexes) const override;
void setStartupProject(ProjectNode *projectNode);
Node *nodeForIndex(const QModelIndex &index) const; Node *nodeForIndex(const QModelIndex &index) const;
WrapperNode *wrapperForNode(const Node *node) const;
QModelIndex indexForNode(const Node *node) const; QModelIndex indexForNode(const Node *node) const;
bool projectFilterEnabled(); bool projectFilterEnabled();
@@ -81,53 +83,34 @@ signals:
void renamed(const Utils::FileName &oldName, const Utils::FileName &newName); void renamed(const Utils::FileName &oldName, const Utils::FileName &newName);
private: private:
void aboutToShowInSimpleTreeChanged(ProjectExplorer::FolderNode *node); void startupProjectChanged(Project *project);
void showInSimpleTreeChanged(ProjectExplorer::FolderNode *node);
void foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders);
void foldersAdded();
void foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders);
void foldersRemoved();
// files
void filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles);
void filesAdded();
void filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles);
void filesRemoved();
void nodeSortKeyAboutToChange(Node *node);
void nodeSortKeyChanged();
void nodeUpdated(ProjectExplorer::Node *node); void nodeUpdated(ProjectExplorer::Node *node);
void added(FolderNode* folderNode, const QList<Node*> &newNodeList); bool filter(Node *node) const; // Returns true if node is hidden.
void removed(FolderNode* parentNode, const QList<Node*> &newNodeList);
void removeFromCache(QList<FolderNode *> list);
void changedSortKey(FolderNode *folderNode, Node *node);
void fetchMore(FolderNode *foldernode) const;
void recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const;
void recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const;
void recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const;
QList<Node*> childNodes(FolderNode *parentNode, const QSet<Node*> &blackList = QSet<Node*>()) const;
FolderNode *visibleFolderNode(FolderNode *node) const;
bool filter(Node *node) const;
bool m_filterProjects = false; bool m_filterProjects = false;
bool m_filterGeneratedFiles = true; bool m_filterGeneratedFiles = true;
SessionNode *m_rootNode;
mutable QHash<FolderNode*, QList<Node*> > m_childNodes;
ProjectNode *m_startupProject = nullptr; ProjectNode *m_startupProject = nullptr;
FolderNode *m_parentFolderForChange = nullptr;
Node *m_nodeForSortKeyChange = nullptr;
static const QLoggingCategory &logger(); static const QLoggingCategory &logger();
friend class FlatModelManager; void update();
void doUpdate();
void rebuildModel();
void addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen);
void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen);
ExpandData expandDataForNode(const Node *node) const;
void onExpanded(const QModelIndex &idx);
void onCollapsed(const QModelIndex &idx);
void loadExpandData();
void saveExpandData();
void handleProjectAdded(Project *project);
QTimer m_timer;
QTreeView *m_view = nullptr;
QSet<ExpandData> m_toExpand;
}; };
int caseFriendlyCompare(const QString &a, const QString &b); int caseFriendlyCompare(const QString &a, const QString &b);

View File

@@ -68,30 +68,21 @@ void Node::setPriority(int p)
m_priority = p; m_priority = p;
} }
void Node::emitNodeSortKeyAboutToChange()
{
if (parentFolderNode())
ProjectTree::instance()->emitNodeSortKeyAboutToChange(this);
}
void Node::emitNodeSortKeyChanged()
{
if (parentFolderNode())
ProjectTree::instance()->emitNodeSortKeyChanged(this);
}
void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line) void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line)
{ {
if (m_filePath == path && m_line == line) if (m_filePath == path && m_line == line)
return; return;
emitNodeSortKeyAboutToChange();
m_filePath = path; m_filePath = path;
m_line = line; m_line = line;
emitNodeSortKeyChanged();
emitNodeUpdated(); emitNodeUpdated();
} }
Node::~Node()
{
}
NodeType Node::nodeType() const NodeType Node::nodeType() const
{ {
return m_nodeType; return m_nodeType;
@@ -186,7 +177,12 @@ void Node::setEnabled(bool enabled)
void Node::emitNodeUpdated() void Node::emitNodeUpdated()
{ {
if (parentFolderNode()) if (parentFolderNode())
ProjectTree::instance()->emitNodeUpdated(this); ProjectTree::emitNodeUpdated(this);
}
void Node::emitTreeChanged()
{
ProjectTree::emitDataChanged();
} }
Node *Node::trim(const QSet<Node *> &keepers) Node *Node::trim(const QSet<Node *> &keepers)
@@ -511,9 +507,7 @@ void FolderNode::setDisplayName(const QString &name)
{ {
if (m_displayName == name) if (m_displayName == name)
return; return;
emitNodeSortKeyAboutToChange();
m_displayName = name; m_displayName = name;
emitNodeSortKeyChanged();
emitNodeUpdated(); emitNodeUpdated();
} }
@@ -588,8 +582,6 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files)
if (files.isEmpty()) if (files.isEmpty())
return; return;
ProjectTree::instance()->emitFilesAboutToBeAdded(this, files);
foreach (FileNode *file, files) { foreach (FileNode *file, files) {
QTC_ASSERT(!file->parentFolderNode(), QTC_ASSERT(!file->parentFolderNode(),
qDebug("File node has already a parent folder")); qDebug("File node has already a parent folder"));
@@ -606,7 +598,7 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files)
} }
} }
ProjectTree::instance()->emitFilesAdded(this); ProjectTree::emitDataChanged();
} }
/*! /*!
@@ -627,8 +619,6 @@ void FolderNode::removeFileNodes(const QList<FileNode *> &files)
QList<FileNode*> toRemove = files; QList<FileNode*> toRemove = files;
Utils::sort(toRemove); Utils::sort(toRemove);
ProjectTree::instance()->emitFilesAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin(); auto toRemoveIter = toRemove.constBegin();
auto filesIter = m_fileNodes.begin(); auto filesIter = m_fileNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
@@ -641,7 +631,7 @@ void FolderNode::removeFileNodes(const QList<FileNode *> &files)
filesIter = m_fileNodes.erase(filesIter); filesIter = m_fileNodes.erase(filesIter);
} }
ProjectTree::instance()->emitFilesRemoved(this); ProjectTree::emitDataChanged();
} }
/*! /*!
@@ -655,7 +645,6 @@ void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders)
if (subFolders.isEmpty()) if (subFolders.isEmpty())
return; return;
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, subFolders);
foreach (FolderNode *folder, subFolders) { foreach (FolderNode *folder, subFolders) {
QTC_ASSERT(!folder->parentFolderNode(), QTC_ASSERT(!folder->parentFolderNode(),
qDebug("Project node has already a parent folder")); qDebug("Project node has already a parent folder"));
@@ -677,7 +666,7 @@ void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders)
qDebug("project nodes have to be added via addProjectNodes")); qDebug("project nodes have to be added via addProjectNodes"));
} }
ProjectTree::instance()->emitFoldersAdded(this); ProjectTree::emitDataChanged();
} }
/*! /*!
@@ -696,8 +685,6 @@ void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders)
QList<FolderNode*> toRemove = subFolders; QList<FolderNode*> toRemove = subFolders;
Utils::sort(toRemove); Utils::sort(toRemove);
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin(); auto toRemoveIter = toRemove.constBegin();
auto folderIter = m_folderNodes.begin(); auto folderIter = m_folderNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
@@ -712,7 +699,7 @@ void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders)
folderIter = m_folderNodes.erase(folderIter); folderIter = m_folderNodes.erase(folderIter);
} }
ProjectTree::instance()->emitFoldersRemoved(this); ProjectTree::emitDataChanged();
} }
bool FolderNode::showInSimpleTree() const bool FolderNode::showInSimpleTree() const
@@ -867,8 +854,6 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
foreach (ProjectNode *projectNode, subProjects) foreach (ProjectNode *projectNode, subProjects)
folderNodes << projectNode; folderNodes << projectNode;
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes);
foreach (ProjectNode *project, subProjects) { foreach (ProjectNode *project, subProjects) {
QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this, QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
qDebug("Project node has already a parent")); qDebug("Project node has already a parent"));
@@ -876,10 +861,9 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
m_folderNodes.append(project); m_folderNodes.append(project);
m_projectNodes.append(project); m_projectNodes.append(project);
} }
Utils::sort(m_folderNodes); Utils::sort(m_folderNodes);
Utils::sort(m_projectNodes); Utils::sort(m_projectNodes);
ProjectTree::instance()->emitFoldersAdded(this);
} }
} }
@@ -898,8 +882,6 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
toRemove << projectNode; toRemove << projectNode;
Utils::sort(toRemove); Utils::sort(toRemove);
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin(); auto toRemoveIter = toRemove.constBegin();
auto folderIter = m_folderNodes.begin(); auto folderIter = m_folderNodes.begin();
auto projectIter = m_projectNodes.begin(); auto projectIter = m_projectNodes.begin();
@@ -918,8 +900,6 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
projectIter = m_projectNodes.erase(projectIter); projectIter = m_projectNodes.erase(projectIter);
folderIter = m_folderNodes.erase(folderIter); folderIter = m_folderNodes.erase(folderIter);
} }
ProjectTree::instance()->emitFoldersRemoved(this);
} }
} }
@@ -967,12 +947,6 @@ bool SessionNode::showInSimpleTree() const
return true; return true;
} }
void SessionNode::projectDisplayNameChanged(Node *node)
{
ProjectTree::instance()->emitNodeSortKeyAboutToChange(node);
ProjectTree::instance()->emitNodeSortKeyChanged(node);
}
QList<ProjectNode*> SessionNode::projectNodes() const QList<ProjectNode*> SessionNode::projectNodes() const
{ {
return m_projectNodes; return m_projectNodes;
@@ -990,8 +964,6 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
foreach (ProjectNode *projectNode, projectNodes) foreach (ProjectNode *projectNode, projectNodes)
folderNodes << projectNode; folderNodes << projectNode;
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes);
foreach (ProjectNode *project, projectNodes) { foreach (ProjectNode *project, projectNodes) {
QTC_ASSERT(!project->parentFolderNode(), QTC_ASSERT(!project->parentFolderNode(),
qDebug("Project node has already a parent folder")); qDebug("Project node has already a parent folder"));
@@ -1002,8 +974,6 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
Utils::sort(m_folderNodes); Utils::sort(m_folderNodes);
Utils::sort(m_projectNodes); Utils::sort(m_projectNodes);
ProjectTree::instance()->emitFoldersAdded(this);
} }
} }
@@ -1015,9 +985,6 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
toRemove << projectNode; toRemove << projectNode;
Utils::sort(toRemove); Utils::sort(toRemove);
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin(); auto toRemoveIter = toRemove.constBegin();
auto folderIter = m_folderNodes.begin(); auto folderIter = m_folderNodes.begin();
auto projectIter = m_projectNodes.begin(); auto projectIter = m_projectNodes.begin();
@@ -1035,8 +1002,6 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
projectIter = m_projectNodes.erase(projectIter); projectIter = m_projectNodes.erase(projectIter);
folderIter = m_folderNodes.erase(folderIter); folderIter = m_folderNodes.erase(folderIter);
} }
ProjectTree::instance()->emitFoldersRemoved(this);
} }
} }

View File

@@ -104,8 +104,9 @@ class NodesVisitor;
class SessionManager; class SessionManager;
// Documentation inside. // Documentation inside.
class PROJECTEXPLORER_EXPORT Node class PROJECTEXPLORER_EXPORT Node : public QObject
{ {
Q_OBJECT
public: public:
enum PriorityLevel { enum PriorityLevel {
DefaultPriority = 0, DefaultPriority = 0,
@@ -116,7 +117,7 @@ public:
DefaultProjectFilePriority = 500000 DefaultProjectFilePriority = 500000
}; };
virtual ~Node() = default; virtual ~Node();
NodeType nodeType() const; NodeType nodeType() const;
int priority() const; int priority() const;
@@ -141,6 +142,7 @@ public:
void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line); void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
void emitNodeUpdated(); void emitNodeUpdated();
void emitTreeChanged();
virtual Node *trim(const QSet<Node *> &keepers); virtual Node *trim(const QSet<Node *> &keepers);
@@ -161,9 +163,6 @@ protected:
void setPriority(int priority); void setPriority(int priority);
void setParentFolderNode(FolderNode *parentFolder); void setParentFolderNode(FolderNode *parentFolder);
void emitNodeSortKeyAboutToChange();
void emitNodeSortKeyChanged();
private: private:
FolderNode *m_parentFolderNode = nullptr; FolderNode *m_parentFolderNode = nullptr;
Utils::FileName m_filePath; Utils::FileName m_filePath;
@@ -177,6 +176,7 @@ class PROJECTEXPLORER_EXPORT FileNode : public Node
{ {
public: public:
FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1); FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1);
FileNode(const FileNode &other) : FileNode(other.filePath(), other.fileType(), true) {}
FileType fileType() const; FileType fileType() const;
bool isGenerated() const; bool isGenerated() const;
@@ -255,8 +255,8 @@ public:
void addFolderNodes(const QList<FolderNode*> &subFolders); void addFolderNodes(const QList<FolderNode*> &subFolders);
void removeFolderNodes(const QList<FolderNode*> &subFolders); void removeFolderNodes(const QList<FolderNode*> &subFolders);
FolderNode *asFolderNode() final { return this; } FolderNode *asFolderNode() override { return this; }
const FolderNode *asFolderNode() const final { return this; } const FolderNode *asFolderNode() const override { return this; }
protected: protected:
QList<FolderNode*> m_folderNodes; QList<FolderNode*> m_folderNodes;
@@ -330,11 +330,8 @@ public:
SessionNode(); SessionNode();
QList<ProjectAction> supportedActions(Node *node) const override; QList<ProjectAction> supportedActions(Node *node) const override;
QList<ProjectNode*> projectNodes() const; QList<ProjectNode*> projectNodes() const;
QString addFileFilter() const override; QString addFileFilter() const override;
void accept(NodesVisitor *visitor) override; void accept(NodesVisitor *visitor) override;
bool showInSimpleTree() const override; bool showInSimpleTree() const override;

View File

@@ -258,167 +258,14 @@ void ProjectTree::updateContext()
void ProjectTree::emitNodeUpdated(Node *node) void ProjectTree::emitNodeUpdated(Node *node)
{ {
if (!isInNodeHierarchy(node)) if (!s_instance->isInNodeHierarchy(node))
return; return;
emit nodeUpdated(node); emit s_instance->nodeUpdated(node);
} }
void ProjectTree::emitAboutToChangeShowInSimpleTree(FolderNode *node) void ProjectTree::emitDataChanged()
{ {
if (!isInNodeHierarchy(node)) instance()->dataChanged();
return;
emit aboutToChangeShowInSimpleTree(node);
}
void ProjectTree::emitShowInSimpleTreeChanged(FolderNode *node)
{
if (!isInNodeHierarchy(node))
return;
emit showInSimpleTreeChanged(node);
}
void ProjectTree::emitFoldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode *> &newFolders)
{
if (!isInNodeHierarchy(parentFolder))
return;
m_foldersAdded = newFolders;
emit foldersAboutToBeAdded(parentFolder, newFolders);
}
void ProjectTree::emitFoldersAdded(FolderNode *folder)
{
if (!isInNodeHierarchy(folder))
return;
emit foldersAdded();
if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus))
return;
if (!m_currentNode) {
Core::IDocument *document = Core::EditorManager::currentDocument();
const FileName fileName = document ? document->filePath() : FileName();
FindNodesForFileVisitor findNodes(fileName);
foreach (FolderNode *fn, m_foldersAdded)
fn->accept(&findNodes);
Node *bestNode = ProjectTreeWidget::mostExpandedNode(findNodes.nodes());
if (!bestNode)
return;
updateFromNode(bestNode);
}
m_foldersAdded.clear();
}
void ProjectTree::emitFoldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode *> &staleFolders)
{
if (!isInNodeHierarchy(parentFolder))
return;
Node *n = ProjectTree::currentNode();
while (n) {
if (FolderNode *fn = n->asFolderNode()) {
if (staleFolders.contains(fn)) {
ProjectNode *pn = n->parentProjectNode();
// Make sure the node we are switching too isn't going to be removed also
while (staleFolders.contains(pn))
pn = pn->parentFolderNode()->parentProjectNode();
m_resetCurrentNodeFolder = true;
break;
}
}
n = n->parentFolderNode();
}
emit foldersAboutToBeRemoved(parentFolder, staleFolders);
}
void ProjectTree::emitFoldersRemoved(FolderNode *folder)
{
if (!isInNodeHierarchy(folder))
return;
emit foldersRemoved();
if (m_resetCurrentNodeFolder) {
updateFromFocus(true);
m_resetCurrentNodeFolder = false;
}
}
void ProjectTree::emitFilesAboutToBeAdded(FolderNode *folder, const QList<FileNode *> &newFiles)
{
if (!isInNodeHierarchy(folder))
return;
m_filesAdded = newFiles;
emit filesAboutToBeAdded(folder, newFiles);
}
void ProjectTree::emitFilesAdded(FolderNode *folder)
{
if (!isInNodeHierarchy(folder))
return;
emit filesAdded();
if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus))
return;
if (!m_currentNode) {
Core::IDocument *document = Core::EditorManager::currentDocument();
const FileName fileName = document ? document->filePath() : FileName();
int index = Utils::indexOf(m_filesAdded, Utils::equal(&FileNode::filePath, fileName));
if (index == -1)
return;
updateFromNode(m_filesAdded.at(index));
}
m_filesAdded.clear();
}
void ProjectTree::emitFilesAboutToBeRemoved(FolderNode *folder, const QList<FileNode *> &staleFiles)
{
if (!isInNodeHierarchy(folder))
return;
if (m_currentNode)
if (FileNode *fileNode = m_currentNode->asFileNode())
if (staleFiles.contains(fileNode))
m_resetCurrentNodeFile = true;
emit filesAboutToBeRemoved(folder, staleFiles);
}
void ProjectTree::emitFilesRemoved(FolderNode *folder)
{
if (!isInNodeHierarchy(folder))
return;
emit filesRemoved();
if (m_resetCurrentNodeFile) {
updateFromFocus(true);
m_resetCurrentNodeFile = false;
}
}
void ProjectTree::emitNodeSortKeyAboutToChange(Node *node)
{
if (!isInNodeHierarchy(node))
return;
emit nodeSortKeyAboutToChange(node);
}
void ProjectTree::emitNodeSortKeyChanged(Node *node)
{
if (!isInNodeHierarchy(node))
return;
emit nodeSortKeyChanged();
} }
void ProjectTree::collapseAll() void ProjectTree::collapseAll()

View File

@@ -68,61 +68,14 @@ signals:
// Emitted whenever the model needs to send a update signal. // Emitted whenever the model needs to send a update signal.
void nodeUpdated(ProjectExplorer::Node *node); void nodeUpdated(ProjectExplorer::Node *node);
void dataChanged();
// projects
void aboutToChangeShowInSimpleTree(ProjectExplorer::FolderNode*);
void showInSimpleTreeChanged(ProjectExplorer::FolderNode *node);
// folders & projects
void foldersAboutToBeAdded(FolderNode *parentFolder,
const QList<FolderNode*> &newFolders);
void foldersAdded();
void foldersAboutToBeRemoved(FolderNode *parentFolder,
const QList<FolderNode*> &staleFolders);
void foldersRemoved();
// files
void filesAboutToBeAdded(FolderNode *folder,
const QList<FileNode*> &newFiles);
void filesAdded();
void filesAboutToBeRemoved(FolderNode *folder,
const QList<FileNode*> &staleFiles);
void filesRemoved();
void nodeSortKeyAboutToChange(Node *node);
void nodeSortKeyChanged();
void aboutToShowContextMenu(ProjectExplorer::Project *project, void aboutToShowContextMenu(ProjectExplorer::Project *project,
ProjectExplorer::Node *node); ProjectExplorer::Node *node);
public: // for nodes to emit signals, do not call unless you are a node public: // for nodes to emit signals, do not call unless you are a node
void emitNodeUpdated(ProjectExplorer::Node *node); static void emitNodeUpdated(ProjectExplorer::Node *node);
static void emitDataChanged();
// projects
void emitAboutToChangeShowInSimpleTree(ProjectExplorer::FolderNode *node);
void emitShowInSimpleTreeChanged(ProjectExplorer::FolderNode *node);
// folders & projects
void emitFoldersAboutToBeAdded(FolderNode *parentFolder,
const QList<FolderNode*> &newFolders);
void emitFoldersAdded(FolderNode *folder);
void emitFoldersAboutToBeRemoved(FolderNode *parentFolder,
const QList<FolderNode*> &staleFolders);
void emitFoldersRemoved(FolderNode *folder);
// files
void emitFilesAboutToBeAdded(FolderNode *folder,
const QList<FileNode*> &newFiles);
void emitFilesAdded(FolderNode *folder);
void emitFilesAboutToBeRemoved(FolderNode *folder,
const QList<FileNode*> &staleFiles);
void emitFilesRemoved(FolderNode *folder);
void emitNodeSortKeyAboutToChange(Node *node);
void emitNodeSortKeyChanged(Node *node);
void collapseAll(); void collapseAll();
private: private:
@@ -144,14 +97,9 @@ private:
private: private:
static ProjectTree *s_instance; static ProjectTree *s_instance;
QList<Internal::ProjectTreeWidget *> m_projectTreeWidgets; QList<QPointer<Internal::ProjectTreeWidget>> m_projectTreeWidgets;
Node *m_currentNode = nullptr; QPointer<Node> m_currentNode;
Project *m_currentProject = nullptr; Project *m_currentProject = nullptr;
QList<FileNode *> m_filesAdded;
QList<FolderNode *> m_foldersAdded;
bool m_resetCurrentNodeFolder = false;
bool m_resetCurrentNodeFile = false;
bool m_resetCurrentNodeProject = false;
Internal::ProjectTreeWidget *m_focusForContextMenu = nullptr; Internal::ProjectTreeWidget *m_focusForContextMenu = nullptr;
Core::Context m_lastProjectContext; Core::Context m_lastProjectContext;
}; };

View File

@@ -167,17 +167,15 @@ private:
*/ */
ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
{ {
m_model = new FlatModel(SessionManager::sessionNode(), this); // We keep one instance per tree as this also manages the
Project *pro = SessionManager::startupProject(); // simple/non-simple etc state which is per tree.
if (pro) m_model = new FlatModel(this);
m_model->setStartupProject(pro->rootProjectNode());
m_view = new ProjectTreeView; m_view = new ProjectTreeView;
m_view->setModel(m_model); m_view->setModel(m_model);
m_view->setItemDelegate(new ProjectTreeItemDelegate(this)); m_view->setItemDelegate(new ProjectTreeItemDelegate(this));
setFocusProxy(m_view); setFocusProxy(m_view);
m_view->installEventFilter(this); m_view->installEventFilter(this);
initView(); m_model->setView(m_view);
auto layout = new QVBoxLayout(); auto layout = new QVBoxLayout();
layout->addWidget(ItemViewFind::createSearchableWrapper( layout->addWidget(ItemViewFind::createSearchableWrapper(
@@ -198,8 +196,6 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
this, &ProjectTreeWidget::setGeneratedFilesFilter); this, &ProjectTreeWidget::setGeneratedFilesFilter);
// connections // connections
connect(m_model, &QAbstractItemModel::modelReset,
this, &ProjectTreeWidget::initView);
connect(m_model, &FlatModel::renamed, connect(m_model, &FlatModel::renamed,
this, &ProjectTreeWidget::renamed); this, &ProjectTreeWidget::renamed);
connect(m_view, &QAbstractItemView::activated, connect(m_view, &QAbstractItemView::activated,
@@ -209,19 +205,6 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
connect(m_view, &QWidget::customContextMenuRequested, connect(m_view, &QWidget::customContextMenuRequested,
this, &ProjectTreeWidget::showContextMenu); this, &ProjectTreeWidget::showContextMenu);
SessionManager *sessionManager = SessionManager::instance();
connect(sessionManager, &SessionManager::projectAdded,
this, &ProjectTreeWidget::handleProjectAdded);
connect(sessionManager, &SessionManager::startupProjectChanged,
this, &ProjectTreeWidget::startupProjectChanged);
connect(sessionManager, &SessionManager::aboutToLoadSession,
this, &ProjectTreeWidget::disableAutoExpand);
connect(sessionManager, &SessionManager::sessionLoaded,
this, &ProjectTreeWidget::loadExpandData);
connect(sessionManager, &SessionManager::aboutToSaveSession,
this, &ProjectTreeWidget::saveExpandData);
m_toggleSync = new QToolButton; m_toggleSync = new QToolButton;
m_toggleSync->setIcon(Utils::Icons::LINK.icon()); m_toggleSync->setIcon(Utils::Icons::LINK.icon());
m_toggleSync->setCheckable(true); m_toggleSync->setCheckable(true);
@@ -230,6 +213,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
connect(m_toggleSync, &QAbstractButton::clicked, connect(m_toggleSync, &QAbstractButton::clicked,
this, &ProjectTreeWidget::toggleAutoSynchronization); this, &ProjectTreeWidget::toggleAutoSynchronization);
setCurrentItem(ProjectTree::currentNode());
setAutoSynchronization(true); setAutoSynchronization(true);
m_projectTreeWidgets << this; m_projectTreeWidgets << this;
@@ -268,14 +252,6 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e
{ {
Node *node = m_model->nodeForIndex(parent); Node *node = m_model->nodeForIndex(parent);
QTC_ASSERT(node, return); QTC_ASSERT(node, return);
const QString path = node->filePath().toString();
const QString displayName = node->displayName();
auto it = m_toExpand.find(ExpandData(path, displayName));
if (it != m_toExpand.end()) {
m_view->expand(parent);
m_toExpand.erase(it);
}
int i = start; int i = start;
while (i <= end) { while (i <= end) {
QModelIndex idx = m_model->index(i, 0, parent); QModelIndex idx = m_model->index(i, 0, parent);
@@ -317,68 +293,6 @@ Node *ProjectTreeWidget::mostExpandedNode(const QList<Node *> &nodes)
return bestNode; return bestNode;
} }
void ProjectTreeWidget::disableAutoExpand()
{
m_autoExpand = false;
}
void ProjectTreeWidget::loadExpandData()
{
m_autoExpand = true;
QList<QVariant> data = SessionManager::value(QLatin1String("ProjectTree.ExpandData")).value<QList<QVariant>>();
QSet<ExpandData> set = Utils::transform<QSet>(data, [](const QVariant &v) {
QStringList list = v.toStringList();
if (list.size() != 2)
return ExpandData();
return ExpandData(list.at(0), list.at(1));
});
set.remove(ExpandData());
recursiveLoadExpandData(m_view->rootIndex(), set);
// store remaning nodes to expand
m_toExpand = set;
}
void ProjectTreeWidget::recursiveLoadExpandData(const QModelIndex &index, QSet<ExpandData> &data)
{
Node *node = m_model->nodeForIndex(index);
const QString path = node->filePath().toString();
const QString displayName = node->displayName();
auto it = data.find(ExpandData(path, displayName));
if (it != data.end()) {
m_view->expand(index);
data.erase(it);
int count = m_model->rowCount(index);
for (int i = 0; i < count; ++i)
recursiveLoadExpandData(index.child(i, 0), data);
}
}
void ProjectTreeWidget::saveExpandData()
{
QList<QVariant> data;
recursiveSaveExpandData(m_view->rootIndex(), &data);
// TODO if there are multiple ProjectTreeWidgets, the last one saves the data
SessionManager::setValue(QLatin1String("ProjectTree.ExpandData"), data);
}
void ProjectTreeWidget::recursiveSaveExpandData(const QModelIndex &index, QList<QVariant> *data)
{
Q_ASSERT(data);
if (m_view->isExpanded(index) || index == m_view->rootIndex()) {
// Note: We store the path+displayname of the node, which isn't unique for e.g. .pri files
// but works for most nodes
Node *node = m_model->nodeForIndex(index);
const QStringList &list = ExpandData(node->filePath().toString(), node->displayName()).toStringList();
data->append(QVariant::fromValue(list));
int count = m_model->rowCount(index);
for (int i = 0; i < count; ++i)
recursiveSaveExpandData(index.child(i, 0), data);
}
}
QToolButton *ProjectTreeWidget::toggleSync() QToolButton *ProjectTreeWidget::toggleSync()
{ {
return m_toggleSync; return m_toggleSync;
@@ -427,9 +341,9 @@ void ProjectTreeWidget::editCurrentItem()
m_view->edit(m_view->selectionModel()->currentIndex()); m_view->edit(m_view->selectionModel()->currentIndex());
} }
void ProjectTreeWidget::renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath) void ProjectTreeWidget::renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath)
{ {
update();
Q_UNUSED(oldPath); Q_UNUSED(oldPath);
if (!currentNode() || currentNode()->filePath() != newPath) { if (!currentNode() || currentNode()->filePath() != newPath) {
// try to find the node // try to find the node
@@ -453,7 +367,6 @@ void ProjectTreeWidget::setCurrentItem(Node *node)
} else { } else {
m_view->clearSelection(); m_view->clearSelection();
} }
} }
void ProjectTreeWidget::handleCurrentItemChange(const QModelIndex &current) void ProjectTreeWidget::handleCurrentItemChange(const QModelIndex &current)
@@ -491,45 +404,6 @@ void ProjectTreeWidget::showContextMenu(const QPoint &pos)
ProjectTree::showContextMenu(this, m_view->mapToGlobal(pos), node); ProjectTree::showContextMenu(this, m_view->mapToGlobal(pos), node);
} }
void ProjectTreeWidget::handleProjectAdded(Project *project)
{
Node *node = project->rootProjectNode();
QModelIndex idx = m_model->indexForNode(node);
if (m_autoExpand) // disabled while session restoring
m_view->setExpanded(idx, true);
m_view->setCurrentIndex(idx);
connect(m_model, &FlatModel::rowsInserted,
this, &ProjectTreeWidget::rowsInserted);
}
void ProjectTreeWidget::startupProjectChanged(Project *project)
{
if (project) {
ProjectNode *node = project->rootProjectNode();
m_model->setStartupProject(node);
} else {
m_model->setStartupProject(0);
}
}
void ProjectTreeWidget::initView()
{
QModelIndex sessionIndex = m_model->index(0, 0);
// hide root folder
m_view->setRootIndex(sessionIndex);
while (m_model->canFetchMore(sessionIndex))
m_model->fetchMore(sessionIndex);
// expand top level projects
for (int i = 0; i < m_model->rowCount(sessionIndex); ++i)
m_view->expand(m_model->index(i, 0, sessionIndex));
setCurrentItem(ProjectTree::currentNode());
}
void ProjectTreeWidget::openItem(const QModelIndex &mainIndex) void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
{ {
Node *node = m_model->nodeForIndex(mainIndex); Node *node = m_model->nodeForIndex(mainIndex);

View File

@@ -47,6 +47,7 @@ class FileNode;
namespace Internal { namespace Internal {
class FlatModel; class FlatModel;
class WrapperNode;
class ProjectTreeWidget : public QWidget class ProjectTreeWidget : public QWidget
{ {
@@ -78,32 +79,20 @@ private:
void handleCurrentItemChange(const QModelIndex &current); void handleCurrentItemChange(const QModelIndex &current);
void showContextMenu(const QPoint &pos); void showContextMenu(const QPoint &pos);
void openItem(const QModelIndex &mainIndex); void openItem(const QModelIndex &mainIndex);
void handleProjectAdded(ProjectExplorer::Project *project);
void startupProjectChanged(ProjectExplorer::Project *project);
void initView();
void loadExpandData();
void saveExpandData();
void disableAutoExpand();
void setCurrentItem(ProjectExplorer::Node *node); void setCurrentItem(ProjectExplorer::Node *node);
void recursiveLoadExpandData(const QModelIndex &index, QSet<ExpandData> &data);
void recursiveSaveExpandData(const QModelIndex &index, QList<QVariant> *data);
static int expandedCount(Node *node); static int expandedCount(Node *node);
void rowsInserted(const QModelIndex &parent, int start, int end); void rowsInserted(const QModelIndex &parent, int start, int end);
void renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath); void renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath);
QSet<ExpandData> m_toExpand;
QTreeView *m_view = nullptr; QTreeView *m_view = nullptr;
FlatModel *m_model = nullptr; FlatModel *m_model = nullptr;
QAction *m_filterProjectsAction = nullptr; QAction *m_filterProjectsAction = nullptr;
QAction *m_filterGeneratedFilesAction; QAction *m_filterGeneratedFilesAction;
QToolButton *m_toggleSync; QToolButton *m_toggleSync;
QModelIndex m_subIndex;
QString m_modelId; QString m_modelId;
bool m_autoSync = false; bool m_autoSync = false;
bool m_autoExpand = true;
Utils::FileName m_delayedRename; Utils::FileName m_delayedRename;
static QList<ProjectTreeWidget *> m_projectTreeWidgets; static QList<ProjectTreeWidget *> m_projectTreeWidgets;

View File

@@ -93,7 +93,7 @@ public:
static QString windowTitleAddition(const QString &filePath); static QString windowTitleAddition(const QString &filePath);
static QString sessionTitle(const QString &filePath); static QString sessionTitle(const QString &filePath);
std::unique_ptr<SessionNode> m_sessionNode; SessionNode m_sessionNode;
QString m_sessionName = QLatin1String("default"); QString m_sessionName = QLatin1String("default");
bool m_virginSession = true; bool m_virginSession = true;
bool m_loadingSession = false; bool m_loadingSession = false;
@@ -124,8 +124,6 @@ SessionManager::SessionManager(QObject *parent) : QObject(parent)
m_instance = this; m_instance = this;
d = new SessionManagerPrivate; d = new SessionManagerPrivate;
d->m_sessionNode.reset(new SessionNode);
connect(ModeManager::instance(), &ModeManager::currentModeChanged, connect(ModeManager::instance(), &ModeManager::currentModeChanged,
this, &SessionManager::saveActiveMode); this, &SessionManager::saveActiveMode);
@@ -383,13 +381,13 @@ void SessionManager::addProject(Project *pro)
QTC_ASSERT(!d->m_projects.contains(pro), return); QTC_ASSERT(!d->m_projects.contains(pro), return);
d->m_projects.append(pro); d->m_projects.append(pro);
d->m_sessionNode->addProjectNodes(QList<ProjectNode *>() << pro->rootProjectNode()); d->m_sessionNode.addProjectNodes({ pro->rootProjectNode() });
connect(pro, &Project::fileListChanged, connect(pro, &Project::fileListChanged,
m_instance, &SessionManager::clearProjectFileCache); m_instance, &SessionManager::clearProjectFileCache);
connect(pro, &Project::displayNameChanged, m_instance, [pro] { connect(pro, &Project::displayNameChanged, m_instance, [pro] {
d->m_sessionNode->projectDisplayNameChanged(pro->rootProjectNode()); d->m_sessionNode.emitNodeUpdated();
emit m_instance->projectDisplayNameChanged(pro); emit m_instance->projectDisplayNameChanged(pro);
}); });
@@ -650,11 +648,9 @@ Project *SessionManager::projectForNode(Node *node)
if (!rootProjectNode) if (!rootProjectNode)
rootProjectNode = node->parentFolderNode(); rootProjectNode = node->parentFolderNode();
while (rootProjectNode && rootProjectNode->parentFolderNode() != d->m_sessionNode.get()) while (rootProjectNode && rootProjectNode->parentFolderNode() != &d->m_sessionNode)
rootProjectNode = rootProjectNode->parentFolderNode(); rootProjectNode = rootProjectNode->parentFolderNode();
Q_ASSERT(rootProjectNode);
return Utils::findOrDefault(d->m_projects, Utils::equal(&Project::rootProjectNode, rootProjectNode)); return Utils::findOrDefault(d->m_projects, Utils::equal(&Project::rootProjectNode, rootProjectNode));
} }
@@ -742,7 +738,7 @@ void SessionManager::removeProjects(QList<Project *> remove)
m_instance, &SessionManager::clearProjectFileCache); m_instance, &SessionManager::clearProjectFileCache);
d->m_projectFileCache.remove(pro); d->m_projectFileCache.remove(pro);
d->m_sessionNode->removeProjectNodes(QList<ProjectNode *>() << pro->rootProjectNode()); d->m_sessionNode.removeProjectNodes({ pro->rootProjectNode() });
emit m_instance->projectRemoved(pro); emit m_instance->projectRemoved(pro);
delete pro; delete pro;
} }
@@ -1095,7 +1091,7 @@ QString SessionManager::lastSession()
SessionNode *SessionManager::sessionNode() SessionNode *SessionManager::sessionNode()
{ {
return d->m_sessionNode.get(); return &d->m_sessionNode;
} }
void SessionManager::reportProjectLoadingProgress() void SessionManager::reportProjectLoadingProgress()

View File

@@ -2083,15 +2083,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
removeProjectNodes(projectNodes()); removeProjectNodes(projectNodes());
removeFolderNodes(folderNodes()); removeFolderNodes(folderNodes());
bool changesShowInSimpleTree = showInSimpleTree() ^ showInSimpleTree(result->projectType);
if (changesShowInSimpleTree)
ProjectTree::instance()->emitAboutToChangeShowInSimpleTree(this);
m_projectType = result->projectType; m_projectType = result->projectType;
if (changesShowInSimpleTree)
ProjectTree::instance()->emitShowInSimpleTreeChanged(this);
} }
// //
@@ -2232,6 +2224,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
updateGeneratedFiles(buildDirectory); updateGeneratedFiles(buildDirectory);
cleanupProFileReaders(); cleanupProFileReaders();
ProjectNode::emitTreeChanged();
} }
void QmakeProFileNode::cleanupProFileReaders() void QmakeProFileNode::cleanupProFileReaders()