source: src/Patterns/Observer/Observable.hpp@ e2e035e

Last change on this file since e2e035e was e2e035e, checked in by Frederik Heber <heber@…>, 14 years ago

Refactored all Observer stuff into own subfolder and split up into distinct modules.

  • Observer/all.hpp is all that's needed.
  • Property mode set to 100644
File size: 4.2 KB
Line 
1/*
2 * Observable.hpp
3 *
4 * Created on: Dec 1, 2011
5 * Author: heber
6 */
7
8#ifndef OBSERVABLE_HPP_
9#define OBSERVABLE_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <map>
17#include <set>
18#include <string>
19
20#include "Observer/defs.hpp"
21#include "Observer/Observer.hpp"
22
23/**
24 * An Observable implements all neccessary method for being observed.
25 *
26 * That is, it provides methods for signing on and of from an
27 * Observable that can be used by any observer. The actual
28 * observer-mechanism is handled at a central static place
29 * to avoid memory issues when many observable are around but only few
30 * are actually observed.
31 */
32class Observable : public Observer {
33public:
34 Observable(std::string _name);
35 virtual ~Observable();
36
37 /**
38 * Sign an Observer on to this Observable. The Observer will be notified
39 * whenever something inside the Observable changes. The Observer can
40 * assign itself a priority for the changes in the range of -20:+20.
41 * The Observer with lower priority will be called before the others,
42 * same as with Unix nice-levels. This can be used when an Object
43 * contains other objects that observe it (derived values), and these objects have
44 * to recalculate their states before the changes should be propageted to the
45 * UI. A default priority of 0 should be fine in most cases, since there is
46 * ussually no need to order the update sequence.
47 */
48 virtual void signOn(Observer *target, int priority=0) const;
49
50 /**
51 * Sign of a previously signed on Observer. After this no more
52 * updates will be recieved from that observer.
53 */
54 virtual void signOff(Observer *target) const;
55
56 /**
57 * Sign on for specialized notifications
58 */
59 virtual void signOn(Observer *target, Notification_ptr notification) const;
60
61 /**
62 * Stop receiving a specialized notification
63 */
64 virtual void signOff(Observer *target, Notification_ptr notification) const;
65
66 /**
67 * Ask an Observer if it is currently in a blocked state, i.e. if
68 * Changes are in Progress, that are not yet published.
69 */
70 virtual bool isBlocked() const;
71
72 Notification_ptr getChannel(size_t no) const;
73
74protected:
75 virtual void update(Observable *publisher);
76 virtual void subjectKilled(Observable *publisher);
77
78 virtual void notifyAll();
79protected:
80// Observer mechanism is done from a static central place
81 /**
82 * Internal method.
83 * Do not call directly. Use OBSERVE macro instead
84 */
85 static void start_observer_internal(Observable *publisher);
86 /**
87 * Internal method.
88 * Do not call directly. Use OBSERVE macro instead
89 */
90 static void finish_observer_internal(Observable *publisher);
91
92 static void enque_notification_internal(Observable *publisher, Notification_ptr notification);
93
94 typedef std::map<Observable*, Channels *> ChannelMap;
95 static ChannelMap NotificationChannels;
96
97private:
98 typedef std::multimap<int,Observer*> callees_t;
99 typedef std::set<Notification*> notificationSet;
100 static std::map<Observable*, int> depth;
101 static std::map<Observable*,callees_t> callTable;
102 static std::map<Observable*,notificationSet> notifications;
103 static std::set<Observable*> busyObservables;
104
105 //! @cond
106 // Structure for RAII-Style notification
107public:
108 /**
109 * This structure implements the Observer-mechanism RAII-Idiom.
110 * It triggers certain functions on creation and destruction so that
111 * Observer mechanisms can be linked to scope block.
112 */
113 class _Observable_protector {
114 public:
115 _Observable_protector(Observable *);
116 _Observable_protector(const _Observable_protector&);
117 ~_Observable_protector();
118 private:
119 Observable *protege;
120 };
121 //! @endcond
122};
123
124
125// extra macro is necessary to work with __LINE__
126#define PASTE(a,b) PASTE_HELPER(a,b)
127#define PASTE_HELPER(a,b) a ## b
128#define OBSERVE Observable::_Observable_protector PASTE(_scope_obs_protector_,__LINE__)(this)
129#define NOTIFY(channelno) do{const ChannelMap::const_iterator iter=NotificationChannels.find(this);ASSERT(iter!=NotificationChannels.end(),"NOTIFY() - channel not found.");Observable::enque_notification_internal(this,iter->second->getChannel(channelno));}while(0)
130#define LOCK_OBSERVABLE(observable) Observable::_Observable_protector PASTE(_scope_obs_protector_,__LINE__)(&(observable))
131
132#endif /* OBSERVABLE_HPP_ */
Note: See TracBrowser for help on using the repository browser.