wxWidgets Observable Library
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 <memory>
28 #include <mutex>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 #include <wx/event.h>
34 
35 #include "observable_evt.h"
36 
37 #ifndef DECL_EXP
38 #if defined(_MSC_VER) || defined(__CYGWIN__)
39 #define DECL_EXP __declspec(dllexport)
40 #elif defined(__GNUC__) || defined(__clang__)
41 #define DECL_EXP __attribute__((visibility("default")))
42 #else
43 #define DECL_EXP
44 #endif
45 #endif // DECL_EXP
46 
48 std::string ptr_key(const void* ptr);
49 
50 class Observable;
51 class ObservableListener;
52 
54 class KeyProvider {
55 public:
56 
58  virtual std::string GetKey() const = 0;
59 };
60 
61 
67  friend class Observable;
68  friend ListenersByKey& GetInstance(const std::string& key);
69 
70 public:
71  ListenersByKey() {}
72 
73 private:
74  static ListenersByKey& GetInstance(const std::string& key);
75 
76  ListenersByKey(const ListenersByKey&) = delete;
77  ListenersByKey& operator=(const ListenersByKey&) = default;
78 
79  std::vector<std::pair<wxEvtHandler*, wxEventType>> listeners;
80 };
81 
83 class Observable : public KeyProvider {
84  friend class ObservableListener;
85 
86 public:
88  Observable(const std::string& _key)
89  : key(_key), m_list(ListenersByKey::GetInstance(_key)) {}
90 
92  Observable(const KeyProvider& kp) : Observable(kp.GetKey()) {}
93 
95  virtual const void Notify();
96 
98  const void Notify(std::shared_ptr<const void> p) { Notify(p, "", 0, 0); }
99 
104  bool Unlisten(wxEvtHandler* listener, wxEventType ev);
105 
107  std::string GetKey() const { return key; }
108 
110  const std::string key;
111 
112 protected:
118  const void Notify(std::shared_ptr<const void> ptr, const std::string& s,
119  int num, void* client_data);
120 
126  const void Notify(const std::string& s, void* client_data) {
127  Notify(nullptr, s, 0, client_data);
128  }
129 
130 
131 private:
133  void Listen(wxEvtHandler* listener, wxEventType ev_type);
134 
135  ListenersByKey& m_list;
136 
137  mutable std::mutex m_mutex;
138 };
139 
143 class DECL_EXP ObservableListener final {
144 public:
146  ObservableListener() : key(""), listener(0), ev_type(wxEVT_NULL) {}
147 
149  ObservableListener(const std::string& k, wxEvtHandler* l, wxEventType e)
150  : key(k), listener(l), ev_type(e) {
151  Listen();
152  }
153 
155  ObservableListener(const KeyProvider& kp, wxEvtHandler* l, wxEventType e) :
156  ObservableListener(kp.GetKey(), l, e) {}
157 
160  : key(other.key), listener(other.listener), ev_type(other.ev_type) {
161  other.Unlisten();
162  Listen();
163  }
164 
165  ObservableListener(const ObservableListener& other) = delete;
166  ObservableListener& operator=(ObservableListener&) = delete;
167 
168  ~ObservableListener() { Unlisten(); }
169 
171  void Listen(const std::string& key, wxEvtHandler* listener, wxEventType evt);
172 
177  void Listen(const KeyProvider& kp, wxEvtHandler* l, wxEventType evt) {
178  Listen(kp.GetKey(), l, evt);
179  }
180 
181 private:
182  void Listen();
183  void Unlisten();
184 
185  std::string key;
186  wxEvtHandler* listener;
187  wxEventType ev_type;
188 };
189 
191 template <typename T>
192 std::shared_ptr<const T> UnpackEvtPointer(ObservedEvt ev) {
193  return std::static_pointer_cast<const T>(ev.GetSharedPtr());
194 }
195 
196 #endif // OBSERVABLE_H
Interface implemented by classes which listens.
Definition: observable.h:54
virtual std::string GetKey() const =0
Return key used to listen and notify.
Private helper class.
Definition: observable.h:66
Keeps listening over it's lifespan, removes itself on destruction.
Definition: observable.h:143
ObservableListener(ObservableListener &&other)
A listener can only be transferred using std::move().
Definition: observable.h:159
ObservableListener(const KeyProvider &kp, wxEvtHandler *l, wxEventType e)
Construct a listening object listening to kp.GetKey()
Definition: observable.h:155
ObservableListener(const std::string &k, wxEvtHandler *l, wxEventType e)
Construct a listening object listening to key k.
Definition: observable.h:149
void Listen(const KeyProvider &kp, wxEvtHandler *l, wxEventType evt)
Set object to send wxEventType ev to listener on changes in a KeyProvider.
Definition: observable.h:177
ObservableListener()
Default constructor, does not listen to anything.
Definition: observable.h:146
The observable notify/listen basic nuts and bolts.
Definition: observable.h:83
std::string GetKey() const
Retrieve the actual listening key:
Definition: observable.h:107
const std::string key
The key used to create and clone.
Definition: observable.h:110
const void Notify(std::shared_ptr< const void > p)
Notify all listeners about variable change with a shared_ptr payload.
Definition: observable.h:98
Observable(const std::string &_key)
Create an instance listening to given key.
Definition: observable.h:88
Observable(const KeyProvider &kp)
Create an instance listening to key provided by kp.GetKey().
Definition: observable.h:92
const void Notify(const std::string &s, void *client_data)
Notify all listeners: send them a 'type' ObservedEvt message as defined by listen() with optional dat...
Definition: observable.h:126
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.
std::shared_ptr< const void > GetSharedPtr() const
Retrieve pointer set by SetSharedPtr().