#include <string>
#include <iostream>
#include <sstream>
+#include <typeinfo>
-#include <boost/utility.hpp>
-
-#if PROPS_STANDALONE
-#else
#include <simgear/compiler.h>
-#include <simgear/debug/logstream.hxx>
+#if PROPS_STANDALONE
+// taken from: boost/utility/enable_if.hpp
+#ifndef SG_LOG
+# define SG_GENERAL 0
+# define SG_ALERT 0
+# define SG_WARN 1
+# define SG_LOG(type, level, message) (type) ? (std::cerr <<message << endl) : (std::cout <<message << endl)
#endif
+namespace boost {
+ template <bool B, class T = void>
+ struct enable_if_c {
+ typedef T type;
+ };
+
+ template <class T>
+ struct enable_if_c<false, T> {};
+
+ template <class Cond, class T = void>
+ struct enable_if : public enable_if_c<Cond::value, T> {};
+
+ template <bool B, class T = void>
+ struct disable_if_c {
+ typedef T type;
+ };
+ template <class T>
+ struct disable_if_c<true, T> {};
-#include <simgear/math/SGMathFwd.hxx>
-#include <simgear/math/sg_types.hxx>
+ template <class Cond, class T = void>
+ struct disable_if : public disable_if_c<Cond::value, T> {};
+}
+#else
+# include <boost/utility.hpp>
+# include <boost/type_traits/is_enum.hpp>
+
+# include <simgear/debug/logstream.hxx>
+# include <simgear/math/SGMathFwd.hxx>
+# include <simgear/math/sg_types.hxx>
+#endif
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
// XXX This whole file should be in the simgear namespace, but I don't
// have the guts yet...
+using namespace std;
+
namespace simgear
{
/**
* Abstract base class for a raw value.
*
- * <p>The property manager is implemented in two layers. The {@link
- * SGPropertyNode} is the highest and most abstract layer,
- * representing an LValue/RValue pair: it records the position of the
- * property in the property tree and contains facilities for
- * navigation to other nodes. It is guaranteed to be persistent: the
- * {@link SGPropertyNode} will not change during a session, even if
- * the property is bound and unbound multiple times.</p>
+ * The property manager is implemented in two layers. The SGPropertyNode is the
+ * highest and most abstract layer, representing an LValue/RValue pair: it
+ * records the position of the property in the property tree and contains
+ * facilities for navigation to other nodes. It is guaranteed to be persistent:
+ * the SGPropertyNode will not change during a session, even if the property is
+ * bound and unbound multiple times.
*
- * <p>When the property value is not managed internally in the
+ * When the property value is not managed internally in the
* SGPropertyNode, the SGPropertyNode will contain a reference to an
* SGRawValue (this class), which provides an abstract way to get,
* set, and clone the underlying value. The SGRawValue may change
* unbound to various data source, but the abstract SGPropertyNode
* layer insulates the application from those changes.
*
- * <p>The SGPropertyNode class always keeps a *copy* of a raw value,
- * not the original one passed to it; if you override a derived class
- * but do not replace the {@link #clone} method, strange things will
- * happen.</p>
+ * The SGPropertyNode class always keeps a *copy* of a raw value, not the
+ * original one passed to it; if you override a derived class but do not replace
+ * the {@link SGRaw::clone clone()} method, strange things will happen.
*
- * <p>All derived SGRawValue classes must implement {@link #getValue},
- * {@link #setValue}, and {@link #clone} for the appropriate type.</p>
+ * All derived SGRawValue classes must implement getValue(), setValue(), and
+ * {@link SGRaw::clone clone()} for the appropriate type.
*
* @see SGPropertyNode
* @see SGRawValuePointer
{
public:
virtual ~SGPropertyChangeListener ();
- virtual void valueChanged (SGPropertyNode * node);
- virtual void childAdded (SGPropertyNode * parent, SGPropertyNode * child);
- virtual void childRemoved (SGPropertyNode * parent, SGPropertyNode * child);
+
+ /// Called if value of \a node has changed.
+ virtual void valueChanged(SGPropertyNode * node);
+
+ /// Called if \a child has been added to the given \a parent.
+ virtual void childAdded(SGPropertyNode * parent, SGPropertyNode * child);
+
+ /// Called if \a child has been removed from its \a parent.
+ virtual void childRemoved(SGPropertyNode * parent, SGPropertyNode * child);
protected:
friend class SGPropertyNode;
* whether the property should normally be saved and restored.</p>
*/
enum Attribute {
+ NO_ATTR = 0,
READ = 1,
WRITE = 2,
ARCHIVE = 4,
simgear::PropertyList getChildren (const std::string& name) const
{ return getChildren(name.c_str()); }
+ /**
+ * Remove child by pointer (if it is a child of this node).
+ *
+ * @return true, if the node was deleted.
+ */
+ bool removeChild(SGPropertyNode* node);
+
+ // TODO do we need the removeXXX methods to return the deleted nodes?
/**
* Remove child by position.
*/
- SGPropertyNode_ptr removeChild (int pos, bool keep = true);
+ SGPropertyNode_ptr removeChild(int pos);
/**
* Remove a child node
*/
- SGPropertyNode_ptr removeChild (const char * name, int index = 0,
- bool keep = true);
+ SGPropertyNode_ptr removeChild(const char * name, int index = 0);
/**
* Remove a child node
*/
- SGPropertyNode_ptr removeChild (const std::string& name, int index = 0,
- bool keep = true)
- { return removeChild(name.c_str(), index, keep); }
+ SGPropertyNode_ptr removeChild(const std::string& name, int index = 0)
+ { return removeChild(name.c_str(), index); }
/**
* Remove all children with the specified name.
*/
- simgear::PropertyList removeChildren (const char * name, bool keep = true);
+ simgear::PropertyList removeChildren(const char * name);
/**
* Remove all children with the specified name.
*/
- simgear::PropertyList removeChildren (const std::string& name,
- bool keep = true)
- { return removeChildren(name.c_str(), keep); }
+ simgear::PropertyList removeChildren(const std::string& name)
+ { return removeChildren(name.c_str()); }
+
+ /**
+ * Remove all children (does not change the value of the node)
+ */
+ void removeAllChildren();
//
// Alias support.
return setValue(&val[0]);
}
+ /**
+ * Set relative node to given value and afterwards make read only.
+ *
+ * @param relative_path Path to node
+ * @param value Value to set
+ *
+ * @return whether value could be set
+ */
+ template<typename T>
+ bool setValueReadOnly(const std::string& relative_path, const T& value)
+ {
+ SGPropertyNode* node = getNode(relative_path, true);
+ bool ret = node->setValue(value);
+ node->setAttributes(READ);
+ return ret;
+ }
+
+#if !PROPS_STANDALONE
/**
* Interpolate current value to target value within given time.
*
*
* @param type Type of interpolation ("numeric", "color", etc.)
* @param values Nodes containing intermediate and target values
- * @param duration Durations for each interpolation step (in seconds)
+ * @param deltas Durations for each interpolation step (in seconds)
* @param easing Easing function (http://easings.net/)
*/
bool interpolate( const std::string& type,
*/
static void setInterpolationMgr(simgear::PropertyInterpolationMgr* mgr);
+ /**
+ * Get the interpolation manager
+ */
+ static simgear::PropertyInterpolationMgr* getInterpolationMgr();
+#endif
+
/**
* Print the value of the property to a stream.
*/
void fireChildAdded (SGPropertyNode * parent, SGPropertyNode * child);
void fireChildRemoved (SGPropertyNode * parent, SGPropertyNode * child);
+ SGPropertyNode_ptr eraseChild(simgear::PropertyList::iterator child);
+
/**
* Protected constructor for making new nodes on demand.
*/
/// counted pointer
SGPropertyNode * _parent;
simgear::PropertyList _children;
- simgear::PropertyList _removedChildren;
mutable std::string _buffer;
simgear::props::Type _type;
bool _tied;
SGPropertyNode * getChildImpl (Itr begin, Itr end, int index = 0, bool create = false);
// very internal method
template<typename Itr>
- SGPropertyNode* getExistingChild (Itr begin, Itr end, int index, bool create);
+ SGPropertyNode* getExistingChild (Itr begin, Itr end, int index);
// very internal path parsing function
template<typename SplitItr>
friend SGPropertyNode* find_node_aux(SGPropertyNode * current, SplitItr& itr,
// Convenience functions for use in templates
template<typename T>
-T getValue(const SGPropertyNode*);
+#if PROPS_STANDALONE
+T
+#else
+typename boost::disable_if<boost::is_enum<T>, T>::type
+#endif
+getValue(const SGPropertyNode*);
template<>
inline bool getValue<bool>(const SGPropertyNode* node) { return node->getBoolValue(); }
return node->getStringValue ();
}
+template<>
+inline std::string getValue<std::string>(const SGPropertyNode* node)
+{
+ return node->getStringValue();
+}
+
+namespace simgear
+{
+ /**
+ * Default trait for extracting enum values from SGPropertyNode. Create your
+ * own specialization for specific enum types to enable validation of values.
+ */
+ template<class T>
+ struct enum_traits
+ {
+ /**
+ * Typename of the enum
+ */
+ static const char* name() { return typeid(T).name(); }
+
+ /**
+ * @return Default value (will be used if validation fails)
+ */
+ static T defVal() { return T(); }
+
+ /**
+ * @return Whether the given integer value has an enum value defined
+ */
+ static bool validate(int) { return true; }
+ };
+} // namespace simgear
+
+/** Extract enum from SGPropertyNode */
+template<typename T>
+#if PROPS_STANDALONE
+inline T
+#else
+inline typename boost::enable_if<boost::is_enum<T>, T>::type
+#endif
+getValue(const SGPropertyNode* node)
+{
+ typedef simgear::enum_traits<T> Traits;
+ int val = node->getIntValue();
+ if( !Traits::validate(val) )
+ {
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "Invalid value for enum (" << Traits::name() << ", val = " << val << ")"
+ );
+ return Traits::defVal();
+ }
+ return static_cast<T>(node->getIntValue());
+}
+
inline bool setValue(SGPropertyNode* node, bool value)
{
return node->setBoolValue(value);
{
_property->addChangeListener(this,initial);
}
+
+ SGPropertyChangeCallback(const SGPropertyChangeCallback<T>& other) :
+ _obj(other._obj), _callback(other._callback), _property(other._property)
+ {
+ _property->addChangeListener(this,false);
+ }
+
virtual ~SGPropertyChangeCallback()
{
_property->removeChangeListener(this);