MuseScore/libmscore/notifier.hpp

116 lines
3.2 KiB
C++

//=============================================================================
// 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<typename Data> class Notifier;
//---------------------------------------------------------
// Listener
//---------------------------------------------------------
template<typename Data>
class Listener {
Notifier<Data>* _notifier = nullptr;
public:
Listener() = default;
Listener(Notifier<Data>* n) : _notifier(n) {}
// do not copy notifier attachment
Listener(const Listener<Data>&) {}
Listener& operator=(const Listener<Data>&) { return *this; }
~Listener();
void setNotifier(Notifier<Data>* n);
void detachNotifier(Notifier<Data>* n) { if (_notifier == n) setNotifier(nullptr); }
Notifier<Data>* notifier() { return _notifier; }
const Notifier<Data>* notifier() const { return _notifier; }
virtual void receive(Data d) = 0;
};
//---------------------------------------------------------
// Notifier
//---------------------------------------------------------
template<typename Data>
class Notifier {
std::vector<Listener<Data>*> _listeners;
bool _atChange = false;
public:
Notifier() = default;
// do not copy listeners list
Notifier(const Notifier<Data>&) {}
Notifier& operator=(const Notifier<Data>&) { return *this; }
~Notifier()
{
_atChange = true; // we don't need to update listeners list anymore
for (Listener<Data>* l : _listeners)
l->detachNotifier(this);
}
void addListener(Listener<Data>* l)
{
if (_atChange || !l)
return;
_atChange = true;
_listeners.push_back(l);
l->setNotifier(this);
_atChange = false;
}
void removeListener(Listener<Data>* 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<Data>* l : _listeners)
l->receive(d);
}
};
template<typename Data>
Listener<Data>::~Listener()
{
if (_notifier)
_notifier->removeListener(this);
}
template<typename Data>
void Listener<Data>::setNotifier(Notifier<Data>* n)
{
if (n == _notifier)
return;
Notifier<Data>* oldNotifier = _notifier;
_notifier = n;
if (oldNotifier)
oldNotifier->removeListener(this);
if (_notifier)
_notifier->addListener(this);
}
} // namespace Ms
#endif