// Events.h: interface for the events.
//
//////////////////////////////////////////////////////////////////////
//*******************************************************************
//*******************************************************************
// File: Events.h 2002NOV17
//
// Created by: Manuel Alejandro Gomez
// E-mail: nsx@tutopia.com
//*******************************************************************
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name and all copyright
// notices remains intact.
//
// An email letting me know how you are using it would be nice as well.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//*******************************************************************
#if !defined(MAG_Events_H__0_0_001_INCLUDED)
# define MAG_Events_H__0_0_001_INCLUDED
# if _MSC_VER > 1000
# pragma once
# endif // _MSC_VER > 1000
// Extracting from ATLBASE.H
# pragma warning(disable: 4201) // nameless unions are part of C++
# pragma warning(disable: 4127) // constant expression
# pragma warning(disable: 4505) // unreferenced local function has been removed
# pragma warning(disable: 4512) // can't generate assignment operator (so what?)
# pragma warning(disable: 4514) // unreferenced inlines are common
# pragma warning(disable: 4103) // pragma pack
# pragma warning(disable: 4702) // unreachable code
# pragma warning(disable: 4237) // bool
# pragma warning(disable: 4710) // function couldn't be inlined
# pragma warning(disable: 4355) // 'this' : used in base member initializer list
# pragma warning(disable: 4097) // typedef name used as synonym for class-name
# pragma warning(disable: 4786) // identifier was truncated in the debug information
# pragma warning(disable: 4268) // const static/global data initialized to zeros
# pragma warning(disable: 4291) // allow placement new
# include <windows.h>
# include <CrtDbg.h>
// STL files using for events system
# include <iostream>
# include <vector>
# include <map>
using namespace std;
// Aligment
# ifdef _MSC_VER
# pragma pack(push,8)
# endif /* _MSC_VER */
// Namespace declaration for including a more extensive
// class helpers
# if defined(__cplusplus)
# define _EVENTS Events::
# define _EVENTS_BEGIN namespace Events {
# define _EVENTS_END };
# define _EVENTS_USING using namespace Events;
# else
# define _EVENTS ::
# define _EVENTS_BEGIN
# define _EVENTS_END
# define _EVENTS_USING
# endif /* __cplusplus */
// Begin namespace for events if you use this in a simple
// system you could remove this declartion for direct use
_EVENTS_BEGIN
// Base structs for polimorphics use.
struct EventArgs { };
class SourceEvents;
// Interface for Delegate class use for polimorphic.
struct IDelegate {
// Notificator for the subscription join events with
// events providers
virtual void Notify(SourceEvents*, EventArgs*) = 0;
// Using for a simple ID system
virtual bool Match(long) = 0;
// Return a Code ID for a Delegate class
virtual long Code() = 0;
};
// if you use this with MFC inheritance SourceEvents for CObject
class SourceEvents /* : public CObject */{
// Attributes
protected:
// Events Map definition
typedef vector<IDelegate*> LIST;
typedef LIST* LISTPTR;
typedef map< LPTSTR, LISTPTR > EVENTMAP;
typedef EVENTMAP::value_type VALUEMAP;
// Define a Event handler
EVENTMAP m_EventsHandler;
// Methods
protected:
// is a abstract class
SourceEvents() { }
~SourceEvents() { UninitEvents(); }
// Initialization of EventsHandler take action in
// inherited class using MACROS _BEGIN_EVENTS_HANDLER, _EVENT_HANDLER
// and _END_EVENTS_HANDLER
virtual void InitEvents() = 0;
// Destroy all events slots
void UninitEvents() {
EVENTMAP::iterator end = m_EventsHandler.end();
for(EVENTMAP::iterator it = m_EventsHandler.begin(); it != end; it++ ) {
// If correct unsubscription method was do, free extramemory for events system
if( 0 == (*it).second->size() ) {
it->second->clear();
delete it->second;
}
// If no correct unsubscription methos was do, WARNING
else {
cerr << "El evento " << (*it).first << " no fue liberado (UnJoinTo -> JoinTo( ..., false)\n";
cerr << "memory leaks was reported" << endl;
}
}
m_EventsHandler.clear();
}
// Fired method
void Fire(LPTSTR eventName, SourceEvents* obj, EventArgs* e) {
LISTPTR lista = m_EventsHandler[eventName];
_ASSERTE(NULL != lista);
LIST::iterator end = lista->end();
for(LIST::iterator it = lista->begin(); it != end; it++) {
(*it)->Notify(obj, e);
}
}
public:
// For subscription method
void Attach(LPTSTR eventName, IDelegate* del) {
LISTPTR lista = m_EventsHandler[eventName];
_ASSERTE(NULL != lista);
lista->insert( lista->end(), del );
}
// For un subscription method
void Detach(LPTSTR eventName, IDelegate* del) {
LISTPTR lista = m_EventsHandler[eventName];
_ASSERTE(NULL != lista);
LIST::iterator end = lista->end();
// un subscription a object and delete a delegator
for(LIST::iterator it = lista->begin(); it != end; it++) {
IDelegate* deg = *it;
if( deg->Match( del->Code() ) ) {
lista->erase(it);
delete deg;
}
}
delete del;
}
};
// Real Delegate class implement the interface of IDelegate
// and is a template class for improve flexibility
template< typename _source, typename _target, typename _args >
class Delegate : public IDelegate {
public:
typedef void (_target::* PFN)(_source*, _args*);
typedef Delegate<_source, _target, _args> CTYPE;
typedef CTYPE* POINTER;
typedef CTYPE& REFERENCE;
Delegate(_target* obj, PFN pFn) : m_Obj(*obj), m_pFn(pFn) {
_ASSERTE(pFn);
// A simple ID generator, one class only catch a event of
// certain type once.
m_code = reinterpret_cast<long>( static_cast<void*>(obj) );
}
void Notify(SourceEvents* obj, EventArgs* e) {
// Notify a event occur
(m_Obj.*m_pFn)(static_cast<_source*>(obj), static_cast<_args*>(e));
}
// Return a ID for thos Delegate
long Code() { return m_code; }
// Compare ID for this class with other ID
bool Match(long code) { return (code == m_code); }
protected:
long m_code;
PFN m_pFn;
_target& m_Obj;
};
// Ending Events namespace
_EVENTS_END;
/**** Complexity reduction *****************************************
For using this simple event system there are task that can be
automated using MACROS.
This MACROS provide a way for ease use of this system.
********************************************************************/
// MACRO: _BEGIN_EVENTS_HANDLER
//
// This MACRO define the initialization for events.
//
// Syntax: _BEGIN_EVENTS_HANDLER
//
/* Example code generated by this macho:
constructor() : SourceEvents() { InitEvents(); }
...
...
...
_BEGIN_EVENTS_HANDLER --> void InitEvents() { ...
*/
#define _BEGIN_EVENTS_HANDLER void InitEvents() {
// MACRO: _EVENTS_HANDLER( _name )
//
// were _name is the name of event
//
// This MACRO define the initialization for events.
//
// Syntax: _EVENTS_HANDLER( Close )
//
/* Example code generated by this macho:
constructor() : SourceEvents() { InitEvents(); }
...
void InitEvents() {
_EVENTS_HANDLER( Close ) --> m_EventsHandler.insert( SourceEvents::VALUEMAP( "Close", new SourceEvents::LIST()) );
...
*/
#define _EVENT_HANDLER( _name ) m_EventsHandler.insert( SourceEvents::VALUEMAP( #_name, new SourceEvents::LIST()) );
// MACRO: END_EVENTS_HANDLER
//
// This MACRO define the end for initialization events.
//
// Syntax: END_EVENTS_HANDLER
//
/* Example code generated by this macho:
constructor() : SourceEvents() { InitEvents(); }
...
void InitEvents() {
m_EventsHandler.insert( SourceEvents::VALUEMAP( "Close", new SourceEvents::LIST()) );
...
_END_EVENTS_HANDLER --> }
*/
#define _END_EVENTS_HANDLER }
// MACRO: _raise( _name, _arg )
//
// _name is the event name, if the name is incorrect an assert is throw
// _arg is the event struct arguments, a pointer to struct or class inherited
// from EventArgs and contain all the data needed for the subscription
//
// This MACRO define the end for initialization events.
//
// Syntax: _raise( Close, e )
//
/* Example code generated by this macho:
class Document : public SourceEvents {
void OnClose() {
DocumentEventArgs e;
e.Pagina = m_Pagina;
e.nPaginas = m_nPaginas;
...
_raise( Close, &e ); --> Fire( "Close", this, &e );
...
}
*/
#define _raise( _name, _arg ) Fire( #_name, this, _arg );
// MACRO: _hook( _src_ptr, _name, _source, _target, _eventargs, _fn )
//
// _src_ptr name of pointer to Source events class
// _name is the event name, if the name is incorrect an assert is throw
// _source is the class name of source events
// _target is the class name of target events
// _eventargs is the struct or class name for events arguments
// _fn if the name of the catch events member function
//
// This MACRO is for internal use.
//
// Syntax: _hook( pObj, Close, Source, Target, SourceEventArgs, OnClose )
//
/* Example code generated by this macho:
class Document : public SourceEvents {
void OnClose() {
DocumentEventArgs e;
e.Pagina = m_Pagina;
e.nPaginas = m_nPaginas;
...
_raise( Close, &e );
...
}
void JoinTo(Source* pObj) {
_hook( pObj, Close, Source, Target, SourceEventArgs, OnClose ); --> \
pObj->Attach( "Close", new Delegate<Source, Target, SourceEventArgs>(this, (void(Target::*)(Source*, SourceEventArgs*)) OnClose) );
...
}
*/
#define _hook( _src_ptr, _name, _source, _target, _eventargs, _fn ) \
_src_ptr->Attach( #_name, new Delegate<_source, _target, _eventargs>(this, (void(_target::*)(_source*, _eventargs*)) _fn) )
// MACRO: _unhook( _src_ptr, _name, _source, _target, _eventargs, _fn )
//
// _src_ptr name of pointer to Source events class
// _name is the event name, if the name is incorrect an assert is throw
// _source is the class name of source events
// _target is the class name of target events
// _eventargs is the struct or class name for events arguments
// _fn if the name of the catch events member function
//
// This MACRO is for internal use.
//
// Syntax: _unhook( pObj, Close, Source, Target, SourceEventArgs, OnClose )
//
/* Example code generated by this macho:
class Document : public SourceEvents {
void OnClose() {
DocumentEventArgs e;
e.Pagina = m_Pagina;
e.nPaginas = m_nPaginas;
...
_raise( Close, &e );
...
}
void UnJoinTo(Source* pObj) {
_unhook( pObj, Close, Source, Target, SourceEventArgs, OnClose ); --> \
pObj->Detach( "Close", new Delegate<Source, Target, SourceEventArgs>(this, (void(Target::*)(Source*, SourceEventArgs*)) OnClose) );
...
}
*/
#define _unhook( _src_ptr, _name, _source, _target, _eventargs, _fn ) \
_src_ptr->Detach( #_name, new Delegate<_source, _target, _eventargs>(this, (void(_target::*)(_source*, _eventargs*)) _fn) )
// MACRO: _DECLARE_HOOK_LIST( _source )
//
// _source is the class name of source events
//
// This MACRO is for use in target class for implementing the Join
// and Unjoin methods.
//
// Syntax: _DECLARE_HOOK_LIST( Document )
//
/* Example code generated by this macho:
class View {
void OnClose(Document* source, DocumentEventArgs* e) {
...
}
_DECLARE_HOOK_LIST( Document )
*/
#define _DECLARE_HOOK_LIST( _source ) void JoinTo(_source* pObj, bool join = true);
// MACRO: _BEGIN_HOOK_LIST( _source, _target, _eventargs )
//
// _source is the class name of source events
// _target is the class name of target events
// _eventargs is the struct or class name for events arguments
//
// This MACRO is for use in target class for implementing the Join
// and Unjoin methods.
//
// Syntax: _BEGIN_HOOK_LIST( Document, View, DocumentEventArgs )
//
/* Example code generated by this macho:
class View {
void OnClose(Document* source, DocumentEventArgs* e) {
...
}
_BEGIN_HOOK_LIST(Document, View, DocumentEventArgs) -->
void JoinTo(Document* pObj, bool join = true) {
...
}
*/
#define _BEGIN_HOOK_LIST( _source, _target, _eventargs ) \
void _target::JoinTo(_source* pObj, bool join) { \
typedef _source SOURCE; \
typedef _target TARGET; \
typedef _eventargs ARGS;
// MACRO: _HOOK( _name, _fn )
//
// _name is the name of the event
// _fn is the name of the function events (callback)
//
// This MACRO is for use in target class for implementing the Join
// and Unjoin methods.
//
// Syntax: _HOOK( Close, OnClose )
//
/* Example code generated by this macho:
class View {
void OnClose(Document* source, DocumentEventArgs* e) {
...
}
_BEGIN_HOOK_LIST(Document, View, DocumentEventArgs)
_HOOK( Close, OnClose ) --> if(join) _hook( pObj, Close, SOURCE, TARGET, ARGS, OnClose ); \
else _unhook( pObj, Close, SOURCE, TARGET, ARGS, OnClose );
...
}
*/
#define _HOOK( _name, _fn ) \
if(join) _hook( pObj, _name, SOURCE, TARGET, ARGS, _fn ); \
else _unhook( pObj, _name, SOURCE, TARGET, ARGS, _fn );
// MACRO: _END_HOOK_LIST
//
// This MACRO is for use in target class for implementing the Join
// and Unjoin methods.
//
// Syntax: _END_HOOK_LIST
//
/* Example code generated by this macho:
class View {
void OnClose(Document* source, DocumentEventArgs* e) {
...
}
_BEGIN_HOOK_LIST(Document, View, DocumentEventArgs)
_HOOK( Close, OnClose )
_END_HOOK_LIST()
...
*/
#define _END_HOOK_LIST() }
// MACRO: UnJoinTo( _name )
//
// _name is the name of the events
//
// This MACRO is for use in target class for implementing the Join
// and Unjoin methods.
//
// Syntax: pTarget->UnJoinTo(pSource)
//
/* Example code generated by this macho:
...
pTarget->UnJoinTo(pSource) --> pTarget->JoinTo(pSource, false);
*/
#define UnJoinTo( _name ) JoinTo( _name, false)
#endif // End of MAG_Events_H__0_0_001_INCLUDED