OpenCPN Partial API docs
observable.cpp
1 /*************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose: Implement observable.h
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 #include <algorithm>
25 #include <atomic>
26 #include <mutex>
27 #include <sstream>
28 #include <unordered_map>
29 
30 #include <wx/log.h>
31 
32 #include "observable.h"
33 
34 std::string ptr_key(const void* ptr) {
35  std::ostringstream oss;
36  oss << ptr;
37  return oss.str();
38 }
39 
40 /* ListenersByKey implementation. */
41 
42 ListenersByKey& ListenersByKey::GetInstance(const std::string& key) {
43  static std::unordered_map<std::string, ListenersByKey> instances;
44  static std::mutex s_mutex;
45 
46  std::lock_guard<std::mutex> lock(s_mutex);
47  if (instances.find(key) == instances.end()) {
48  instances[key] = ListenersByKey();
49  }
50  return instances[key];
51 }
52 
53 /* Observable implementation. */
54 
55 using ev_pair = std::pair<wxEvtHandler*, wxEventType>;
56 
57 void Observable::Listen(wxEvtHandler* listener, wxEventType ev_type) {
58  std::lock_guard<std::mutex> lock(m_mutex);
59  const auto& listeners = m_list.listeners;
60 
61  ev_pair key_pair(listener, ev_type);
62  auto found = std::find(listeners.begin(), listeners.end(), key_pair);
63  assert((found == listeners.end()) && "Duplicate listener");
64  m_list.listeners.push_back(key_pair);
65 }
66 
67 bool Observable::Unlisten(wxEvtHandler* listener, wxEventType ev_type) {
68  std::lock_guard<std::mutex> lock(m_mutex);
69  auto& listeners = m_list.listeners;
70 
71  ev_pair key_pair(listener, ev_type);
72  auto found = std::find(listeners.begin(), listeners.end(), key_pair);
73  if (found == listeners.end()) return false;
74  listeners.erase(found);
75  return true;
76 }
77 
78 const void Observable::Notify(std::shared_ptr<const void> ptr,
79  const std::string& s, int num,
80  void* client_data) {
81  std::lock_guard<std::mutex> lock(m_mutex);
82  auto& listeners = m_list.listeners;
83 
84  for (auto l = listeners.begin(); l != listeners.end(); l++) {
85  auto evt = new ObservedEvt(l->second);
86  evt->SetSharedPtr(ptr);
87  evt->SetClientData(client_data);
88  evt->SetString(s.c_str()); // Better safe than sorry: force a deep copy
89  evt->SetInt(num);
90  wxQueueEvent(l->first, evt);
91  }
92 }
93 
94 const void Observable::Notify() { Notify("", 0); }
95 
96 /* ObservableListener implementation. */
97 
98 void ObservableListener::Listen(const std::string& k, wxEvtHandler* l,
99  wxEventType e) {
100  if (key != "") Unlisten();
101  key = k;
102  listener = l;
103  ev_type = e;
104  Listen();
105 }
106 
107 void ObservableListener::Listen() {
108  if (key != "") {
109  assert(listener);
110  Observable(key).Listen(listener, ev_type);
111  }
112 }
113 
114 void ObservableListener::Unlisten() {
115  if (key != "") {
116  assert(listener);
117  Observable(key).Unlisten(listener, ev_type);
118  key = "";
119  }
120 }
Private helper class.
Definition: observable.h:65
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
The observable notify/listen basic nuts and bolts.
Definition: observable.h:82
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