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);
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(projectDirectory().fileName());
setCanBuildProducts();
// Timer:
m_delayedParsingTimer.setSingleShot(true);

View File

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

View File

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

View File

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

View File

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

View File

@@ -420,6 +420,7 @@ public:
QAction *m_closeAllProjects;
QAction *m_buildProjectOnlyAction;
Utils::ParameterAction *m_buildAction;
Utils::ParameterAction *m_buildForRunConfigAction;
Utils::ProxyAction *m_modeBarBuildAction;
QAction *m_buildActionContextMenu;
QAction *m_buildDependenciesActionContextMenu;
@@ -1043,6 +1044,17 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_modeBarBuildAction->setAction(cmd->action());
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
dd->m_deployAction = new Utils::ParameterAction(tr("Deploy Project"), tr("Deploy Project \"%1\""),
Utils::ParameterAction::AlwaysEnabled, this);
@@ -1391,6 +1403,21 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
connect(dd->m_buildActionContextMenu, &QAction::triggered, dd, [] {
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, [] {
dd->queue(SessionManager::projectOrder(ProjectTree::currentProject()),
{ Id(Constants::BUILDSTEPS_BUILD) });
@@ -2436,8 +2463,13 @@ void ProjectExplorerPluginPrivate::updateActions()
? Icons::CANCELBUILD_FLAT.icon()
: buildAction->icon());
const RunConfiguration * const runConfig = project && project->activeTarget()
? project->activeTarget()->activeRunConfiguration() : nullptr;
// Normal actions
m_buildAction->setParameter(projectName);
if (runConfig)
m_buildForRunConfigAction->setParameter(runConfig->displayName());
m_rebuildAction->setParameter(projectName);
m_cleanAction->setParameter(projectName);
@@ -2445,6 +2477,11 @@ void ProjectExplorerPluginPrivate::updateActions()
m_rebuildAction->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_rebuildAction->setToolTip(buildActionState.second);
m_cleanAction->setToolTip(buildActionState.second);
@@ -2935,6 +2972,7 @@ void ProjectExplorerPluginPrivate::activeRunConfigurationChanged()
rc = startupProject->activeTarget()->activeRunConfiguration();
if (rc == previousRunConfiguration)
return;
updateActions();
emit m_instance->updateRunActions();
}

View File

@@ -212,6 +212,15 @@ const ProjectNode *Node::managingProject() const
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.
*/

View File

@@ -121,6 +121,8 @@ public:
// or node->parentProjectNode() for all other cases.
const ProjectNode *managingProject() const; // see above.
Project *getProject() const;
const Utils::FilePath &filePath() const; // file system path
int line() const;
virtual QString displayName() const;
@@ -359,6 +361,13 @@ public:
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:
void setIsProduct() { m_isProduct = true; }

View File

@@ -28,6 +28,7 @@
#include "qbsnodetreebuilder.h"
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"
#include "qbsprojectmanagerplugin.h"
#include "qbsrunconfiguration.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);
}
void QbsProductNode::build()
{
QbsProjectManagerPlugin::buildNamedProduct(static_cast<QbsProject *>(getProject()),
QbsProject::uniqueProductName(qbsProductData()));
}
QStringList QbsProductNode::targetApplications() const
{
return QStringList{m_qbsProductData.targetExecutable()};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -129,6 +129,7 @@ QmakeProject::QmakeProject(const FilePath &fileName) :
setId(Constants::QMAKEPROJECT_ID);
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(fileName.toFileInfo().completeBaseName());
setCanBuildProducts();
const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
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)
{
handleSubDirContextMenu(action,

View File

@@ -62,9 +62,11 @@ public:
void buildFileContextMenu();
void buildFile();
static void buildProduct(ProjectExplorer::Project *project, ProjectExplorer::Node *proFileNode);
private:
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::Node *contextProFileNode,
ProjectExplorer::FileNode *buildableFile);