ProjectExplorer: Add "build for current run config" menu entry

This lets users build the executable corresponding to the currently
active run configuration. It's functionally equivalent to locating the
corresponding node in the project tree and choosing "Build" from the
context menu.

Fixes: QTCREATORBUG-22403
Change-Id: Ic2b729c7ce17f1ad944dc06746bb9d6db90b6c61
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2019-06-03 17:36:02 +02:00
parent 9e50d47b5c
commit 0c74f6cc21
18 changed files with 118 additions and 3 deletions

View File

@@ -87,6 +87,7 @@ CMakeProject::CMakeProject(const FilePath &fileName) : Project(Constants::CMAKEM
setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID); setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(projectDirectory().fileName()); setDisplayName(projectDirectory().fileName());
setCanBuildProducts();
// Timer: // Timer:
m_delayedParsingTimer.setSingleShot(true); m_delayedParsingTimer.setSingleShot(true);

View File

@@ -26,6 +26,7 @@
#include "cmakeprojectnodes.h" #include "cmakeprojectnodes.h"
#include "cmakeconfigitem.h" #include "cmakeconfigitem.h"
#include "cmakeproject.h"
#include "cmakeprojectconstants.h" #include "cmakeprojectconstants.h"
#include "cmakeprojectplugin.h" #include "cmakeprojectplugin.h"
@@ -264,6 +265,11 @@ Utils::optional<Utils::FilePath> CMakeTargetNode::visibleAfterAddFileAction() co
return filePath().pathAppended("CMakeLists.txt"); return filePath().pathAppended("CMakeLists.txt");
} }
void CMakeTargetNode::build()
{
static_cast<CMakeProject *>(getProject())->buildCMakeTarget(displayName());
}
void CMakeTargetNode::setTargetInformation(const QList<Utils::FilePath> &artifacts, void CMakeTargetNode::setTargetInformation(const QList<Utils::FilePath> &artifacts,
const QString &type) const QString &type)
{ {

View File

@@ -76,6 +76,8 @@ public:
bool addFiles(const QStringList &filePaths, QStringList *notAdded) override; bool addFiles(const QStringList &filePaths, QStringList *notAdded) override;
Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const override; Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const override;
void build() override;
QVariant data(Core::Id role) const override; QVariant data(Core::Id role) const override;
void setConfig(const CMakeConfig &config); void setConfig(const CMakeConfig &config);

View File

@@ -164,6 +164,7 @@ public:
bool m_isParsing = false; bool m_isParsing = false;
bool m_hasParsingData = false; bool m_hasParsingData = false;
bool m_needsInitialExpansion = false; bool m_needsInitialExpansion = false;
bool m_canBuildProducts = false;
std::unique_ptr<Core::IDocument> m_document; std::unique_ptr<Core::IDocument> m_document;
std::unique_ptr<ProjectNode> m_rootProjectNode; std::unique_ptr<ProjectNode> m_rootProjectNode;
std::unique_ptr<ContainerNode> m_containerNode; std::unique_ptr<ContainerNode> m_containerNode;
@@ -227,6 +228,11 @@ QString Project::mimeType() const
return document()->mimeType(); return document()->mimeType();
} }
bool Project::canBuildProducts() const
{
return d->m_canBuildProducts;
}
Core::IDocument *Project::document() const Core::IDocument *Project::document() const
{ {
QTC_CHECK(d->m_document); QTC_CHECK(d->m_document);
@@ -938,6 +944,11 @@ void Project::setRequiredKitPredicate(const Kit::Predicate &predicate)
d->m_requiredKitPredicate = predicate; d->m_requiredKitPredicate = predicate;
} }
void Project::setCanBuildProducts()
{
d->m_canBuildProducts = true;
}
Kit::Predicate Project::preferredKitPredicate() const Kit::Predicate Project::preferredKitPredicate() const
{ {
return d->m_preferredKitPredicate; return d->m_preferredKitPredicate;

View File

@@ -99,6 +99,7 @@ public:
Core::Id id() const; Core::Id id() const;
QString mimeType() const; QString mimeType() const;
bool canBuildProducts() const;
Core::IDocument *document() const; Core::IDocument *document() const;
Utils::FilePath projectFilePath() const; Utils::FilePath projectFilePath() const;
@@ -249,6 +250,8 @@ protected:
// The predicate used to select kits available in TargetSetupPage. // The predicate used to select kits available in TargetSetupPage.
void setRequiredKitPredicate(const Kit::Predicate &predicate); void setRequiredKitPredicate(const Kit::Predicate &predicate);
void setCanBuildProducts();
void setId(Core::Id id); void setId(Core::Id id);
void setRootProjectNode(std::unique_ptr<ProjectNode> &&root); // takes ownership! void setRootProjectNode(std::unique_ptr<ProjectNode> &&root); // takes ownership!
void setProjectLanguages(Core::Context language); void setProjectLanguages(Core::Context language);

View File

@@ -420,6 +420,7 @@ public:
QAction *m_closeAllProjects; QAction *m_closeAllProjects;
QAction *m_buildProjectOnlyAction; QAction *m_buildProjectOnlyAction;
Utils::ParameterAction *m_buildAction; Utils::ParameterAction *m_buildAction;
Utils::ParameterAction *m_buildForRunConfigAction;
Utils::ProxyAction *m_modeBarBuildAction; Utils::ProxyAction *m_modeBarBuildAction;
QAction *m_buildActionContextMenu; QAction *m_buildActionContextMenu;
QAction *m_buildDependenciesActionContextMenu; QAction *m_buildDependenciesActionContextMenu;
@@ -1043,6 +1044,17 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_modeBarBuildAction->setAction(cmd->action()); dd->m_modeBarBuildAction->setAction(cmd->action());
ModeManager::addAction(dd->m_modeBarBuildAction, Constants::P_ACTION_BUILDPROJECT); ModeManager::addAction(dd->m_modeBarBuildAction, Constants::P_ACTION_BUILDPROJECT);
// build for run config
dd->m_buildForRunConfigAction = new Utils::ParameterAction(
tr("Build for Run Configuration"), tr("Build for Run Configuration \"%1\""),
Utils::ParameterAction::EnabledWithParameter, this);
dd->m_buildForRunConfigAction->setIcon(buildIcon);
cmd = ActionManager::registerAction(dd->m_buildForRunConfigAction,
"ProjectExplorer.BuildForRunConfig");
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_buildForRunConfigAction->text());
mbuild->addAction(cmd, Constants::G_BUILD_BUILD);
// deploy action // deploy action
dd->m_deployAction = new Utils::ParameterAction(tr("Deploy Project"), tr("Deploy Project \"%1\""), dd->m_deployAction = new Utils::ParameterAction(tr("Deploy Project"), tr("Deploy Project \"%1\""),
Utils::ParameterAction::AlwaysEnabled, this); Utils::ParameterAction::AlwaysEnabled, this);
@@ -1391,6 +1403,21 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
connect(dd->m_buildActionContextMenu, &QAction::triggered, dd, [] { connect(dd->m_buildActionContextMenu, &QAction::triggered, dd, [] {
dd->queue({ ProjectTree::currentProject() }, { Id(Constants::BUILDSTEPS_BUILD) }); dd->queue({ ProjectTree::currentProject() }, { Id(Constants::BUILDSTEPS_BUILD) });
}); });
connect(dd->m_buildForRunConfigAction, &QAction::triggered, dd, [] {
const Project * const project = SessionManager::startupProject();
QTC_ASSERT(project, return);
const Target * const target = project->activeTarget();
QTC_ASSERT(target, return);
const RunConfiguration * const runConfig = target->activeRunConfiguration();
QTC_ASSERT(runConfig, return);
const auto buildKeyMatcher = [runConfig](const ProjectNode *candidate) {
return candidate->buildKey() == runConfig->buildKey();
};
ProjectNode * const productNode
= project->rootProjectNode()->findProjectNode(buildKeyMatcher);
QTC_ASSERT(productNode->isProduct(), return);
productNode->build();
});
connect(dd->m_buildDependenciesActionContextMenu, &QAction::triggered, dd, [] { connect(dd->m_buildDependenciesActionContextMenu, &QAction::triggered, dd, [] {
dd->queue(SessionManager::projectOrder(ProjectTree::currentProject()), dd->queue(SessionManager::projectOrder(ProjectTree::currentProject()),
{ Id(Constants::BUILDSTEPS_BUILD) }); { Id(Constants::BUILDSTEPS_BUILD) });
@@ -2436,8 +2463,13 @@ void ProjectExplorerPluginPrivate::updateActions()
? Icons::CANCELBUILD_FLAT.icon() ? Icons::CANCELBUILD_FLAT.icon()
: buildAction->icon()); : buildAction->icon());
const RunConfiguration * const runConfig = project && project->activeTarget()
? project->activeTarget()->activeRunConfiguration() : nullptr;
// Normal actions // Normal actions
m_buildAction->setParameter(projectName); m_buildAction->setParameter(projectName);
if (runConfig)
m_buildForRunConfigAction->setParameter(runConfig->displayName());
m_rebuildAction->setParameter(projectName); m_rebuildAction->setParameter(projectName);
m_cleanAction->setParameter(projectName); m_cleanAction->setParameter(projectName);
@@ -2445,6 +2477,11 @@ void ProjectExplorerPluginPrivate::updateActions()
m_rebuildAction->setEnabled(buildActionState.first); m_rebuildAction->setEnabled(buildActionState.first);
m_cleanAction->setEnabled(buildActionState.first); m_cleanAction->setEnabled(buildActionState.first);
// The last condition is there to prevent offering this action for custom run configurations.
m_buildForRunConfigAction->setEnabled(buildActionState.first
&& runConfig && project->canBuildProducts()
&& !runConfig->buildTargetInfo().projectFilePath.isEmpty());
m_buildAction->setToolTip(buildActionState.second); m_buildAction->setToolTip(buildActionState.second);
m_rebuildAction->setToolTip(buildActionState.second); m_rebuildAction->setToolTip(buildActionState.second);
m_cleanAction->setToolTip(buildActionState.second); m_cleanAction->setToolTip(buildActionState.second);
@@ -2935,6 +2972,7 @@ void ProjectExplorerPluginPrivate::activeRunConfigurationChanged()
rc = startupProject->activeTarget()->activeRunConfiguration(); rc = startupProject->activeTarget()->activeRunConfiguration();
if (rc == previousRunConfiguration) if (rc == previousRunConfiguration)
return; return;
updateActions();
emit m_instance->updateRunActions(); emit m_instance->updateRunActions();
} }

View File

@@ -212,6 +212,15 @@ const ProjectNode *Node::managingProject() const
return const_cast<Node *>(this)->managingProject(); return const_cast<Node *>(this)->managingProject();
} }
Project *Node::getProject() const
{
if (const ContainerNode * const cn = asContainerNode())
return cn->project();
if (!m_parentFolderNode)
return nullptr;
return m_parentFolderNode->getProject();
}
/*! /*!
The path of the file or folder in the filesystem the node represents. The path of the file or folder in the filesystem the node represents.
*/ */

View File

@@ -121,6 +121,8 @@ public:
// or node->parentProjectNode() for all other cases. // or node->parentProjectNode() for all other cases.
const ProjectNode *managingProject() const; // see above. const ProjectNode *managingProject() const; // see above.
Project *getProject() const;
const Utils::FilePath &filePath() const; // file system path const Utils::FilePath &filePath() const; // file system path
int line() const; int line() const;
virtual QString displayName() const; virtual QString displayName() const;
@@ -359,6 +361,13 @@ public:
bool isProduct() const { return m_isProduct; } bool isProduct() const { return m_isProduct; }
// TODO: Currently used only for "Build for current run config" functionality, but we should
// probably use it to centralize the node-specific "Build" functionality that
// currently each project manager plugin adds to the context menu by itself.
// The function should then move up to the Node class, so it can also serve the
// "build single file" case.
virtual void build() {}
protected: protected:
void setIsProduct() { m_isProduct = true; } void setIsProduct() { m_isProduct = true; }

View File

@@ -28,6 +28,7 @@
#include "qbsnodetreebuilder.h" #include "qbsnodetreebuilder.h"
#include "qbsproject.h" #include "qbsproject.h"
#include "qbsprojectmanagerconstants.h" #include "qbsprojectmanagerconstants.h"
#include "qbsprojectmanagerplugin.h"
#include "qbsrunconfiguration.h" #include "qbsrunconfiguration.h"
#include <android/androidconstants.h> #include <android/androidconstants.h>
@@ -391,6 +392,12 @@ bool QbsProductNode::renameFile(const QString &filePath, const QString &newFileP
return prjNode->project()->renameFileInProduct(filePath, newFilePath, m_qbsProductData, grp); return prjNode->project()->renameFileInProduct(filePath, newFilePath, m_qbsProductData, grp);
} }
void QbsProductNode::build()
{
QbsProjectManagerPlugin::buildNamedProduct(static_cast<QbsProject *>(getProject()),
QbsProject::uniqueProductName(qbsProductData()));
}
QStringList QbsProductNode::targetApplications() const QStringList QbsProductNode::targetApplications() const
{ {
return QStringList{m_qbsProductData.targetExecutable()}; return QStringList{m_qbsProductData.targetExecutable()};

View File

@@ -70,6 +70,7 @@ public:
bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = nullptr) override; bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = nullptr) override;
bool renameFile(const QString &filePath, const QString &newFilePath) override; bool renameFile(const QString &filePath, const QString &newFilePath) override;
void build() override;
QStringList targetApplications() const override; QStringList targetApplications() const override;
QString buildKey() const override; QString buildKey() const override;

View File

@@ -129,6 +129,7 @@ QbsProject::QbsProject(const FilePath &fileName) :
setId(Constants::PROJECT_ID); setId(Constants::PROJECT_ID);
setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setCanBuildProducts();
rebuildProjectTree(); rebuildProjectTree();

View File

@@ -578,5 +578,11 @@ void QbsProjectManagerPlugin::reparseProject(QbsProject *project)
project->parseCurrentBuildConfiguration(); project->parseCurrentBuildConfiguration();
} }
void QbsProjectManagerPlugin::buildNamedProduct(QbsProject *project, const QString &product)
{
QbsProjectManagerPlugin::runStepsForProducts(project, QStringList(product),
{Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD)});
}
} // namespace Internal } // namespace Internal
} // namespace QbsProjectManager } // namespace QbsProjectManager

View File

@@ -42,6 +42,10 @@ class QbsProjectManagerPlugin : public ExtensionSystem::IPlugin
Q_OBJECT Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QbsProjectManager.json") Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QbsProjectManager.json")
public:
static void buildNamedProduct(QbsProject *project, const QString &product);
private:
~QbsProjectManagerPlugin() final; ~QbsProjectManagerPlugin() final;
bool initialize(const QStringList &arguments, QString *errorMessage) final; bool initialize(const QStringList &arguments, QString *errorMessage) final;
@@ -77,7 +81,7 @@ class QbsProjectManagerPlugin : public ExtensionSystem::IPlugin
const QStringList &activeFileTags); const QStringList &activeFileTags);
void buildSingleFile(QbsProject *project, const QString &file); void buildSingleFile(QbsProject *project, const QString &file);
void runStepsForProducts(QbsProject *project, const QStringList &products, static void runStepsForProducts(QbsProject *project, const QStringList &products,
const QList<Core::Id> &stepTypes); const QList<Core::Id> &stepTypes);
QbsProjectManagerPluginPrivate *d = nullptr; QbsProjectManagerPluginPrivate *d = nullptr;

View File

@@ -24,7 +24,9 @@
****************************************************************************/ ****************************************************************************/
#include "qmakenodes.h" #include "qmakenodes.h"
#include "qmakeproject.h" #include "qmakeproject.h"
#include "qmakeprojectmanager.h"
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
@@ -255,6 +257,11 @@ bool QmakeProFileNode::validParse() const
return pro && pro->validParse(); return pro && pro->validParse();
} }
void QmakeProFileNode::build()
{
QmakeManager::buildProduct(getProject(), this);
}
QStringList QmakeProFileNode::targetApplications() const QStringList QmakeProFileNode::targetApplications() const
{ {
QStringList apps; QStringList apps;

View File

@@ -97,6 +97,8 @@ public:
bool parseInProgress() const override; bool parseInProgress() const override;
bool validParse() const override; bool validParse() const override;
void build() override;
QStringList targetApplications() const override; QStringList targetApplications() const override;
AddNewInformation addNewInformation(const QStringList &files, Node *context) const override; AddNewInformation addNewInformation(const QStringList &files, Node *context) const override;
QVariant data(Core::Id role) const override; QVariant data(Core::Id role) const override;

View File

@@ -129,6 +129,7 @@ QmakeProject::QmakeProject(const FilePath &fileName) :
setId(Constants::QMAKEPROJECT_ID); setId(Constants::QMAKEPROJECT_ID);
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(fileName.toFileInfo().completeBaseName()); setDisplayName(fileName.toFileInfo().completeBaseName());
setCanBuildProducts();
const QTextCodec *codec = Core::EditorManager::defaultTextCodec(); const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
m_qmakeVfs->setTextCodec(codec); m_qmakeVfs->setTextCodec(codec);

View File

@@ -194,6 +194,11 @@ void QmakeManager::buildFile()
} }
} }
void QmakeManager::buildProduct(Project *project, Node *proFileNode)
{
handleSubDirContextMenu(BUILD, false, project, proFileNode, nullptr);
}
void QmakeManager::handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild) void QmakeManager::handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild)
{ {
handleSubDirContextMenu(action, handleSubDirContextMenu(action,

View File

@@ -62,9 +62,11 @@ public:
void buildFileContextMenu(); void buildFileContextMenu();
void buildFile(); void buildFile();
static void buildProduct(ProjectExplorer::Project *project, ProjectExplorer::Node *proFileNode);
private: private:
void handleSubDirContextMenu(Action action, bool isFileBuild); void handleSubDirContextMenu(Action action, bool isFileBuild);
void handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild, static void handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild,
ProjectExplorer::Project *contextProject, ProjectExplorer::Project *contextProject,
ProjectExplorer::Node *contextProFileNode, ProjectExplorer::Node *contextProFileNode,
ProjectExplorer::FileNode *buildableFile); ProjectExplorer::FileNode *buildableFile);