OpenCPN Partial API docs
Loading...
Searching...
No Matches
observable.h
1/*************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: General observable implementation with several specializations.
5 *
6 * Copyright (C) 2022 Alec Leamas
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 **************************************************************************/
23
24#ifndef OBSERVABLE_H
25#define OBSERVABLE_H
26
27#include <functional>
28#include <memory>
29#include <mutex>
30#include <string>
31#include <utility>
32#include <vector>
33
34#include <wx/event.h>
35
36#include "observable_evt.h"
37
38#ifndef DECL_EXP
39#if defined(_MSC_VER) || defined(__CYGWIN__)
40#define DECL_EXP __declspec(dllexport)
41#elif defined(__GNUC__) || defined(__clang__)
42#define DECL_EXP __attribute__((visibility("default")))
43#else
44#define DECL_EXP
45#endif
46#endif // DECL_EXP
47
49std::string ptr_key(const void* ptr);
50
51class Observable;
53
60public:
64 virtual ~KeyProvider() = default;
65
71 virtual std::string GetKey() const = 0;
72};
73
79 friend class Observable;
80 friend ListenersByKey& GetInstance(const std::string& key);
81
82public:
84
85private:
86 static ListenersByKey& GetInstance(const std::string& key);
87
88 ListenersByKey(const ListenersByKey&) = delete;
89 ListenersByKey& operator=(const ListenersByKey&) = default;
90
91 std::vector<std::pair<wxEvtHandler*, wxEventType>> listeners;
92};
93
95class Observable : public KeyProvider {
96 friend class ObservableListener;
97
98public:
99 Observable(const std::string& _key)
100 : key(_key), m_list(ListenersByKey::GetInstance(_key)) {}
101
102 Observable(const KeyProvider& kp) : Observable(kp.GetKey()) {}
103
107 virtual ~Observable() = default;
108
110 virtual const void Notify();
111
112 const void Notify(std::shared_ptr<const void> p) { Notify(p, "", 0, 0); }
113
118 bool Unlisten(wxEvtHandler* listener, wxEventType ev);
119
120 std::string GetKey() const { return key; }
121
123 const std::string key;
124
125protected:
131 const void Notify(std::shared_ptr<const void> ptr, const std::string& s,
132 int num, void* client_data);
133
134 const void Notify(const std::string& s, void* client_data) {
135 Notify(nullptr, s, 0, client_data);
136 }
137
138private:
140 void Listen(wxEvtHandler* listener, wxEventType ev_type);
141
142 ListenersByKey& m_list;
143
144 mutable std::mutex m_mutex;
145};
146
150class DECL_EXP ObservableListener final {
151public:
153 ObservableListener() : key(""), listener(0), ev_type(wxEVT_NULL) {}
154
156 ObservableListener(const std::string& k, wxEvtHandler* l, wxEventType e)
157 : key(k), listener(l), ev_type(e) {
158 Listen();
159 }
160
161 ObservableListener(const KeyProvider& kp, wxEvtHandler* l, wxEventType e)
162 : ObservableListener(kp.GetKey(), l, e) {}
163
166 : key(other.key), listener(other.listener), ev_type(other.ev_type) {
167 other.Unlisten();
168 Listen();
169 }
170
173 key = other.key;
174 listener = other.listener;
175 ev_type = other.ev_type;
176 other.Unlisten();
177 Listen();
178 return *this;
179 }
180
181 ObservableListener(const ObservableListener& other) = delete;
182 ObservableListener& operator=(ObservableListener&) = delete;
183
184 ~ObservableListener() { Unlisten(); }
185
187 void Listen(const std::string& key, wxEvtHandler* listener, wxEventType evt);
188
189 void Listen(const KeyProvider& kp, wxEvtHandler* l, wxEventType evt) {
190 Listen(kp.GetKey(), l, evt);
191 }
192
193private:
194 void Listen();
195 void Unlisten();
196
197 std::string key;
198 wxEvtHandler* listener;
199 wxEventType ev_type;
200};
201
247class ObsListener : public wxEvtHandler {
248public:
251
254 this->m_listener = std::move(other.m_listener);
255 }
256 ObsListener& operator=(ObsListener&& other) {
257 m_listener = std::move(other.m_listener);
258 return *this;
259 }
260 ObsListener(const ObsListener&) = delete;
261 ObsListener& operator=(ObsListener&) = delete;
262
265 std::function<void(ObservedEvt& ev)> action) {
266 Init(kp, action);
267 }
268
270 ObsListener(const KeyProvider& kp, std::function<void()> action)
271 : ObsListener(kp, [&](ObservedEvt&) { action(); }) {}
272
274 void Init(const KeyProvider& kp,
275 std::function<void(ObservedEvt& ev)> action) {
276 const wxEventTypeTag<ObservedEvt> EvtObs(wxNewEventType());
277 // i. e. wxDEFINE_EVENT(), avoiding the evil macro.
278 m_listener.Listen(kp, this, EvtObs);
279 Bind(EvtObs, action);
280 }
281
282private:
283 ObservableListener m_listener;
284};
285
287template <typename T>
288std::shared_ptr<const T> UnpackEvtPointer(ObservedEvt ev) {
289 return std::static_pointer_cast<const T>(ev.GetSharedPtr());
290}
291
292#endif // OBSERVABLE_H
Interface implemented by classes which listens.
Definition observable.h:59
virtual ~KeyProvider()=default
Destroy the Key Provider object.
virtual std::string GetKey() const =0
Get the Key object from the Key Provider.
Private helper class.
Definition observable.h:78
Define an action to be performed when a KeyProvider is notified.
Definition observable.h:247
ObsListener()
Create an object which does not listen until Init();.
Definition observable.h:250
ObsListener(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Create object which invokes action when kp is notified.
Definition observable.h:264
ObsListener(const KeyProvider &kp, std::function< void()> action)
Create object which invokes action when kp is notified.
Definition observable.h:270
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition observable.h:274
ObsListener(ObsListener &&other)
ObsListener can only be assigned using std::move.
Definition observable.h:253
Keeps listening over it's lifespan, removes itself on destruction.
Definition observable.h:150
ObservableListener(ObservableListener &&other)
A listener can only be transferred using std::move().
Definition observable.h:165
ObservableListener & operator=(ObservableListener &&other)
A listener can only be transferred using std::move().
Definition observable.h:172
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
ObservableListener(const std::string &k, wxEvtHandler *l, wxEventType e)
Construct a listening object.
Definition observable.h:156
ObservableListener()
Default constructor, does not listen to anything.
Definition observable.h:153
The observable notify/listen basic nuts and bolts.
Definition observable.h:95
virtual ~Observable()=default
Destroy the Observable object.
std::string GetKey() const
Get the Key object from the Key Provider.
Definition observable.h:120
const std::string key
The key used to create and clone.
Definition observable.h:123
bool Unlisten(wxEvtHandler *listener, wxEventType ev)
Remove window listening to ev from list of listeners.
virtual const void Notify()
Notify all listeners about variable change.
Custom event class for OpenCPN's notification system.
std::shared_ptr< const void > GetSharedPtr() const
Gets the event's payload data.