ProjectExplorer: Fix some corner cases in signal subscriptions

Handle cases where targets/projects are removed and then added again.

This is currently not done anywhere, but there should not be nasty
surprises when somebody decides to do that later.

Change-Id: I47f9b4a1577f2021bcee87ccdd5435e3628b2a95
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Tobias Hunger
2018-06-01 15:13:51 +02:00
parent 9b43b55dc0
commit 34b205ed22
2 changed files with 35 additions and 30 deletions

View File

@@ -27,6 +27,7 @@
#include "project.h"
#include "projectconfiguration.h"
#include "session.h"
#include "target.h"
#include <utils/qtcassert.h>
@@ -37,13 +38,8 @@ 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, [this]() {
unsubscribeAll();
m_subscriber = Connector(); // Reset subscriber
deleteLater();
});
}
if (receiver != parent)
connect(receiver, &QObject::destroyed, this, &Subscription::destroy);
}
Subscription::~Subscription()
@@ -58,12 +54,7 @@ void Subscription::subscribe(ProjectConfiguration *pc)
connectTo(pc);
if (auto p = qobject_cast<Project *>(pc)) {
for (Target *t : p->targets()) {
for (ProjectConfiguration *pc : t->projectConfigurations())
connectTo(pc);
}
} else if (auto t = qobject_cast<Target *>(pc)) {
if (auto t = qobject_cast<Target *>(pc)) {
for (ProjectConfiguration *pc : t->projectConfigurations())
connectTo(pc);
}
@@ -73,14 +64,9 @@ void Subscription::unsubscribe(ProjectConfiguration *pc)
{
disconnectFrom(pc);
if (auto p = qobject_cast<Project *>(pc)) {
for (Target *t : p->targets()) {
for (ProjectConfiguration *pc : t->projectConfigurations())
unsubscribe(pc);
}
} else if (auto t = qobject_cast<Target *>(pc)) {
if (auto t = qobject_cast<Target *>(pc)) {
for (ProjectConfiguration *pc : t->projectConfigurations())
unsubscribe(pc);
disconnectFrom(pc);
}
}
@@ -93,6 +79,9 @@ void Subscription::unsubscribeAll()
void Subscription::connectTo(ProjectConfiguration *pc)
{
if (!m_subscriber)
return; // May happen during shutdown of a subscription
QTC_ASSERT(!m_connections.contains(pc), return);
QMetaObject::Connection conn = m_subscriber(pc);
@@ -110,18 +99,27 @@ void Subscription::disconnectFrom(ProjectConfiguration *pc)
m_connections.remove(pc);
}
void Subscription::destroy()
{
unsubscribeAll();
m_subscriber = Connector(); // Reset subscriber
deleteLater();
}
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);
}
QTC_ASSERT(m_subscriber, return);
for (Target *t : p->targets())
subscribe(t);
// Disconnect on removal of a project, to make it save to remove/add a project:
connect(SessionManager::instance(), &SessionManager::projectRemoved,
this, [this, p](Project *reported) { if (p == reported) { destroy(); } });
connect(p, &Project::addedProjectConfiguration, this, &ProjectSubscription::subscribe);
connect(p, &Project::removedProjectConfiguration, this, &ProjectSubscription::unsubscribe);
}
ProjectSubscription::~ProjectSubscription() = default;
@@ -130,8 +128,13 @@ TargetSubscription::TargetSubscription(const Subscription::Connector &s, const Q
Target *t) :
Subscription(s, r, t)
{
for (ProjectConfiguration *pc : t->projectConfigurations())
m_subscriber(pc);
QTC_ASSERT(m_subscriber, return);
subscribe(t);
// Disconnect on removal of a target, to make it save to remove/add a target:
connect(t->project(), &Project::removedTarget, this,
[t, this](const Target *reportedTarget) { if (t == reportedTarget) { destroy(); } });
connect(t, &Target::addedProjectConfiguration, this, &TargetSubscription::subscribe);
connect(t, &Target::removedProjectConfiguration, this, &TargetSubscription::unsubscribe);
}

View File

@@ -57,6 +57,8 @@ protected:
void connectTo(ProjectConfiguration *pc);
void disconnectFrom(ProjectConfiguration *pc);
void destroy();
Connector m_subscriber;
QHash<ProjectConfiguration *, QMetaObject::Connection> m_connections;
};