//============================================================================= // MuseScore // Music Composition & Notation // // Copyright (C) 2018 Werner Schweer // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 // as published by the Free Software Foundation and appearing in // the file LICENCE.GPL //============================================================================= #ifndef __NOTIFIER_H__ #define __NOTIFIER_H__ namespace Ms { template class Notifier; //--------------------------------------------------------- // Listener //--------------------------------------------------------- template class Listener { Notifier* _notifier = nullptr; public: Listener() = default; Listener(Notifier* n) : _notifier(n) {} // do not copy notifier attachment Listener(const Listener&) {} Listener(Listener&&); Listener& operator=(const Listener&) { return *this; } Listener& operator=(Listener&&); ~Listener(); void setNotifier(Notifier* n); void detachNotifier(Notifier* n) { if (_notifier == n) setNotifier(nullptr); } Notifier* notifier() { return _notifier; } const Notifier* notifier() const { return _notifier; } virtual void receive(Data d) = 0; template friend void swap(Listener& l1, Listener& l2); }; //--------------------------------------------------------- // Notifier //--------------------------------------------------------- template class Notifier { std::vector*> _listeners; bool _atChange = false; public: Notifier() = default; // do not copy listeners list Notifier(const Notifier&) {} Notifier& operator=(const Notifier&) { return *this; } ~Notifier() { _atChange = true; // we don't need to update listeners list anymore for (Listener* l : _listeners) l->detachNotifier(this); } void addListener(Listener* l) { if (_atChange || !l) return; _atChange = true; _listeners.push_back(l); l->setNotifier(this); _atChange = false; } void removeListener(Listener* l) { if (_atChange || !l) return; _atChange = true; _listeners.erase(std::remove(_listeners.begin(), _listeners.end(), l), _listeners.end()); l->detachNotifier(this); _atChange = false; } void notify(Data d) const { for (Listener* l : _listeners) l->receive(d); } }; template Listener::Listener(Listener&& other) { if (Notifier* n = other.notifier()) { n->removeListener(other); setNotifier(n); } } template Listener& Listener::operator=(Listener&& other) { if (Notifier* n = other.notifier()) { n->removeListener(other); setNotifier(n); } else setNotifier(nullptr); return *this; } template Listener::~Listener() { if (_notifier) _notifier->removeListener(this); } template void Listener::setNotifier(Notifier* n) { if (n == _notifier) return; Notifier* oldNotifier = _notifier; _notifier = n; if (oldNotifier) oldNotifier->removeListener(this); if (_notifier) _notifier->addListener(this); } template void swap(Listener& l1, Listener& l2) { Notifier* n1 = l1.notifier(); Notifier* n2 = l2.notifier(); l1.setNotifier(n2); l2.setNotifier(n1); } } // namespace Ms #endif