diff --git a/simgear/props/PropertyBasedElement.cxx b/simgear/props/PropertyBasedElement.cxx index f9f7fb27..2241b396 100644 --- a/simgear/props/PropertyBasedElement.cxx +++ b/simgear/props/PropertyBasedElement.cxx @@ -24,6 +24,7 @@ namespace simgear //---------------------------------------------------------------------------- PropertyBasedElement::PropertyBasedElement(SGPropertyNode* node): + SGPropertyChangeListener(true /* recursive */), _node(node) { _node->addChangeListener(this); diff --git a/simgear/props/PropertyBasedMgr.cxx b/simgear/props/PropertyBasedMgr.cxx index c133d152..7d7d6b43 100644 --- a/simgear/props/PropertyBasedMgr.cxx +++ b/simgear/props/PropertyBasedMgr.cxx @@ -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 ) diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index afe98269..9b2a9f98 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -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; _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::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(_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,7 +2570,11 @@ SGPropertyChangeListener::childRemoved (SGPropertyNode * parent, void SGPropertyChangeListener::register_property (SGPropertyNode * node) { - _properties.push_back(node); + auto it = std::find(_properties.begin(), _properties.end(), node); + if (it != _properties.end()) { + return; // duplicate listen + } + _properties.push_back(node); } void @@ -2519,8 +2582,9 @@ SGPropertyChangeListener::unregister_property (SGPropertyNode * node) { vector::iterator it = find(_properties.begin(), _properties.end(), node); - if (it != _properties.end()) - _properties.erase(it); + if (it != _properties.end()) { + _properties.erase(it); + } } #if !PROPS_STANDALONE diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index 595e013d..ee1267e7 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -22,6 +22,8 @@ #include #include +#include // for fabs + #include #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::DefaultValue() return ""; } + /** * A raw value bound to a pointer. * @@ -683,8 +688,7 @@ private: template SGRawExtended* SGRawBase::makeContainer() const { - return new SGRawValueContainer(static_cast*>(this) - ->getValue()); + return new SGRawValueContainer(static_cast*>(this)->getValue()); } template @@ -734,13 +738,22 @@ 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: - friend class SGPropertyNode; - virtual void register_property (SGPropertyNode * node); - virtual void unregister_property (SGPropertyNode * node); + 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: - std::vector _properties; + const bool _recursive = false; + std::vector _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;