OpenCPN Partial API docs
Loading...
Searching...
No Matches
observable.cpp
Go to the documentation of this file.
1/*************************************************************************
2 *
3 * Copyright (C) 2022 - 2025 Alec Leamas
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <https://www.gnu.org/licenses/>.
17 **************************************************************************/
18
25#include <algorithm>
26#include <mutex>
27#include <sstream>
28#include <unordered_map>
29
30#include <wx/log.h>
31
32#include "observable.h"
33
34namespace obs {
35
36std::string PtrKey(const void* ptr) {
37 std::ostringstream oss;
38 oss << ptr;
39 return oss.str();
40}
41
42/* ListenersByKey implementation. */
43
44ListenersByKey& ListenersByKey::GetInstance(const std::string& key) {
45 static std::unordered_map<std::string, ListenersByKey> instances;
46 static std::mutex s_mutex;
47
48 std::lock_guard<std::mutex> lock(s_mutex);
49 if (instances.find(key) == instances.end()) {
50 instances[key] = ListenersByKey();
51 }
52 return instances[key];
53}
54
55/* Observable implementation. */
56
57using EvPair = std::pair<wxEvtHandler*, wxEventType>;
58
59void Observable::Listen(wxEvtHandler* listener, wxEventType ev_type) {
60 std::lock_guard<std::mutex> lock(m_mutex);
61 const auto& listeners = m_list.listeners;
62
63 EvPair key_pair(listener, ev_type);
64 auto found = std::find(listeners.begin(), listeners.end(), key_pair);
65 assert((found == listeners.end()) && "Duplicate listener");
66 m_list.listeners.push_back(key_pair);
67}
68
69bool Observable::Unlisten(wxEvtHandler* listener, wxEventType ev_type) {
70 std::lock_guard<std::mutex> lock(m_mutex);
71 auto& listeners = m_list.listeners;
72
73 EvPair key_pair(listener, ev_type);
74 auto found = std::find(listeners.begin(), listeners.end(), key_pair);
75 if (found == listeners.end()) return false;
76 listeners.erase(found);
77 return true;
78}
79
80void Observable::Notify(const std::shared_ptr<const void>& ptr,
81 const std::string& s, int num, void* client_data) {
82 std::lock_guard<std::mutex> lock(m_mutex);
83 auto& listeners = m_list.listeners;
84
85 for (const auto& l : listeners) {
86 auto evt = new ObservedEvt(l.second);
87 evt->SetSharedPtr(ptr);
88 evt->SetClientData(client_data);
89 evt->SetString(s.c_str()); // Better safe than sorry: force a deep copy
90 evt->SetInt(num);
91 wxQueueEvent(l.first, evt);
92 }
93}
94
95void Observable::Notify() { Notify("", nullptr); }
96/* ObservableListener implementation. */
97
98} // namespace obs
99
100void ObservableListener::Listen(const std::string& k, wxEvtHandler* l,
101 wxEventType e) {
102 if (!m_key.empty()) Unlisten();
103 m_key = k;
104 m_listener = l;
105 m_ev_type = e;
106 Listen();
107}
108
109void ObservableListener::Listen() {
110 if (!m_key.empty()) {
111 assert(m_listener);
112 obs::Observable(m_key).Listen(m_listener, m_ev_type);
113 }
114}
115
116void ObservableListener::Unlisten() {
117 if (!m_key.empty()) {
118 assert(m_listener);
119 obs::Observable(m_key).Unlisten(m_listener, m_ev_type);
120 m_key = "";
121 }
122}
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listeners on changes in key.
Custom event class for OpenCPN's notification system.
The observable notify/listen basic nuts and bolts.
Definition observable.h:100
virtual void Notify()
Notify all listeners to configured key about variable change.
bool Unlisten(wxEvtHandler *listener, wxEventType ev)
Remove window listening to ev from list of listeners.
General observable pattern implementation built on top of wxWidgets event handling.
std::string PtrKey(const void *ptr)
Return address as printable string.