diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafSignal.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafSignal.h index 074dd579c8..329f52d6bb 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafSignal.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafSignal.h @@ -44,18 +44,77 @@ namespace caf { -class SignalObserver +class SignalEmitter; +class SignalObserver; + +//================================================================================================== +/// Basic delete signal emitted by any observer when deleted. +/// Allows a regular signal to disconnect from the observer. +//================================================================================================== +class DeleteSignal { public: - virtual ~SignalObserver() = default; + using DisconnectCallback = std::function; + + DeleteSignal( SignalObserver* observer ) + : m_observer( observer ) + { + } + + template + void connect( ClassType* signal ) + { + static_assert( std::is_convertible::value, + "Only classes that inherit SignalObserver can connect as an observer of a Signal." ); + + DisconnectCallback lambda = [=]( SignalObserver* observer ) { ( signal->disconnect )( observer ); }; + auto signalCasted = dynamic_cast( signal ); + + if ( signalCasted ) m_disconnectCallbacks[signalCasted] = lambda; + } + void disconnect( SignalObserver* observer ) { m_disconnectCallbacks.erase( observer ); } + void send() + { + for ( auto signalCallbackPair : m_disconnectCallbacks ) + { + signalCallbackPair.second( m_observer ); + } + } + +private: + std::map m_disconnectCallbacks; + + SignalObserver* m_observer; }; +//================================================================================================== +/// SignalEmitter +/// Should be inherited by any object that emits signals. +//================================================================================================== class SignalEmitter { public: virtual ~SignalEmitter() = default; }; +//================================================================================================== +/// SignalObserver. +/// Should be inherited by any object that observes and reacts to signals. +//================================================================================================== +class SignalObserver +{ +public: + DeleteSignal beingDeleted; + +public: + SignalObserver() + : beingDeleted( this ) + { + } + virtual ~SignalObserver() { beingDeleted.send(); } + +}; // namespace caf + //================================================================================================== /// General signal class. /// Connect any member function with the signature void(const Signal*, const SignalData* data) @@ -63,7 +122,7 @@ public: /// The method should accept that data may be nullptr //================================================================================================== template -class Signal +class Signal : public SignalObserver { public: using MemberCallback = std::function; @@ -74,7 +133,13 @@ public: : m_emitter( emitter ) { } - virtual ~Signal() = default; + virtual ~Signal() + { + for ( auto observerCallbackPair : m_observerCallbacks ) + { + observerCallbackPair.first->beingDeleted.disconnect( this ); + } + } template void connect( ClassType* observer, void ( ClassType::*method )( const SignalEmitter*, Args... args ) ) @@ -86,9 +151,14 @@ public: ( observer->*method )( emitter, args... ); }; m_observerCallbacks[observer] = std::make_pair( lambda, true ); + observer->beingDeleted.connect( this ); } - void disconnect( SignalObserver* observer ) { m_observerCallbacks.erase( observer ); } + void disconnect( SignalObserver* observer ) + { + m_observerCallbacks.erase( observer ); + observer->beingDeleted.disconnect( this ); + } void send( Args... args ) { for ( auto observerCallbackPair : m_observerCallbacks )