forked from qt-creator/qt-creator
ProjectExplorer: Make subscriptions more robust
Make sure not to continue to connect after the receiver was destructed and make sure to disconnect from everything when that happens. Task-number: QTCREATORBUG-19391 Change-Id: I4d09a7dca2a5260c3d4744607dccbde5964a0623 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
|
||||||
#include <utils/asconst.h>
|
#include <utils/asconst.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -37,42 +38,42 @@ namespace Internal {
|
|||||||
Subscription::Subscription(const Subscription::Connector &s, const QObject *receiver, QObject *parent) :
|
Subscription::Subscription(const Subscription::Connector &s, const QObject *receiver, QObject *parent) :
|
||||||
QObject(parent), m_subscriber(s)
|
QObject(parent), m_subscriber(s)
|
||||||
{
|
{
|
||||||
if (receiver != parent)
|
if (receiver != parent) {
|
||||||
connect(receiver, &QObject::destroyed, this, &QObject::deleteLater);
|
connect(receiver, &QObject::destroyed, this, [this]() {
|
||||||
|
unsubscribeAll();
|
||||||
|
m_subscriber = Connector(); // Reset subscriber
|
||||||
|
deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Subscription::~Subscription()
|
Subscription::~Subscription()
|
||||||
{
|
{
|
||||||
for (const auto &c : Utils::asConst(m_connections))
|
unsubscribeAll();
|
||||||
disconnect(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Subscription::subscribe(ProjectConfiguration *pc)
|
void Subscription::subscribe(ProjectConfiguration *pc)
|
||||||
{
|
{
|
||||||
if (!m_subscriber)
|
if (!m_subscriber)
|
||||||
return;
|
return;
|
||||||
QMetaObject::Connection conn = m_subscriber(pc);
|
|
||||||
if (conn)
|
connectTo(pc);
|
||||||
m_connections.insert(pc, conn);
|
|
||||||
|
|
||||||
if (auto p = qobject_cast<Project *>(pc)) {
|
if (auto p = qobject_cast<Project *>(pc)) {
|
||||||
for (Target *t : p->targets()) {
|
for (Target *t : p->targets()) {
|
||||||
for (ProjectConfiguration *pc : t->projectConfigurations())
|
for (ProjectConfiguration *pc : t->projectConfigurations())
|
||||||
m_subscriber(pc);
|
connectTo(pc);
|
||||||
}
|
}
|
||||||
} else if (auto t = qobject_cast<Target *>(pc)) {
|
} else if (auto t = qobject_cast<Target *>(pc)) {
|
||||||
for (ProjectConfiguration *pc : t->projectConfigurations())
|
for (ProjectConfiguration *pc : t->projectConfigurations())
|
||||||
m_subscriber(pc);
|
connectTo(pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Subscription::unsubscribe(ProjectConfiguration *pc)
|
void Subscription::unsubscribe(ProjectConfiguration *pc)
|
||||||
{
|
{
|
||||||
auto c = m_connections.value(pc);
|
disconnectFrom(pc);
|
||||||
if (c) {
|
|
||||||
disconnect(c);
|
|
||||||
m_connections.remove(pc);
|
|
||||||
}
|
|
||||||
if (auto p = qobject_cast<Project *>(pc)) {
|
if (auto p = qobject_cast<Project *>(pc)) {
|
||||||
for (Target *t : p->targets()) {
|
for (Target *t : p->targets()) {
|
||||||
for (ProjectConfiguration *pc : t->projectConfigurations())
|
for (ProjectConfiguration *pc : t->projectConfigurations())
|
||||||
@@ -82,7 +83,32 @@ void Subscription::unsubscribe(ProjectConfiguration *pc)
|
|||||||
for (ProjectConfiguration *pc : t->projectConfigurations())
|
for (ProjectConfiguration *pc : t->projectConfigurations())
|
||||||
unsubscribe(pc);
|
unsubscribe(pc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subscription::unsubscribeAll()
|
||||||
|
{
|
||||||
|
for (const auto &c : Utils::asConst(m_connections))
|
||||||
|
disconnect(c);
|
||||||
|
m_connections.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subscription::connectTo(ProjectConfiguration *pc)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_connections.contains(pc), return);
|
||||||
|
|
||||||
|
QMetaObject::Connection conn = m_subscriber(pc);
|
||||||
|
if (conn)
|
||||||
|
m_connections.insert(pc, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subscription::disconnectFrom(ProjectConfiguration *pc)
|
||||||
|
{
|
||||||
|
auto c = m_connections.value(pc);
|
||||||
|
if (!c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
disconnect(c);
|
||||||
|
m_connections.remove(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectSubscription::ProjectSubscription(const Subscription::Connector &s, const QObject *r,
|
ProjectSubscription::ProjectSubscription(const Subscription::Connector &s, const QObject *r,
|
||||||
|
@@ -53,6 +53,10 @@ protected:
|
|||||||
void subscribe(ProjectConfiguration *pc);
|
void subscribe(ProjectConfiguration *pc);
|
||||||
void unsubscribe(ProjectConfiguration *pc);
|
void unsubscribe(ProjectConfiguration *pc);
|
||||||
|
|
||||||
|
void unsubscribeAll();
|
||||||
|
void connectTo(ProjectConfiguration *pc);
|
||||||
|
void disconnectFrom(ProjectConfiguration *pc);
|
||||||
|
|
||||||
Connector m_subscriber;
|
Connector m_subscriber;
|
||||||
QHash<ProjectConfiguration *, QMetaObject::Connection> m_connections;
|
QHash<ProjectConfiguration *, QMetaObject::Connection> m_connections;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user