OpenCPN Partial API docs
Loading...
Searching...
No Matches
observable.h
Go to the documentation of this file.
1/*************************************************************************
2 *
3 *
4 * Copyright (C) 2022 - 2025 Alec Leamas
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **************************************************************************/
21
29#ifndef OBSERVABLE_H
30#define OBSERVABLE_H
31
32#include <functional>
33#include <memory>
34#include <mutex>
35#include <string>
36#include <utility>
37#include <vector>
38
39#include <wx/event.h>
40
41#include "observable_evt.h"
42
43#ifndef DECL_EXP
44#if defined(_MSC_VER) || defined(__CYGWIN__)
45#define DECL_EXP __declspec(dllexport)
46#elif defined(__GNUC__) || defined(__clang__)
47#define DECL_EXP __attribute__((visibility("default")))
48#else
49#define DECL_EXP
50#endif
51#endif // DECL_EXP
52
54std::string ptr_key(const void* ptr);
55
56class Observable;
58
65public:
69 virtual ~KeyProvider() = default;
70
76 [[nodiscard]] virtual std::string GetKey() const = 0;
77};
78
84 friend class Observable;
85 friend ListenersByKey& GetInstance(const std::string& key);
86
87public:
88 ListenersByKey() = default;
89 ListenersByKey(const ListenersByKey&) = delete;
90
91private:
92 static ListenersByKey& GetInstance(const std::string& key);
93
94 ListenersByKey& operator=(const ListenersByKey&) = default;
95
96 std::vector<std::pair<wxEvtHandler*, wxEventType>> listeners;
97};
98
100class Observable : public KeyProvider {
101 friend class ObservableListener;
102
103public:
104 explicit Observable(const std::string& _key)
105 : key(_key), m_list(ListenersByKey::GetInstance(_key)) {}
106
107 explicit Observable(const KeyProvider& kp) : Observable(kp.GetKey()) {}
108
112 ~Observable() override = default;
113
115 virtual void Notify();
116
117 void Notify(const std::shared_ptr<const void>& p) { Notify(p, "", 0, nullptr); }
118
123 bool Unlisten(wxEvtHandler* listener, wxEventType ev);
124
125 std::string GetKey() const override { return key; }
126
128 const std::string key;
129
130protected:
136 void Notify(const std::shared_ptr<const void>& ptr, const std::string& s,
137 int num, void* client_data);
138
139 void Notify(const std::string& s, void* client_data) {
140 Notify(nullptr, s, 0, client_data);
141 }
142
143private:
145 void Listen(wxEvtHandler* listener, wxEventType ev_type);
146
147 ListenersByKey& m_list;
148
149 mutable std::mutex m_mutex;
150};
151
155class DECL_EXP ObservableListener final {
156 friend class ObsListener;
157
158public:
160 ObservableListener() : listener(nullptr), ev_type(wxEVT_NULL) {}
161
163 ObservableListener (std::string k, wxEvtHandler* l, wxEventType e)
164 : key(std::move(k)), listener(l), ev_type(e) {
165 Listen();
166 }
167
168 ObservableListener(const KeyProvider& kp, wxEvtHandler* l, wxEventType e)
169 : ObservableListener(kp.GetKey(), l, e) {}
170
173 key = other.key;
174 listener = other.listener;
175 ev_type = other.ev_type;
176 other.Unlisten();
177 Listen();
178 }
179
182 key = other.key;
183 listener = other.listener;
184 ev_type = other.ev_type;
185 other.Unlisten();
186 Listen();
187 return *this;
188 }
189
190 ObservableListener(const ObservableListener& other) = delete;
191 ObservableListener& operator=(ObservableListener&) = delete;
192
193 ~ObservableListener() { Unlisten(); }
194
196 void Listen(const std::string& key, wxEvtHandler* listener, wxEventType evt);
197
199 void Listen(const KeyProvider& kp, wxEvtHandler* l, wxEventType evt) {
200 Listen(kp.GetKey(), l, evt);
201 }
202
203private:
204 void Listen();
205 void Unlisten();
206
207 std::string key;
208 wxEvtHandler* listener;
209 wxEventType ev_type;
210};
211
257class ObsListener : public wxEvtHandler {
258public:
260 ObsListener() : m_obs_evt(wxNewEventType()) {}
261
263 ObsListener(ObsListener&& other) noexcept: m_obs_evt(wxNewEventType()) {
264 m_listener.Unlisten();
265 Unbind(other.m_obs_evt, other.m_action);
266 m_action = other.m_action;
267 Bind(m_obs_evt, m_action);
268 m_listener.Listen(other.m_listener.key, this, m_obs_evt);
269 }
270
271 ObsListener& operator=(ObsListener&& other) noexcept {
272 m_listener.Unlisten();
273 Unbind(other.m_obs_evt, other.m_action);
274 m_action = other.m_action;
275 Bind(m_obs_evt, m_action);
276 m_listener.Listen(other.m_listener.key, this, m_obs_evt);
277 return *this;
278 }
279
280 ObsListener(const ObsListener&) = delete;
281 ObsListener& operator=(ObsListener&) = delete;
282
285 const std::function<void(ObservedEvt& ev)>& action)
286 : m_obs_evt(wxNewEventType()) {
287 Init(kp, action);
288 }
289
291 ObsListener(const KeyProvider& kp, const std::function<void()>& action)
292 : ObsListener(kp, [&](ObservedEvt&) { action(); }) {}
293
295 void Init(const KeyProvider& kp,
296 const std::function<void(ObservedEvt& ev)>& action) {
297 m_action = action;
298 const wxEventTypeTag<ObservedEvt> EvtObs(wxNewEventType());
299 // i. e. wxDEFINE_EVENT(), avoiding the evil macro.
300 m_listener.Listen(kp, this, EvtObs);
301 Bind(EvtObs, action);
302 }
303
304private:
305 ObservableListener m_listener;
306 std::function<void(ObservedEvt& ev)> m_action;
307 const wxEventTypeTag<ObservedEvt> m_obs_evt;
308};
309
311template <typename T>
312std::shared_ptr<const T> UnpackEvtPointer(const ObservedEvt& ev) {
313 return std::static_pointer_cast<const T>(ev.GetSharedPtr());
314}
315
316#endif // OBSERVABLE_H
Interface implemented by classes which listens.
Definition observable.h:64
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:83
Define an action to be performed when a KeyProvider is notified.
Definition observable.h:257
ObsListener()
Create an object which does not listen until Init();.
Definition observable.h:260
ObsListener(const KeyProvider &kp, const std::function< void()> &action)
Create object which invokes action when kp is notified.
Definition observable.h:291
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
Definition observable.h:295
ObsListener(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Create object which invokes action when kp is notified.
Definition observable.h:284
ObsListener(ObsListener &&other) noexcept
ObsListener can only be assigned using std::move.
Definition observable.h:263
Keeps listening over its lifespan, removes itself on destruction.
Definition observable.h:155
ObservableListener(ObservableListener &&other) noexcept
A listener can only be transferred using std::move().
Definition observable.h:172
ObservableListener(std::string k, wxEvtHandler *l, wxEventType e)
Construct a listening object.
Definition observable.h:163
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
void Listen(const KeyProvider &kp, wxEvtHandler *l, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Definition observable.h:199
ObservableListener & operator=(ObservableListener &&other) noexcept
A listener can only be transferred using std::move().
Definition observable.h:181
ObservableListener()
Default constructor, does not listen to anything.
Definition observable.h:160
The observable notify/listen basic nuts and bolts.
Definition observable.h:100
~Observable() override=default
Destroy the Observable object.
virtual void Notify()
Notify all listeners about variable change.
const std::string key
The key used to create and clone.
Definition observable.h:128
bool Unlisten(wxEvtHandler *listener, wxEventType ev)
Remove window listening to ev from list of listeners.
std::string GetKey() const override
Get the Key object from the Key Provider.
Definition observable.h:125
Custom event class for OpenCPN's notification system.
std::shared_ptr< const void > GetSharedPtr() const
Gets the event's payload data.
std::shared_ptr< const T > UnpackEvtPointer(const ObservedEvt &ev)
Shorthand for accessing ObservedEvt.SharedPtr().
Definition observable.h:312
std::string ptr_key(const void *ptr)
Return address as printable string.
wxCommandEvt subclass which can carry also a shared_ptr<void>