ProjectExplorer: Use visitor-by-lambda for project tree

And inline it into user code. Less code in total and no intermediate
node lists.

Change-Id: I3724883408bfaa868266110aee27bbffd4d96bd8
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
hjk
2017-03-06 18:03:43 +01:00
parent 05e8f34d3e
commit d6df4492d0
15 changed files with 55 additions and 321 deletions

View File

@@ -28,7 +28,6 @@
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectnodes.h> #include <projectexplorer/projectnodes.h>
#include <projectexplorer/nodesvisitor.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <resourceeditor/resourcenode.h> #include <resourceeditor/resourcenode.h>

View File

@@ -1,114 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "nodesvisitor.h"
#include "projectnodes.h"
using namespace ProjectExplorer;
/*!
\class NodesVisitor
\brief Base class for visitors that can be used to traverse a node hierarchy.
The class follows the visitor pattern as described in Gamma et al. Pass
an instance of NodesVisitor to FolderNode::accept(): The visit functions
will be called for each node in the subtree, except for file nodes:
Access these through FolderNode::fileNodes() in visitProjectNode()
and visitoFolderNode().
*/
/*!
\fn NodesVisitor::visitSessionNode(SessionNode *)
Called for the root session node.
The default implementation does nothing.
*/
/*!
\fn NodesVisitor::visitProjectNode(SessionNode *)
Called for a project node.
The default implementation does nothing.
*/
/*!
\fn NodesVisitor::visitFolderNode(SessionNode *)
Called for a folder node that is _not_ a SessionNode or a ProjectNode.
The default implementation does nothing.
*/
/*!
\class FindNodeForFileVisitor
Searches the first node that has the given file as its path.
*/
FindNodesForFileVisitor::FindNodesForFileVisitor(const Utils::FileName &fileToSearch)
: m_path(fileToSearch)
{
}
QList<Node*> FindNodesForFileVisitor::nodes() const
{
return m_nodes;
}
void FindNodesForFileVisitor::visitFolderNode(FolderNode *node)
{
if (node->filePath() == m_path)
m_nodes << node;
foreach (FileNode *fileNode, node->fileNodes()) {
if (fileNode->filePath() == m_path)
m_nodes << fileNode;
}
}
/*!
\class FindAllFilesVisitor
Collects file information from all sub file nodes.
*/
Utils::FileNameList FindAllFilesVisitor::filePaths() const
{
return m_filePaths;
}
void FindAllFilesVisitor::visitFolderNode(FolderNode *folderNode)
{
m_filePaths.append(folderNode->filePath());
foreach (const FileNode *fileNode, folderNode->fileNodes())
m_filePaths.append(fileNode->filePath());
}
NodesVisitor::~NodesVisitor()
{
}

View File

@@ -1,79 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "projectexplorer_export.h"
#include <utils/fileutils.h>
#include <QStringList>
namespace ProjectExplorer {
class Node;
class FileNode;
class SessionNode;
class FolderNode;
class PROJECTEXPLORER_EXPORT NodesVisitor
{
public:
virtual ~NodesVisitor();
virtual void visitFolderNode(FolderNode *) { }
protected:
NodesVisitor() {}
};
/* useful visitors */
class PROJECTEXPLORER_EXPORT FindNodesForFileVisitor : public NodesVisitor
{
public:
explicit FindNodesForFileVisitor(const Utils::FileName &fileToSearch);
QList<Node*> nodes() const;
void visitFolderNode(FolderNode *node) override;
private:
Utils::FileName m_path;
QList<Node *> m_nodes;
};
class PROJECTEXPLORER_EXPORT FindAllFilesVisitor : public NodesVisitor
{
public:
Utils::FileNameList filePaths() const;
void visitFolderNode(FolderNode *folderNode) override;
private:
Utils::FileNameList m_filePaths;
};
} // namespace ProjectExplorer

View File

@@ -63,7 +63,6 @@
#include "dependenciespanel.h" #include "dependenciespanel.h"
#include "foldernavigationwidget.h" #include "foldernavigationwidget.h"
#include "iprojectmanager.h" #include "iprojectmanager.h"
#include "nodesvisitor.h"
#include "appoutputpane.h" #include "appoutputpane.h"
#include "processstep.h" #include "processstep.h"
#include "kitinformation.h" #include "kitinformation.h"

View File

@@ -80,7 +80,6 @@ HEADERS += projectexplorer.h \
sessionview.h \ sessionview.h \
projectwizardpage.h \ projectwizardpage.h \
buildstepspage.h \ buildstepspage.h \
nodesvisitor.h \
projectmodels.h \ projectmodels.h \
currentprojectfind.h \ currentprojectfind.h \
toolchain.h \ toolchain.h \
@@ -227,7 +226,6 @@ SOURCES += projectexplorer.cpp \
sessionview.cpp \ sessionview.cpp \
projectwizardpage.cpp \ projectwizardpage.cpp \
buildstepspage.cpp \ buildstepspage.cpp \
nodesvisitor.cpp \
projectmodels.cpp \ projectmodels.cpp \
currentprojectfind.cpp \ currentprojectfind.cpp \
toolchain.cpp \ toolchain.cpp \

View File

@@ -100,7 +100,6 @@ Project {
"localenvironmentaspect.cpp", "localenvironmentaspect.h", "localenvironmentaspect.cpp", "localenvironmentaspect.h",
"miniprojecttargetselector.cpp", "miniprojecttargetselector.h", "miniprojecttargetselector.cpp", "miniprojecttargetselector.h",
"namedwidget.cpp", "namedwidget.h", "namedwidget.cpp", "namedwidget.h",
"nodesvisitor.cpp", "nodesvisitor.h",
"osparser.cpp", "osparser.h", "osparser.cpp", "osparser.h",
"panelswidget.cpp", "panelswidget.h", "panelswidget.cpp", "panelswidget.h",
"processparameters.cpp", "processparameters.h", "processparameters.cpp", "processparameters.h",

View File

@@ -25,7 +25,6 @@
#include "projectnodes.h" #include "projectnodes.h"
#include "nodesvisitor.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include "projecttree.h" #include "projecttree.h"
@@ -58,7 +57,7 @@ namespace ProjectExplorer {
A Visitor can be used to traverse all Projects and other Folders. A Visitor can be used to traverse all Projects and other Folders.
\sa ProjectExplorer::FileNode, ProjectExplorer::FolderNode, ProjectExplorer::ProjectNode \sa ProjectExplorer::FileNode, ProjectExplorer::FolderNode, ProjectExplorer::ProjectNode
\sa ProjectExplorer::NodesWatcher, ProjectExplorer::NodesVisitor \sa ProjectExplorer::NodesWatcher
*/ */
Node::Node(NodeType nodeType, const Utils::FileName &filePath, int line) : Node::Node(NodeType nodeType, const Utils::FileName &filePath, int line) :
@@ -516,15 +515,6 @@ void FolderNode::compress()
} }
} }
void FolderNode::accept(NodesVisitor *visitor)
{
visitor->visitFolderNode(this);
for (Node *n : m_nodes) {
if (FolderNode *subFolder = n->asFolderNode())
subFolder->accept(visitor);
}
}
void FolderNode::setDisplayName(const QString &name) void FolderNode::setDisplayName(const QString &name)
{ {
if (m_displayName == name) if (m_displayName == name)

View File

@@ -88,11 +88,9 @@ enum ProjectAction {
HasSubProjectRunConfigurations HasSubProjectRunConfigurations
}; };
class Node;
class FileNode; class FileNode;
class FolderNode; class FolderNode;
class ProjectNode; class ProjectNode;
class NodesVisitor;
// Documentation inside. // Documentation inside.
class PROJECTEXPLORER_EXPORT Node : public QObject class PROJECTEXPLORER_EXPORT Node : public QObject
@@ -207,8 +205,6 @@ public:
void buildTree(QList<FileNode *> &files, const Utils::FileName &overrideBaseDir = Utils::FileName()); void buildTree(QList<FileNode *> &files, const Utils::FileName &overrideBaseDir = Utils::FileName());
void compress(); void compress();
virtual void accept(NodesVisitor *visitor);
void setDisplayName(const QString &name); void setDisplayName(const QString &name);
void setIcon(const QIcon &icon); void setIcon(const QIcon &icon);

View File

@@ -29,7 +29,6 @@
#include "project.h" #include "project.h"
#include "projectnodes.h" #include "projectnodes.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include "nodesvisitor.h"
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>

View File

@@ -272,29 +272,27 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e
Node *ProjectTreeWidget::nodeForFile(const Utils::FileName &fileName) Node *ProjectTreeWidget::nodeForFile(const Utils::FileName &fileName)
{ {
return mostExpandedNode(SessionManager::nodesForFile(fileName)); Node *bestNode = nullptr;
}
Node *ProjectTreeWidget::mostExpandedNode(const QList<Node *> &nodes)
{
Node *bestNode = 0;
int bestNodeExpandCount = INT_MAX; int bestNodeExpandCount = INT_MAX;
foreach (Node *node, nodes) { SessionManager::sessionNode()->forEachGenericNode([&](Node *node) {
if (!bestNode) { if (node->filePath() == fileName) {
bestNode = node; if (!bestNode) {
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
} else if (node->nodeType() < bestNode->nodeType()) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
} else if (node->nodeType() == bestNode->nodeType()) {
int nodeExpandCount = ProjectTreeWidget::expandedCount(node);
if (nodeExpandCount < bestNodeExpandCount) {
bestNode = node; bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
} else if (node->nodeType() < bestNode->nodeType()) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
} else if (node->nodeType() == bestNode->nodeType()) {
int nodeExpandCount = ProjectTreeWidget::expandedCount(node);
if (nodeExpandCount < bestNodeExpandCount) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
}
} }
} }
} });
return bestNode; return bestNode;
} }

View File

@@ -62,7 +62,6 @@ public:
void showMessage(ProjectExplorer::Node *node, const QString &message); void showMessage(ProjectExplorer::Node *node, const QString &message);
static Node *nodeForFile(const Utils::FileName &fileName); static Node *nodeForFile(const Utils::FileName &fileName);
static Node *mostExpandedNode(const QList<Node*> &nodes);
void toggleAutoSynchronization(); void toggleAutoSynchronization();
void editCurrentItem(); void editCurrentItem();

View File

@@ -31,9 +31,8 @@
#include "buildconfiguration.h" #include "buildconfiguration.h"
#include "deployconfiguration.h" #include "deployconfiguration.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include "nodesvisitor.h"
#include "editorconfiguration.h"
#include "projectnodes.h" #include "projectnodes.h"
#include "editorconfiguration.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
@@ -624,23 +623,18 @@ QList<Project *> SessionManager::projectOrder(const Project *project)
return result; return result;
} }
QList<Node *> SessionManager::nodesForFile(const Utils::FileName &fileName)
{
FindNodesForFileVisitor findNodes(fileName);
sessionNode()->accept(&findNodes);
return findNodes.nodes();
}
// node for file returns a randomly selected node if there are multiple // node for file returns a randomly selected node if there are multiple
// prefer to use nodesForFile and figure out which node you want // prefer to use nodesForFile and figure out which node you want
Node *SessionManager::nodeForFile(const Utils::FileName &fileName) Node *SessionManager::nodeForFile(const Utils::FileName &fileName)
{ {
Node *node = nullptr; Node *node = nullptr;
foreach (Node *n, nodesForFile(fileName)) { sessionNode()->forEachGenericNode([&](Node *n) {
// prefer file nodes if (n->filePath() == fileName) {
if (!node || (node->nodeType() != NodeType::File && n->nodeType() == NodeType::File)) // prefer file nodes
node = n; if (!node || (node->nodeType() != NodeType::File && n->nodeType() == NodeType::File))
} node = n;
}
});
return node; return node;
} }

View File

@@ -116,7 +116,6 @@ public:
static SessionNode *sessionNode(); static SessionNode *sessionNode();
static Project *projectForNode(Node *node); static Project *projectForNode(Node *node);
static QList<Node *> nodesForFile(const Utils::FileName &fileName);
static Node *nodeForFile(const Utils::FileName &fileName); static Node *nodeForFile(const Utils::FileName &fileName);
static Project *projectForFile(const Utils::FileName &fileName); static Project *projectForFile(const Utils::FileName &fileName);

View File

@@ -48,12 +48,11 @@
#include <projectexplorer/buildmanager.h> #include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildtargetinfo.h> #include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deploymentdata.h> #include <projectexplorer/deploymentdata.h>
#include <projectexplorer/nodesvisitor.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/headerpath.h> #include <projectexplorer/headerpath.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/toolchain.h>
#include <proparser/qmakevfs.h> #include <proparser/qmakevfs.h>
#include <qtsupport/profilereader.h> #include <qtsupport/profilereader.h>
#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtkitinformation.h>
@@ -157,66 +156,8 @@ QDebug operator<<(QDebug d, const QmakeProjectFiles &f)
return d; return d;
} }
// A visitor to collect all files of a project in a QmakeProjectFiles struct
class ProjectFilesVisitor : public NodesVisitor
{
ProjectFilesVisitor(QmakeProjectFiles *files);
public:
static void findProjectFiles(QmakeProFileNode *rootNode, QmakeProjectFiles *files);
void visitFolderNode(FolderNode *folderNode) final;
private:
QmakeProjectFiles *m_files;
};
ProjectFilesVisitor::ProjectFilesVisitor(QmakeProjectFiles *files) :
m_files(files)
{
}
namespace {
// uses std::unique, so takes a sorted list
void unique(QStringList &list)
{
list.erase(std::unique(list.begin(), list.end()), list.end());
}
}
void ProjectFilesVisitor::findProjectFiles(QmakeProFileNode *rootNode, QmakeProjectFiles *files)
{
files->clear();
ProjectFilesVisitor visitor(files);
rootNode->accept(&visitor);
for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
Utils::sort(files->files[i]);
unique(files->files[i]);
Utils::sort(files->generatedFiles[i]);
unique(files->generatedFiles[i]);
}
Utils::sort(files->proFiles);
unique(files->proFiles);
}
void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
{
if (ProjectNode *projectNode = folderNode->asProjectNode())
m_files->proFiles.append(projectNode->filePath().toString());
if (dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
m_files->files[static_cast<int>(FileType::Resource)].push_back(folderNode->filePath().toString());
foreach (FileNode *fileNode, folderNode->fileNodes()) {
const int type = static_cast<int>(fileNode->fileType());
QStringList &targetList = fileNode->isGenerated() ? m_files->generatedFiles[type] : m_files->files[type];
targetList.push_back(fileNode->filePath().toString());
}
}
}
// ----------- QmakeProjectFile // ----------- QmakeProjectFile
namespace Internal {
QmakeProjectFile::QmakeProjectFile(const QString &filePath) QmakeProjectFile::QmakeProjectFile(const QString &filePath)
{ {
setId("Qmake.ProFile"); setId("Qmake.ProFile");
@@ -303,10 +244,26 @@ QmakeProFile *QmakeProject::rootProFile() const
void QmakeProject::updateFileList() void QmakeProject::updateFileList()
{ {
QmakeProjectFiles newFiles; QmakeProjectFiles files;
ProjectFilesVisitor::findProjectFiles(rootProjectNode(), &newFiles); rootProjectNode()->forEachNode([&](FileNode *fileNode) {
if (newFiles != *m_projectFiles) { const int type = static_cast<int>(fileNode->fileType());
*m_projectFiles = newFiles; QStringList &targetList = fileNode->isGenerated() ? files.generatedFiles[type] : files.files[type];
targetList.push_back(fileNode->filePath().toString());
}, [&](FolderNode *folderNode) {
if (ProjectNode *projectNode = folderNode->asProjectNode())
files.proFiles.append(projectNode->filePath().toString());
if (dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
files.files[static_cast<int>(FileType::Resource)].push_back(folderNode->filePath().toString());
});
for (QStringList &f : files.files)
f.removeDuplicates();
for (QStringList &f : files.generatedFiles)
f.removeDuplicates();
files.proFiles.removeDuplicates();
if (files != *m_projectFiles) {
*m_projectFiles = files;
emit fileListChanged(); emit fileListChanged();
} }
} }

View File

@@ -31,12 +31,12 @@
#include "todoitemsmodel.h" #include "todoitemsmodel.h"
#include "todoitemsscanner.h" #include "todoitemsscanner.h"
#include <projectexplorer/nodesvisitor.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/idocument.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectnodes.h> #include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h> #include <projectexplorer/projecttree.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/idocument.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <QTimer> #include <QTimer>
@@ -148,13 +148,13 @@ void TodoItemsProvider::setItemsListWithinSubproject()
if (node) { if (node) {
ProjectNode *projectNode = node->parentProjectNode(); ProjectNode *projectNode = node->parentProjectNode();
if (projectNode) { if (projectNode) {
// FIXME: The name doesn't match the implementation that lists all files.
FindAllFilesVisitor filesVisitor; QSet<Utils::FileName> subprojectFileNames;
projectNode->accept(&filesVisitor); projectNode->forEachGenericNode([&](Node *node) {
subprojectFileNames.insert(node->filePath());
});
// files must be both in the current subproject and the startup-project. // files must be both in the current subproject and the startup-project.
QSet<Utils::FileName> subprojectFileNames =
QSet<Utils::FileName>::fromList(filesVisitor.filePaths());
QSet<QString> fileNames = QSet<QString>::fromList( QSet<QString> fileNames = QSet<QString>::fromList(
m_startupProject->files(ProjectExplorer::Project::SourceFiles)); m_startupProject->files(ProjectExplorer::Project::SourceFiles));
QHashIterator<QString, QList<TodoItem> > it(m_itemsHash); QHashIterator<QString, QList<TodoItem> > it(m_itemsHash);