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;
|
ProjectNode *oldNode = d->m_rootProjectNode;
|
||||||
d->m_rootProjectNode = root;
|
d->m_rootProjectNode = root;
|
||||||
if (root)
|
if (root) {
|
||||||
root->setParentFolderNode(d->m_containerNode);
|
root->setParentFolderNode(d->m_containerNode);
|
||||||
ProjectTree::emitSubtreeChanged(root);
|
// Only announce non-null root, null is only used when project is destroyed.
|
||||||
emit fileListChanged();
|
// In that case SessionManager::projectRemoved() triggers the update.
|
||||||
|
ProjectTree::emitSubtreeChanged(root);
|
||||||
|
emit fileListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
delete oldNode;
|
delete oldNode;
|
||||||
}
|
}
|
||||||
|
@@ -74,15 +74,14 @@ FlatModel::FlatModel(QObject *parent)
|
|||||||
: TreeModel<WrapperNode, WrapperNode>(new WrapperNode(nullptr), parent)
|
: TreeModel<WrapperNode, WrapperNode>(new WrapperNode(nullptr), parent)
|
||||||
{
|
{
|
||||||
ProjectTree *tree = ProjectTree::instance();
|
ProjectTree *tree = ProjectTree::instance();
|
||||||
connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::update);
|
connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::updateSubtree);
|
||||||
|
|
||||||
SessionManager *sm = SessionManager::instance();
|
SessionManager *sm = SessionManager::instance();
|
||||||
connect(sm, &SessionManager::projectRemoved, this, &FlatModel::update);
|
connect(sm, &SessionManager::projectRemoved, this, &FlatModel::handleProjectRemoved);
|
||||||
connect(sm, &SessionManager::sessionLoaded, this, &FlatModel::loadExpandData);
|
connect(sm, &SessionManager::aboutToLoadSession, this, &FlatModel::loadExpandData);
|
||||||
connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData);
|
connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData);
|
||||||
connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded);
|
connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded);
|
||||||
connect(sm, &SessionManager::startupProjectChanged, this, [this] { layoutChanged(); });
|
connect(sm, &SessionManager::startupProjectChanged, this, [this] { layoutChanged(); });
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant FlatModel::data(const QModelIndex &index, int role) const
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlatModel::update()
|
void FlatModel::addOrRebuildProjectModel(Project *project)
|
||||||
{
|
{
|
||||||
rebuildModel();
|
WrapperNode *container = nodeForProject(project);
|
||||||
}
|
if (container) {
|
||||||
|
container->removeChildren();
|
||||||
void FlatModel::rebuildModel()
|
} else {
|
||||||
{
|
container = new WrapperNode(project->containerNode());
|
||||||
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);
|
|
||||||
rootItem()->appendChild(container);
|
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) {
|
if (node->m_node) {
|
||||||
const QString path = node->m_node->filePath().toString();
|
const QString path = node->m_node->filePath().toString();
|
||||||
const QString displayName = node->m_node->displayName();
|
const QString displayName = node->m_node->displayName();
|
||||||
@@ -216,6 +200,37 @@ void FlatModel::rebuildModel()
|
|||||||
emit requestExpansion(node->index());
|
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)
|
void FlatModel::onCollapsed(const QModelIndex &idx)
|
||||||
@@ -238,9 +253,22 @@ ExpandData FlatModel::expandDataForNode(const Node *node) const
|
|||||||
|
|
||||||
void FlatModel::handleProjectAdded(Project *project)
|
void FlatModel::handleProjectAdded(Project *project)
|
||||||
{
|
{
|
||||||
Node *node = project->containerNode();
|
addOrRebuildProjectModel(project);
|
||||||
m_toExpand.insert(expandDataForNode(node));
|
}
|
||||||
update();
|
|
||||||
|
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()
|
void FlatModel::loadExpandData()
|
||||||
|
@@ -90,7 +90,7 @@ private:
|
|||||||
|
|
||||||
static const QLoggingCategory &logger();
|
static const QLoggingCategory &logger();
|
||||||
|
|
||||||
void update();
|
void updateSubtree(FolderNode *node);
|
||||||
void rebuildModel();
|
void rebuildModel();
|
||||||
void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen);
|
void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen);
|
||||||
|
|
||||||
@@ -98,6 +98,9 @@ private:
|
|||||||
void loadExpandData();
|
void loadExpandData();
|
||||||
void saveExpandData();
|
void saveExpandData();
|
||||||
void handleProjectAdded(Project *project);
|
void handleProjectAdded(Project *project);
|
||||||
|
void handleProjectRemoved(Project *project);
|
||||||
|
WrapperNode *nodeForProject(Project *project);
|
||||||
|
void addOrRebuildProjectModel(Project *project);
|
||||||
|
|
||||||
QTimer m_timer;
|
QTimer m_timer;
|
||||||
QSet<ExpandData> m_toExpand;
|
QSet<ExpandData> m_toExpand;
|
||||||
|
@@ -318,6 +318,7 @@ public:
|
|||||||
const ContainerNode *asContainerNode() const final { return this; }
|
const ContainerNode *asContainerNode() const final { return this; }
|
||||||
|
|
||||||
ProjectNode *rootProjectNode() const;
|
ProjectNode *rootProjectNode() const;
|
||||||
|
Project *project() const { return m_project; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Project *m_project;
|
Project *m_project;
|
||||||
|
Reference in New Issue
Block a user