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
56public:
57 virtual std::string GetKey() const = 0;
58};
59
65 friend class Observable;
66 friend ListenersByKey& GetInstance(const std::string& key);
67
68public:
70
71private:
72 static ListenersByKey& GetInstance(const std::string& key);
73
74 ListenersByKey(const ListenersByKey&) = delete;
75 ListenersByKey& operator=(const ListenersByKey&) = default;
76
77 std::vector<std::pair<wxEvtHandler*, wxEventType>> listeners;
78};
79
81class Observable : public KeyProvider {
82 friend class ObservableListener;
83
84public:
85 Observable(const std::string& _key)
86 : key(_key), m_list(ListenersByKey::GetInstance(_key)) {}
87
88 Observable(const KeyProvider& kp) : Observable(kp.GetKey()) {}
89
91 virtual const void Notify();
92
93 const void Notify(std::shared_ptr<const void> p) { Notify(p, "", 0, 0); }
94
99 bool Unlisten(wxEvtHandler* listener, wxEventType ev);
100
101 std::string GetKey() const { return key; }
102
104 const std::string key;
105
106protected:
112 const void Notify(std::shared_ptr<const void> ptr, const std::string& s,
113 int num, void* client_data);
114
115 const void Notify(const std::string& s, void* client_data) {
116 Notify(nullptr, s, 0, client_data);
117 }
118
119private:
121 void Listen(wxEvtHandler* listener, wxEventType ev_type);
122
123 ListenersByKey& m_list;
124
125 mutable std::mutex m_mutex;
126};
127
131class DECL_EXP ObservableListener final {
132public:
134 ObservableListener() : key(""), listener(0), ev_type(wxEVT_NULL) {}
135
137 ObservableListener(const std::string& k, wxEvtHandler* l, wxEventType e)
138 : key(k), listener(l), ev_type(e) {
139 Listen();
140 }
141
142 ObservableListener(const KeyProvider& kp, wxEvtHandler* l, wxEventType e)
143 : ObservableListener(kp.GetKey(), l, e) {}
144
147 : key(other.key), listener(other.listener), ev_type(other.ev_type) {
148 other.Unlisten();
149 Listen();
150 }
151
154 key = other.key;
155 listener = other.listener;
156 ev_type = other.ev_type;
157 other.Unlisten();
158 Listen();
159 return *this;
160 }
161
162 ObservableListener(const ObservableListener& other) = delete;
163 ObservableListener& operator=(ObservableListener&) = delete;
164
165 ~ObservableListener() { Unlisten(); }
166
168 void Listen(const std::string& key, wxEvtHandler* listener, wxEventType evt);
169
170 void Listen(const KeyProvider& kp, wxEvtHandler* l, wxEventType evt) {
171 Listen(kp.GetKey(), l, evt);
172 }
173
174private:
175 void Listen();
176 void Unlisten();
177
178 std::string key;
179 wxEvtHandler* listener;
180 wxEventType ev_type;
181};
182
228class ObsListener : public wxEvtHandler {
229public:
232
235 this->m_listener = std::move(other.m_listener);
236 }
237 ObsListener& operator=(ObsListener&& other) {
238 m_listener = std::move(other.m_listener);
239 return *this;
240 }
241 ObsListener(const ObsListener&) = delete;
242 ObsListener& operator=(ObsListener&) = delete;
243
246 std::function<void(ObservedEvt& ev)> action) {
247 Init(kp, action);
248 }
249
251 ObsListener(const KeyProvider& kp, std::function<void()> action)
252 : ObsListener(kp, [&](ObservedEvt&) { action(); }) {}
253
255 void Init(const KeyProvider& kp,
256 std::function<void(ObservedEvt& ev)> action) {
257 const wxEventTypeTag<ObservedEvt> EvtObs(wxNewEventType());
258 // i. e. wxDEFINE_EVENT(), avoiding the evil macro.
259 m_listener.Listen(kp, this, EvtObs);
260 Bind(EvtObs, action);
261 }
262
263private:
264 ObservableListener m_listener;
265};
266
268template <typename T>
269std::shared_ptr<const T> UnpackEvtPointer(ObservedEvt ev) {
270 return std::static_pointer_cast<const T>(ev.GetSharedPtr());
271}
272
273#endif // OBSERVABLE_H
Interface implemented by classes which listens.
Definition observable.h:55
Private helper class.
Definition observable.h:64
Define an action to be performed when a KeyProvider is notified.
Definition observable.h:228
ObsListener()
Create an object which does not listen until Init();.
Definition observable.h:231
ObsListener(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Create object which invokes action when kp is notified.
Definition observable.h:245
ObsListener(const KeyProvider &kp, std::function< void()> action)
Create object which invokes action when kp is notified.
Definition observable.h:251
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition observable.h:255
ObsListener(ObsListener &&other)
ObsListener can only be assigned using std::move.
Definition observable.h:234
Keeps listening over it's lifespan, removes itself on destruction.
Definition observable.h:131
ObservableListener(ObservableListener &&other)
A listener can only be transferred using std::move().
Definition observable.h:146
ObservableListener & operator=(ObservableListener &&other)
A listener can only be transferred using std::move().
Definition observable.h:153
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:137
ObservableListener()
Default constructor, does not listen to anything.
Definition observable.h:134
The observable notify/listen basic nuts and bolts.
Definition observable.h:81
const std::string key
The key used to create and clone.
Definition observable.h:104
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.
Adds a std::shared<void> element to wxCommandEvent.