Explicit handling of recursive listeners.
Use a different strategy for recursive listeners, and make them opt-in.
This commit is contained in:
parent
ea9da65b7c
commit
bd88bf1126
@ -24,6 +24,7 @@ namespace simgear
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
PropertyBasedElement::PropertyBasedElement(SGPropertyNode* node):
|
||||
SGPropertyChangeListener(true /* recursive */),
|
||||
_node(node)
|
||||
{
|
||||
_node->addChangeListener(this);
|
||||
|
@ -30,7 +30,6 @@ namespace simgear
|
||||
void PropertyBasedMgr::init()
|
||||
{
|
||||
_props->addChangeListener(this);
|
||||
_props->fireCreatedRecursive();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -92,6 +91,7 @@ namespace simgear
|
||||
PropertyBasedMgr::PropertyBasedMgr( SGPropertyNode_ptr props,
|
||||
const std::string& name_elements,
|
||||
ElementFactory element_factory ):
|
||||
SGPropertyChangeListener(true /* recursive*/),
|
||||
_props( props ),
|
||||
_name_elements( name_elements ),
|
||||
_element_factory( element_factory )
|
||||
|
@ -48,6 +48,8 @@ using std::stringstream;
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
#define ALTERNATE_RECURSIVE 1
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Local classes.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@ -2361,8 +2363,26 @@ SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
|
||||
_listeners = new vector<SGPropertyChangeListener*>;
|
||||
_listeners->push_back(listener);
|
||||
listener->register_property(this);
|
||||
if (initial)
|
||||
listener->valueChanged(this);
|
||||
|
||||
#ifdef ALTERNATE_RECURSIVE
|
||||
if (listener->isRecursive()) {
|
||||
for (auto child : _children) {
|
||||
if (initial) {
|
||||
fireChildAdded(child);
|
||||
}
|
||||
child->addChangeListener(listener, initial);
|
||||
}
|
||||
}
|
||||
|
||||
if (initial) {
|
||||
listener->doValueChanged(this);
|
||||
}
|
||||
#else
|
||||
if (initial) {
|
||||
listener->doValueChanged(this);
|
||||
fireCreatedRecursive(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -2370,6 +2390,7 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
||||
{
|
||||
if (_listeners == 0)
|
||||
return;
|
||||
|
||||
vector<SGPropertyChangeListener*>::iterator it =
|
||||
find(_listeners->begin(), _listeners->end(), listener);
|
||||
if (it != _listeners->end()) {
|
||||
@ -2380,6 +2401,14 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
||||
_listeners = 0;
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
#ifdef ALTERNATE_RECURSIVE
|
||||
if (listener->isRecursive()) {
|
||||
for (auto child : _children) {
|
||||
child->removeChangeListener(listener);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -2432,11 +2461,13 @@ SGPropertyNode::fireValueChanged (SGPropertyNode * node)
|
||||
{
|
||||
if (_listeners != 0) {
|
||||
for (unsigned int i = 0; i < _listeners->size(); i++) {
|
||||
(*_listeners)[i]->valueChanged(node);
|
||||
(*_listeners)[i]->doValueChanged(node);
|
||||
}
|
||||
}
|
||||
#if !defined(ALTERNATE_RECURSIVE)
|
||||
if (_parent != 0)
|
||||
_parent->fireValueChanged(node);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -2444,12 +2475,19 @@ SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
|
||||
SGPropertyNode * child)
|
||||
{
|
||||
if (_listeners != 0) {
|
||||
for (unsigned int i = 0; i < _listeners->size(); i++) {
|
||||
(*_listeners)[i]->childAdded(parent, child);
|
||||
for (auto listen : *_listeners) {
|
||||
listen->doChildAdded(parent, child);
|
||||
#if defined(ALTERNATE_RECURSIVE)
|
||||
if (listen->isRecursive()) {
|
||||
child->addChangeListener(listen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if !defined(ALTERNATE_RECURSIVE)
|
||||
if (_parent != 0)
|
||||
_parent->fireChildAdded(parent, child);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -2457,12 +2495,19 @@ SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
|
||||
SGPropertyNode * child)
|
||||
{
|
||||
if (_listeners != 0) {
|
||||
for (unsigned int i = 0; i < _listeners->size(); i++) {
|
||||
(*_listeners)[i]->childRemoved(parent, child);
|
||||
for (auto listen : *_listeners) {
|
||||
listen->childRemoved(parent, child);
|
||||
#if defined(ALTERNATE_RECURSIVE)
|
||||
if (listen) {
|
||||
child->removeChangeListener(listen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if !defined(ALTERNATE_RECURSIVE)
|
||||
if (_parent != 0)
|
||||
_parent->fireChildRemoved(parent, child);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -2482,6 +2527,11 @@ SGPropertyNode::eraseChild(simgear::PropertyList::iterator child)
|
||||
// Implementation of SGPropertyChangeListener.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGPropertyChangeListener::SGPropertyChangeListener(bool recursive) :
|
||||
_recursive(recursive)
|
||||
{
|
||||
}
|
||||
|
||||
SGPropertyChangeListener::~SGPropertyChangeListener ()
|
||||
{
|
||||
for (int i = static_cast<int>(_properties.size() - 1); i >= 0; i--)
|
||||
@ -2498,7 +2548,16 @@ void
|
||||
SGPropertyChangeListener::childAdded (SGPropertyNode * node,
|
||||
SGPropertyNode * child)
|
||||
{
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
void SGPropertyChangeListener::doChildAdded(SGPropertyNode * parent, SGPropertyNode * child)
|
||||
{
|
||||
childAdded(parent, child);
|
||||
}
|
||||
|
||||
void SGPropertyChangeListener::doValueChanged(SGPropertyNode * node)
|
||||
{
|
||||
valueChanged(node);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2511,6 +2570,10 @@ SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
|
||||
void
|
||||
SGPropertyChangeListener::register_property (SGPropertyNode * node)
|
||||
{
|
||||
auto it = std::find(_properties.begin(), _properties.end(), node);
|
||||
if (it != _properties.end()) {
|
||||
return; // duplicate listen
|
||||
}
|
||||
_properties.push_back(node);
|
||||
}
|
||||
|
||||
@ -2519,9 +2582,10 @@ SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
|
||||
{
|
||||
vector<SGPropertyNode *>::iterator it =
|
||||
find(_properties.begin(), _properties.end(), node);
|
||||
if (it != _properties.end())
|
||||
if (it != _properties.end()) {
|
||||
_properties.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
#if !PROPS_STANDALONE
|
||||
template<>
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <cmath> // for fabs
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#if PROPS_STANDALONE
|
||||
// taken from: boost/utility/enable_if.hpp
|
||||
@ -236,19 +238,12 @@ public:
|
||||
*/
|
||||
virtual SGRaw* clone() const = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class SGRawExtended : public SGRaw
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Make an SGRawValueContainer from the SGRawValue.
|
||||
*
|
||||
* This is a virtual function of SGRawExtended so that
|
||||
* SGPropertyNode::untie doesn't need to know the type of an
|
||||
* extended property.
|
||||
*/
|
||||
virtual SGRawExtended* makeContainer() const = 0;
|
||||
/**
|
||||
* Write value out to a stream
|
||||
*/
|
||||
@ -257,6 +252,15 @@ public:
|
||||
* Read value from a stream and store it.
|
||||
*/
|
||||
virtual std::istream& readFrom(std::istream& stream) = 0;
|
||||
|
||||
/**
|
||||
* Make an SGRawValueContainer from the SGRawValue.
|
||||
*
|
||||
* This is a virtual function of SGRawExtended so that
|
||||
* SGPropertyNode::untie doesn't need to know the type of an
|
||||
* extended property.
|
||||
*/
|
||||
virtual SGRaw* makeContainer() const = 0;
|
||||
};
|
||||
|
||||
// Choose between different base classes based on whether the value is
|
||||
@ -395,6 +399,7 @@ template<> inline const char * SGRawValue<const char *>::DefaultValue()
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A raw value bound to a pointer.
|
||||
*
|
||||
@ -683,8 +688,7 @@ private:
|
||||
template<typename T>
|
||||
SGRawExtended* SGRawBase<T, 0>::makeContainer() const
|
||||
{
|
||||
return new SGRawValueContainer<T>(static_cast<const SGRawValue<T>*>(this)
|
||||
->getValue());
|
||||
return new SGRawValueContainer<T>(static_cast<const SGRawValue<T>*>(this)->getValue());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -734,12 +738,21 @@ public:
|
||||
/// Called if \a child has been removed from its \a parent.
|
||||
virtual void childRemoved(SGPropertyNode * parent, SGPropertyNode * child);
|
||||
|
||||
bool isRecursive() const { return _recursive; }
|
||||
|
||||
protected:
|
||||
SGPropertyChangeListener(bool recursive = false);
|
||||
|
||||
friend class SGPropertyNode;
|
||||
|
||||
virtual void register_property (SGPropertyNode * node);
|
||||
virtual void unregister_property (SGPropertyNode * node);
|
||||
|
||||
void doValueChanged(SGPropertyNode * node);
|
||||
void doChildAdded(SGPropertyNode * parent, SGPropertyNode * child);
|
||||
|
||||
private:
|
||||
const bool _recursive = false;
|
||||
std::vector<SGPropertyNode *> _properties;
|
||||
};
|
||||
|
||||
@ -1142,7 +1155,6 @@ public:
|
||||
(state ? _attr |= attr : _attr &= ~attr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all of the mode attributes for the property node.
|
||||
*/
|
||||
@ -1761,6 +1773,8 @@ protected:
|
||||
static simgear::PropertyInterpolationMgr* _interpolation_mgr;
|
||||
|
||||
private:
|
||||
// friend so we can poll the SGRaw for tied properties directly.
|
||||
friend class SGPropertyChangeListener;
|
||||
|
||||
// Get the raw value
|
||||
bool get_bool () const;
|
||||
|
Loading…
Reference in New Issue
Block a user