forked from qt-creator/qt-creator
ProjectExplorer: Don't rebuild all projects' tree when one is closed
Removes some quadratic-in-number-of-projects behavior on session close/switch. Change-Id: If93bb9a67b0bebddda5319a7594a99ae66f50f5a Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
@@ -477,10 +477,13 @@ void Project::setRootProjectNode(ProjectNode *root)
|
||||
|
||||
ProjectNode *oldNode = d->m_rootProjectNode;
|
||||
d->m_rootProjectNode = root;
|
||||
if (root)
|
||||
if (root) {
|
||||
root->setParentFolderNode(d->m_containerNode);
|
||||
ProjectTree::emitSubtreeChanged(root);
|
||||
emit fileListChanged();
|
||||
// Only announce non-null root, null is only used when project is destroyed.
|
||||
// In that case SessionManager::projectRemoved() triggers the update.
|
||||
ProjectTree::emitSubtreeChanged(root);
|
||||
emit fileListChanged();
|
||||
}
|
||||
|
||||
delete oldNode;
|
||||
}
|
||||
|
@@ -74,15 +74,14 @@ FlatModel::FlatModel(QObject *parent)
|
||||
: TreeModel<WrapperNode, WrapperNode>(new WrapperNode(nullptr), parent)
|
||||
{
|
||||
ProjectTree *tree = ProjectTree::instance();
|
||||
connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::update);
|
||||
connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::updateSubtree);
|
||||
|
||||
SessionManager *sm = SessionManager::instance();
|
||||
connect(sm, &SessionManager::projectRemoved, this, &FlatModel::update);
|
||||
connect(sm, &SessionManager::sessionLoaded, this, &FlatModel::loadExpandData);
|
||||
connect(sm, &SessionManager::projectRemoved, this, &FlatModel::handleProjectRemoved);
|
||||
connect(sm, &SessionManager::aboutToLoadSession, this, &FlatModel::loadExpandData);
|
||||
connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData);
|
||||
connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded);
|
||||
connect(sm, &SessionManager::startupProjectChanged, this, [this] { layoutChanged(); });
|
||||
update();
|
||||
}
|
||||
|
||||
QVariant FlatModel::data(const QModelIndex &index, int role) const
|
||||
@@ -170,42 +169,27 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlatModel::update()
|
||||
void FlatModel::addOrRebuildProjectModel(Project *project)
|
||||
{
|
||||
rebuildModel();
|
||||
}
|
||||
|
||||
void FlatModel::rebuildModel()
|
||||
{
|
||||
QList<Project *> projects = SessionManager::projects();
|
||||
|
||||
Utils::sort(projects, [](Project *p1, Project *p2) {
|
||||
const int displayNameResult = caseFriendlyCompare(p1->displayName(), p2->displayName());
|
||||
if (displayNameResult != 0)
|
||||
return displayNameResult < 0;
|
||||
return p1 < p2; // sort by pointer value
|
||||
});
|
||||
|
||||
QSet<Node *> seen;
|
||||
|
||||
rootItem()->removeChildren();
|
||||
for (Project *project : projects) {
|
||||
WrapperNode *container = new WrapperNode(project->containerNode());
|
||||
|
||||
ProjectNode *projectNode = project->rootProjectNode();
|
||||
if (projectNode) {
|
||||
addFolderNode(container, projectNode, &seen);
|
||||
} else {
|
||||
FileNode *projectFileNode = new FileNode(project->projectFilePath(), FileType::Project, false);
|
||||
seen.insert(projectFileNode);
|
||||
container->appendChild(new WrapperNode(projectFileNode));
|
||||
}
|
||||
|
||||
container->sortChildren(&sortWrapperNodes);
|
||||
WrapperNode *container = nodeForProject(project);
|
||||
if (container) {
|
||||
container->removeChildren();
|
||||
} else {
|
||||
container = new WrapperNode(project->containerNode());
|
||||
rootItem()->appendChild(container);
|
||||
}
|
||||
|
||||
forAllItems([this](WrapperNode *node) {
|
||||
QSet<Node *> seen;
|
||||
|
||||
if (ProjectNode *projectNode = project->rootProjectNode()) {
|
||||
addFolderNode(container, projectNode, &seen);
|
||||
} else {
|
||||
FileNode *projectFileNode = new FileNode(project->projectFilePath(), FileType::Project, false);
|
||||
seen.insert(projectFileNode);
|
||||
container->appendChild(new WrapperNode(projectFileNode));
|
||||
}
|
||||
|
||||
container->forAllChildren([this](WrapperNode *node) {
|
||||
if (node->m_node) {
|
||||
const QString path = node->m_node->filePath().toString();
|
||||
const QString displayName = node->m_node->displayName();
|
||||
@@ -216,6 +200,37 @@ void FlatModel::rebuildModel()
|
||||
emit requestExpansion(node->index());
|
||||
}
|
||||
});
|
||||
|
||||
const QString path = container->m_node->filePath().toString();
|
||||
const QString displayName = container->m_node->displayName();
|
||||
ExpandData ed(path, displayName);
|
||||
if (m_toExpand.contains(ed))
|
||||
emit requestExpansion(container->index());
|
||||
}
|
||||
|
||||
void FlatModel::updateSubtree(FolderNode *node)
|
||||
{
|
||||
// FIXME: This is still excessive, should be limited to the affected subtree.
|
||||
while (FolderNode *parent = node->parentFolderNode())
|
||||
node = parent;
|
||||
if (ContainerNode *container = node->asContainerNode())
|
||||
addOrRebuildProjectModel(container->project());
|
||||
}
|
||||
|
||||
void FlatModel::rebuildModel()
|
||||
{
|
||||
QList<Project *> projects = SessionManager::projects();
|
||||
QTC_CHECK(projects.size() == rootItem()->childCount());
|
||||
|
||||
Utils::sort(projects, [](Project *p1, Project *p2) {
|
||||
const int displayNameResult = caseFriendlyCompare(p1->displayName(), p2->displayName());
|
||||
if (displayNameResult != 0)
|
||||
return displayNameResult < 0;
|
||||
return p1 < p2; // sort by pointer value
|
||||
});
|
||||
|
||||
for (Project *project : projects)
|
||||
addOrRebuildProjectModel(project);
|
||||
}
|
||||
|
||||
void FlatModel::onCollapsed(const QModelIndex &idx)
|
||||
@@ -238,9 +253,22 @@ ExpandData FlatModel::expandDataForNode(const Node *node) const
|
||||
|
||||
void FlatModel::handleProjectAdded(Project *project)
|
||||
{
|
||||
Node *node = project->containerNode();
|
||||
m_toExpand.insert(expandDataForNode(node));
|
||||
update();
|
||||
addOrRebuildProjectModel(project);
|
||||
}
|
||||
|
||||
void FlatModel::handleProjectRemoved(Project *project)
|
||||
{
|
||||
destroyItem(nodeForProject(project));
|
||||
}
|
||||
|
||||
WrapperNode *FlatModel::nodeForProject(Project *project)
|
||||
{
|
||||
QTC_ASSERT(project, return nullptr);
|
||||
ContainerNode *containerNode = project->containerNode();
|
||||
QTC_ASSERT(containerNode, return nullptr);
|
||||
return rootItem()->findFirstLevelChild([containerNode](WrapperNode *node) {
|
||||
return node->m_node == containerNode;
|
||||
});
|
||||
}
|
||||
|
||||
void FlatModel::loadExpandData()
|
||||
|
@@ -90,7 +90,7 @@ private:
|
||||
|
||||
static const QLoggingCategory &logger();
|
||||
|
||||
void update();
|
||||
void updateSubtree(FolderNode *node);
|
||||
void rebuildModel();
|
||||
void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen);
|
||||
|
||||
@@ -98,6 +98,9 @@ private:
|
||||
void loadExpandData();
|
||||
void saveExpandData();
|
||||
void handleProjectAdded(Project *project);
|
||||
void handleProjectRemoved(Project *project);
|
||||
WrapperNode *nodeForProject(Project *project);
|
||||
void addOrRebuildProjectModel(Project *project);
|
||||
|
||||
QTimer m_timer;
|
||||
QSet<ExpandData> m_toExpand;
|
||||
|
@@ -318,6 +318,7 @@ public:
|
||||
const ContainerNode *asContainerNode() const final { return this; }
|
||||
|
||||
ProjectNode *rootProjectNode() const;
|
||||
Project *project() const { return m_project; }
|
||||
|
||||
private:
|
||||
Project *m_project;
|
||||
|
Reference in New Issue
Block a user