OpenCPN Partial API docs
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 
49 std::string ptr_key(const void* ptr);
50 
51 class Observable;
52 class ObservableListener;
53 
55 class KeyProvider {
56 public:
57  virtual std::string GetKey() const = 0;
58 };
59 
60 
66  friend class Observable;
67  friend ListenersByKey& GetInstance(const std::string& key);
68 
69 public:
70  ListenersByKey() {}
71 
72 private:
73  static ListenersByKey& GetInstance(const std::string& key);
74 
75  ListenersByKey(const ListenersByKey&) = delete;
76  ListenersByKey& operator=(const ListenersByKey&) = default;
77 
78  std::vector<std::pair<wxEvtHandler*, wxEventType>> listeners;
79 };
80 
82 class Observable : public KeyProvider {
83  friend class ObservableListener;
84 
85 public:
86  Observable(const std::string& _key)
87  : key(_key), m_list(ListenersByKey::GetInstance(_key)) {}
88 
89  Observable(const KeyProvider& kp) : Observable(kp.GetKey()) {}
90 
92  virtual const void Notify();
93 
94  const void Notify(std::shared_ptr<const void> p) { Notify(p, "", 0, 0); }
95 
100  bool Unlisten(wxEvtHandler* listener, wxEventType ev);
101 
102  std::string GetKey() const { return key; }
103 
105  const std::string key;
106 
107 protected:
113  const void Notify(std::shared_ptr<const void> ptr, const std::string& s,
114  int num, void* client_data);
115 
116  const void Notify(const std::string& s, void* client_data) {
117  Notify(nullptr, s, 0, client_data);
118  }
119 
120 
121 private:
123  void Listen(wxEvtHandler* listener, wxEventType ev_type);
124 
125  ListenersByKey& m_list;
126 
127  mutable std::mutex m_mutex;
128 };
129 
133 class DECL_EXP ObservableListener final {
134 public:
136  ObservableListener() : key(""), listener(0), ev_type(wxEVT_NULL) {}
137 
139  ObservableListener(const std::string& k, wxEvtHandler* l, wxEventType e)
140  : key(k), listener(l), ev_type(e) {
141  Listen();
142  }
143 
144  ObservableListener(const KeyProvider& kp, wxEvtHandler* l, wxEventType e) :
145  ObservableListener(kp.GetKey(), l, e) {}
146 
149  : key(other.key), listener(other.listener), ev_type(other.ev_type) {
150  other.Unlisten();
151  Listen();
152  }
153 
154  ObservableListener(const ObservableListener& other) = delete;
155  ObservableListener& operator=(ObservableListener&) = delete;
156 
157  ~ObservableListener() { Unlisten(); }
158 
160  void Listen(const std::string& key, wxEvtHandler* listener, wxEventType evt);
161 
162  void Listen(const KeyProvider& kp, wxEvtHandler* l, wxEventType evt) {
163  Listen(kp.GetKey(), l, evt);
164  }
165 
166 private:
167  void Listen();
168  void Unlisten();
169 
170  std::string key;
171  wxEvtHandler* listener;
172  wxEventType ev_type;
173 };
174 
210 class ObsListener : public wxEvtHandler {
211 public:
212 
215 
218  std::function<void(ObservedEvt& ev)> action) {
219  Init(kp, action);
220  }
221 
223  ObsListener(const KeyProvider& kp, std::function<void()> action)
224  : ObsListener(kp, [&](ObservedEvt&) { action(); }) {}
225 
227  void Init(const KeyProvider& kp,
228  std::function<void(ObservedEvt& ev)> action) {
229  const wxEventTypeTag<ObservedEvt> EvtObs(wxNewEventType());
230  // i. e. wxDEFINE_EVENT(), avoiding the evil macro.
231  m_listener.Listen(kp, this, EvtObs);
232  Bind(EvtObs, action);
233  }
234 
235 private:
236  ObservableListener m_listener;
237 };
238 
239 
241 template <typename T>
242 std::shared_ptr<const T> UnpackEvtPointer(ObservedEvt ev) {
243  return std::static_pointer_cast<const T>(ev.GetSharedPtr());
244 }
245 
246 #endif // OBSERVABLE_H
Interface implemented by classes which listens.
Definition: observable.h:55
Private helper class.
Definition: observable.h:65
Define an action to be performed when a KeyProvider is notified.
Definition: observable.h:210
ObsListener()
Create an object which does not listen until Init();.
Definition: observable.h:214
ObsListener(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Create object which invokes action when kp is notified.
Definition: observable.h:217
ObsListener(const KeyProvider &kp, std::function< void()> action)
Create object which invokes action when kp is notified.
Definition: observable.h:223
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition: observable.h:227
Keeps listening over it's lifespan, removes itself on destruction.
Definition: observable.h:133
ObservableListener(ObservableListener &&other)
A listener can only be transferred using std::move().
Definition: observable.h:148
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Definition: observable.cpp:98
ObservableListener(const std::string &k, wxEvtHandler *l, wxEventType e)
Construct a listening object.
Definition: observable.h:139
ObservableListener()
Default constructor, does not listen to anything.
Definition: observable.h:136
The observable notify/listen basic nuts and bolts.
Definition: observable.h:82
const std::string key
The key used to create and clone.
Definition: observable.h:105
bool Unlisten(wxEvtHandler *listener, wxEventType ev)
Remove window listening to ev from list of listeners.
Definition: observable.cpp:67
virtual const void Notify()
Notify all listeners about variable change.
Definition: observable.cpp:94
Adds a std::shared<void> element to wxCommandEvent.
Definition: ocpn_plugin.h:1652