Connection guard (detected during #477)

Disconnects Qt signal/slot conenction when destroyed
This commit is contained in:
Klaus Basan
2015-10-31 01:17:37 +01:00
committed by Mathew Sutcliffe
parent 3acf085b92
commit 23856bbc57
11 changed files with 124 additions and 34 deletions

View File

@@ -149,10 +149,10 @@ namespace BlackCore
QList<QMetaObject::Connection> CAirspaceMonitor::connectRemoteAircraftProviderSignals( QList<QMetaObject::Connection> CAirspaceMonitor::connectRemoteAircraftProviderSignals(
QObject *receiver, QObject *receiver,
std::function<void(const CAircraftSituation &)> situationSlot, std::function<void(const CAircraftSituation &)> situationSlot,
std::function<void(const BlackMisc::Aviation::CCallsign &, const CAircraftParts &)> partsSlot, std::function<void(const BlackMisc::Aviation::CCallsign &, const CAircraftParts &)> partsSlot,
std::function<void(const CCallsign &)> removedAircraftSlot, std::function<void(const CCallsign &)> removedAircraftSlot,
std::function<void(const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot std::function<void(const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot
) )
{ {
Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver"); Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver");

View File

@@ -35,12 +35,14 @@ namespace BlackCore
this->setObjectName("Simulator:" + info.getIdentifier()); this->setObjectName("Simulator:" + info.getIdentifier());
// provider signals // provider signals
m_remoteAircraftProviderConnections = this->m_remoteAircraftProvider->connectRemoteAircraftProviderSignals( m_remoteAircraftProviderConnections.append(
this->m_remoteAircraftProvider->connectRemoteAircraftProviderSignals(
this, // receiver must match object in bind this, // receiver must match object in bind
std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftSituation, this, std::placeholders::_1), std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftSituation, this, std::placeholders::_1),
std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftParts, this, std::placeholders::_1, std::placeholders::_2), std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftParts, this, std::placeholders::_1, std::placeholders::_2),
std::bind(&CSimulatorCommon::ps_remoteProviderRemovedAircraft, this, std::placeholders::_1), std::bind(&CSimulatorCommon::ps_remoteProviderRemovedAircraft, this, std::placeholders::_1),
std::bind(&CSimulatorCommon::ps_recalculateRenderedAircraft, this, std::placeholders::_1)); std::bind(&CSimulatorCommon::ps_recalculateRenderedAircraft, this, std::placeholders::_1))
);
// timer // timer
this->m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer")); this->m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer"));
@@ -219,14 +221,7 @@ namespace BlackCore
void CSimulatorCommon::unload() void CSimulatorCommon::unload()
{ {
this->disconnectFrom(); // disconnect from simulator this->disconnectFrom(); // disconnect from simulator
this->m_remoteAircraftProviderConnections.disconnectAll();
// disconnect as many signals as possible
for (const QMetaObject::Connection &c : m_remoteAircraftProviderConnections)
{
QObject::disconnect(c);
}
m_remoteAircraftProviderConnections.clear();
this->disconnect();
CLogHandler::instance()->disconnect(); CLogHandler::instance()->disconnect();
} }

View File

@@ -27,6 +27,7 @@
#include "blackmisc/network/textmessage.h" #include "blackmisc/network/textmessage.h"
#include "blackmisc/network/client.h" #include "blackmisc/network/client.h"
#include "blackmisc/pixmap.h" #include "blackmisc/pixmap.h"
#include "blackmisc/connectionguard.h"
#include <QObject> #include <QObject>
namespace BlackCore namespace BlackCore
@@ -137,7 +138,7 @@ namespace BlackCore
bool setInitialAircraftSituation(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const; bool setInitialAircraftSituation(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const;
protected: protected:
IInterpolator *m_interpolator = nullptr; //!< interpolator instance IInterpolator *m_interpolator = nullptr; //!< interpolator instance
bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold) bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold)
private: private:
@@ -152,7 +153,7 @@ namespace BlackCore
BlackMisc::Aviation::CCallsignSet m_callsignsToBeRendered; //!< callsigns which will be rendered BlackMisc::Aviation::CCallsignSet m_callsignsToBeRendered; //!< callsigns which will be rendered
int m_maxRenderedAircraft = MaxAircraftInfinite; //!< max.rendered aircraft int m_maxRenderedAircraft = MaxAircraftInfinite; //!< max.rendered aircraft
BlackMisc::PhysicalQuantities::CLength m_maxRenderedDistance { 0.0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()}; //!< max.distance for rendering BlackMisc::PhysicalQuantities::CLength m_maxRenderedDistance { 0.0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()}; //!< max.distance for rendering
QList<QMetaObject::Connection> m_remoteAircraftProviderConnections; //!< connected signal/slots BlackMisc::CConnectionGuard m_remoteAircraftProviderConnections; //!< connected signal/slots
}; };
} // namespace } // namespace

View File

@@ -42,6 +42,7 @@ namespace BlackGui
this->m_parentDockableInfoArea = nullptr; this->m_parentDockableInfoArea = nullptr;
}); });
Q_ASSERT_X(con, Q_FUNC_INFO, "Connection failed"); Q_ASSERT_X(con, Q_FUNC_INFO, "Connection failed");
this->m_connections.append(con);
return true; return true;
} }

View File

@@ -16,7 +16,7 @@
#include "blackgui/dockwidgetinfoarea.h" #include "blackgui/dockwidgetinfoarea.h"
#include "blackgui/infoarea.h" #include "blackgui/infoarea.h"
#include "blackgui/enableforframelesswindow.h" #include "blackgui/enableforframelesswindow.h"
#include "blackmisc/qtconnectionlist.h" #include "blackmisc/connectionguard.h"
#include <QWidget> #include <QWidget>
namespace BlackGui namespace BlackGui
@@ -69,6 +69,7 @@ namespace BlackGui
private: private:
BlackGui::CDockWidgetInfoArea *m_parentDockableInfoArea = nullptr; //!< my parent dockable widget BlackGui::CDockWidgetInfoArea *m_parentDockableInfoArea = nullptr; //!< my parent dockable widget
BlackMisc::CConnectionGuard m_connections;
}; };
} }
} // namespace } // namespace

View File

@@ -0,0 +1,45 @@
/* Copyright (C) 2015
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "connectionguard.h"
namespace BlackMisc
{
CConnectionGuard::CConnectionGuard(const QMetaObject::Connection &connection)
{
this->m_connections.append(connection);
}
void CConnectionGuard::append(const QMetaObject::Connection &connection)
{
this->m_connections.append(connection);
}
void CConnectionGuard::append(const QList<QMetaObject::Connection> &connections)
{
this->m_connections.append(connections);
}
CConnectionGuard::~CConnectionGuard()
{
disconnectAll();
}
int CConnectionGuard::disconnectAll()
{
if (this->m_connections.isEmpty()) { return 0; }
int c = 0;
for (const QMetaObject::Connection &con : this->m_connections)
{
if (QObject::disconnect(con)) { c++; }
}
this->m_connections.clear();
return c;
}
} // ns

View File

@@ -0,0 +1,54 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_CONNECTIONGUARD_H
#define BLACKMISC_CONNECTIONGUARD_H
#include "blackmisc/blackmiscexport.h"
#include <QList>
#include <QObject>
namespace BlackMisc
{
/*!
* List of QMetaObject::Connection. The trick here is that those connections will
* be disconnected when the object is destroyed. So it can be used with lambdas or bind which feature
* non QObjects, if those might be destroyed before the signaling QObject.
*/
class BLACKMISC_EXPORT CConnectionGuard : public QObject
{
Q_OBJECT
public:
//! Constructor
CConnectionGuard() = default;
//! Constructor
CConnectionGuard(const QMetaObject::Connection &connection);
//! Destructor
~CConnectionGuard();
//! Add connection
void append(const QMetaObject::Connection &connection);
//! Add connections
void append(const QList<QMetaObject::Connection> &connections);
//! Disconnect all
int disconnectAll();
private:
QList<QMetaObject::Connection> m_connections;
};
} // BlackMisc
#endif

View File

@@ -21,7 +21,7 @@ namespace BlackMisc
{ {
CWebDataServicesAware::~CWebDataServicesAware() CWebDataServicesAware::~CWebDataServicesAware()
{ {
disconnectSignals(); this->m_swiftConnections.disconnectAll();
} }
CServerList CWebDataServicesAware::getVatsimFsdServers() const CServerList CWebDataServicesAware::getVatsimFsdServers() const
@@ -264,7 +264,7 @@ namespace BlackMisc
void CWebDataServicesAware::setProvider(IWebDataServicesProvider *webDataReaderProvider) void CWebDataServicesAware::setProvider(IWebDataServicesProvider *webDataReaderProvider)
{ {
Q_ASSERT_X(webDataReaderProvider, Q_FUNC_INFO, "missing provider"); Q_ASSERT_X(webDataReaderProvider, Q_FUNC_INFO, "missing provider");
disconnectSignals(); this->m_swiftConnections.disconnectAll();
m_webDataReaderProvider = webDataReaderProvider; m_webDataReaderProvider = webDataReaderProvider;
} }
@@ -275,7 +275,7 @@ namespace BlackMisc
void CWebDataServicesAware::gracefulShutdown() void CWebDataServicesAware::gracefulShutdown()
{ {
disconnectSignals(); this->m_swiftConnections.disconnectAll();
this->m_webDataReaderProvider = nullptr; this->m_webDataReaderProvider = nullptr;
} }
@@ -317,13 +317,5 @@ namespace BlackMisc
return this->m_webDataReaderProvider->readDbDataFromDisk(dir, inBackround); return this->m_webDataReaderProvider->readDbDataFromDisk(dir, inBackround);
} }
void CWebDataServicesAware::disconnectSignals()
{
for (QMetaObject::Connection &c : m_swiftConnections)
{
QObject::disconnect(c);
}
m_swiftConnections.clear();
}
} // namespace } // namespace
} // namespace } // namespace

View File

@@ -26,6 +26,7 @@
#include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/simulation/simulatedaircraft.h"
#include "blackmisc/weather/metarset.h" #include "blackmisc/weather/metarset.h"
#include "blackmisc/countrylist.h" #include "blackmisc/countrylist.h"
#include "blackmisc/connectionguard.h"
#include <functional> #include <functional>
@@ -343,8 +344,8 @@ namespace BlackMisc
CWebDataServicesAware(IWebDataServicesProvider *webDataReaderProvider = nullptr) : m_webDataReaderProvider(webDataReaderProvider) { } CWebDataServicesAware(IWebDataServicesProvider *webDataReaderProvider = nullptr) : m_webDataReaderProvider(webDataReaderProvider) { }
private: private:
IWebDataServicesProvider *m_webDataReaderProvider = nullptr; //!< access to object IWebDataServicesProvider *m_webDataReaderProvider = nullptr; //!< access to object
QList<QMetaObject::Connection> m_swiftConnections; //!< signal connection with swift BlackMisc::CConnectionGuard m_swiftConnections; //!< signal connection with swift
//! Disconnect all signals //! Disconnect all signals
void disconnectSignals(); void disconnectSignals();

View File

@@ -110,7 +110,7 @@ namespace BlackMisc
virtual QList<QMetaObject::Connection> connectRemoteAircraftProviderSignals( virtual QList<QMetaObject::Connection> connectRemoteAircraftProviderSignals(
QObject *receiver, QObject *receiver,
std::function<void(const BlackMisc::Aviation::CAircraftSituation &)> addedSituationSlot, std::function<void(const BlackMisc::Aviation::CAircraftSituation &)> addedSituationSlot,
std::function<void(const BlackMisc::Aviation::CCallsign &, const BlackMisc::Aviation::CAircraftParts &)> addedPartsSlot, std::function<void(const BlackMisc::Aviation::CCallsign &, const BlackMisc::Aviation::CAircraftParts &)> addedPartsSlot,
std::function<void(const BlackMisc::Aviation::CCallsign &)> removedAircraftSlot, std::function<void(const BlackMisc::Aviation::CCallsign &)> removedAircraftSlot,
std::function<void(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &)> aircraftSnapshot std::function<void(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &)> aircraftSnapshot
) = 0; ) = 0;

View File

@@ -72,10 +72,10 @@ namespace BlackMisc
QList<QMetaObject::Connection> CRemoteAircraftProviderDummy::connectRemoteAircraftProviderSignals( QList<QMetaObject::Connection> CRemoteAircraftProviderDummy::connectRemoteAircraftProviderSignals(
QObject *receiver, QObject *receiver,
std::function<void (const CAircraftSituation &)> situationSlot, std::function<void (const CAircraftSituation &)> situationSlot,
std::function<void (const BlackMisc::Aviation::CCallsign &, const CAircraftParts &)> partsSlot, std::function<void (const BlackMisc::Aviation::CCallsign &, const CAircraftParts &)> partsSlot,
std::function<void (const CCallsign &)> removedAircraftSlot, std::function<void (const CCallsign &)> removedAircraftSlot,
std::function<void (const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot std::function<void (const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot
) )
{ {
Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver"); Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver");