Commit bd5e2faa authored by hjk's avatar hjk
Browse files

ProjectNodes: Handle supported actions one-by-one



Getting the full list for a node can get quite expensive e.g. in
cases of recursive calls of QMakeProjectManager::findPriFile.

However, the FlatModel needs to decide quickly on whether an item
is editable to potentially allow renaming.

So split up QList<Actions> supportedActions() into individual
bool supportsAction(action) calls and make sure Rename is not
on the critical path.

Task-number: QTCREATORBUG-17953
Change-Id: I31841847f8aa7d7b94c63d76ce71efb1c930fa69
Reviewed-by: Tobias Hunger's avatarTobias Hunger <tobias.hunger@qt.io>
parent 8410c0bb
......@@ -42,9 +42,3 @@ bool AutotoolsProjectNode::showInSimpleTree() const
{
return true;
}
QList<ProjectAction> AutotoolsProjectNode::supportedActions(Node *node) const
{
Q_UNUSED(node);
return QList<ProjectAction>();
}
......@@ -51,7 +51,6 @@ public:
AutotoolsProjectNode(const Utils::FileName &projectDirectory);
bool showInSimpleTree() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
};
} // namespace Internal
......
......@@ -56,12 +56,6 @@ bool CMakeInputsNode::showInSimpleTree() const
return false;
}
QList<ProjectExplorer::ProjectAction> CMakeInputsNode::supportedActions(ProjectExplorer::Node *node) const
{
Q_UNUSED(node);
return QList<ProjectExplorer::ProjectAction>();
}
CMakeListsNode::CMakeListsNode(const Utils::FileName &cmakeListPath) :
ProjectExplorer::ProjectNode(cmakeListPath)
{
......@@ -80,12 +74,6 @@ bool CMakeListsNode::showInSimpleTree() const
return false;
}
QList<ProjectExplorer::ProjectAction> CMakeListsNode::supportedActions(ProjectExplorer::Node *node) const
{
Q_UNUSED(node);
return QList<ProjectExplorer::ProjectAction>();
}
CMakeProjectNode::CMakeProjectNode(const Utils::FileName &directory) :
ProjectExplorer::ProjectNode(directory)
{
......@@ -103,12 +91,6 @@ QString CMakeProjectNode::tooltip() const
return QString();
}
QList<ProjectExplorer::ProjectAction> CMakeProjectNode::supportedActions(ProjectExplorer::Node *node) const
{
Q_UNUSED(node);
return QList<ProjectExplorer::ProjectAction>();
}
CMakeTargetNode::CMakeTargetNode(const Utils::FileName &directory) :
ProjectExplorer::ProjectNode(directory)
{
......@@ -126,12 +108,6 @@ QString CMakeTargetNode::tooltip() const
return m_tooltip;
}
QList<ProjectExplorer::ProjectAction> CMakeTargetNode::supportedActions(ProjectExplorer::Node *node) const
{
Q_UNUSED(node);
return QList<ProjectExplorer::ProjectAction>();
}
void CMakeTargetNode::setTargetInformation(const QList<Utils::FileName> &artifacts,
const QString &type)
{
......
......@@ -28,8 +28,6 @@
#include <projectexplorer/projectnodes.h>
namespace CMakeProjectManager {
class CMakeProject;
namespace Internal {
class CMakeInputsNode : public ProjectExplorer::ProjectNode
......@@ -40,7 +38,6 @@ public:
static Utils::FileName inputsPathFromCMakeListsPath(const Utils::FileName &cmakeLists);
bool showInSimpleTree() const final;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
};
class CMakeListsNode : public ProjectExplorer::ProjectNode
......@@ -49,7 +46,6 @@ public:
CMakeListsNode(const Utils::FileName &cmakeListPath);
bool showInSimpleTree() const final;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
};
class CMakeProjectNode : public ProjectExplorer::ProjectNode
......@@ -59,7 +55,6 @@ public:
bool showInSimpleTree() const final;
QString tooltip() const final;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
};
class CMakeTargetNode : public ProjectExplorer::ProjectNode
......@@ -71,7 +66,6 @@ public:
bool showInSimpleTree() const final;
QString tooltip() const final;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
private:
QString m_tooltip;
......
......@@ -78,16 +78,14 @@ bool GenericProjectNode::showInSimpleTree() const
return true;
}
QList<ProjectAction> GenericProjectNode::supportedActions(Node *node) const
bool GenericProjectNode::supportsAction(ProjectAction action, Node *node) const
{
Q_UNUSED(node);
return {
AddNewFile,
AddExistingFile,
AddExistingDirectory,
RemoveFile,
Rename
};
return action == AddNewFile
|| action == AddExistingFile
|| action == AddExistingDirectory
|| action == RemoveFile
|| action == Rename;
}
bool GenericProjectNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
......
......@@ -44,8 +44,7 @@ public:
explicit GenericProjectNode(GenericProject *project);
bool showInSimpleTree() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0) override;
......
......@@ -37,23 +37,19 @@ NimProjectNode::NimProjectNode(NimProject &project,
, m_project(project)
{}
QList<ProjectAction> NimProjectNode::supportedActions(Node *node) const
bool NimProjectNode::supportsAction(ProjectAction action, Node *node) const
{
static const QList<ProjectAction> fileActions = {ProjectAction::Rename,
ProjectAction::RemoveFile
};
static const QList<ProjectAction> folderActions = {ProjectAction::AddNewFile,
ProjectAction::RemoveFile,
ProjectAction::AddExistingFile
};
switch (node->nodeType()) {
case NodeType::File:
return fileActions;
return action == ProjectAction::Rename
|| action == ProjectAction::RemoveFile;
case NodeType::Folder:
case NodeType::Project:
return folderActions;
return action == ProjectAction::AddNewFile
|| action == ProjectAction::RemoveFile
|| action == ProjectAction::AddExistingFile;
default:
return ProjectNode::supportedActions(node);
return ProjectNode::supportsAction(action, node);
}
}
......
......@@ -38,7 +38,7 @@ class NimProjectNode : public ProjectExplorer::ProjectNode
public:
NimProjectNode(NimProject &project, const Utils::FileName &projectFilePath);
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *) override;
bool removeFiles(const QStringList &filePaths, QStringList *) override;
bool deleteFiles(const QStringList &) override;
......
......@@ -2938,8 +2938,6 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
Node *currentNode = ProjectTree::currentNode();
if (currentNode && currentNode->managingProject()) {
QList<ProjectAction> actions = currentNode->supportedActions(currentNode);
ProjectNode *pn;
if (ContainerNode *cn = currentNode->asContainerNode())
pn = cn->rootProjectNode();
......@@ -2967,56 +2965,61 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
}
}
}
auto supports = [currentNode](ProjectAction action) {
return currentNode->supportsAction(action, currentNode);
};
if (currentNode->asFolderNode()) {
// Also handles ProjectNode
m_addNewFileAction->setEnabled(actions.contains(AddNewFile)
m_addNewFileAction->setEnabled(currentNode->supportsAction(AddNewFile, currentNode)
&& !ICore::isNewItemDialogRunning());
m_addNewSubprojectAction->setEnabled(currentNode->nodeType() == NodeType::Project
&& actions.contains(AddSubProject)
&& supports(AddSubProject)
&& !ICore::isNewItemDialogRunning());
m_removeProjectAction->setEnabled(currentNode->nodeType() == NodeType::Project
&& actions.contains(RemoveSubProject));
m_addExistingFilesAction->setEnabled(actions.contains(AddExistingFile));
m_addExistingDirectoryAction->setEnabled(actions.contains(AddExistingDirectory));
m_renameFileAction->setEnabled(actions.contains(Rename));
&& supports(RemoveSubProject));
m_addExistingFilesAction->setEnabled(supports(AddExistingFile));
m_addExistingDirectoryAction->setEnabled(supports(AddExistingDirectory));
m_renameFileAction->setEnabled(supports(Rename));
} else if (currentNode->asFileNode()) {
// Enable and show remove / delete in magic ways:
// If both are disabled show Remove
// If both are enabled show both (can't happen atm)
// If only removeFile is enabled only show it
// If only deleteFile is enable only show it
bool enableRemove = actions.contains(RemoveFile);
bool enableRemove = supports(RemoveFile);
m_removeFileAction->setEnabled(enableRemove);
bool enableDelete = actions.contains(EraseFile);
bool enableDelete = supports(EraseFile);
m_deleteFileAction->setEnabled(enableDelete);
m_deleteFileAction->setVisible(enableDelete);
m_removeFileAction->setVisible(!enableDelete || enableRemove);
m_renameFileAction->setEnabled(actions.contains(Rename));
m_renameFileAction->setEnabled(supports(Rename));
const bool currentNodeIsTextFile = isTextFile(
ProjectTree::currentNode()->filePath().toString());
m_diffFileAction->setEnabled(isDiffServiceAvailable()
&& currentNodeIsTextFile && TextEditor::TextDocument::currentTextDocument());
m_duplicateFileAction->setVisible(actions.contains(DuplicateFile));
m_duplicateFileAction->setEnabled(actions.contains(DuplicateFile));
m_duplicateFileAction->setVisible(supports(DuplicateFile));
m_duplicateFileAction->setEnabled(supports(DuplicateFile));
EditorManager::populateOpenWithMenu(m_openWithMenu,
ProjectTree::currentNode()->filePath().toString());
}
if (actions.contains(HidePathActions)) {
if (supports(HidePathActions)) {
m_openTerminalHere->setVisible(false);
m_showInGraphicalShell->setVisible(false);
m_searchOnFileSystem->setVisible(false);
}
if (actions.contains(HideFileActions)) {
if (supports(HideFileActions)) {
m_deleteFileAction->setVisible(false);
m_removeFileAction->setVisible(false);
}
if (actions.contains(HideFolderActions)) {
if (supports(HideFolderActions)) {
m_addNewFileAction->setVisible(false);
m_addNewSubprojectAction->setVisible(false);
m_removeProjectAction->setVisible(false);
......@@ -3052,8 +3055,7 @@ void ProjectExplorerPluginPrivate::addNewSubproject()
QString location = directoryFor(currentNode);
if (currentNode->nodeType() == NodeType::Project
&& currentNode->supportedActions(
currentNode).contains(AddSubProject)) {
&& currentNode->supportsAction(AddSubProject, currentNode)) {
QVariantMap map;
map.insert(QLatin1String(Constants::PREFERRED_PROJECT_NODE), QVariant::fromValue(currentNode));
Project *project = ProjectTree::currentProject();
......
......@@ -145,7 +145,7 @@ Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
if (Node *node = nodeForIndex(index)) {
if (!node->asProjectNode()) {
// either folder or file node
if (node->supportedActions(node).contains(Rename))
if (node->supportsAction(Rename, node))
f = f | Qt::ItemIsEditable;
}
}
......
......@@ -215,14 +215,9 @@ bool Node::isEnabled() const
return parent ? parent->isEnabled() : true;
}
QList<ProjectAction> Node::supportedActions(Node *node) const
bool Node::supportsAction(ProjectAction, Node *) const
{
if (FolderNode *folder = parentFolderNode()) {
QList<ProjectAction> list = folder->supportedActions(node);
list.append(InheritedFromParent);
return list;
}
return {};
return false;
}
void Node::setEnabled(bool enabled)
......@@ -364,6 +359,14 @@ QList<FileNode *> FileNode::scanForFiles(const Utils::FileName &directory,
return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0);
}
bool FileNode::supportsAction(ProjectAction action, Node *node) const
{
if (action == InheritedFromParent)
return true;
FolderNode *parentFolder = parentFolderNode();
return parentFolder && parentFolder->supportsAction(action, node);
}
/*!
\class ProjectExplorer::FolderNode
......@@ -593,6 +596,14 @@ QString FolderNode::addFileFilter() const
return parentFolderNode()->addFileFilter();
}
bool FolderNode::supportsAction(ProjectAction action, Node *node) const
{
if (action == InheritedFromParent)
return true;
FolderNode *parentFolder = parentFolderNode();
return parentFolder && parentFolder->supportsAction(action, node);
}
bool FolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
{
ProjectNode *pn = managingProject();
......@@ -812,11 +823,10 @@ QString ContainerNode::displayName() const
return name;
}
QList<ProjectAction> ContainerNode::supportedActions(Node *node) const
bool ContainerNode::supportsAction(ProjectAction action, Node *node) const
{
if (Node *rootNode = m_project->rootProjectNode())
return rootNode->supportedActions(node);
return {};
Node *rootNode = m_project->rootProjectNode();
return rootNode && rootNode->supportsAction(action, node);
}
ProjectNode *ContainerNode::rootProjectNode() const
......
......@@ -130,7 +130,7 @@ public:
virtual QString tooltip() const;
bool isEnabled() const;
virtual QList<ProjectAction> supportedActions(Node *node) const;
virtual bool supportsAction(ProjectAction action, Node *node) const;
void setEnabled(bool enabled);
void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
......@@ -179,6 +179,7 @@ public:
static QList<FileNode *> scanForFiles(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &fileName)> factory,
QFutureInterface<QList<FileNode *>> *future = nullptr);
bool supportsAction(ProjectAction action, Node *node) const override;
private:
FileType m_fileType;
......@@ -225,6 +226,8 @@ public:
virtual QString addFileFilter() const;
bool supportsAction(ProjectAction action, Node *node) const override;
virtual bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0);
virtual bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0);
virtual bool deleteFiles(const QStringList &filePaths);
......@@ -309,7 +312,7 @@ public:
ContainerNode(Project *project);
QString displayName() const final;
QList<ProjectAction> supportedActions(Node *node) const final;
bool supportsAction(ProjectAction action, Node *node) const final;
ContainerNode *asContainerNode() final { return this; }
const ContainerNode *asContainerNode() const final { return this; }
......
......@@ -240,8 +240,7 @@ static inline AddNewTree *buildAddProjectTree(ProjectNode *root, const QString &
}
}
const QList<ProjectAction> &list = root->supportedActions(root);
if (list.contains(AddSubProject) && !list.contains(InheritedFromParent)) {
if (root->supportsAction(AddSubProject, root) && !root->supportsAction(InheritedFromParent, root)) {
if (projectPath.isEmpty() || root->canAddSubProject(projectPath)) {
FolderNode::AddNewInformation info = root->addNewInformation(QStringList() << projectPath, contextNode);
auto item = new AddNewTree(root, children, info);
......@@ -265,8 +264,7 @@ static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList
children.append(child);
}
const QList<ProjectAction> &list = root->supportedActions(root);
if (list.contains(AddNewFile) && !list.contains(InheritedFromParent)) {
if (root->supportsAction(AddNewFile, root) && !root->supportsAction(InheritedFromParent, root)) {
FolderNode::AddNewInformation info = root->addNewInformation(files, contextNode);
auto item = new AddNewTree(root, children, info);
selector->inspect(item, root == contextNode);
......
......@@ -122,11 +122,7 @@ public:
PythonProjectNode(PythonProject *project);
bool showInSimpleTree() const override;
QList<ProjectAction> supportedActions(Node *node) const override;
QString addFileFilter() const override;
bool renameFile(const QString &filePath, const QString &newFilePath) override;
private:
......@@ -655,13 +651,6 @@ bool PythonProjectNode::showInSimpleTree() const
return true;
}
QList<ProjectAction> PythonProjectNode::supportedActions(Node *node) const
{
Q_UNUSED(node);
//return { AddNewFile, AddExistingFile, AddExistingDirectory, RemoveFile, Rename };
return {};
}
QString PythonProjectNode::addFileFilter() const
{
return QLatin1String("*.py");
......
......@@ -45,6 +45,8 @@
#include <QIcon>
#include <QStyle>
using namespace ProjectExplorer;
// ----------------------------------------------------------------------
// Helpers:
// ----------------------------------------------------------------------
......@@ -223,26 +225,23 @@ public:
};
static QList<ProjectExplorer::ProjectAction> supportedNodeActions(ProjectExplorer::Node *node,
bool managesFiles)
static bool supportsNodeAction(ProjectAction action, Node *node)
{
QList<ProjectExplorer::ProjectAction> actions;
const QbsProject * const project = parentQbsProjectNode(node)->project();
if (!project->isProjectEditable())
return actions;
if (managesFiles)
actions << ProjectExplorer::AddNewFile << ProjectExplorer::AddExistingFile;
return false;
auto equalsNodeFilePath = [node](const QString &str)
{
return str == node->filePath().toString();
};
if (node->nodeType() == ProjectExplorer::NodeType::File
&& !Utils::contains(project->qbsProject().buildSystemFiles(), equalsNodeFilePath)) {
actions << ProjectExplorer::RemoveFile << ProjectExplorer::Rename;
if (action == RemoveFile || action == Rename) {
if (node->nodeType() == ProjectExplorer::NodeType::File)
return !Utils::contains(project->qbsProject().buildSystemFiles(), equalsNodeFilePath);
}
return actions;
return false;
}
// ----------------------------------------------------------------------
......@@ -271,9 +270,9 @@ QbsFolderNode::QbsFolderNode(const Utils::FileName &folderPath, ProjectExplorer:
{
}
QList<ProjectExplorer::ProjectAction> QbsFolderNode::supportedActions(ProjectExplorer::Node *node) const
bool QbsFolderNode::supportsAction(ProjectAction action, Node *node) const
{
return supportedNodeActions(node, false);
return supportsNodeAction(action, node);
}
// ---------------------------------------------------------------------------
......@@ -289,12 +288,6 @@ bool QbsBaseProjectNode::showInSimpleTree() const
return false;
}
QList<ProjectExplorer::ProjectAction> QbsBaseProjectNode::supportedActions(ProjectExplorer::Node *node) const
{
Q_UNUSED(node);
return QList<ProjectExplorer::ProjectAction>();
}
// --------------------------------------------------------------------
// QbsGroupNode:
// --------------------------------------------------------------------
......@@ -309,9 +302,12 @@ QbsGroupNode::QbsGroupNode(const qbs::GroupData &grp, const QString &productPath
m_qbsGroupData = grp;
}
QList<ProjectExplorer::ProjectAction> QbsGroupNode::supportedActions(ProjectExplorer::Node *node) const
bool QbsGroupNode::supportsAction(ProjectAction action, Node *node) const
{
return supportedNodeActions(node, true);
if (action == AddNewFile || action == AddExistingFile)
return true;
return supportsNodeAction(action, node);
}
bool QbsGroupNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
......@@ -388,9 +384,12 @@ bool QbsProductNode::showInSimpleTree() const
return true;
}
QList<ProjectExplorer::ProjectAction> QbsProductNode::supportedActions(ProjectExplorer::Node *node) const
bool QbsProductNode::supportsAction(ProjectAction action, Node *node) const
{
return supportedNodeActions(node, true);
if (action == AddNewFile || action == AddExistingFile)
return true;
return supportsNodeAction(action, node);
}
bool QbsProductNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
......
......@@ -55,7 +55,7 @@ public:
const QString &displayName);
private:
QList<ProjectExplorer::ProjectAction> supportedActions(ProjectExplorer::Node *node) const override;
bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const final;
};
// ---------------------------------------------------------------------------
......@@ -70,10 +70,6 @@ public:
explicit QbsBaseProjectNode(const Utils::FileName &absoluteFilePath);
bool showInSimpleTree() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
private:
friend class QbsGroupNode;
};
// --------------------------------------------------------------------
......@@ -85,7 +81,7 @@ class QbsGroupNode : public QbsBaseProjectNode
public:
QbsGroupNode(const qbs::GroupData &grp, const QString &productPath);
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const final;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0) override;
bool renameFile(const QString &filePath, const QString &newFilePath) override;
......@@ -107,7 +103,7 @@ public:
explicit QbsProductNode(const qbs::ProductData &prd);
bool showInSimpleTree() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const final;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0) override;
bool renameFile(const QString &filePath, const QString &newFilePath) override;
......
......@@ -74,9 +74,13 @@ QmakeProFileNode *QmakePriFileNode::proFileNode() const
return m_qmakeProFileNode;
}
QList<ProjectAction> QmakePriFileNode::supportedActions(Node *node) const
bool QmakePriFileNode::supportsAction(ProjectAction action, Node *node) const
{
QList<ProjectAction> actions;
if (action == Rename || action == DuplicateFile) {
FileNode *fileNode = node->asFileNode();
return (fileNode && fileNode->fileType() != FileType::Project)
|| dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(node);