Commit e52ebbf2 authored by Tobias Hunger's avatar Tobias Hunger

ProjectExplorer: Add subscribeSignal method to targets and projects

Add a subscribeSignal method to targets and projects that will make
sure all signals of all project configurations added during the lifetime
of the project/target will get connected (if the type matches).

Use this to connect to some signal in all BuildConfigurations of
a project and get rid of code that keeps connecting to the current
build configuration.

Use Project::buildEnvironmentChanged as an example and convert its
usages.

Change-Id: I689bcebac4b191bf3f8a18765bf18eaac371c5fe
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent 34456aa9
......@@ -236,8 +236,15 @@ MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep) :
makeStep, &MakeStep::setAdditionalArguments);
connect(makeStep, &MakeStep::additionalArgumentsChanged,
this, &MakeStepConfigWidget::updateDetails);
connect(m_makeStep->project(), &Project::environmentChanged,
this, &MakeStepConfigWidget::updateDetails);
m_makeStep->project()->subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive())
updateDetails();
});
connect(makeStep->project(), &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive())
updateDetails();
});
}
QString MakeStepConfigWidget::displayName() const
......
......@@ -475,8 +475,16 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep
connect(m_buildStep, &CMakeBuildStep::buildTargetsChanged, this, &CMakeBuildStepConfigWidget::buildTargetsChanged);
connect(m_buildStep, &CMakeBuildStep::targetToBuildChanged, this, &CMakeBuildStepConfigWidget::selectedBuildTargetsChanged);
connect(static_cast<CMakeProject *>(m_buildStep->project()), &CMakeProject::environmentChanged,
this, &CMakeBuildStepConfigWidget::updateDetails);
m_buildStep->project()->subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive())
updateDetails();
});
connect(m_buildStep->project(), &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive())
updateDetails();
});
}
void CMakeBuildStepConfigWidget::toolArgumentsEdited()
......
......@@ -232,7 +232,7 @@ GenericMakeStepConfigWidget::GenericMakeStepConfigWidget(GenericMakeStep *makeSt
m_ui->makeLineEdit->setText(m_makeStep->m_makeCommand);
m_ui->makeArgumentsLineEdit->setText(m_makeStep->m_makeArguments);
updateMakeOverrrideLabel();
updateMakeOverrideLabel();
updateDetails();
connect(m_ui->targetsList, &QListWidget::itemChanged,
......@@ -243,17 +243,26 @@ GenericMakeStepConfigWidget::GenericMakeStepConfigWidget(GenericMakeStep *makeSt
this, &GenericMakeStepConfigWidget::makeArgumentsLineEditTextEdited);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
this, &GenericMakeStepConfigWidget::updateMakeOverrrideLabel);
this, &GenericMakeStepConfigWidget::updateMakeOverrideLabel);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
this, &GenericMakeStepConfigWidget::updateDetails);
connect(m_makeStep->target(), &Target::kitChanged,
this, &GenericMakeStepConfigWidget::updateMakeOverrrideLabel);
connect(pro, &GenericProject::environmentChanged,
this, &GenericMakeStepConfigWidget::updateMakeOverrrideLabel);
connect(pro, &GenericProject::environmentChanged,
this, &GenericMakeStepConfigWidget::updateDetails);
this, &GenericMakeStepConfigWidget::updateMakeOverrideLabel);
pro->subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive()) {
updateMakeOverrideLabel();
updateDetails();
}
});
connect(pro, &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive()) {
updateMakeOverrideLabel();
updateDetails();
}
});
}
GenericMakeStepConfigWidget::~GenericMakeStepConfigWidget()
......@@ -266,7 +275,7 @@ QString GenericMakeStepConfigWidget::displayName() const
return tr("Make", "GenericMakestep display name.");
}
void GenericMakeStepConfigWidget::updateMakeOverrrideLabel()
void GenericMakeStepConfigWidget::updateMakeOverrideLabel()
{
BuildConfiguration *bc = m_makeStep->buildConfiguration();
if (!bc)
......
......@@ -91,7 +91,7 @@ private:
void itemChanged(QListWidgetItem *item);
void makeLineEditTextEdited();
void makeArgumentsLineEditTextEdited();
void updateMakeOverrrideLabel();
void updateMakeOverrideLabel();
void updateDetails();
Ui::GenericMakeStep *m_ui;
......
......@@ -260,7 +260,15 @@ IosBuildStepConfigWidget::IosBuildStepConfigWidget(IosBuildStep *buildStep)
this, &IosBuildStepConfigWidget::updateDetails);
connect(m_buildStep->target(), &Target::kitChanged,
this, &IosBuildStepConfigWidget::updateDetails);
connect(pro, &Project::environmentChanged, this, &IosBuildStepConfigWidget::updateDetails);
pro->subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive())
updateDetails();
});
connect(pro, &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive())
updateDetails();
});
}
IosBuildStepConfigWidget::~IosBuildStepConfigWidget()
......
......@@ -260,7 +260,15 @@ IosPresetBuildStepConfigWidget::IosPresetBuildStepConfigWidget(IosPresetBuildSte
this, &IosPresetBuildStepConfigWidget::updateDetails);
connect(m_buildStep->target(), &Target::kitChanged,
this, &IosPresetBuildStepConfigWidget::updateDetails);
connect(pro, &Project::environmentChanged, this, &IosPresetBuildStepConfigWidget::updateDetails);
pro->subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive())
updateDetails();
});
connect(pro, &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive())
updateDetails();
});
}
IosPresetBuildStepConfigWidget::~IosPresetBuildStepConfigWidget()
......
......@@ -53,7 +53,7 @@ BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) :
m_buildConfiguration = bc;
connect(m_buildConfiguration->target(), &Target::environmentChanged,
connect(m_buildConfiguration, &BuildConfiguration::environmentChanged,
this, &BuildEnvironmentWidget::environmentChanged);
m_clearSystemEnvironmentCheckBox->setChecked(!m_buildConfiguration->useSystemEnvironment());
......
......@@ -88,7 +88,9 @@ LocalEnvironmentAspect::LocalEnvironmentAspect(RunConfiguration *parent,
const BaseEnvironmentModifier &modifier) :
EnvironmentAspect(parent), m_baseEnvironmentModifier(modifier)
{
connect(parent->target(), &Target::environmentChanged,
parent->target()->subscribeSignal(&BuildConfiguration::environmentChanged,
this, &LocalEnvironmentAspect::buildEnvironmentHasChanged);
connect(parent->target(), &Target::activeBuildConfigurationChanged,
this, &LocalEnvironmentAspect::buildEnvironmentHasChanged);
}
......
......@@ -223,13 +223,6 @@ QString Project::makeUnique(const QString &preferredName, const QStringList &use
return tryName;
}
void Project::changeEnvironment()
{
auto t = qobject_cast<Target *>(sender());
if (t == activeTarget())
emit environmentChanged();
}
void Project::changeBuildConfigurationEnabled()
{
auto t = qobject_cast<Target *>(sender());
......@@ -247,7 +240,6 @@ void Project::addTarget(Target *t)
// add it
d->m_targets.push_back(t);
connect(t, &Target::environmentChanged, this, &Project::changeEnvironment);
connect(t, &Target::buildConfigurationEnabledChanged,
this, &Project::changeBuildConfigurationEnabled);
connect(t, &Target::buildDirectoryChanged, this, &Project::onBuildDirectoryChanged);
......@@ -306,7 +298,6 @@ void Project::setActiveTarget(Target *target)
d->m_activeTarget = target;
emit activeProjectConfigurationChanged(d->m_activeTarget);
emit activeTargetChanged(d->m_activeTarget);
emit environmentChanged();
emit buildConfigurationEnabledChanged();
}
}
......
......@@ -28,6 +28,7 @@
#include "projectexplorer_export.h"
#include "kit.h"
#include "subscription.h"
#include <coreplugin/id.h>
#include <coreplugin/idocument.h>
......@@ -168,6 +169,24 @@ public:
bool isParsing() const;
bool hasParsingData() const;
template<typename S, typename R, typename T>
void subscribeSignal(void (S::*sig)(), R*recv, T (R::*sl)()) {
new Internal::ProjectSubscription([sig, recv, sl, this](ProjectConfiguration *pc) {
if (S* sender = qobject_cast<S*>(pc))
return connect(sender, sig, recv, sl);
return QMetaObject::Connection();
}, recv, this);
}
template<typename S, typename R, typename T>
void subscribeSignal(void (S::*sig)(), R*recv, T sl) {
new Internal::ProjectSubscription([sig, recv, sl, this](ProjectConfiguration *pc) {
if (S* sender = qobject_cast<S*>(pc))
return connect(sender, sig, recv, sl);
return QMetaObject::Connection();
}, recv, this);
}
signals:
void displayNameChanged();
void fileListChanged();
......@@ -188,7 +207,6 @@ signals:
void removedTarget(ProjectExplorer::Target *target);
void addedTarget(ProjectExplorer::Target *target);
void environmentChanged();
void buildConfigurationEnabledChanged();
void buildDirectoryChanged();
......@@ -226,7 +244,6 @@ protected:
virtual void projectLoaded(); // Called when the project is fully loaded.
private:
void changeEnvironment();
void changeBuildConfigurationEnabled();
void onBuildDirectoryChanged();
......
......@@ -21,6 +21,7 @@ HEADERS += projectexplorer.h \
projectimporter.h \
projectwindow.h \
removetaskhandler.h \
subscription.h \
targetsetuppage.h \
targetsetupwidget.h \
kit.h \
......@@ -168,6 +169,7 @@ SOURCES += projectexplorer.cpp \
projectimporter.cpp \
projectwindow.cpp \
removetaskhandler.cpp \
subscription.cpp \
targetsetuppage.cpp \
targetsetupwidget.cpp \
kit.cpp \
......
/****************************************************************************
**
** Copyright (C) 2017 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 "subscription.h"
#include "project.h"
#include "projectconfiguration.h"
#include "target.h"
#include <utils/asconst.h>
namespace ProjectExplorer {
namespace Internal {
Subscription::Subscription(const Subscription::Connector &s, const QObject *receiver, QObject *parent) :
QObject(parent), m_subscriber(s)
{
if (receiver != parent)
connect(receiver, &QObject::destroyed, this, &QObject::deleteLater);
}
Subscription::~Subscription()
{
for (const auto &c : Utils::asConst(m_connections))
disconnect(c);
}
void Subscription::subscribe(ProjectConfiguration *pc)
{
if (!m_subscriber)
return;
QMetaObject::Connection conn = m_subscriber(pc);
if (conn)
m_connections.insert(pc, conn);
}
void Subscription::unsubscribe(ProjectConfiguration *pc)
{
auto c = m_connections.value(pc);
if (c) {
disconnect(c);
m_connections.remove(pc);
}
}
ProjectSubscription::ProjectSubscription(const Subscription::Connector &s, const QObject *r,
Project *p) :
Subscription(s, r, p)
{
if (m_subscriber) {
for (const Target *t : p->targets()) {
for (ProjectConfiguration *pc : t->projectConfigurations())
m_subscriber(pc);
}
connect(p, &Project::addedProjectConfiguration, this, &ProjectSubscription::subscribe);
connect(p, &Project::removedProjectConfiguration, this, &ProjectSubscription::unsubscribe);
}
}
ProjectSubscription::~ProjectSubscription() = default;
TargetSubscription::TargetSubscription(const Subscription::Connector &s, const QObject *r,
Target *t) :
Subscription(s, r, t)
{
for (ProjectConfiguration *pc : t->projectConfigurations())
m_subscriber(pc);
connect(t, &Target::addedProjectConfiguration, this, &TargetSubscription::subscribe);
connect(t, &Target::removedProjectConfiguration, this, &TargetSubscription::unsubscribe);
}
TargetSubscription::~TargetSubscription() = default;
} // namespace Internal
} // namespace ProjectExplorer
/****************************************************************************
**
** Copyright (C) 2017 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 <QHash>
#include <QObject>
#include <functional>
namespace ProjectExplorer {
class Project;
class ProjectConfiguration;
class Target;
namespace Internal {
class PROJECTEXPLORER_EXPORT Subscription : public QObject
{
Q_OBJECT
public:
using Connector = std::function<QMetaObject::Connection(ProjectConfiguration *)>;
Subscription(const Connector &s, const QObject *receiver, QObject *parent);
~Subscription() override;
protected:
void subscribe(ProjectConfiguration *pc);
void unsubscribe(ProjectConfiguration *pc);
Connector m_subscriber;
QHash<ProjectConfiguration *, QMetaObject::Connection> m_connections;
};
class PROJECTEXPLORER_EXPORT ProjectSubscription : public Subscription
{
public:
ProjectSubscription(const Connector &s, const QObject *receiver, Project *p);
~ProjectSubscription() final;
};
class PROJECTEXPLORER_EXPORT TargetSubscription : public Subscription
{
public:
TargetSubscription(const Connector &s, const QObject *receiver, Target *t);
~TargetSubscription() final;
};
} // namespace Internal
} // namespace ProjectExplorer
......@@ -153,13 +153,6 @@ Target::~Target()
delete d;
}
void Target::changeEnvironment()
{
auto bc = qobject_cast<BuildConfiguration *>(sender());
if (bc == activeBuildConfiguration())
emit environmentChanged();
}
void Target::changeBuildConfigurationEnabled()
{
auto bc = qobject_cast<BuildConfiguration *>(sender());
......@@ -246,8 +239,6 @@ void Target::addBuildConfiguration(BuildConfiguration *bc)
emit addedProjectConfiguration(bc);
emit addedBuildConfiguration(bc);
connect(bc, &BuildConfiguration::environmentChanged,
this, &Target::changeEnvironment);
connect(bc, &BuildConfiguration::enabledChanged,
this, &Target::changeBuildConfigurationEnabled);
connect(bc, &BuildConfiguration::buildDirectoryChanged,
......@@ -303,7 +294,6 @@ void Target::setActiveBuildConfiguration(BuildConfiguration *bc)
d->m_activeBuildConfiguration = bc;
emit activeProjectConfigurationChanged(d->m_activeBuildConfiguration);
emit activeBuildConfigurationChanged(d->m_activeBuildConfiguration);
emit environmentChanged();
emit buildConfigurationEnabledChanged();
emit buildDirectoryChanged();
}
......
......@@ -28,6 +28,8 @@
#include "projectconfiguration.h"
#include "projectexplorer_export.h"
#include "subscription.h"
QT_FORWARD_DECLARE_CLASS(QIcon)
namespace Utils { class Environment; }
......@@ -112,6 +114,25 @@ public:
QVariant namedSettings(const QString &name) const;
void setNamedSettings(const QString &name, const QVariant &value);
template<typename S, typename R, typename T>
void subscribeSignal(void (S::*sig)(), R*recv, T (R::*sl)()) {
new Internal::TargetSubscription([sig, recv, sl, this](ProjectConfiguration *pc) {
if (S* sender = qobject_cast<S*>(pc))
return connect(sender, sig, recv, sl);
return QMetaObject::Connection();
}, recv, this);
}
template<typename S, typename R, typename T>
void subscribeSignal(void (S::*sig)(), R*recv, T sl) {
new Internal::TargetSubscription([sig, recv, sl, this](ProjectConfiguration *pc) {
if (S* sender = qobject_cast<S*>(pc))
return connect(sender, sig, recv, sl);
return QMetaObject::Connection();
}, recv, this);
}
signals:
void targetEnabled(bool);
void iconChanged();
......@@ -139,10 +160,6 @@ signals:
void addedDeployConfiguration(ProjectExplorer::DeployConfiguration *dc);
void activeDeployConfigurationChanged(ProjectExplorer::DeployConfiguration *dc);
/// convenience signal, emitted if either the active buildconfiguration emits
/// environmentChanged() or if the active build configuration changes
void environmentChanged();
/// convenience signal, emitted if either the active configuration emits
/// enabledChanged() or if the active build configuration changes
void buildConfigurationEnabledChanged();
......@@ -166,7 +183,6 @@ private:
void updateDeviceState();
void onBuildDirectoryChanged();
void changeEnvironment();
void changeBuildConfigurationEnabled();
void changeDeployConfigurationEnabled();
void changeRunConfigurationEnabled();
......
......@@ -140,7 +140,15 @@ QbsProject::QbsProject(const FileName &fileName) :
connect(this, &Project::activeTargetChanged, this, &QbsProject::changeActiveTarget);
connect(this, &Project::addedTarget, this, &QbsProject::targetWasAdded);
connect(this, &Project::removedTarget, this, &QbsProject::targetWasRemoved);
connect(this, &Project::environmentChanged, this, &QbsProject::delayParsing);
subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive())
startParsing();
});
connect(this, &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive())
startParsing();
});
connect(&m_parsingDelay, &QTimer::timeout, this, &QbsProject::startParsing);
......
......@@ -98,8 +98,15 @@ QmakeProjectConfigWidget::QmakeProjectConfigWidget(QmakeBuildConfiguration *bc)
this, &QmakeProjectConfigWidget::shadowBuildEdited);
QmakeProject *project = static_cast<QmakeProject *>(bc->target()->project());
connect(project, &QmakeProject::environmentChanged,
this, &QmakeProjectConfigWidget::environmentChanged);
project->subscribeSignal(&BuildConfiguration::environmentChanged, this, [this]() {
if (static_cast<BuildConfiguration *>(sender())->isActive())
environmentChanged();
});
connect(project, &Project::activeProjectConfigurationChanged,
this, [this](ProjectConfiguration *pc) {
if (pc->isActive())
environmentChanged();
});
connect(project, &QmakeProject::buildDirectoryInitialized,
this, &QmakeProjectConfigWidget::updateProblemLabel);
connect(project, &QmakeProject::proFilesEvaluated,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment