Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

837 lines
28 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: events.h
  8. //
  9. // History: 09-24-1999 VivekJ created
  10. //--------------------------------------------------------------------------
  11. /************************************************************************
  12. * This file contains classes that provide support for the Observer pattern,
  13. * or publish-subscribe.
  14. *
  15. * Event sources send notifications to event observers. The parameterized type
  16. * is the event observer class, or (C++) interface.
  17. *
  18. * To use this mechanism, derive your event source class from CEventSource
  19. * parameterized by the observer class(es) or interface(es). Add a specific observer object
  20. * to the list of observers by calling the AddObserver function. The observer object class
  21. * should derive from CObserverBase.
  22. *
  23. * When the source wishes to call a particular notification method in the
  24. * observer class, use ScFireEvent template method.
  25. * specify observer's method as a 1st parameter. for instance: CMyObserver::MyEvent
  26. * [optionaly] specify parameters to event as 2nd and following parameters to ScFireEvent
  27. *
  28. * All event observer notification methods MUST return SC's.
  29. *
  30. * You can not have other method with the same name as event on observer - it won't compile.
  31. *
  32. * When sources/observers are deleted, the connection between them is broken automatically.
  33. * There is no support as yet to manually break a connection, although such a method can
  34. * be easily added to either the source or observer (make sure both sides of the connection
  35. * are broken.
  36. *
  37. * See the test code at the end of the file as an example.
  38. ************************************************************************/
  39. // a #define to make it easy to implement only some observer methods.
  40. #define DEFAULT_OBSERVER_METHOD SC sc; return sc;
  41. #include "cpputil.h"
  42. /*+-------------------------------------------------------------------------*
  43. * class CObserverBase
  44. *
  45. *
  46. * PURPOSE:
  47. *
  48. *+-------------------------------------------------------------------------*/
  49. class CObserverBase;
  50. /*+-------------------------------------------------------------------------*
  51. * class CEventSourceBase
  52. *
  53. *
  54. * PURPOSE: provides general Event Source interface
  55. *
  56. *+-------------------------------------------------------------------------*/
  57. class CEventSourceBase
  58. {
  59. public:
  60. virtual ~CEventSourceBase() {}
  61. virtual void UnadviseSource(CObserverBase &observer) =0;
  62. };
  63. /*+-------------------------------------------------------------------------*
  64. * class _CEventSource
  65. *
  66. *
  67. * PURPOSE: implements connection between event source and observer
  68. *
  69. * NOTE: This class IS NOT intended for external use - use CEventSource instead
  70. *
  71. *+-------------------------------------------------------------------------*/
  72. template<class CObserver>
  73. class _CEventSource : public CEventSourceBase
  74. {
  75. private:
  76. typedef CObserver * POBSERVER;
  77. typedef _CEventSource<CObserver> ThisClass;
  78. // no std::set, or std::map please
  79. // those cannot be shared by several DLL's
  80. // see KB article Q172/3/96
  81. // since some items may be gone and some new added during the operation,
  82. // std::list is the best choice, since it does not reallocate on insert
  83. // but that is not enough - see CListIntegrityProtector class below
  84. struct ObserverData
  85. {
  86. POBSERVER pObject; // pointer to the object
  87. bool bDeleted; // true means entry remove pending, pObject not valid
  88. };
  89. typedef std::list< ObserverData > CObserverList;
  90. CObserverList m_observerList;
  91. // count of active locks.
  92. // when value is 0, it is safe to remove deleted items from the list.
  93. int m_nStackDepth;
  94. // removes deleted items from the list
  95. void CleanupDeleted();
  96. protected:
  97. typedef CObserverList::iterator iterator;
  98. /***************************************************************************\
  99. *
  100. * CLASS: CListIntegrityProtector
  101. *
  102. * PURPOSE: locks the list in the owning class from item deletion.
  103. * thus assures the list is safe to iterate, the client just
  104. * needs to skip deleted entries.
  105. * Destructor will release the lock, an in case this is the last
  106. * lock - will perforn the cleanup.
  107. *
  108. * this technique is needed, since objects get deleted and created
  109. * during the events, so the observer list is changed, which
  110. * invalidated the iterators. Using the std::list and postponing
  111. * cleanup allowed to deal with 'live' list safelly.
  112. *
  113. * USAGE: Create the object of this class in scope where you need to
  114. * make sure the items does not get deleted from the list.
  115. *
  116. \***************************************************************************/
  117. friend class CListIntegrityProtector;
  118. class CListIntegrityProtector
  119. {
  120. DECLARE_NOT_COPIABLE(CListIntegrityProtector)
  121. DECLARE_NOT_ASSIGNABLE(CListIntegrityProtector)
  122. ThisClass *m_pOwner;
  123. public:
  124. // constructor (increments iterator count)
  125. CListIntegrityProtector(ThisClass *pOwner) : m_pOwner(pOwner)
  126. {
  127. ASSERT(pOwner);
  128. if (pOwner)
  129. ++(pOwner->m_nStackDepth);
  130. }
  131. // destructor (decrements iterator count - cleans up if not iterators left)
  132. ~CListIntegrityProtector()
  133. {
  134. ASSERT(m_pOwner);
  135. if ( m_pOwner && ( 0 == --(m_pOwner->m_nStackDepth) ) )
  136. m_pOwner->CleanupDeleted();
  137. }
  138. };
  139. protected:
  140. CObserverList & GetObserverList() { return m_observerList;}
  141. public:
  142. _CEventSource() : m_nStackDepth(0) {};
  143. virtual ~_CEventSource(); // disconnects all listeners
  144. void _AddObserver(CObserver &observer);
  145. virtual void UnadviseSource(CObserverBase &observer); // to disconnect a particular observer. (only disconnects this side)
  146. };
  147. /***************************************************************************\
  148. *
  149. * CLASSES: _CEventSource1 - _CEventSource5
  150. *
  151. * PURPOSE: these classes do not add anything to _CEventSource
  152. * defining them is just required for using them as base classes
  153. * of CEventSource_ [ same class cannot appear twice in base class list]
  154. *
  155. * NOTE: These classes ARE NOT intended for external use
  156. *
  157. \***************************************************************************/
  158. template<class CObserver> class _CEventSource1 : public _CEventSource<CObserver> {};
  159. template<class CObserver> class _CEventSource2 : public _CEventSource<CObserver> {};
  160. template<class CObserver> class _CEventSource3 : public _CEventSource<CObserver> {};
  161. template<class CObserver> class _CEventSource4 : public _CEventSource<CObserver> {};
  162. template<class CObserver> class _CEventSource5 : public _CEventSource<CObserver> {};
  163. /*+-------------------------------------------------------------------------*
  164. * CVoid
  165. *
  166. * This is a do-nothing class that is used for the _CEventSourceX
  167. * specializations below. _CEventSourceX used specializations of "void"
  168. * and the default types for the Es2-Es5 template parameters of CEventSource
  169. * used to be "void". Newer (i.e. Win64) compilers, however, will issue
  170. * C2182 ("illegal use of type 'void'") and won't allow void to be the
  171. * default type.
  172. *--------------------------------------------------------------------------*/
  173. class CVoid {};
  174. /***************************************************************************\
  175. *
  176. * SPECIALIZATIONS: _CEventSource1 - _CEventSource5 for void parameters
  177. *
  178. * PURPOSE: This allows to have single template for different count of observers.
  179. * The specialization defines empty and harmless base clases
  180. * for default template parameters
  181. *
  182. * NOTE: These classes ARE NOT intended for external use
  183. *
  184. \***************************************************************************/
  185. template<> class _CEventSource2<CVoid> {}; // specializes _CEventSource2<CVoid> as empty class
  186. template<> class _CEventSource3<CVoid> {}; // specializes _CEventSource3<CVoid> as empty class
  187. template<> class _CEventSource4<CVoid> {}; // specializes _CEventSource4<CVoid> as empty class
  188. template<> class _CEventSource5<CVoid> {}; // specializes _CEventSource5<CVoid> as empty class
  189. /***************************************************************************\
  190. *
  191. * CLASS: CEventSource
  192. *
  193. * PURPOSE: This class implements Event emitting capability to be used by
  194. * event-emitter classes derived from it.
  195. * Implements ScFireEvent methods and AddObserver method
  196. *
  197. * USAGE: use spacialization of this class as base class for your event-emitter class
  198. * See the list of possible usage paterns below:
  199. * class CMyClassWithEvents : public CEventSource<CMyObserver> ...
  200. * class CMyClassWithEvents : public CEventSource<CMyObserver1, CMyObserver2> ...
  201. * ...
  202. * class CMyClassWithEvents : public CEventSource<CMyObserver1, CMyObserver2, CMyObserver3, CMyObserver4, CMyObserver5> ...
  203. *
  204. * NOTE: Do not derive from this class more than once - add template parameters instead
  205. *
  206. \***************************************************************************/
  207. template<class Es1, class Es2 = CVoid, class Es3 = CVoid, class Es4 = CVoid, class Es5 = CVoid>
  208. class CEventSource : public _CEventSource1<Es1>,
  209. public _CEventSource2<Es2>, // NOTE: this will be empty class if Es2 == CVoid
  210. public _CEventSource3<Es3>, // NOTE: this will be empty class if Es3 == CVoid
  211. public _CEventSource4<Es4>, // NOTE: this will be empty class if Es4 == CVoid
  212. public _CEventSource5<Es5> // NOTE: this will be empty class if Es5 == CVoid
  213. {
  214. public:
  215. /***************************************************************************\
  216. *
  217. * METHOD: CEventSource::ScFireEvent<Observer>
  218. *
  219. * PURPOSE: implements ScFireEvent for parameter-less events
  220. *
  221. * PARAMETERS:
  222. * SC (Observer::*_EventName)() - pointer to Observer's method
  223. *
  224. * RETURNS:
  225. * SC - result code
  226. *
  227. * NOTE: It must be both declared and defined here - will not compile else
  228. *
  229. \***************************************************************************/
  230. template<class observerclass>
  231. SC ScFireEvent(SC (observerclass::*_EventName)())
  232. {
  233. DECLARE_SC(sc, TEXT("CEventSource::ScFireEvent - no parameters"));
  234. typedef _CEventSource<observerclass> BC;
  235. BC::CListIntegrityProtector(this); // protect the list while iterating
  236. for(BC::iterator iter = BC::GetObserverList().begin(); iter != BC::GetObserverList().end(); ++iter)
  237. {
  238. // skip deleted objects
  239. if (iter->bDeleted)
  240. continue;
  241. // sanity check
  242. sc = ScCheckPointers( iter->pObject, E_UNEXPECTED);
  243. if (sc)
  244. return sc;
  245. // invoke method "_EventName" on object pointed by *iter
  246. sc = ((iter->pObject)->*_EventName)();
  247. if(sc)
  248. return sc;
  249. }
  250. return sc;
  251. }
  252. /***************************************************************************\
  253. *
  254. * METHOD: CEventSource::ScFireEvent<Observer, P1>
  255. *
  256. * PURPOSE: implements ScFireEvent for events with one parameter
  257. *
  258. * PARAMETERS:
  259. * SC (Observer::*_EventName)() - pointer to Observer's method
  260. * _P1 p1 - parameter to be passed
  261. *
  262. * RETURNS:
  263. * SC - result code
  264. *
  265. * NOTE: It must be both declared and defined here - will not compile else
  266. *
  267. \***************************************************************************/
  268. template<class observerclass, class _P1>
  269. SC ScFireEvent(SC (observerclass::*_EventName)(_P1 p1), _P1 p1)
  270. {
  271. DECLARE_SC(sc, TEXT("CEventSource::ScFireEvent - one parameter"));
  272. typedef _CEventSource<observerclass> BC;
  273. BC::CListIntegrityProtector(this); // protect the list while iterating
  274. for(BC::iterator iter = BC::GetObserverList().begin(); iter != BC::GetObserverList().end(); ++iter)
  275. {
  276. // skip deleted objects
  277. if (iter->bDeleted)
  278. continue;
  279. // sanity check
  280. sc = ScCheckPointers( iter->pObject, E_UNEXPECTED);
  281. if (sc)
  282. return sc;
  283. // invoke method "_EventName" on object pointed by *iter
  284. sc = ((iter->pObject)->*_EventName)(p1);
  285. if(sc)
  286. return sc;
  287. }
  288. return sc;
  289. }
  290. /***************************************************************************\
  291. *
  292. * METHOD: CEventSource::ScFireEvent<Observer, P1, P2>
  293. *
  294. * PURPOSE: implements ScFireEvent for events with two parameters
  295. *
  296. * PARAMETERS:
  297. * SC (Observer::*_EventName)() - pointer to Observer's method
  298. * _P1 p1 - parameter to be passed
  299. * _P2 p2 - parameter to be passed
  300. *
  301. * RETURNS:
  302. * SC - result code
  303. *
  304. * NOTE: It must be both declared and defined here - will not compile else
  305. *
  306. \***************************************************************************/
  307. template<class observerclass, class _P1, class _P2>
  308. SC ScFireEvent(SC (observerclass::*_EventName)(_P1 p1, _P2 p2), _P1 p1, _P2 p2)
  309. {
  310. DECLARE_SC(sc, TEXT("CEventSource::ScFireEvent - two parameters"));
  311. typedef _CEventSource<observerclass> BC;
  312. BC::CListIntegrityProtector(this); // protect the list while iterating
  313. for(BC::iterator iter = BC::GetObserverList().begin(); iter != BC::GetObserverList().end(); ++iter)
  314. {
  315. // skip deleted objects
  316. if (iter->bDeleted)
  317. continue;
  318. // sanity check
  319. sc = ScCheckPointers( iter->pObject, E_UNEXPECTED);
  320. if (sc)
  321. return sc;
  322. // invoke method "_EventName" on object pointed by *iter
  323. sc = ((iter->pObject)->*_EventName)(p1, p2);
  324. if(sc)
  325. return sc;
  326. }
  327. return sc;
  328. }
  329. /***************************************************************************\
  330. *
  331. * METHOD: CEventSource::ScFireEvent<Observer, P1, P2, P3>
  332. *
  333. * PURPOSE: implements ScFireEvent for events with three parameters
  334. *
  335. * PARAMETERS:
  336. * SC (Observer::*_EventName)() - pointer to Observer's method
  337. * _P1 p1 - parameter to be passed
  338. * _P2 p2 - parameter to be passed
  339. * _P3 p3 - parameter to be passed
  340. *
  341. * RETURNS:
  342. * SC - result code
  343. *
  344. * NOTE: It must be both declared and defined here - will not compile else
  345. *
  346. \***************************************************************************/
  347. template<class observerclass, class _P1, class _P2, class _P3>
  348. SC ScFireEvent(SC (observerclass::*_EventName)(_P1 p1, _P2 p2, _P3 p3), _P1 p1, _P2 p2, _P3 p3)
  349. {
  350. DECLARE_SC(sc, TEXT("CEventSource::ScFireEvent - three parameters"));
  351. typedef _CEventSource<observerclass> BC;
  352. BC::CListIntegrityProtector(this); // protect the list while iterating
  353. for(BC::iterator iter = BC::GetObserverList().begin(); iter != BC::GetObserverList().end(); ++iter)
  354. {
  355. // skip deleted objects
  356. if (iter->bDeleted)
  357. continue;
  358. // sanity check
  359. sc = ScCheckPointers( iter->pObject, E_UNEXPECTED);
  360. if (sc)
  361. return sc;
  362. // invoke method "_EventName" on object pointed by *iter
  363. sc = ((iter->pObject)->*_EventName)(p1, p2, p3);
  364. if(sc)
  365. return sc;
  366. }
  367. return sc;
  368. }
  369. /***************************************************************************\
  370. *
  371. * METHOD: CEventSource::ScFireEvent<Observer, P1, P2, P3, P4>
  372. *
  373. * PURPOSE: implements ScFireEvent for events with four parameters
  374. *
  375. * PARAMETERS:
  376. * SC (Observer::*_EventName)() - pointer to Observer's method
  377. * _P1 p1 - parameter to be passed
  378. * _P2 p2 - parameter to be passed
  379. * _P3 p3 - parameter to be passed
  380. * _P4 p4 - parameter to be passed
  381. *
  382. * RETURNS:
  383. * SC - result code
  384. *
  385. * NOTE: It must be both declared and defined here - will not compile else
  386. *
  387. \***************************************************************************/
  388. template<class observerclass, class _P1, class _P2, class _P3, class _P4>
  389. SC ScFireEvent(SC (observerclass::*_EventName)(_P1 p1, _P2 p2, _P3 p3, _P4 p4), _P1 p1, _P2 p2, _P3 p3, _P4 p4)
  390. {
  391. DECLARE_SC(sc, TEXT("CEventSource::ScFireEvent - three parameters"));
  392. typedef _CEventSource<observerclass> BC;
  393. BC::CListIntegrityProtector(this); // protect the list while iterating
  394. for(BC::iterator iter = BC::GetObserverList().begin(); iter != BC::GetObserverList().end(); ++iter)
  395. {
  396. // skip deleted objects
  397. if (iter->bDeleted)
  398. continue;
  399. // sanity check
  400. sc = ScCheckPointers( iter->pObject, E_UNEXPECTED);
  401. if (sc)
  402. return sc;
  403. // invoke method "_EventName" on object pointed by *iter
  404. sc = ((iter->pObject)->*_EventName)(p1, p2, p3, p4);
  405. if(sc)
  406. return sc;
  407. }
  408. return sc;
  409. }
  410. /***************************************************************************\
  411. *
  412. * METHOD: CEventSource::ScFireEvent<Observer, P1, P2, P3, P4, P5>
  413. *
  414. * PURPOSE: implements ScFireEvent for events with four parameters
  415. *
  416. * PARAMETERS:
  417. * SC (Observer::*_EventName)() - pointer to Observer's method
  418. * _P1 p1 - parameter to be passed
  419. * _P2 p2 - parameter to be passed
  420. * _P3 p3 - parameter to be passed
  421. * _P4 p4 - parameter to be passed
  422. * _P5 p5 - parameter to be passed
  423. *
  424. * RETURNS:
  425. * SC - result code
  426. *
  427. * NOTE: It must be both declared and defined here - will not compile else
  428. *
  429. \***************************************************************************/
  430. template<class observerclass, class _P1, class _P2, class _P3, class _P4, class _P5>
  431. SC ScFireEvent(SC (observerclass::*_EventName)(_P1 p1, _P2 p2, _P3 p3, _P4 p4, _P5 p5), _P1 p1, _P2 p2, _P3 p3, _P4 p4, _P5 p5)
  432. {
  433. DECLARE_SC(sc, TEXT("CEventSource::ScFireEvent - three parameters"));
  434. typedef _CEventSource<observerclass> BC;
  435. BC::CListIntegrityProtector(this); // protect the list while iterating
  436. for(BC::iterator iter = BC::GetObserverList().begin(); iter != BC::GetObserverList().end(); ++iter)
  437. {
  438. // skip deleted objects
  439. if (iter->bDeleted)
  440. continue;
  441. // sanity check
  442. sc = ScCheckPointers( iter->pObject, E_UNEXPECTED);
  443. if (sc)
  444. return sc;
  445. // invoke method "_EventName" on object pointed by *iter
  446. sc = ((iter->pObject)->*_EventName)(p1, p2, p3, p4, p5);
  447. if(sc)
  448. return sc;
  449. }
  450. return sc;
  451. }
  452. /***************************************************************************\
  453. *
  454. * METHOD: CEventSource::AddObserver<Observer>
  455. *
  456. * PURPOSE: adds observer to the list
  457. *
  458. * PARAMETERS:
  459. * Observer &observer - observer to add to the list
  460. *
  461. * RETURNS:
  462. *
  463. * NOTE: It must be both declared and defined here - will not compile else
  464. *
  465. \***************************************************************************/
  466. template<class observerclass>
  467. void AddObserver(observerclass &observer)
  468. {
  469. typedef _CEventSource<observerclass> BC;
  470. // NOTE: if you are getting the error here, probably you are passing a type
  471. // derived from actual Observer class to AddObserver(). Please cast it to appr. type
  472. BC::_AddObserver(observer);
  473. }
  474. };
  475. /*+-------------------------------------------------------------------------*
  476. * class CObserverBase
  477. *
  478. *
  479. * PURPOSE:
  480. *
  481. *+-------------------------------------------------------------------------*/
  482. class CObserverBase
  483. {
  484. typedef CEventSourceBase * PEVENTSOURCE;
  485. // no std::set, or std::map please
  486. // those cannot be shared by several DLL's
  487. // see KB article Q172/3/96 (Q172396)
  488. typedef std::list<PEVENTSOURCE> CSourceList; // list of all event sources that this object is connected to.
  489. typedef CSourceList::iterator iterator;
  490. CSourceList m_sourceList;
  491. CSourceList & GetSourceList() { return m_sourceList;}
  492. public:
  493. CObserverBase() {};
  494. virtual ~CObserverBase();
  495. void UnadviseObserver(CEventSourceBase &source); // to disconnect a particular source (this side only)
  496. void _AddSource(CEventSourceBase &source);
  497. void UnadviseAll(); // disconnects all connections - both sides
  498. };
  499. //############################################################################
  500. //############################################################################
  501. //
  502. // Implementation of class CObserverBase
  503. //
  504. //############################################################################
  505. //############################################################################
  506. /*+-------------------------------------------------------------------------*
  507. *
  508. * CObserverBase::UnadviseObserver
  509. *
  510. * PURPOSE:
  511. *
  512. * PARAMETERS:
  513. * CEventSourceBase & source :
  514. *
  515. * RETURNS:
  516. * void
  517. *
  518. *+-------------------------------------------------------------------------*/
  519. inline void
  520. CObserverBase::UnadviseObserver(CEventSourceBase &source)
  521. {
  522. DECLARE_SC(sc, TEXT("CObserverBase::UnadviseObserver"));
  523. iterator it = std::find( GetSourceList().begin(), GetSourceList().end(), &source );
  524. // check if found
  525. if ( it == GetSourceList().end() )
  526. {
  527. sc = E_UNEXPECTED;
  528. return;
  529. }
  530. GetSourceList().erase(it);
  531. }
  532. inline void
  533. CObserverBase::_AddSource(CEventSourceBase &source)
  534. {
  535. GetSourceList().push_back(&source);
  536. }
  537. /*+-------------------------------------------------------------------------*
  538. *
  539. * CObserverBase::~CObserverBase
  540. *
  541. * PURPOSE: Destructor
  542. *
  543. *+-------------------------------------------------------------------------*/
  544. inline CObserverBase::~CObserverBase()
  545. {
  546. // disconnect all sources connected to this observer.
  547. iterator iter;
  548. for(iter = GetSourceList().begin(); iter != GetSourceList().end(); iter++)
  549. {
  550. (*iter)->UnadviseSource(*this);
  551. }
  552. }
  553. //############################################################################
  554. //############################################################################
  555. //
  556. // Implementation of class CEventSource
  557. //
  558. //############################################################################
  559. //############################################################################
  560. /*+-------------------------------------------------------------------------*
  561. *
  562. * _CEventSource::_AddObserver
  563. *
  564. * PURPOSE:
  565. *
  566. * PARAMETERS:
  567. * CObserver & observer :
  568. *
  569. *+-------------------------------------------------------------------------*/
  570. template<class CObserver>
  571. void
  572. _CEventSource<CObserver>::_AddObserver(CObserver &observer)
  573. {
  574. ObserverData observerData = { &observer, false /*bDeleted*/ };
  575. GetObserverList().push_back( observerData );
  576. observer._AddSource(*this);
  577. }
  578. /*+-------------------------------------------------------------------------*
  579. *
  580. * _CEventSource::~_CEventSource
  581. *
  582. * PURPOSE: Destructor
  583. *
  584. *+-------------------------------------------------------------------------*/
  585. template<class CObserver>
  586. _CEventSource<CObserver>::~_CEventSource()
  587. {
  588. //disconnect all observers connected to this source
  589. {
  590. CListIntegrityProtector(this); // protect the list while iterating
  591. iterator iter;
  592. for(iter = GetObserverList().begin(); iter != GetObserverList().end(); ++iter)
  593. {
  594. if (!iter->bDeleted && iter->pObject)
  595. iter->pObject->UnadviseObserver(*this);
  596. }
  597. }
  598. ASSERT( m_nStackDepth == 0 );
  599. GetObserverList().clear();
  600. }
  601. /*+-------------------------------------------------------------------------*
  602. *
  603. * _CEventSource<CObserver>::CleanupDeleted()
  604. *
  605. * PURPOSE: removes entries marked as deleted
  606. *
  607. *+-------------------------------------------------------------------------*/
  608. template<class CObserver>
  609. void _CEventSource<CObserver>::CleanupDeleted()
  610. {
  611. ASSERT ( m_nStackDepth == 0 );
  612. for(iterator iter = GetObserverList().begin(); iter != GetObserverList().end();)
  613. {
  614. if (iter->bDeleted)
  615. iter = GetObserverList().erase( iter );
  616. else
  617. ++iter; // valid - skip
  618. }
  619. }
  620. /*+-------------------------------------------------------------------------*
  621. *
  622. * CEventSource::UnadviseSource
  623. *
  624. * PURPOSE:
  625. *
  626. * PARAMETERS:
  627. * CObserver & observer :
  628. *
  629. *+-------------------------------------------------------------------------*/
  630. template<class CObserver>
  631. void
  632. _CEventSource<CObserver>::UnadviseSource(CObserverBase &observer)
  633. {
  634. // we cannot dynamic cast the observer pointer to a CObserver pointer,
  635. // becuase UnadviseSource is called from ~CObserverBase(), by which time
  636. // the CObserver sub-object has already been deleted. Instead, we search for
  637. // the CObserverBase pointer in the Observer List.
  638. iterator iter, iterNext;
  639. bool bFound = false;
  640. CListIntegrityProtector(this); // protect the list while iterating
  641. for(iter = GetObserverList().begin(); iter != GetObserverList().end(); iter++)
  642. {
  643. if(!iter->bDeleted && static_cast<CObserverBase *>(iter->pObject) == &observer)
  644. {
  645. // do not alter the list directly, let the cleanup do the work
  646. // just mark the entry as invalid
  647. iter->bDeleted = true;
  648. iter->pObject = NULL;
  649. bFound = true;
  650. break;
  651. }
  652. }
  653. ASSERT(bFound);
  654. }
  655. //############################################################################
  656. //############################################################################
  657. //
  658. // stoopid test code
  659. //
  660. //############################################################################
  661. //############################################################################
  662. #ifdef TEST_EVENTS
  663. class CTestObserver : public CObserverBase
  664. {
  665. public:
  666. SC ScMyEvent(int a)
  667. {
  668. ASSERT(0 && "Reached here!");
  669. return S_OK;
  670. }
  671. };
  672. class CTestObserver2 : public CObserverBase
  673. {
  674. public:
  675. SC ScMyEvent(int a)
  676. {
  677. ASSERT(0 && "Reached here!");
  678. return S_OK;
  679. }
  680. SC ScMyEvent2(int a,int d)
  681. {
  682. ASSERT(0 && "Reached here!");
  683. return S_OK;
  684. }
  685. };
  686. class CTestObserver3 : public CObserverBase
  687. {
  688. public:
  689. SC ScMyOtherEvent()
  690. {
  691. ASSERT(0 && "Reached here!");
  692. return S_OK;
  693. }
  694. };
  695. class CTestEventSource : public CEventSource<CTestObserver,CTestObserver2, CTestObserver3>
  696. {
  697. public:
  698. void FireEvent()
  699. {
  700. DECLARE_SC(sc, TEXT("FireEvent"));
  701. sc = ScFireEvent(CTestObserver::ScMyEvent, 42 /*arg1*/);
  702. sc = ScFireEvent(CTestObserver2::ScMyEvent2, 42 /*arg1*/, 24 /*arg1*/);
  703. sc = ScFireEvent(CTestObserver3::ScMyOtherEvent);
  704. }
  705. };
  706. static void DoEventTest()
  707. {
  708. CTestEventSource source;
  709. CTestObserver observer_1;
  710. CTestObserver2 observer_2;
  711. CTestObserver3 observer_3;
  712. source.AddObserver(observer_2);
  713. source.AddObserver(observer_3);
  714. source.AddObserver(observer_1);
  715. source.FireEvent(); // should fire to observer1 only.
  716. {
  717. // new scope
  718. CTestObserver observer2;
  719. source.AddObserver(observer2);
  720. source.FireEvent(); // should fire to observer1 and observer2.
  721. // observer2 is deleted here.
  722. }
  723. source.FireEvent(); // should fire to observer1 only.
  724. }
  725. class CTestObject
  726. {
  727. public:
  728. CTestObject()
  729. {
  730. DoEventTest();
  731. }
  732. };
  733. #endif