1 // props.cxx - implementation of a property list.
2 // Started Fall 2000 by David Megginson, david@megginson.com
3 // This code is released into the Public Domain.
5 // See props.html for documentation [replace with URL when available].
10 # include <simgear_config.h>
14 #include "PropertyInterpolationMgr.hxx"
15 #include "vectorPropTemplates.hxx"
27 #include <boost/algorithm/string/find_iterator.hpp>
28 #include <boost/algorithm/string/predicate.hpp>
29 #include <boost/algorithm/string/classification.hpp>
30 #include <boost/bind.hpp>
31 #include <boost/functional/hash.hpp>
32 #include <boost/range.hpp>
38 #include <simgear/compiler.h>
39 #include <simgear/debug/logstream.hxx>
41 #if ( _MSC_VER == 1200 )
42 // MSVC 6 is buggy, and needs something strange here
43 using std::vector<SGPropertyNode_ptr>;
44 using std::vector<SGPropertyChangeListener *>;
45 using std::vector<SGPropertyNode *>;
56 using std::stringstream;
58 using namespace simgear;
60 ////////////////////////////////////////////////////////////////////////
62 ////////////////////////////////////////////////////////////////////////
65 * Comparator class for sorting by index.
70 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
71 return (n1->getIndex() < n2->getIndex());
76 ////////////////////////////////////////////////////////////////////////
77 // Convenience macros for value access.
78 ////////////////////////////////////////////////////////////////////////
80 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
81 #define TEST_WRITE if (!getAttribute(WRITE)) return false
83 ////////////////////////////////////////////////////////////////////////
84 // Local path normalization code.
85 ////////////////////////////////////////////////////////////////////////
88 * Parse the name for a path component.
90 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
93 template<typename Range>
95 parse_name (const SGPropertyNode *node, const Range &path)
97 typename Range::iterator i = path.begin();
98 typename Range::iterator max = path.end();
102 if (i != path.end() && *i == '.') {
105 if (i != max && *i != '/')
106 throw std::string("illegal character after . or ..");
107 } else if (isalpha(*i) || *i == '_') {
110 // The rules inside a name are a little
113 if (isalpha(*i) || isdigit(*i) || *i == '_' ||
114 *i == '-' || *i == '.') {
116 } else if (*i == '[' || *i == '/') {
119 std::string err = "'";
121 err.append("' found in propertyname after '"+node->getNameString()+"'");
122 err.append("\nname may contain only ._- and alphanumeric characters");
130 if (path.begin() == i) {
131 std::string err = "'";
133 err.append("' found in propertyname after '"+node->getNameString()+"'");
134 err.append("\nname must begin with alpha or '_'");
138 return Range(path.begin(), i);
141 // Validate the name of a single node
142 inline bool validateName(const std::string& name)
144 using namespace boost;
147 if (!isalpha(name[0]) && name[0] != '_')
149 return all(make_iterator_range(name.begin(), name.end()),
150 is_alnum() || is_any_of("_-."));
153 ////////////////////////////////////////////////////////////////////////
154 // Other static utility functions.
155 ////////////////////////////////////////////////////////////////////////
159 copy_string (const char * s)
161 size_t slen = strlen(s);
162 char * copy = new char[slen + 1];
164 // the source string length is known so no need to check for '\0'
165 // when copying every single character
166 memcpy(copy, s, slen);
167 *(copy + slen) = '\0';
172 compare_strings (const char * s1, const char * s2)
174 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
178 * Locate a child node by name and index.
180 template<typename Itr>
182 find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
184 size_t nNodes = nodes.size();
185 boost::iterator_range<Itr> name(begin, end);
186 for (size_t i = 0; i < nNodes; i++) {
187 SGPropertyNode * node = nodes[i];
189 // searching for a matching index is a lot less time consuming than
190 // comparing two strings so do that first.
191 if (node->getIndex() == index && boost::equals(node->getName(), name))
192 return static_cast<int>(i);
198 * Locate the child node with the highest index of the same name
201 find_last_child (const char * name, const PropertyList& nodes)
203 size_t nNodes = nodes.size();
206 for (size_t i = 0; i < nNodes; i++) {
207 SGPropertyNode * node = nodes[i];
208 if (compare_strings(node->getName(), name))
210 int idx = node->getIndex();
211 if (idx > index) index = idx;
218 * Get first unused index for child nodes with the given name
221 first_unused_index( const char * name,
222 const PropertyList& nodes,
225 const char* nameEnd = name + strlen(name);
227 for( int index = min_index; index < std::numeric_limits<int>::max(); ++index )
229 if( find_child(name, nameEnd, index, nodes) < 0 )
233 SG_LOG(SG_GENERAL, SG_ALERT, "Too many nodes: " << name);
237 template<typename Itr>
238 inline SGPropertyNode*
239 SGPropertyNode::getExistingChild (Itr begin, Itr end, int index)
241 int pos = find_child(begin, end, index, _children);
243 return _children[pos];
247 template<typename Itr>
249 SGPropertyNode::getChildImpl (Itr begin, Itr end, int index, bool create)
251 SGPropertyNode* node = getExistingChild(begin, end, index);
256 node = new SGPropertyNode(begin, end, index, this);
257 _children.push_back(node);
258 fireChildAdded(node);
265 template<typename SplitItr>
267 find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
270 typedef typename SplitItr::value_type Range;
271 // Run off the end of the list
276 // Success! This is the one we want.
280 // Empty name at this point is empty, not root.
282 return find_node_aux(current, ++itr, create, last_index);
283 Range name = parse_name(current, token);
284 if (equals(name, "."))
285 return find_node_aux(current, ++itr, create, last_index);
286 if (equals(name, "..")) {
287 SGPropertyNode * parent = current->getParent();
289 throw std::string("attempt to move past root with '..'");
290 return find_node_aux(parent, ++itr, create, last_index);
293 if (last_index >= 0) {
294 // If we are at the last token and last_index is valid, use
295 // last_index as the index value
297 while (!(++itr).eof()) {
311 if (name.end() != token.end()) {
312 if (*name.end() == '[') {
313 typename Range::iterator i = name.end() + 1, end = token.end();
314 for (;i != end; ++i) {
316 index = (index * 10) + (*i - '0');
321 if (i == token.end() || *i != ']')
322 throw std::string("unterminated index (looking for ']')");
324 throw std::string("illegal characters in token: ")
325 + std::string(name.begin(), name.end());
329 return find_node_aux(current->getChildImpl(name.begin(), name.end(),
330 index, create), itr, create,
334 // Internal function for parsing property paths. last_index provides
335 // and index value for the last node name token, if supplied.
336 template<typename Range>
338 find_node (SGPropertyNode * current,
343 using namespace boost;
344 typedef split_iterator<typename range_result_iterator<Range>::type>
347 PathSplitIterator itr
348 = make_split_iterator(path, first_finder("/", is_equal()));
349 if (*path.begin() == '/')
350 return find_node_aux(current->getRootNode(), itr, create, last_index);
352 return find_node_aux(current, itr, create, last_index);
355 ////////////////////////////////////////////////////////////////////////
356 // Private methods from SGPropertyNode (may be inlined for speed).
357 ////////////////////////////////////////////////////////////////////////
360 SGPropertyNode::get_bool () const
363 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
365 return _local_val.bool_val;
369 SGPropertyNode::get_int () const
372 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
374 return _local_val.int_val;
378 SGPropertyNode::get_long () const
381 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
383 return _local_val.long_val;
387 SGPropertyNode::get_float () const
390 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
392 return _local_val.float_val;
396 SGPropertyNode::get_double () const
399 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
401 return _local_val.double_val;
405 SGPropertyNode::get_string () const
408 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
410 return _local_val.string_val;
414 SGPropertyNode::set_bool (bool val)
417 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
424 _local_val.bool_val = val;
431 SGPropertyNode::set_int (int val)
434 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
441 _local_val.int_val = val;
448 SGPropertyNode::set_long (long val)
451 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
458 _local_val.long_val = val;
465 SGPropertyNode::set_float (float val)
468 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
475 _local_val.float_val = val;
482 SGPropertyNode::set_double (double val)
485 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
492 _local_val.double_val = val;
499 SGPropertyNode::set_string (const char * val)
502 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
509 delete [] _local_val.string_val;
510 _local_val.string_val = copy_string(val);
517 SGPropertyNode::clearValue ()
519 if (_type == props::ALIAS) {
522 } else if (_type != props::NONE) {
525 _local_val.bool_val = SGRawValue<bool>::DefaultValue();
528 _local_val.int_val = SGRawValue<int>::DefaultValue();
531 _local_val.long_val = SGRawValue<long>::DefaultValue();
534 _local_val.float_val = SGRawValue<float>::DefaultValue();
537 _local_val.double_val = SGRawValue<double>::DefaultValue();
540 case props::UNSPECIFIED:
542 delete [] _local_val.string_val;
544 _local_val.string_val = 0;
546 default: // avoid compiler warning
558 * Get the value as a string.
561 SGPropertyNode::make_string () const
563 if (!getAttribute(READ))
567 return _value.alias->getStringValue();
569 return get_bool() ? "true" : "false";
571 case props::UNSPECIFIED:
590 sstr << std::setprecision(10) << get_double();
592 case props::EXTENDED:
594 props::Type realType = _value.val->getType();
595 // Perhaps this should be done for all types?
596 if (realType == props::VEC3D || realType == props::VEC4D)
598 static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
604 _buffer = sstr.str();
605 return _buffer.c_str();
609 * Trace a write access for a property.
612 SGPropertyNode::trace_write () const
615 cerr << "TRACE: Write node " << getPath () << ", value \""
616 << make_string() << '"' << endl;
618 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
619 << ", value \"" << make_string() << '"');
624 * Trace a read access for a property.
627 SGPropertyNode::trace_read () const
630 cerr << "TRACE: Write node " << getPath () << ", value \""
631 << make_string() << '"' << endl;
633 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
634 << ", value \"" << make_string() << '"');
638 ////////////////////////////////////////////////////////////////////////
639 // Public methods from SGPropertyNode.
640 ////////////////////////////////////////////////////////////////////////
643 * Last used attribute
644 * Update as needed when enum Attribute is changed
646 const int SGPropertyNode::LAST_USED_ATTRIBUTE = PRESERVE;
649 * Default constructor: always creates a root node.
651 SGPropertyNode::SGPropertyNode ()
659 _local_val.string_val = 0;
667 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
668 : SGReferenced(node),
671 _parent(0), // don't copy the parent
675 _listeners(0) // CHECK!!
677 _local_val.string_val = 0;
679 if (_type == props::NONE)
681 if (_type == props::ALIAS) {
682 _value.alias = node._value.alias;
687 if (_tied || _type == props::EXTENDED) {
688 _value.val = node._value.val->clone();
693 set_bool(node.get_bool());
696 set_int(node.get_int());
699 set_long(node.get_long());
702 set_float(node.get_float());
705 set_double(node.get_double());
708 case props::UNSPECIFIED:
709 set_string(node.get_string());
718 * Convenience constructor.
720 template<typename Itr>
721 SGPropertyNode::SGPropertyNode (Itr begin, Itr end,
723 SGPropertyNode * parent)
732 _local_val.string_val = 0;
734 if (!validateName(_name))
735 throw std::string("plain name expected instead of '") + _name + '\'';
738 SGPropertyNode::SGPropertyNode( const std::string& name,
740 SGPropertyNode * parent)
749 _local_val.string_val = 0;
751 if (!validateName(name))
752 throw std::string("plain name expected instead of '") + _name + '\'';
758 SGPropertyNode::~SGPropertyNode ()
760 // zero out all parent pointers, else they might be dangling
761 for (unsigned i = 0; i < _children.size(); ++i)
762 _children[i]->_parent = 0;
766 vector<SGPropertyChangeListener*>::iterator it;
767 for (it = _listeners->begin(); it != _listeners->end(); ++it)
768 (*it)->unregister_property(this);
775 * Alias to another node.
778 SGPropertyNode::alias (SGPropertyNode * target)
780 if (target && (_type != props::ALIAS) && (!_tied))
784 _value.alias = target;
785 _type = props::ALIAS;
793 SG_LOG(SG_GENERAL, SG_ALERT,
794 "Failed to create alias for " << getPath() << ". "
795 "The target property does not exist.");
798 if (_type == props::ALIAS)
800 if (_value.alias == target)
801 return true; // ok, identical alias requested
802 SG_LOG(SG_GENERAL, SG_ALERT,
803 "Failed to create alias at " << target->getPath() << ". "
804 "Source "<< getPath() << " is already aliasing another property.");
809 SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
810 "Source " << getPath() << " is a tied property.");
819 * Alias to another node by path.
822 SGPropertyNode::alias (const char * path)
824 return alias(getNode(path, true));
832 SGPropertyNode::unalias ()
834 if (_type != props::ALIAS)
842 * Get the target of an alias.
845 SGPropertyNode::getAliasTarget ()
847 return (_type == props::ALIAS ? _value.alias : 0);
851 const SGPropertyNode *
852 SGPropertyNode::getAliasTarget () const
854 return (_type == props::ALIAS ? _value.alias : 0);
858 * create a non-const child by name after the last node with the same name.
861 SGPropertyNode::addChild(const char * name, int min_index, bool append)
864 ? std::max(find_last_child(name, _children) + 1, min_index)
865 : first_unused_index(name, _children, min_index);
867 SGPropertyNode_ptr node;
868 node = new SGPropertyNode(name, name + strlen(name), pos, this);
869 _children.push_back(node);
870 fireChildAdded(node);
875 * Create multiple children with unused indices
877 simgear::PropertyList
878 SGPropertyNode::addChildren( const std::string& name,
883 simgear::PropertyList nodes;
884 std::set<int> used_indices;
888 // First grab all used indices. This saves us of testing every index if it
889 // is used for every element to be created
890 for( size_t i = 0; i < nodes.size(); i++ )
892 const SGPropertyNode* node = nodes[i];
894 if( node->getNameString() == name && node->getIndex() >= min_index )
895 used_indices.insert(node->getIndex());
900 // If we don't want to fill the holes just find last node
901 min_index = std::max(find_last_child(name.c_str(), _children) + 1, min_index);
904 for( int index = min_index;
905 index < std::numeric_limits<int>::max() && nodes.size() < count;
908 if( used_indices.find(index) == used_indices.end() )
910 SGPropertyNode_ptr node;
911 node = new SGPropertyNode(name, index, this);
912 _children.push_back(node);
913 fireChildAdded(node);
914 nodes.push_back(node);
922 * Get a non-const child by index.
925 SGPropertyNode::getChild (int position)
927 if (position >= 0 && position < nChildren())
928 return _children[position];
935 * Get a const child by index.
937 const SGPropertyNode *
938 SGPropertyNode::getChild (int position) const
940 if (position >= 0 && position < nChildren())
941 return _children[position];
948 * Get a non-const child by name and index, creating if necessary.
952 SGPropertyNode::getChild (const char * name, int index, bool create)
954 return getChildImpl(name, name + strlen(name), index, create);
958 SGPropertyNode::getChild (const std::string& name, int index, bool create)
960 SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
964 node = new SGPropertyNode(name, index, this);
965 _children.push_back(node);
966 fireChildAdded(node);
974 * Get a const child by name and index.
976 const SGPropertyNode *
977 SGPropertyNode::getChild (const char * name, int index) const
979 int pos = find_child(name, name + strlen(name), index, _children);
981 return _children[pos];
988 * Get all children with the same name (but different indices).
991 SGPropertyNode::getChildren (const char * name) const
993 PropertyList children;
994 size_t max = _children.size();
996 for (size_t i = 0; i < max; i++)
997 if (compare_strings(_children[i]->getName(), name))
998 children.push_back(_children[i]);
1000 sort(children.begin(), children.end(), CompareIndices());
1004 //------------------------------------------------------------------------------
1005 bool SGPropertyNode::removeChild(SGPropertyNode* node)
1007 if( node->_parent != this )
1010 PropertyList::iterator it =
1011 std::find(_children.begin(), _children.end(), node);
1012 if( it == _children.end() )
1019 //------------------------------------------------------------------------------
1020 SGPropertyNode_ptr SGPropertyNode::removeChild(int pos)
1022 if (pos < 0 || pos >= (int)_children.size())
1023 return SGPropertyNode_ptr();
1025 return eraseChild(_children.begin() + pos);
1030 * Remove a child node
1033 SGPropertyNode::removeChild(const char * name, int index)
1035 SGPropertyNode_ptr ret;
1036 int pos = find_child(name, name + strlen(name), index, _children);
1038 ret = removeChild(pos);
1044 * Remove all children with the specified name.
1047 SGPropertyNode::removeChildren(const char * name)
1049 PropertyList children;
1051 for (int pos = static_cast<int>(_children.size() - 1); pos >= 0; pos--)
1052 if (compare_strings(_children[pos]->getName(), name))
1053 children.push_back(removeChild(pos));
1055 sort(children.begin(), children.end(), CompareIndices());
1060 SGPropertyNode::removeAllChildren()
1062 for(unsigned i = 0; i < _children.size(); ++i)
1064 SGPropertyNode_ptr& node = _children[i];
1066 node->setAttribute(REMOVED, true);
1068 fireChildRemoved(node);
1075 SGPropertyNode::getDisplayName (bool simplify) const
1077 std::string display_name = _name;
1078 if (_index != 0 || !simplify) {
1080 sstr << '[' << _index << ']';
1081 display_name += sstr.str();
1083 return display_name;
1087 SGPropertyNode::getPath (bool simplify) const
1089 typedef std::vector<SGConstPropertyNode_ptr> PList;
1091 for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
1092 pathList.push_back(node);
1094 for (PList::reverse_iterator itr = pathList.rbegin(),
1095 rend = pathList.rend();
1099 result += (*itr)->getDisplayName(simplify);
1105 SGPropertyNode::getType () const
1107 if (_type == props::ALIAS)
1108 return _value.alias->getType();
1109 else if (_type == props::EXTENDED)
1110 return _value.val->getType();
1117 SGPropertyNode::getBoolValue () const
1119 // Shortcut for common case
1120 if (_attr == (READ|WRITE) && _type == props::BOOL)
1123 if (getAttribute(TRACE_READ))
1125 if (!getAttribute(READ))
1126 return SGRawValue<bool>::DefaultValue();
1129 return _value.alias->getBoolValue();
1133 return get_int() == 0 ? false : true;
1135 return get_long() == 0L ? false : true;
1137 return get_float() == 0.0 ? false : true;
1139 return get_double() == 0.0L ? false : true;
1141 case props::UNSPECIFIED:
1142 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1145 return SGRawValue<bool>::DefaultValue();
1150 SGPropertyNode::getIntValue () const
1152 // Shortcut for common case
1153 if (_attr == (READ|WRITE) && _type == props::INT)
1156 if (getAttribute(TRACE_READ))
1158 if (!getAttribute(READ))
1159 return SGRawValue<int>::DefaultValue();
1162 return _value.alias->getIntValue();
1164 return int(get_bool());
1168 return int(get_long());
1170 return int(get_float());
1172 return int(get_double());
1174 case props::UNSPECIFIED:
1175 return atoi(get_string());
1178 return SGRawValue<int>::DefaultValue();
1183 SGPropertyNode::getLongValue () const
1185 // Shortcut for common case
1186 if (_attr == (READ|WRITE) && _type == props::LONG)
1189 if (getAttribute(TRACE_READ))
1191 if (!getAttribute(READ))
1192 return SGRawValue<long>::DefaultValue();
1195 return _value.alias->getLongValue();
1197 return long(get_bool());
1199 return long(get_int());
1203 return long(get_float());
1205 return long(get_double());
1207 case props::UNSPECIFIED:
1208 return strtol(get_string(), 0, 0);
1211 return SGRawValue<long>::DefaultValue();
1216 SGPropertyNode::getFloatValue () const
1218 // Shortcut for common case
1219 if (_attr == (READ|WRITE) && _type == props::FLOAT)
1222 if (getAttribute(TRACE_READ))
1224 if (!getAttribute(READ))
1225 return SGRawValue<float>::DefaultValue();
1228 return _value.alias->getFloatValue();
1230 return float(get_bool());
1232 return float(get_int());
1234 return float(get_long());
1238 return float(get_double());
1240 case props::UNSPECIFIED:
1241 return atof(get_string());
1244 return SGRawValue<float>::DefaultValue();
1249 SGPropertyNode::getDoubleValue () const
1251 // Shortcut for common case
1252 if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1253 return get_double();
1255 if (getAttribute(TRACE_READ))
1257 if (!getAttribute(READ))
1258 return SGRawValue<double>::DefaultValue();
1262 return _value.alias->getDoubleValue();
1264 return double(get_bool());
1266 return double(get_int());
1268 return double(get_long());
1270 return double(get_float());
1272 return get_double();
1274 case props::UNSPECIFIED:
1275 return strtod(get_string(), 0);
1278 return SGRawValue<double>::DefaultValue();
1283 SGPropertyNode::getStringValue () const
1285 // Shortcut for common case
1286 if (_attr == (READ|WRITE) && _type == props::STRING)
1287 return get_string();
1289 if (getAttribute(TRACE_READ))
1291 if (!getAttribute(READ))
1292 return SGRawValue<const char *>::DefaultValue();
1293 return make_string();
1297 SGPropertyNode::setBoolValue (bool value)
1299 // Shortcut for common case
1300 if (_attr == (READ|WRITE) && _type == props::BOOL)
1301 return set_bool(value);
1303 bool result = false;
1305 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1308 _type = props::BOOL;
1313 result = _value.alias->setBoolValue(value);
1316 result = set_bool(value);
1319 result = set_int(int(value));
1322 result = set_long(long(value));
1325 result = set_float(float(value));
1328 result = set_double(double(value));
1331 case props::UNSPECIFIED:
1332 result = set_string(value ? "true" : "false");
1339 if (getAttribute(TRACE_WRITE))
1345 SGPropertyNode::setIntValue (int value)
1347 // Shortcut for common case
1348 if (_attr == (READ|WRITE) && _type == props::INT)
1349 return set_int(value);
1351 bool result = false;
1353 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1356 _local_val.int_val = 0;
1361 result = _value.alias->setIntValue(value);
1364 result = set_bool(value == 0 ? false : true);
1367 result = set_int(value);
1370 result = set_long(long(value));
1373 result = set_float(float(value));
1376 result = set_double(double(value));
1379 case props::UNSPECIFIED: {
1381 sprintf(buf, "%d", value);
1382 result = set_string(buf);
1390 if (getAttribute(TRACE_WRITE))
1396 SGPropertyNode::setLongValue (long value)
1398 // Shortcut for common case
1399 if (_attr == (READ|WRITE) && _type == props::LONG)
1400 return set_long(value);
1402 bool result = false;
1404 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1406 _type = props::LONG;
1407 _local_val.long_val = 0L;
1412 result = _value.alias->setLongValue(value);
1415 result = set_bool(value == 0L ? false : true);
1418 result = set_int(int(value));
1421 result = set_long(value);
1424 result = set_float(float(value));
1427 result = set_double(double(value));
1430 case props::UNSPECIFIED: {
1432 sprintf(buf, "%ld", value);
1433 result = set_string(buf);
1441 if (getAttribute(TRACE_WRITE))
1447 SGPropertyNode::setFloatValue (float value)
1449 // Shortcut for common case
1450 if (_attr == (READ|WRITE) && _type == props::FLOAT)
1451 return set_float(value);
1453 bool result = false;
1455 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1457 _type = props::FLOAT;
1458 _local_val.float_val = 0;
1463 result = _value.alias->setFloatValue(value);
1466 result = set_bool(value == 0.0 ? false : true);
1469 result = set_int(int(value));
1472 result = set_long(long(value));
1475 result = set_float(value);
1478 result = set_double(double(value));
1481 case props::UNSPECIFIED: {
1483 sprintf(buf, "%f", value);
1484 result = set_string(buf);
1492 if (getAttribute(TRACE_WRITE))
1498 SGPropertyNode::setDoubleValue (double value)
1500 // Shortcut for common case
1501 if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1502 return set_double(value);
1504 bool result = false;
1506 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1508 _local_val.double_val = value;
1509 _type = props::DOUBLE;
1514 result = _value.alias->setDoubleValue(value);
1517 result = set_bool(value == 0.0L ? false : true);
1520 result = set_int(int(value));
1523 result = set_long(long(value));
1526 result = set_float(float(value));
1529 result = set_double(value);
1532 case props::UNSPECIFIED: {
1534 sprintf(buf, "%f", value);
1535 result = set_string(buf);
1543 if (getAttribute(TRACE_WRITE))
1549 SGPropertyNode::setStringValue (const char * value)
1551 // Shortcut for common case
1552 if (_attr == (READ|WRITE) && _type == props::STRING)
1553 return set_string(value);
1555 bool result = false;
1557 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1559 _type = props::STRING;
1564 result = _value.alias->setStringValue(value);
1567 result = set_bool((compare_strings(value, "true")
1568 || atoi(value)) ? true : false);
1571 result = set_int(atoi(value));
1574 result = set_long(strtol(value, 0, 0));
1577 result = set_float(atof(value));
1580 result = set_double(strtod(value, 0));
1583 case props::UNSPECIFIED:
1584 result = set_string(value);
1586 case props::EXTENDED:
1588 stringstream sstr(value);
1589 static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1597 if (getAttribute(TRACE_WRITE))
1603 SGPropertyNode::setUnspecifiedValue (const char * value)
1605 bool result = false;
1607 if (_type == props::NONE) {
1609 _type = props::UNSPECIFIED;
1611 props::Type type = _type;
1612 if (type == props::EXTENDED)
1613 type = _value.val->getType();
1616 result = _value.alias->setUnspecifiedValue(value);
1619 result = set_bool((compare_strings(value, "true")
1620 || atoi(value)) ? true : false);
1623 result = set_int(atoi(value));
1626 result = set_long(strtol(value, 0, 0));
1629 result = set_float(atof(value));
1632 result = set_double(strtod(value, 0));
1635 case props::UNSPECIFIED:
1636 result = set_string(value);
1639 result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1642 result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1649 if (getAttribute(TRACE_WRITE))
1654 //------------------------------------------------------------------------------
1655 bool SGPropertyNode::interpolate( const std::string& type,
1656 const SGPropertyNode& target,
1658 const std::string& easing )
1660 if( !_interpolation_mgr )
1662 SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
1664 // no interpolation possible -> set to target immediately
1665 setUnspecifiedValue( target.getStringValue() );
1669 return _interpolation_mgr->interpolate(this, type, target, duration, easing);
1672 //------------------------------------------------------------------------------
1673 bool SGPropertyNode::interpolate( const std::string& type,
1674 const simgear::PropertyList& values,
1675 const double_list& deltas,
1676 const std::string& easing )
1678 if( !_interpolation_mgr )
1680 SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
1682 // no interpolation possible -> set to last value immediately
1683 if( !values.empty() )
1684 setUnspecifiedValue(values.back()->getStringValue());
1688 return _interpolation_mgr->interpolate(this, type, values, deltas, easing);
1691 //------------------------------------------------------------------------------
1692 void SGPropertyNode::setInterpolationMgr(simgear::PropertyInterpolationMgr* mgr)
1694 _interpolation_mgr = mgr;
1697 //------------------------------------------------------------------------------
1698 simgear::PropertyInterpolationMgr* SGPropertyNode::getInterpolationMgr()
1700 return _interpolation_mgr;
1703 simgear::PropertyInterpolationMgr* SGPropertyNode::_interpolation_mgr = 0;
1705 //------------------------------------------------------------------------------
1706 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1708 if (!getAttribute(READ))
1712 return _value.alias->printOn(stream);
1714 stream << (get_bool() ? "true" : "false");
1717 stream << get_int();
1720 stream << get_long();
1723 stream << get_float();
1726 stream << get_double();
1729 case props::UNSPECIFIED:
1730 stream << get_string();
1732 case props::EXTENDED:
1733 static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1737 default: // avoid compiler warning
1744 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1747 if (_type == props::ALIAS || _tied)
1750 useDefault = useDefault && hasValue();
1751 std::string old_val;
1753 old_val = getStringValue();
1755 _type = props::STRING;
1757 _value.val = rawValue.clone();
1760 int save_attributes = getAttributes();
1761 setAttribute( WRITE, true );
1762 setStringValue(old_val.c_str());
1763 setAttributes( save_attributes );
1769 SGPropertyNode::untie ()
1776 bool val = getBoolValue();
1778 _type = props::BOOL;
1779 _local_val.bool_val = val;
1783 int val = getIntValue();
1786 _local_val.int_val = val;
1790 long val = getLongValue();
1792 _type = props::LONG;
1793 _local_val.long_val = val;
1796 case props::FLOAT: {
1797 float val = getFloatValue();
1799 _type = props::FLOAT;
1800 _local_val.float_val = val;
1803 case props::DOUBLE: {
1804 double val = getDoubleValue();
1806 _type = props::DOUBLE;
1807 _local_val.double_val = val;
1811 case props::UNSPECIFIED: {
1812 std::string val = getStringValue();
1814 _type = props::STRING;
1815 _local_val.string_val = copy_string(val.c_str());
1818 case props::EXTENDED: {
1819 SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1820 _value.val = 0; // Prevent clearValue() from deleting
1822 _type = props::EXTENDED;
1823 _value.val = val->makeContainer();
1837 SGPropertyNode::getRootNode ()
1842 return _parent->getRootNode();
1845 const SGPropertyNode *
1846 SGPropertyNode::getRootNode () const
1851 return _parent->getRootNode();
1855 SGPropertyNode::getNode (const char * relative_path, bool create)
1857 using namespace boost;
1859 return find_node(this, make_iterator_range(relative_path, relative_path
1860 + strlen(relative_path)),
1865 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1867 using namespace boost;
1868 return find_node(this, make_iterator_range(relative_path, relative_path
1869 + strlen(relative_path)),
1873 const SGPropertyNode *
1874 SGPropertyNode::getNode (const char * relative_path) const
1876 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1879 const SGPropertyNode *
1880 SGPropertyNode::getNode (const char * relative_path, int index) const
1882 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1885 ////////////////////////////////////////////////////////////////////////
1886 // Convenience methods using relative paths.
1887 ////////////////////////////////////////////////////////////////////////
1891 * Test whether another node has a value attached.
1894 SGPropertyNode::hasValue (const char * relative_path) const
1896 const SGPropertyNode * node = getNode(relative_path);
1897 return (node == 0 ? false : node->hasValue());
1902 * Get the value type for another node.
1905 SGPropertyNode::getType (const char * relative_path) const
1907 const SGPropertyNode * node = getNode(relative_path);
1908 return (node == 0 ? props::UNSPECIFIED : node->getType());
1913 * Get a bool value for another node.
1916 SGPropertyNode::getBoolValue (const char * relative_path,
1917 bool defaultValue) const
1919 const SGPropertyNode * node = getNode(relative_path);
1920 return (node == 0 ? defaultValue : node->getBoolValue());
1925 * Get an int value for another node.
1928 SGPropertyNode::getIntValue (const char * relative_path,
1929 int defaultValue) const
1931 const SGPropertyNode * node = getNode(relative_path);
1932 return (node == 0 ? defaultValue : node->getIntValue());
1937 * Get a long value for another node.
1940 SGPropertyNode::getLongValue (const char * relative_path,
1941 long defaultValue) const
1943 const SGPropertyNode * node = getNode(relative_path);
1944 return (node == 0 ? defaultValue : node->getLongValue());
1949 * Get a float value for another node.
1952 SGPropertyNode::getFloatValue (const char * relative_path,
1953 float defaultValue) const
1955 const SGPropertyNode * node = getNode(relative_path);
1956 return (node == 0 ? defaultValue : node->getFloatValue());
1961 * Get a double value for another node.
1964 SGPropertyNode::getDoubleValue (const char * relative_path,
1965 double defaultValue) const
1967 const SGPropertyNode * node = getNode(relative_path);
1968 return (node == 0 ? defaultValue : node->getDoubleValue());
1973 * Get a string value for another node.
1976 SGPropertyNode::getStringValue (const char * relative_path,
1977 const char * defaultValue) const
1979 const SGPropertyNode * node = getNode(relative_path);
1980 return (node == 0 ? defaultValue : node->getStringValue());
1985 * Set a bool value for another node.
1988 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1990 return getNode(relative_path, true)->setBoolValue(value);
1995 * Set an int value for another node.
1998 SGPropertyNode::setIntValue (const char * relative_path, int value)
2000 return getNode(relative_path, true)->setIntValue(value);
2005 * Set a long value for another node.
2008 SGPropertyNode::setLongValue (const char * relative_path, long value)
2010 return getNode(relative_path, true)->setLongValue(value);
2015 * Set a float value for another node.
2018 SGPropertyNode::setFloatValue (const char * relative_path, float value)
2020 return getNode(relative_path, true)->setFloatValue(value);
2025 * Set a double value for another node.
2028 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
2030 return getNode(relative_path, true)->setDoubleValue(value);
2035 * Set a string value for another node.
2038 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
2040 return getNode(relative_path, true)->setStringValue(value);
2045 * Set an unknown value for another node.
2048 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
2051 return getNode(relative_path, true)->setUnspecifiedValue(value);
2056 * Test whether another node is tied.
2059 SGPropertyNode::isTied (const char * relative_path) const
2061 const SGPropertyNode * node = getNode(relative_path);
2062 return (node == 0 ? false : node->isTied());
2067 * Tie a node reached by a relative path, creating it if necessary.
2070 SGPropertyNode::tie (const char * relative_path,
2071 const SGRawValue<bool> &rawValue,
2074 return getNode(relative_path, true)->tie(rawValue, useDefault);
2079 * Tie a node reached by a relative path, creating it if necessary.
2082 SGPropertyNode::tie (const char * relative_path,
2083 const SGRawValue<int> &rawValue,
2086 return getNode(relative_path, true)->tie(rawValue, useDefault);
2091 * Tie a node reached by a relative path, creating it if necessary.
2094 SGPropertyNode::tie (const char * relative_path,
2095 const SGRawValue<long> &rawValue,
2098 return getNode(relative_path, true)->tie(rawValue, useDefault);
2103 * Tie a node reached by a relative path, creating it if necessary.
2106 SGPropertyNode::tie (const char * relative_path,
2107 const SGRawValue<float> &rawValue,
2110 return getNode(relative_path, true)->tie(rawValue, useDefault);
2115 * Tie a node reached by a relative path, creating it if necessary.
2118 SGPropertyNode::tie (const char * relative_path,
2119 const SGRawValue<double> &rawValue,
2122 return getNode(relative_path, true)->tie(rawValue, useDefault);
2127 * Tie a node reached by a relative path, creating it if necessary.
2130 SGPropertyNode::tie (const char * relative_path,
2131 const SGRawValue<const char *> &rawValue,
2134 return getNode(relative_path, true)->tie(rawValue, useDefault);
2139 * Attempt to untie another node reached by a relative path.
2142 SGPropertyNode::untie (const char * relative_path)
2144 SGPropertyNode * node = getNode(relative_path);
2145 return (node == 0 ? false : node->untie());
2149 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2152 if (_listeners == 0)
2153 _listeners = new vector<SGPropertyChangeListener*>;
2154 _listeners->push_back(listener);
2155 listener->register_property(this);
2157 listener->valueChanged(this);
2161 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2163 if (_listeners == 0)
2165 vector<SGPropertyChangeListener*>::iterator it =
2166 find(_listeners->begin(), _listeners->end(), listener);
2167 if (it != _listeners->end()) {
2168 _listeners->erase(it);
2169 listener->unregister_property(this);
2170 if (_listeners->empty()) {
2171 vector<SGPropertyChangeListener*>* tmp = _listeners;
2179 SGPropertyNode::fireValueChanged ()
2181 fireValueChanged(this);
2185 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2187 fireChildAdded(this, child);
2191 SGPropertyNode::fireCreatedRecursive(bool fire_self)
2195 _parent->fireChildAdded(this);
2197 if( _children.empty() && getType() != simgear::props::NONE )
2198 return fireValueChanged();
2201 for(size_t i = 0; i < _children.size(); ++i)
2202 _children[i]->fireCreatedRecursive(true);
2206 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2208 fireChildRemoved(this, child);
2212 SGPropertyNode::fireChildrenRemovedRecursive()
2214 for(size_t i = 0; i < _children.size(); ++i)
2216 SGPropertyNode* child = _children[i];
2217 fireChildRemoved(this, child);
2218 child->fireChildrenRemovedRecursive();
2223 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2225 if (_listeners != 0) {
2226 for (unsigned int i = 0; i < _listeners->size(); i++) {
2227 (*_listeners)[i]->valueChanged(node);
2231 _parent->fireValueChanged(node);
2235 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2236 SGPropertyNode * child)
2238 if (_listeners != 0) {
2239 for (unsigned int i = 0; i < _listeners->size(); i++) {
2240 (*_listeners)[i]->childAdded(parent, child);
2244 _parent->fireChildAdded(parent, child);
2248 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2249 SGPropertyNode * child)
2251 if (_listeners != 0) {
2252 for (unsigned int i = 0; i < _listeners->size(); i++) {
2253 (*_listeners)[i]->childRemoved(parent, child);
2257 _parent->fireChildRemoved(parent, child);
2260 //------------------------------------------------------------------------------
2262 SGPropertyNode::eraseChild(simgear::PropertyList::iterator child)
2264 SGPropertyNode_ptr node = *child;
2265 node->setAttribute(REMOVED, true);
2267 fireChildRemoved(node);
2269 _children.erase(child);
2273 ////////////////////////////////////////////////////////////////////////
2274 // Implementation of SGPropertyChangeListener.
2275 ////////////////////////////////////////////////////////////////////////
2277 SGPropertyChangeListener::~SGPropertyChangeListener ()
2279 for (int i = static_cast<int>(_properties.size() - 1); i >= 0; i--)
2280 _properties[i]->removeChangeListener(this);
2284 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2290 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2291 SGPropertyNode * child)
2297 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2298 SGPropertyNode * child)
2304 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2306 _properties.push_back(node);
2310 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2312 vector<SGPropertyNode *>::iterator it =
2313 find(_properties.begin(), _properties.end(), node);
2314 if (it != _properties.end())
2315 _properties.erase(it);
2319 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2322 = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2323 for (int i = 0; i < 3; ++i) {
2334 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2336 for (int i = 0; i < 3; ++i) {
2337 stream >> result[i];
2343 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2346 = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();
2347 for (int i = 0; i < 4; ++i) {
2358 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2360 for (int i = 0; i < 4; ++i) {
2361 stream >> result[i];
2368 bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
2370 props::Type ltype = lhs.getType();
2371 props::Type rtype = rhs.getType();
2378 return false; // XXX Should we look in aliases?
2380 return lhs.getValue<bool>() == rhs.getValue<bool>();
2382 return lhs.getValue<int>() == rhs.getValue<int>();
2384 return lhs.getValue<long>() == rhs.getValue<long>();
2386 return lhs.getValue<float>() == rhs.getValue<float>();
2388 return lhs.getValue<double>() == rhs.getValue<double>();
2390 case props::UNSPECIFIED:
2391 return !strcmp(lhs.getStringValue(), rhs.getStringValue());
2393 return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
2395 return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
2403 bool SGPropertyNode::compare(const SGPropertyNode& lhs,
2404 const SGPropertyNode& rhs)
2408 int lhsChildren = lhs.nChildren();
2409 int rhsChildren = rhs.nChildren();
2410 if (lhsChildren != rhsChildren)
2412 if (lhsChildren == 0)
2413 return compareNodeValue(lhs, rhs);
2414 for (size_t i = 0; i < lhs._children.size(); ++i) {
2415 const SGPropertyNode* lchild = lhs._children[i];
2416 const SGPropertyNode* rchild = rhs._children[i];
2417 // I'm guessing that the nodes will usually be in the same
2419 if (lchild->getIndex() != rchild->getIndex()
2420 || lchild->getNameString() != rchild->getNameString()) {
2422 for (PropertyList::const_iterator itr = rhs._children.begin(),
2423 end = rhs._children.end();
2426 if (lchild->getIndex() == (*itr)->getIndex()
2427 && lchild->getNameString() == (*itr)->getNameString()) {
2434 if (!compare(*lchild, *rchild))
2440 struct PropertyPlaceLess {
2441 typedef bool result_type;
2442 bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const
2444 int comp = lhs->getNameString().compare(rhs->getNameString());
2446 return lhs->getIndex() < rhs->getIndex();
2452 size_t hash_value(const SGPropertyNode& node)
2454 using namespace boost;
2456 if (node.nChildren() == 0) {
2457 switch (node.getType()) {
2462 return hash_value(node.getValue<bool>());
2464 return hash_value(node.getValue<int>());
2466 return hash_value(node.getValue<long>());
2468 return hash_value(node.getValue<float>());
2470 return hash_value(node.getValue<double>());
2472 case props::UNSPECIFIED:
2474 const char *val = node.getStringValue();
2475 return hash_range(val, val + strlen(val));
2479 const SGVec3d val = node.getValue<SGVec3d>();
2480 return hash_range(&val[0], &val[3]);
2484 const SGVec4d val = node.getValue<SGVec4d>();
2485 return hash_range(&val[0], &val[4]);
2487 case props::ALIAS: // XXX Should we look in aliases?
2493 PropertyList children(node._children.begin(), node._children.end());
2494 sort(children.begin(), children.end(), PropertyPlaceLess());
2495 for (PropertyList::const_iterator itr = children.begin(),
2496 end = children.end();
2499 hash_combine(seed, (*itr)->_name);
2500 hash_combine(seed, (*itr)->_index);
2501 hash_combine(seed, hash_value(**itr));