diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index da349f8e1c5..d064120f295 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -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); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index f14f627b34f..ea218c22574 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -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 CMakeTargetNode::visibleAfterAddFileAction() co return filePath().pathAppended("CMakeLists.txt"); } +void CMakeTargetNode::build() +{ + static_cast(getProject())->buildCMakeTarget(displayName()); +} + void CMakeTargetNode::setTargetInformation(const QList &artifacts, const QString &type) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h index 5a617379258..b924ec62a8c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h @@ -76,6 +76,8 @@ public: bool addFiles(const QStringList &filePaths, QStringList *notAdded) override; Utils::optional visibleAfterAddFileAction() const override; + void build() override; + QVariant data(Core::Id role) const override; void setConfig(const CMakeConfig &config); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 16ae9a38dce..026cb381ba5 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -164,6 +164,7 @@ public: bool m_isParsing = false; bool m_hasParsingData = false; bool m_needsInitialExpansion = false; + bool m_canBuildProducts = false; std::unique_ptr m_document; std::unique_ptr m_rootProjectNode; std::unique_ptr 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; diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index e66e049c0ca..a7e2ad2a926 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -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 &&root); // takes ownership! void setProjectLanguages(Core::Context language); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 8169fab0a0c..bb6f77f0332 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -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(); } diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index e6825e98be9..f8747e529cf 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -212,6 +212,15 @@ const ProjectNode *Node::managingProject() const return const_cast(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. */ diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index ce36882aa9c..8660080a2b3 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -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; } diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp index e5071cabba1..27aabb710c0 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp @@ -28,6 +28,7 @@ #include "qbsnodetreebuilder.h" #include "qbsproject.h" #include "qbsprojectmanagerconstants.h" +#include "qbsprojectmanagerplugin.h" #include "qbsrunconfiguration.h" #include @@ -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(getProject()), + QbsProject::uniqueProductName(qbsProductData())); +} + QStringList QbsProductNode::targetApplications() const { return QStringList{m_qbsProductData.targetExecutable()}; diff --git a/src/plugins/qbsprojectmanager/qbsnodes.h b/src/plugins/qbsprojectmanager/qbsnodes.h index 3d8f90c3df4..6927c00db24 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.h +++ b/src/plugins/qbsprojectmanager/qbsnodes.h @@ -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; diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 209e87b4bca..788d8bc9f95 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -129,6 +129,7 @@ QbsProject::QbsProject(const FilePath &fileName) : setId(Constants::PROJECT_ID); setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + setCanBuildProducts(); rebuildProjectTree(); diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index f8eb477e649..c30add24d97 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -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 diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h index f7b37e8d809..267b7777ae3 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h @@ -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 &stepTypes); + static void runStepsForProducts(QbsProject *project, const QStringList &products, + const QList &stepTypes); QbsProjectManagerPluginPrivate *d = nullptr; QAction *m_reparseQbs = nullptr; diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index a71ab8c3d6a..9370519f39b 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -24,7 +24,9 @@ ****************************************************************************/ #include "qmakenodes.h" + #include "qmakeproject.h" +#include "qmakeprojectmanager.h" #include #include @@ -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; diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 92b84fbcb02..b7432bcc14d 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -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; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 3b5e4531b6a..8730d534525 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -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); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp index adbc1709fb8..fc6f56d6787 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp @@ -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, diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h index ab163f1a764..722ab075773 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h @@ -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);