116 lines
3.2 KiB
C++
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
|
|
|