]> git.mxchange.org Git - simgear.git/blob - simgear/props/props.cxx
canvas::Layout: support for contents margins.
[simgear.git] / simgear / props / props.cxx
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.
4 //
5 // See props.html for documentation [replace with URL when available].
6 //
7 // $Id$
8
9 #ifdef HAVE_CONFIG_H
10 #  include <simgear_config.h>
11 #endif
12
13 #include "props.hxx"
14 #include "PropertyInterpolationMgr.hxx"
15 #include "vectorPropTemplates.hxx"
16
17 #include <algorithm>
18 #include <limits>
19
20 #include <set>
21 #include <sstream>
22 #include <iomanip>
23 #include <iterator>
24 #include <stdio.h>
25 #include <string.h>
26
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>
33
34 #if PROPS_STANDALONE
35 #include <iostream>
36 #else
37
38 #include <simgear/compiler.h>
39 #include <simgear/debug/logstream.hxx>
40
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 *>;
46 #endif
47 #endif
48
49 #if PROPS_STANDALONE
50 using std::cerr;
51 #endif
52 using std::endl;
53 using std::find;
54 using std::sort;
55 using std::string;
56 using std::vector;
57 using std::stringstream;
58
59 using namespace simgear;
60
61 ////////////////////////////////////////////////////////////////////////
62 // Local classes.
63 ////////////////////////////////////////////////////////////////////////
64
65 /**
66  * Comparator class for sorting by index.
67  */
68 class CompareIndices
69 {
70 public:
71   int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
72     return (n1->getIndex() < n2->getIndex());
73   }
74 };
75
76
77 ////////////////////////////////////////////////////////////////////////
78 // Convenience macros for value access.
79 ////////////////////////////////////////////////////////////////////////
80
81 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
82 #define TEST_WRITE if (!getAttribute(WRITE)) return false
83
84 ////////////////////////////////////////////////////////////////////////
85 // Local path normalization code.
86 ////////////////////////////////////////////////////////////////////////
87
88 /**
89  * Parse the name for a path component.
90  *
91  * Name: [_a-zA-Z][-._a-zA-Z0-9]*
92  */
93
94 template<typename Range>
95 inline Range
96 parse_name (const SGPropertyNode *node, const Range &path)
97 {
98   typename Range::iterator i = path.begin();
99   typename Range::iterator max = path.end();
100
101   if (*i == '.') {
102     i++;
103     if (i != path.end() && *i == '.') {
104       i++;
105     }
106     if (i != max && *i != '/')
107       throw string("illegal character after . or ..");
108   } else if (isalpha(*i) || *i == '_') {
109     i++;
110
111                                 // The rules inside a name are a little
112                                 // less restrictive.
113     while (i != max) {
114       if (isalpha(*i) || isdigit(*i) || *i == '_' ||
115           *i == '-' || *i == '.') {
116         // name += path[i];
117       } else if (*i == '[' || *i == '/') {
118         break;
119       } else {
120         string err = "'";
121         err.push_back(*i);
122         err.append("' found in propertyname after '"+node->getNameString()+"'");
123         err.append("\nname may contain only ._- and alphanumeric characters");
124         throw err;
125       }
126       i++;
127     }
128   }
129
130   else {
131     if (path.begin() == i) {
132       string err = "'";
133       err.push_back(*i);
134       err.append("' found in propertyname after '"+node->getNameString()+"'");
135       err.append("\nname must begin with alpha or '_'");
136       throw err;
137     }
138   }
139   return Range(path.begin(), i);
140 }
141
142 // Validate the name of a single node
143 inline bool validateName(const string& name)
144 {
145   using namespace boost;
146   if (name.empty())
147     return false;
148   if (!isalpha(name[0]) && name[0] != '_')
149     return false;
150   return all(make_iterator_range(name.begin(), name.end()),
151              is_alnum() || is_any_of("_-."));
152 }
153
154 ////////////////////////////////////////////////////////////////////////
155 // Other static utility functions.
156 ////////////////////////////////////////////////////////////////////////
157
158
159 static char *
160 copy_string (const char * s)
161 {
162   size_t slen = strlen(s);
163   char * copy = new char[slen + 1];
164
165   // the source string length is known so no need to check for '\0'
166   // when copying every single character
167   memcpy(copy, s, slen);
168   *(copy + slen) = '\0';
169   return copy;
170 }
171
172 static bool
173 compare_strings (const char * s1, const char * s2)
174 {
175   return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
176 }
177
178 /**
179  * Locate a child node by name and index.
180  */
181 template<typename Itr>
182 static int
183 find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
184 {
185   size_t nNodes = nodes.size();
186   boost::iterator_range<Itr> name(begin, end);
187   for (size_t i = 0; i < nNodes; i++) {
188     SGPropertyNode * node = nodes[i];
189
190     // searching for a matching index is a lot less time consuming than
191     // comparing two strings so do that first.
192     if (node->getIndex() == index && boost::equals(node->getName(), name))
193       return static_cast<int>(i);
194   }
195   return -1;
196 }
197
198 /**
199  * Locate the child node with the highest index of the same name
200  */
201 static int
202 find_last_child (const char * name, const PropertyList& nodes)
203 {
204   size_t nNodes = nodes.size();
205   int index = -1;
206
207   for (size_t i = 0; i < nNodes; i++) {
208     SGPropertyNode * node = nodes[i];
209     if (compare_strings(node->getName(), name))
210     {
211       int idx = node->getIndex();
212       if (idx > index) index = idx;
213     }
214   }
215   return index;
216 }
217
218 /**
219  * Get first unused index for child nodes with the given name
220  */
221 static int
222 first_unused_index( const char * name,
223                     const PropertyList& nodes,
224                     int min_index )
225 {
226   const char* nameEnd = name + strlen(name);
227
228   for( int index = min_index; index < std::numeric_limits<int>::max(); ++index )
229   {
230     if( find_child(name, nameEnd, index, nodes) < 0 )
231       return index;
232   }
233
234   SG_LOG(SG_GENERAL, SG_ALERT, "Too many nodes: " << name);
235   return -1;
236 }
237
238 template<typename Itr>
239 inline SGPropertyNode*
240 SGPropertyNode::getExistingChild (Itr begin, Itr end, int index)
241 {
242   int pos = find_child(begin, end, index, _children);
243   if (pos >= 0)
244     return _children[pos];
245   return 0;
246 }
247
248 template<typename Itr>
249 SGPropertyNode *
250 SGPropertyNode::getChildImpl (Itr begin, Itr end, int index, bool create)
251 {
252     SGPropertyNode* node = getExistingChild(begin, end, index);
253
254     if (node) {
255       return node;
256     } else if (create) {
257       node = new SGPropertyNode(begin, end, index, this);
258       _children.push_back(node);
259       fireChildAdded(node);
260       return node;
261     } else {
262       return 0;
263     }
264 }
265
266 template<typename SplitItr>
267 SGPropertyNode*
268 find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
269               int last_index)
270 {
271   typedef typename SplitItr::value_type Range;
272   // Run off the end of the list
273   if (current == 0) {
274     return 0;
275   }
276
277   // Success! This is the one we want.
278   if (itr.eof())
279     return current;
280   Range token = *itr;
281   // Empty name at this point is empty, not root.
282   if (token.empty())
283     return find_node_aux(current, ++itr, create, last_index);
284   Range name = parse_name(current, token);
285   if (equals(name, "."))
286     return find_node_aux(current, ++itr, create, last_index);
287   if (equals(name, "..")) {
288     SGPropertyNode * parent = current->getParent();
289     if (parent == 0)
290       throw string("attempt to move past root with '..'");
291     return find_node_aux(parent, ++itr, create, last_index);
292   }
293   int index = -1;
294   if (last_index >= 0) {
295     // If we are at the last token and last_index is valid, use
296     // last_index as the index value
297     bool lastTok = true;
298     while (!(++itr).eof()) {
299       if (!itr->empty()) {
300         lastTok = false;
301         break;
302       }
303     }
304     if (lastTok)
305       index = last_index;
306   } else {
307     ++itr;
308   }
309
310   if (index < 0) {
311     index = 0;
312     if (name.end() != token.end()) {
313       if (*name.end() == '[') {
314         typename Range::iterator i = name.end() + 1, end = token.end();
315         for (;i != end; ++i) {
316           if (isdigit(*i)) {
317             index = (index * 10) + (*i - '0');
318           } else {
319             break;
320           }
321         }
322         if (i == token.end() || *i != ']')
323           throw string("unterminated index (looking for ']')");
324       } else {
325         throw string("illegal characters in token: ")
326           + string(name.begin(), name.end());
327       }
328     }
329   }
330   return find_node_aux(current->getChildImpl(name.begin(), name.end(),
331                                              index, create), itr, create,
332                        last_index);
333 }
334
335 // Internal function for parsing property paths. last_index provides
336 // and index value for the last node name token, if supplied.
337 template<typename Range>
338 SGPropertyNode*
339 find_node (SGPropertyNode * current,
340            const Range& path,
341            bool create,
342            int last_index = -1)
343 {
344   using namespace boost;
345   typedef split_iterator<typename range_result_iterator<Range>::type>
346     PathSplitIterator;
347   
348   PathSplitIterator itr
349     = make_split_iterator(path, first_finder("/", is_equal()));
350   if (*path.begin() == '/')
351     return find_node_aux(current->getRootNode(), itr, create, last_index);
352    else
353      return find_node_aux(current, itr, create, last_index);
354 }
355
356 ////////////////////////////////////////////////////////////////////////
357 // Private methods from SGPropertyNode (may be inlined for speed).
358 ////////////////////////////////////////////////////////////////////////
359
360 inline bool
361 SGPropertyNode::get_bool () const
362 {
363   if (_tied)
364     return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
365   else
366     return _local_val.bool_val;
367 }
368
369 inline int
370 SGPropertyNode::get_int () const
371 {
372   if (_tied)
373       return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
374   else
375     return _local_val.int_val;
376 }
377
378 inline long
379 SGPropertyNode::get_long () const
380 {
381   if (_tied)
382     return static_cast<SGRawValue<long>*>(_value.val)->getValue();
383   else
384     return _local_val.long_val;
385 }
386
387 inline float
388 SGPropertyNode::get_float () const
389 {
390   if (_tied)
391     return static_cast<SGRawValue<float>*>(_value.val)->getValue();
392   else
393     return _local_val.float_val;
394 }
395
396 inline double
397 SGPropertyNode::get_double () const
398 {
399   if (_tied)
400     return static_cast<SGRawValue<double>*>(_value.val)->getValue();
401   else
402     return _local_val.double_val;
403 }
404
405 inline const char *
406 SGPropertyNode::get_string () const
407 {
408   if (_tied)
409       return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
410   else
411     return _local_val.string_val;
412 }
413
414 inline bool
415 SGPropertyNode::set_bool (bool val)
416 {
417   if (_tied) {
418     if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
419       fireValueChanged();
420       return true;
421     } else {
422       return false;
423     }
424   } else {
425     _local_val.bool_val = val;
426     fireValueChanged();
427     return true;
428   }
429 }
430
431 inline bool
432 SGPropertyNode::set_int (int val)
433 {
434   if (_tied) {
435     if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
436       fireValueChanged();
437       return true;
438     } else {
439       return false;
440     }
441   } else {
442     _local_val.int_val = val;
443     fireValueChanged();
444     return true;
445   }
446 }
447
448 inline bool
449 SGPropertyNode::set_long (long val)
450 {
451   if (_tied) {
452     if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
453       fireValueChanged();
454       return true;
455     } else {
456       return false;
457     }
458   } else {
459     _local_val.long_val = val;
460     fireValueChanged();
461     return true;
462   }
463 }
464
465 inline bool
466 SGPropertyNode::set_float (float val)
467 {
468   if (_tied) {
469     if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
470       fireValueChanged();
471       return true;
472     } else {
473       return false;
474     }
475   } else {
476     _local_val.float_val = val;
477     fireValueChanged();
478     return true;
479   }
480 }
481
482 inline bool
483 SGPropertyNode::set_double (double val)
484 {
485   if (_tied) {
486     if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
487       fireValueChanged();
488       return true;
489     } else {
490       return false;
491     }
492   } else {
493     _local_val.double_val = val;
494     fireValueChanged();
495     return true;
496   }
497 }
498
499 inline bool
500 SGPropertyNode::set_string (const char * val)
501 {
502   if (_tied) {
503       if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
504       fireValueChanged();
505       return true;
506     } else {
507       return false;
508     }
509   } else {
510     delete [] _local_val.string_val;
511     _local_val.string_val = copy_string(val);
512     fireValueChanged();
513     return true;
514   }
515 }
516
517 void
518 SGPropertyNode::clearValue ()
519 {
520     if (_type == props::ALIAS) {
521         put(_value.alias);
522         _value.alias = 0;
523     } else if (_type != props::NONE) {
524         switch (_type) {
525         case props::BOOL:
526             _local_val.bool_val = SGRawValue<bool>::DefaultValue();
527             break;
528         case props::INT:
529             _local_val.int_val = SGRawValue<int>::DefaultValue();
530             break;
531         case props::LONG:
532             _local_val.long_val = SGRawValue<long>::DefaultValue();
533             break;
534         case props::FLOAT:
535             _local_val.float_val = SGRawValue<float>::DefaultValue();
536             break;
537         case props::DOUBLE:
538             _local_val.double_val = SGRawValue<double>::DefaultValue();
539             break;
540         case props::STRING:
541         case props::UNSPECIFIED:
542             if (!_tied) {
543                 delete [] _local_val.string_val;
544             }
545             _local_val.string_val = 0;
546             break;
547         default: // avoid compiler warning
548             break;
549         }
550         delete _value.val;
551         _value.val = 0;
552     }
553     _tied = false;
554     _type = props::NONE;
555 }
556
557
558 /**
559  * Get the value as a string.
560  */
561 const char *
562 SGPropertyNode::make_string () const
563 {
564     if (!getAttribute(READ))
565         return "";
566     switch (_type) {
567     case props::ALIAS:
568         return _value.alias->getStringValue();
569     case props::BOOL:
570         return get_bool() ? "true" : "false";
571     case props::STRING:
572     case props::UNSPECIFIED:
573         return get_string();
574     case props::NONE:
575         return "";
576     default:
577         break;
578     }
579     stringstream sstr;
580     switch (_type) {
581     case props::INT:
582         sstr << get_int();
583         break;
584     case props::LONG:
585         sstr << get_long();
586         break;
587     case props::FLOAT:
588         sstr << get_float();
589         break;
590     case props::DOUBLE:
591         sstr << std::setprecision(10) << get_double();
592         break;
593     case props::EXTENDED:
594     {
595         props::Type realType = _value.val->getType();
596         // Perhaps this should be done for all types?
597         if (realType == props::VEC3D || realType == props::VEC4D)
598             sstr.precision(10);
599         static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
600     }
601         break;
602     default:
603         return "";
604     }
605     _buffer = sstr.str();
606     return _buffer.c_str();
607 }
608
609 /**
610  * Trace a write access for a property.
611  */
612 void
613 SGPropertyNode::trace_write () const
614 {
615 #if PROPS_STANDALONE
616   cerr << "TRACE: Write node " << getPath () << ", value \""
617        << make_string() << '"' << endl;
618 #else
619   SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
620          << ", value \"" << make_string() << '"');
621 #endif
622 }
623
624 /**
625  * Trace a read access for a property.
626  */
627 void
628 SGPropertyNode::trace_read () const
629 {
630 #if PROPS_STANDALONE
631   cerr << "TRACE: Write node " << getPath () << ", value \""
632        << make_string() << '"' << endl;
633 #else
634   SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
635          << ", value \"" << make_string() << '"');
636 #endif
637 }
638
639 ////////////////////////////////////////////////////////////////////////
640 // Public methods from SGPropertyNode.
641 ////////////////////////////////////////////////////////////////////////
642
643 /**
644  * Last used attribute
645  * Update as needed when enum Attribute is changed
646  */
647 const int SGPropertyNode::LAST_USED_ATTRIBUTE = PRESERVE;
648
649 /**
650  * Default constructor: always creates a root node.
651  */
652 SGPropertyNode::SGPropertyNode ()
653   : _index(0),
654     _parent(0),
655     _type(props::NONE),
656     _tied(false),
657     _attr(READ|WRITE),
658     _listeners(0)
659 {
660   _local_val.string_val = 0;
661   _value.val = 0;
662 }
663
664
665 /**
666  * Copy constructor.
667  */
668 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
669   : SGReferenced(node),
670     _index(node._index),
671     _name(node._name),
672     _parent(0),                 // don't copy the parent
673     _type(node._type),
674     _tied(node._tied),
675     _attr(node._attr),
676     _listeners(0)               // CHECK!!
677 {
678   _local_val.string_val = 0;
679   _value.val = 0;
680   if (_type == props::NONE)
681     return;
682   if (_type == props::ALIAS) {
683     _value.alias = node._value.alias;
684     get(_value.alias);
685     _tied = false;
686     return;
687   }
688   if (_tied || _type == props::EXTENDED) {
689     _value.val = node._value.val->clone();
690     return;
691   }
692   switch (_type) {
693   case props::BOOL:
694     set_bool(node.get_bool());    
695     break;
696   case props::INT:
697     set_int(node.get_int());
698     break;
699   case props::LONG:
700     set_long(node.get_long());
701     break;
702   case props::FLOAT:
703     set_float(node.get_float());
704     break;
705   case props::DOUBLE:
706     set_double(node.get_double());
707     break;
708   case props::STRING:
709   case props::UNSPECIFIED:
710     set_string(node.get_string());
711     break;
712   default:
713     break;
714   }
715 }
716
717
718 /**
719  * Convenience constructor.
720  */
721 template<typename Itr>
722 SGPropertyNode::SGPropertyNode (Itr begin, Itr end,
723                                 int index,
724                                 SGPropertyNode * parent)
725   : _index(index),
726     _name(begin, end),
727     _parent(parent),
728     _type(props::NONE),
729     _tied(false),
730     _attr(READ|WRITE),
731     _listeners(0)
732 {
733   _local_val.string_val = 0;
734   _value.val = 0;
735   if (!validateName(_name))
736     throw string("plain name expected instead of '") + _name + '\'';
737 }
738
739 SGPropertyNode::SGPropertyNode (const string& name,
740                                 int index,
741                                 SGPropertyNode * parent)
742   : _index(index),
743     _name(name),
744     _parent(parent),
745     _type(props::NONE),
746     _tied(false),
747     _attr(READ|WRITE),
748     _listeners(0)
749 {
750   _local_val.string_val = 0;
751   _value.val = 0;
752   if (!validateName(name))
753     throw string("plain name expected instead of '") + _name + '\'';
754 }
755
756 /**
757  * Destructor.
758  */
759 SGPropertyNode::~SGPropertyNode ()
760 {
761   // zero out all parent pointers, else they might be dangling
762   for (unsigned i = 0; i < _children.size(); ++i)
763     _children[i]->_parent = 0;
764   clearValue();
765
766   if (_listeners) {
767     vector<SGPropertyChangeListener*>::iterator it;
768     for (it = _listeners->begin(); it != _listeners->end(); ++it)
769       (*it)->unregister_property(this);
770     delete _listeners;
771   }
772 }
773
774
775 /**
776  * Alias to another node.
777  */
778 bool
779 SGPropertyNode::alias (SGPropertyNode * target)
780 {
781   if (target && (_type != props::ALIAS) && (!_tied))
782   {
783     clearValue();
784     get(target);
785     _value.alias = target;
786     _type = props::ALIAS;
787     return true;
788   }
789
790 #if PROPS_STANDALONE
791 #else
792   if (!target)
793   {
794     SG_LOG(SG_GENERAL, SG_ALERT,
795            "Failed to create alias for " << getPath() << ". "
796            "The target property does not exist.");
797   }
798   else
799   if (_type == props::ALIAS)
800   {
801     if (_value.alias == target)
802         return true; // ok, identical alias requested
803     SG_LOG(SG_GENERAL, SG_ALERT,
804            "Failed to create alias at " << target->getPath() << ". "
805            "Source "<< getPath() << " is already aliasing another property.");
806   }
807   else
808   if (_tied)
809   {
810     SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
811            "Source " << getPath() << " is a tied property.");
812   }
813 #endif
814
815   return false;
816 }
817
818
819 /**
820  * Alias to another node by path.
821  */
822 bool
823 SGPropertyNode::alias (const char * path)
824 {
825   return alias(getNode(path, true));
826 }
827
828
829 /**
830  * Remove an alias.
831  */
832 bool
833 SGPropertyNode::unalias ()
834 {
835   if (_type != props::ALIAS)
836     return false;
837   clearValue();
838   return true;
839 }
840
841
842 /**
843  * Get the target of an alias.
844  */
845 SGPropertyNode *
846 SGPropertyNode::getAliasTarget ()
847 {
848   return (_type == props::ALIAS ? _value.alias : 0);
849 }
850
851
852 const SGPropertyNode *
853 SGPropertyNode::getAliasTarget () const
854 {
855   return (_type == props::ALIAS ? _value.alias : 0);
856 }
857
858 /**
859  * create a non-const child by name after the last node with the same name.
860  */
861 SGPropertyNode *
862 SGPropertyNode::addChild(const char * name, int min_index, bool append)
863 {
864   int pos = append
865           ? std::max(find_last_child(name, _children) + 1, min_index)
866           : first_unused_index(name, _children, min_index);
867
868   SGPropertyNode_ptr node;
869   node = new SGPropertyNode(name, name + strlen(name), pos, this);
870   _children.push_back(node);
871   fireChildAdded(node);
872   return node;
873 }
874
875 /**
876  * Create multiple children with unused indices
877  */
878 simgear::PropertyList
879 SGPropertyNode::addChildren( const std::string& name,
880                              size_t count,
881                              int min_index,
882                              bool append )
883 {
884   simgear::PropertyList nodes;
885   std::set<int> used_indices;
886
887   if( !append )
888   {
889     // First grab all used indices. This saves us of testing every index if it
890     // is used for every element to be created
891     for( size_t i = 0; i < nodes.size(); i++ )
892     {
893       const SGPropertyNode* node = nodes[i];
894
895       if( node->getNameString() == name && node->getIndex() >= min_index )
896         used_indices.insert(node->getIndex());
897     }
898   }
899   else
900   {
901     // If we don't want to fill the holes just find last node
902     min_index = std::max(find_last_child(name.c_str(), _children) + 1, min_index);
903   }
904
905   for( int index = min_index;
906             index < std::numeric_limits<int>::max() && nodes.size() < count;
907           ++index )
908   {
909     if( used_indices.find(index) == used_indices.end() )
910     {
911       SGPropertyNode_ptr node;
912       node = new SGPropertyNode(name, index, this);
913       _children.push_back(node);
914       fireChildAdded(node);
915       nodes.push_back(node);
916     }
917   }
918
919   return nodes;
920 }
921
922 /**
923  * Get a non-const child by index.
924  */
925 SGPropertyNode *
926 SGPropertyNode::getChild (int position)
927 {
928   if (position >= 0 && position < nChildren())
929     return _children[position];
930   else
931     return 0;
932 }
933
934
935 /**
936  * Get a const child by index.
937  */
938 const SGPropertyNode *
939 SGPropertyNode::getChild (int position) const
940 {
941   if (position >= 0 && position < nChildren())
942     return _children[position];
943   else
944     return 0;
945 }
946
947
948 /**
949  * Get a non-const child by name and index, creating if necessary.
950  */
951
952 SGPropertyNode *
953 SGPropertyNode::getChild (const char * name, int index, bool create)
954 {
955   return getChildImpl(name, name + strlen(name), index, create);
956 }
957
958 SGPropertyNode *
959 SGPropertyNode::getChild (const string& name, int index, bool create)
960 {
961   SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
962   if (node) {
963       return node;
964     } else if (create) {
965       node = new SGPropertyNode(name, index, this);
966       _children.push_back(node);
967       fireChildAdded(node);
968       return node;
969     } else {
970       return 0;
971     }
972 }
973
974 /**
975  * Get a const child by name and index.
976  */
977 const SGPropertyNode *
978 SGPropertyNode::getChild (const char * name, int index) const
979 {
980   int pos = find_child(name, name + strlen(name), index, _children);
981   if (pos >= 0)
982     return _children[pos];
983   else
984     return 0;
985 }
986
987
988 /**
989  * Get all children with the same name (but different indices).
990  */
991 PropertyList
992 SGPropertyNode::getChildren (const char * name) const
993 {
994   PropertyList children;
995   size_t max = _children.size();
996
997   for (size_t i = 0; i < max; i++)
998     if (compare_strings(_children[i]->getName(), name))
999       children.push_back(_children[i]);
1000
1001   sort(children.begin(), children.end(), CompareIndices());
1002   return children;
1003 }
1004
1005 //------------------------------------------------------------------------------
1006 bool SGPropertyNode::removeChild(SGPropertyNode* node)
1007 {
1008   if( node->_parent != this )
1009     return false;
1010
1011   PropertyList::iterator it =
1012     std::find(_children.begin(), _children.end(), node);
1013   if( it == _children.end() )
1014     return false;
1015
1016   eraseChild(it);
1017   return true;
1018 }
1019
1020 //------------------------------------------------------------------------------
1021 SGPropertyNode_ptr SGPropertyNode::removeChild(int pos)
1022 {
1023   if (pos < 0 || pos >= (int)_children.size())
1024     return SGPropertyNode_ptr();
1025
1026   return eraseChild(_children.begin() + pos);
1027 }
1028
1029
1030 /**
1031  * Remove a child node
1032  */
1033 SGPropertyNode_ptr
1034 SGPropertyNode::removeChild(const char * name, int index)
1035 {
1036   SGPropertyNode_ptr ret;
1037   int pos = find_child(name, name + strlen(name), index, _children);
1038   if (pos >= 0)
1039     ret = removeChild(pos);
1040   return ret;
1041 }
1042
1043
1044 /**
1045   * Remove all children with the specified name.
1046   */
1047 PropertyList
1048 SGPropertyNode::removeChildren(const char * name)
1049 {
1050   PropertyList children;
1051
1052   for (int pos = static_cast<int>(_children.size() - 1); pos >= 0; pos--)
1053     if (compare_strings(_children[pos]->getName(), name))
1054       children.push_back(removeChild(pos));
1055
1056   sort(children.begin(), children.end(), CompareIndices());
1057   return children;
1058 }
1059
1060 void
1061 SGPropertyNode::removeAllChildren()
1062 {
1063   for(unsigned i = 0; i < _children.size(); ++i)
1064   {
1065     SGPropertyNode_ptr& node = _children[i];
1066     node->_parent = 0;
1067     node->setAttribute(REMOVED, true);
1068     node->clearValue();
1069     fireChildRemoved(node);
1070   }
1071
1072   _children.clear();
1073 }
1074
1075 string
1076 SGPropertyNode::getDisplayName (bool simplify) const
1077 {
1078   string display_name = _name;
1079   if (_index != 0 || !simplify) {
1080     stringstream sstr;
1081     sstr << '[' << _index << ']';
1082     display_name += sstr.str();
1083   }
1084   return display_name;
1085 }
1086
1087 string
1088 SGPropertyNode::getPath (bool simplify) const
1089 {
1090   typedef std::vector<SGConstPropertyNode_ptr> PList;
1091   PList pathList;
1092   for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
1093     pathList.push_back(node);
1094   string result;
1095   for (PList::reverse_iterator itr = pathList.rbegin(),
1096          rend = pathList.rend();
1097        itr != rend;
1098        ++itr) {
1099     result += '/';
1100     result += (*itr)->getDisplayName(simplify);
1101   }
1102   return result;
1103 }
1104
1105 props::Type
1106 SGPropertyNode::getType () const
1107 {
1108   if (_type == props::ALIAS)
1109     return _value.alias->getType();
1110   else if (_type == props::EXTENDED)
1111       return _value.val->getType();
1112   else
1113     return _type;
1114 }
1115
1116
1117 bool 
1118 SGPropertyNode::getBoolValue () const
1119 {
1120                                 // Shortcut for common case
1121   if (_attr == (READ|WRITE) && _type == props::BOOL)
1122     return get_bool();
1123
1124   if (getAttribute(TRACE_READ))
1125     trace_read();
1126   if (!getAttribute(READ))
1127     return SGRawValue<bool>::DefaultValue();
1128   switch (_type) {
1129   case props::ALIAS:
1130     return _value.alias->getBoolValue();
1131   case props::BOOL:
1132     return get_bool();
1133   case props::INT:
1134     return get_int() == 0 ? false : true;
1135   case props::LONG:
1136     return get_long() == 0L ? false : true;
1137   case props::FLOAT:
1138     return get_float() == 0.0 ? false : true;
1139   case props::DOUBLE:
1140     return get_double() == 0.0L ? false : true;
1141   case props::STRING:
1142   case props::UNSPECIFIED:
1143     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1144   case props::NONE:
1145   default:
1146     return SGRawValue<bool>::DefaultValue();
1147   }
1148 }
1149
1150 int 
1151 SGPropertyNode::getIntValue () const
1152 {
1153                                 // Shortcut for common case
1154   if (_attr == (READ|WRITE) && _type == props::INT)
1155     return get_int();
1156
1157   if (getAttribute(TRACE_READ))
1158     trace_read();
1159   if (!getAttribute(READ))
1160     return SGRawValue<int>::DefaultValue();
1161   switch (_type) {
1162   case props::ALIAS:
1163     return _value.alias->getIntValue();
1164   case props::BOOL:
1165     return int(get_bool());
1166   case props::INT:
1167     return get_int();
1168   case props::LONG:
1169     return int(get_long());
1170   case props::FLOAT:
1171     return int(get_float());
1172   case props::DOUBLE:
1173     return int(get_double());
1174   case props::STRING:
1175   case props::UNSPECIFIED:
1176     return atoi(get_string());
1177   case props::NONE:
1178   default:
1179     return SGRawValue<int>::DefaultValue();
1180   }
1181 }
1182
1183 long 
1184 SGPropertyNode::getLongValue () const
1185 {
1186                                 // Shortcut for common case
1187   if (_attr == (READ|WRITE) && _type == props::LONG)
1188     return get_long();
1189
1190   if (getAttribute(TRACE_READ))
1191     trace_read();
1192   if (!getAttribute(READ))
1193     return SGRawValue<long>::DefaultValue();
1194   switch (_type) {
1195   case props::ALIAS:
1196     return _value.alias->getLongValue();
1197   case props::BOOL:
1198     return long(get_bool());
1199   case props::INT:
1200     return long(get_int());
1201   case props::LONG:
1202     return get_long();
1203   case props::FLOAT:
1204     return long(get_float());
1205   case props::DOUBLE:
1206     return long(get_double());
1207   case props::STRING:
1208   case props::UNSPECIFIED:
1209     return strtol(get_string(), 0, 0);
1210   case props::NONE:
1211   default:
1212     return SGRawValue<long>::DefaultValue();
1213   }
1214 }
1215
1216 float 
1217 SGPropertyNode::getFloatValue () const
1218 {
1219                                 // Shortcut for common case
1220   if (_attr == (READ|WRITE) && _type == props::FLOAT)
1221     return get_float();
1222
1223   if (getAttribute(TRACE_READ))
1224     trace_read();
1225   if (!getAttribute(READ))
1226     return SGRawValue<float>::DefaultValue();
1227   switch (_type) {
1228   case props::ALIAS:
1229     return _value.alias->getFloatValue();
1230   case props::BOOL:
1231     return float(get_bool());
1232   case props::INT:
1233     return float(get_int());
1234   case props::LONG:
1235     return float(get_long());
1236   case props::FLOAT:
1237     return get_float();
1238   case props::DOUBLE:
1239     return float(get_double());
1240   case props::STRING:
1241   case props::UNSPECIFIED:
1242     return atof(get_string());
1243   case props::NONE:
1244   default:
1245     return SGRawValue<float>::DefaultValue();
1246   }
1247 }
1248
1249 double 
1250 SGPropertyNode::getDoubleValue () const
1251 {
1252                                 // Shortcut for common case
1253   if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1254     return get_double();
1255
1256   if (getAttribute(TRACE_READ))
1257     trace_read();
1258   if (!getAttribute(READ))
1259     return SGRawValue<double>::DefaultValue();
1260
1261   switch (_type) {
1262   case props::ALIAS:
1263     return _value.alias->getDoubleValue();
1264   case props::BOOL:
1265     return double(get_bool());
1266   case props::INT:
1267     return double(get_int());
1268   case props::LONG:
1269     return double(get_long());
1270   case props::FLOAT:
1271     return double(get_float());
1272   case props::DOUBLE:
1273     return get_double();
1274   case props::STRING:
1275   case props::UNSPECIFIED:
1276     return strtod(get_string(), 0);
1277   case props::NONE:
1278   default:
1279     return SGRawValue<double>::DefaultValue();
1280   }
1281 }
1282
1283 const char *
1284 SGPropertyNode::getStringValue () const
1285 {
1286                                 // Shortcut for common case
1287   if (_attr == (READ|WRITE) && _type == props::STRING)
1288     return get_string();
1289
1290   if (getAttribute(TRACE_READ))
1291     trace_read();
1292   if (!getAttribute(READ))
1293     return SGRawValue<const char *>::DefaultValue();
1294   return make_string();
1295 }
1296
1297 bool
1298 SGPropertyNode::setBoolValue (bool value)
1299 {
1300                                 // Shortcut for common case
1301   if (_attr == (READ|WRITE) && _type == props::BOOL)
1302     return set_bool(value);
1303
1304   bool result = false;
1305   TEST_WRITE;
1306   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1307     clearValue();
1308     _tied = false;
1309     _type = props::BOOL;
1310   }
1311
1312   switch (_type) {
1313   case props::ALIAS:
1314     result = _value.alias->setBoolValue(value);
1315     break;
1316   case props::BOOL:
1317     result = set_bool(value);
1318     break;
1319   case props::INT:
1320     result = set_int(int(value));
1321     break;
1322   case props::LONG:
1323     result = set_long(long(value));
1324     break;
1325   case props::FLOAT:
1326     result = set_float(float(value));
1327     break;
1328   case props::DOUBLE:
1329     result = set_double(double(value));
1330     break;
1331   case props::STRING:
1332   case props::UNSPECIFIED:
1333     result = set_string(value ? "true" : "false");
1334     break;
1335   case props::NONE:
1336   default:
1337     break;
1338   }
1339
1340   if (getAttribute(TRACE_WRITE))
1341     trace_write();
1342   return result;
1343 }
1344
1345 bool
1346 SGPropertyNode::setIntValue (int value)
1347 {
1348                                 // Shortcut for common case
1349   if (_attr == (READ|WRITE) && _type == props::INT)
1350     return set_int(value);
1351
1352   bool result = false;
1353   TEST_WRITE;
1354   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1355     clearValue();
1356     _type = props::INT;
1357     _local_val.int_val = 0;
1358   }
1359
1360   switch (_type) {
1361   case props::ALIAS:
1362     result = _value.alias->setIntValue(value);
1363     break;
1364   case props::BOOL:
1365     result = set_bool(value == 0 ? false : true);
1366     break;
1367   case props::INT:
1368     result = set_int(value);
1369     break;
1370   case props::LONG:
1371     result = set_long(long(value));
1372     break;
1373   case props::FLOAT:
1374     result = set_float(float(value));
1375     break;
1376   case props::DOUBLE:
1377     result = set_double(double(value));
1378     break;
1379   case props::STRING:
1380   case props::UNSPECIFIED: {
1381     char buf[128];
1382     sprintf(buf, "%d", value);
1383     result = set_string(buf);
1384     break;
1385   }
1386   case props::NONE:
1387   default:
1388     break;
1389   }
1390
1391   if (getAttribute(TRACE_WRITE))
1392     trace_write();
1393   return result;
1394 }
1395
1396 bool
1397 SGPropertyNode::setLongValue (long value)
1398 {
1399                                 // Shortcut for common case
1400   if (_attr == (READ|WRITE) && _type == props::LONG)
1401     return set_long(value);
1402
1403   bool result = false;
1404   TEST_WRITE;
1405   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1406     clearValue();
1407     _type = props::LONG;
1408     _local_val.long_val = 0L;
1409   }
1410
1411   switch (_type) {
1412   case props::ALIAS:
1413     result = _value.alias->setLongValue(value);
1414     break;
1415   case props::BOOL:
1416     result = set_bool(value == 0L ? false : true);
1417     break;
1418   case props::INT:
1419     result = set_int(int(value));
1420     break;
1421   case props::LONG:
1422     result = set_long(value);
1423     break;
1424   case props::FLOAT:
1425     result = set_float(float(value));
1426     break;
1427   case props::DOUBLE:
1428     result = set_double(double(value));
1429     break;
1430   case props::STRING:
1431   case props::UNSPECIFIED: {
1432     char buf[128];
1433     sprintf(buf, "%ld", value);
1434     result = set_string(buf);
1435     break;
1436   }
1437   case props::NONE:
1438   default:
1439     break;
1440   }
1441
1442   if (getAttribute(TRACE_WRITE))
1443     trace_write();
1444   return result;
1445 }
1446
1447 bool
1448 SGPropertyNode::setFloatValue (float value)
1449 {
1450                                 // Shortcut for common case
1451   if (_attr == (READ|WRITE) && _type == props::FLOAT)
1452     return set_float(value);
1453
1454   bool result = false;
1455   TEST_WRITE;
1456   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1457     clearValue();
1458     _type = props::FLOAT;
1459     _local_val.float_val = 0;
1460   }
1461
1462   switch (_type) {
1463   case props::ALIAS:
1464     result = _value.alias->setFloatValue(value);
1465     break;
1466   case props::BOOL:
1467     result = set_bool(value == 0.0 ? false : true);
1468     break;
1469   case props::INT:
1470     result = set_int(int(value));
1471     break;
1472   case props::LONG:
1473     result = set_long(long(value));
1474     break;
1475   case props::FLOAT:
1476     result = set_float(value);
1477     break;
1478   case props::DOUBLE:
1479     result = set_double(double(value));
1480     break;
1481   case props::STRING:
1482   case props::UNSPECIFIED: {
1483     char buf[128];
1484     sprintf(buf, "%f", value);
1485     result = set_string(buf);
1486     break;
1487   }
1488   case props::NONE:
1489   default:
1490     break;
1491   }
1492
1493   if (getAttribute(TRACE_WRITE))
1494     trace_write();
1495   return result;
1496 }
1497
1498 bool
1499 SGPropertyNode::setDoubleValue (double value)
1500 {
1501                                 // Shortcut for common case
1502   if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1503     return set_double(value);
1504
1505   bool result = false;
1506   TEST_WRITE;
1507   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1508     clearValue();
1509     _local_val.double_val = value;
1510     _type = props::DOUBLE;
1511   }
1512
1513   switch (_type) {
1514   case props::ALIAS:
1515     result = _value.alias->setDoubleValue(value);
1516     break;
1517   case props::BOOL:
1518     result = set_bool(value == 0.0L ? false : true);
1519     break;
1520   case props::INT:
1521     result = set_int(int(value));
1522     break;
1523   case props::LONG:
1524     result = set_long(long(value));
1525     break;
1526   case props::FLOAT:
1527     result = set_float(float(value));
1528     break;
1529   case props::DOUBLE:
1530     result = set_double(value);
1531     break;
1532   case props::STRING:
1533   case props::UNSPECIFIED: {
1534     char buf[128];
1535     sprintf(buf, "%f", value);
1536     result = set_string(buf);
1537     break;
1538   }
1539   case props::NONE:
1540   default:
1541     break;
1542   }
1543
1544   if (getAttribute(TRACE_WRITE))
1545     trace_write();
1546   return result;
1547 }
1548
1549 bool
1550 SGPropertyNode::setStringValue (const char * value)
1551 {
1552                                 // Shortcut for common case
1553   if (_attr == (READ|WRITE) && _type == props::STRING)
1554     return set_string(value);
1555
1556   bool result = false;
1557   TEST_WRITE;
1558   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1559     clearValue();
1560     _type = props::STRING;
1561   }
1562
1563   switch (_type) {
1564   case props::ALIAS:
1565     result = _value.alias->setStringValue(value);
1566     break;
1567   case props::BOOL:
1568     result = set_bool((compare_strings(value, "true")
1569                        || atoi(value)) ? true : false);
1570     break;
1571   case props::INT:
1572     result = set_int(atoi(value));
1573     break;
1574   case props::LONG:
1575     result = set_long(strtol(value, 0, 0));
1576     break;
1577   case props::FLOAT:
1578     result = set_float(atof(value));
1579     break;
1580   case props::DOUBLE:
1581     result = set_double(strtod(value, 0));
1582     break;
1583   case props::STRING:
1584   case props::UNSPECIFIED:
1585     result = set_string(value);
1586     break;
1587   case props::EXTENDED:
1588   {
1589     stringstream sstr(value);
1590     static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1591   }
1592   break;
1593   case props::NONE:
1594   default:
1595     break;
1596   }
1597
1598   if (getAttribute(TRACE_WRITE))
1599     trace_write();
1600   return result;
1601 }
1602
1603 bool
1604 SGPropertyNode::setUnspecifiedValue (const char * value)
1605 {
1606   bool result = false;
1607   TEST_WRITE;
1608   if (_type == props::NONE) {
1609     clearValue();
1610     _type = props::UNSPECIFIED;
1611   }
1612   props::Type type = _type;
1613   if (type == props::EXTENDED)
1614       type = _value.val->getType();
1615   switch (type) {
1616   case props::ALIAS:
1617     result = _value.alias->setUnspecifiedValue(value);
1618     break;
1619   case props::BOOL:
1620     result = set_bool((compare_strings(value, "true")
1621                        || atoi(value)) ? true : false);
1622     break;
1623   case props::INT:
1624     result = set_int(atoi(value));
1625     break;
1626   case props::LONG:
1627     result = set_long(strtol(value, 0, 0));
1628     break;
1629   case props::FLOAT:
1630     result = set_float(atof(value));
1631     break;
1632   case props::DOUBLE:
1633     result = set_double(strtod(value, 0));
1634     break;
1635   case props::STRING:
1636   case props::UNSPECIFIED:
1637     result = set_string(value);
1638     break;
1639   case props::VEC3D:
1640       result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1641       break;
1642   case props::VEC4D:
1643       result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1644       break;
1645   case props::NONE:
1646   default:
1647     break;
1648   }
1649
1650   if (getAttribute(TRACE_WRITE))
1651     trace_write();
1652   return result;
1653 }
1654
1655 //------------------------------------------------------------------------------
1656 bool SGPropertyNode::interpolate( const std::string& type,
1657                                   const SGPropertyNode& target,
1658                                   double duration,
1659                                   const std::string& easing )
1660 {
1661   if( !_interpolation_mgr )
1662   {
1663     SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
1664
1665     // no interpolation possible -> set to target immediately
1666     setUnspecifiedValue( target.getStringValue() );
1667     return false;
1668   }
1669
1670   return _interpolation_mgr->interpolate(this, type, target, duration, easing);
1671 }
1672
1673 //------------------------------------------------------------------------------
1674 bool SGPropertyNode::interpolate( const std::string& type,
1675                                   const PropertyList& values,
1676                                   const double_list& deltas,
1677                                   const std::string& easing )
1678 {
1679   if( !_interpolation_mgr )
1680   {
1681     SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
1682
1683     // no interpolation possible -> set to last value immediately
1684     if( !values.empty() )
1685       setUnspecifiedValue(values.back()->getStringValue());
1686     return false;
1687   }
1688
1689   return _interpolation_mgr->interpolate(this, type, values, deltas, easing);
1690 }
1691
1692 //------------------------------------------------------------------------------
1693 void SGPropertyNode::setInterpolationMgr(simgear::PropertyInterpolationMgr* mgr)
1694 {
1695   _interpolation_mgr = mgr;
1696 }
1697
1698 //------------------------------------------------------------------------------
1699 simgear::PropertyInterpolationMgr* SGPropertyNode::getInterpolationMgr()
1700 {
1701   return _interpolation_mgr;
1702 }
1703
1704 simgear::PropertyInterpolationMgr* SGPropertyNode::_interpolation_mgr = 0;
1705
1706 //------------------------------------------------------------------------------
1707 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1708 {
1709     if (!getAttribute(READ))
1710         return stream;
1711     switch (_type) {
1712     case props::ALIAS:
1713         return _value.alias->printOn(stream);
1714     case props::BOOL:
1715         stream << (get_bool() ? "true" : "false");
1716         break;
1717     case props::INT:
1718         stream << get_int();
1719         break;
1720     case props::LONG:
1721         stream << get_long();
1722         break;
1723     case props::FLOAT:
1724         stream << get_float();
1725         break;
1726     case props::DOUBLE:
1727         stream << get_double();
1728         break;
1729     case props::STRING:
1730     case props::UNSPECIFIED:
1731         stream << get_string();
1732         break;
1733     case props::EXTENDED:
1734         static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1735         break;
1736     case props::NONE:
1737         break;
1738     default: // avoid compiler warning
1739         break;
1740     }
1741     return stream;
1742 }
1743
1744 template<>
1745 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1746                           bool useDefault)
1747 {
1748     if (_type == props::ALIAS || _tied)
1749         return false;
1750
1751     useDefault = useDefault && hasValue();
1752     std::string old_val;
1753     if (useDefault)
1754         old_val = getStringValue();
1755     clearValue();
1756     _type = props::STRING;
1757     _tied = true;
1758     _value.val = rawValue.clone();
1759
1760     if (useDefault) {
1761         int save_attributes = getAttributes();
1762         setAttribute( WRITE, true );
1763         setStringValue(old_val.c_str());
1764         setAttributes( save_attributes );
1765     }
1766
1767     return true;
1768 }
1769 bool
1770 SGPropertyNode::untie ()
1771 {
1772   if (!_tied)
1773     return false;
1774
1775   switch (_type) {
1776   case props::BOOL: {
1777     bool val = getBoolValue();
1778     clearValue();
1779     _type = props::BOOL;
1780     _local_val.bool_val = val;
1781     break;
1782   }
1783   case props::INT: {
1784     int val = getIntValue();
1785     clearValue();
1786     _type = props::INT;
1787     _local_val.int_val = val;
1788     break;
1789   }
1790   case props::LONG: {
1791     long val = getLongValue();
1792     clearValue();
1793     _type = props::LONG;
1794     _local_val.long_val = val;
1795     break;
1796   }
1797   case props::FLOAT: {
1798     float val = getFloatValue();
1799     clearValue();
1800     _type = props::FLOAT;
1801     _local_val.float_val = val;
1802     break;
1803   }
1804   case props::DOUBLE: {
1805     double val = getDoubleValue();
1806     clearValue();
1807     _type = props::DOUBLE;
1808     _local_val.double_val = val;
1809     break;
1810   }
1811   case props::STRING:
1812   case props::UNSPECIFIED: {
1813     string val = getStringValue();
1814     clearValue();
1815     _type = props::STRING;
1816     _local_val.string_val = copy_string(val.c_str());
1817     break;
1818   }
1819   case props::EXTENDED: {
1820     SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1821     _value.val = 0;             // Prevent clearValue() from deleting
1822     clearValue();
1823     _type = props::EXTENDED;
1824     _value.val = val->makeContainer();
1825     delete val;
1826     break;
1827   }
1828   case props::NONE:
1829   default:
1830     break;
1831   }
1832
1833   _tied = false;
1834   return true;
1835 }
1836
1837 SGPropertyNode *
1838 SGPropertyNode::getRootNode ()
1839 {
1840   if (_parent == 0)
1841     return this;
1842   else
1843     return _parent->getRootNode();
1844 }
1845
1846 const SGPropertyNode *
1847 SGPropertyNode::getRootNode () const
1848 {
1849   if (_parent == 0)
1850     return this;
1851   else
1852     return _parent->getRootNode();
1853 }
1854
1855 SGPropertyNode *
1856 SGPropertyNode::getNode (const char * relative_path, bool create)
1857 {
1858   using namespace boost;
1859
1860   return find_node(this, make_iterator_range(relative_path, relative_path
1861                                              + strlen(relative_path)),
1862                    create);
1863 }
1864
1865 SGPropertyNode *
1866 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1867 {
1868   using namespace boost;
1869   return find_node(this, make_iterator_range(relative_path, relative_path
1870                                              + strlen(relative_path)),
1871                    create, index);
1872 }
1873
1874 const SGPropertyNode *
1875 SGPropertyNode::getNode (const char * relative_path) const
1876 {
1877   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1878 }
1879
1880 const SGPropertyNode *
1881 SGPropertyNode::getNode (const char * relative_path, int index) const
1882 {
1883   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1884 }
1885
1886 ////////////////////////////////////////////////////////////////////////
1887 // Convenience methods using relative paths.
1888 ////////////////////////////////////////////////////////////////////////
1889
1890
1891 /**
1892  * Test whether another node has a value attached.
1893  */
1894 bool
1895 SGPropertyNode::hasValue (const char * relative_path) const
1896 {
1897   const SGPropertyNode * node = getNode(relative_path);
1898   return (node == 0 ? false : node->hasValue());
1899 }
1900
1901
1902 /**
1903  * Get the value type for another node.
1904  */
1905 props::Type
1906 SGPropertyNode::getType (const char * relative_path) const
1907 {
1908   const SGPropertyNode * node = getNode(relative_path);
1909   return (node == 0 ? props::UNSPECIFIED : node->getType());
1910 }
1911
1912
1913 /**
1914  * Get a bool value for another node.
1915  */
1916 bool
1917 SGPropertyNode::getBoolValue (const char * relative_path,
1918                               bool defaultValue) const
1919 {
1920   const SGPropertyNode * node = getNode(relative_path);
1921   return (node == 0 ? defaultValue : node->getBoolValue());
1922 }
1923
1924
1925 /**
1926  * Get an int value for another node.
1927  */
1928 int
1929 SGPropertyNode::getIntValue (const char * relative_path,
1930                              int defaultValue) const
1931 {
1932   const SGPropertyNode * node = getNode(relative_path);
1933   return (node == 0 ? defaultValue : node->getIntValue());
1934 }
1935
1936
1937 /**
1938  * Get a long value for another node.
1939  */
1940 long
1941 SGPropertyNode::getLongValue (const char * relative_path,
1942                               long defaultValue) const
1943 {
1944   const SGPropertyNode * node = getNode(relative_path);
1945   return (node == 0 ? defaultValue : node->getLongValue());
1946 }
1947
1948
1949 /**
1950  * Get a float value for another node.
1951  */
1952 float
1953 SGPropertyNode::getFloatValue (const char * relative_path,
1954                                float defaultValue) const
1955 {
1956   const SGPropertyNode * node = getNode(relative_path);
1957   return (node == 0 ? defaultValue : node->getFloatValue());
1958 }
1959
1960
1961 /**
1962  * Get a double value for another node.
1963  */
1964 double
1965 SGPropertyNode::getDoubleValue (const char * relative_path,
1966                                 double defaultValue) const
1967 {
1968   const SGPropertyNode * node = getNode(relative_path);
1969   return (node == 0 ? defaultValue : node->getDoubleValue());
1970 }
1971
1972
1973 /**
1974  * Get a string value for another node.
1975  */
1976 const char *
1977 SGPropertyNode::getStringValue (const char * relative_path,
1978                                 const char * defaultValue) const
1979 {
1980   const SGPropertyNode * node = getNode(relative_path);
1981   return (node == 0 ? defaultValue : node->getStringValue());
1982 }
1983
1984
1985 /**
1986  * Set a bool value for another node.
1987  */
1988 bool
1989 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1990 {
1991   return getNode(relative_path, true)->setBoolValue(value);
1992 }
1993
1994
1995 /**
1996  * Set an int value for another node.
1997  */
1998 bool
1999 SGPropertyNode::setIntValue (const char * relative_path, int value)
2000 {
2001   return getNode(relative_path, true)->setIntValue(value);
2002 }
2003
2004
2005 /**
2006  * Set a long value for another node.
2007  */
2008 bool
2009 SGPropertyNode::setLongValue (const char * relative_path, long value)
2010 {
2011   return getNode(relative_path, true)->setLongValue(value);
2012 }
2013
2014
2015 /**
2016  * Set a float value for another node.
2017  */
2018 bool
2019 SGPropertyNode::setFloatValue (const char * relative_path, float value)
2020 {
2021   return getNode(relative_path, true)->setFloatValue(value);
2022 }
2023
2024
2025 /**
2026  * Set a double value for another node.
2027  */
2028 bool
2029 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
2030 {
2031   return getNode(relative_path, true)->setDoubleValue(value);
2032 }
2033
2034
2035 /**
2036  * Set a string value for another node.
2037  */
2038 bool
2039 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
2040 {
2041   return getNode(relative_path, true)->setStringValue(value);
2042 }
2043
2044
2045 /**
2046  * Set an unknown value for another node.
2047  */
2048 bool
2049 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
2050                                      const char * value)
2051 {
2052   return getNode(relative_path, true)->setUnspecifiedValue(value);
2053 }
2054
2055
2056 /**
2057  * Test whether another node is tied.
2058  */
2059 bool
2060 SGPropertyNode::isTied (const char * relative_path) const
2061 {
2062   const SGPropertyNode * node = getNode(relative_path);
2063   return (node == 0 ? false : node->isTied());
2064 }
2065
2066
2067 /**
2068  * Tie a node reached by a relative path, creating it if necessary.
2069  */
2070 bool
2071 SGPropertyNode::tie (const char * relative_path,
2072                      const SGRawValue<bool> &rawValue,
2073                      bool useDefault)
2074 {
2075   return getNode(relative_path, true)->tie(rawValue, useDefault);
2076 }
2077
2078
2079 /**
2080  * Tie a node reached by a relative path, creating it if necessary.
2081  */
2082 bool
2083 SGPropertyNode::tie (const char * relative_path,
2084                      const SGRawValue<int> &rawValue,
2085                      bool useDefault)
2086 {
2087   return getNode(relative_path, true)->tie(rawValue, useDefault);
2088 }
2089
2090
2091 /**
2092  * Tie a node reached by a relative path, creating it if necessary.
2093  */
2094 bool
2095 SGPropertyNode::tie (const char * relative_path,
2096                      const SGRawValue<long> &rawValue,
2097                      bool useDefault)
2098 {
2099   return getNode(relative_path, true)->tie(rawValue, useDefault);
2100 }
2101
2102
2103 /**
2104  * Tie a node reached by a relative path, creating it if necessary.
2105  */
2106 bool
2107 SGPropertyNode::tie (const char * relative_path,
2108                      const SGRawValue<float> &rawValue,
2109                      bool useDefault)
2110 {
2111   return getNode(relative_path, true)->tie(rawValue, useDefault);
2112 }
2113
2114
2115 /**
2116  * Tie a node reached by a relative path, creating it if necessary.
2117  */
2118 bool
2119 SGPropertyNode::tie (const char * relative_path,
2120                      const SGRawValue<double> &rawValue,
2121                      bool useDefault)
2122 {
2123   return getNode(relative_path, true)->tie(rawValue, useDefault);
2124 }
2125
2126
2127 /**
2128  * Tie a node reached by a relative path, creating it if necessary.
2129  */
2130 bool
2131 SGPropertyNode::tie (const char * relative_path,
2132                      const SGRawValue<const char *> &rawValue,
2133                      bool useDefault)
2134 {
2135   return getNode(relative_path, true)->tie(rawValue, useDefault);
2136 }
2137
2138
2139 /**
2140  * Attempt to untie another node reached by a relative path.
2141  */
2142 bool
2143 SGPropertyNode::untie (const char * relative_path)
2144 {
2145   SGPropertyNode * node = getNode(relative_path);
2146   return (node == 0 ? false : node->untie());
2147 }
2148
2149 void
2150 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2151                                    bool initial)
2152 {
2153   if (_listeners == 0)
2154     _listeners = new vector<SGPropertyChangeListener*>;
2155   _listeners->push_back(listener);
2156   listener->register_property(this);
2157   if (initial)
2158     listener->valueChanged(this);
2159 }
2160
2161 void
2162 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2163 {
2164   if (_listeners == 0)
2165     return;
2166   vector<SGPropertyChangeListener*>::iterator it =
2167     find(_listeners->begin(), _listeners->end(), listener);
2168   if (it != _listeners->end()) {
2169     _listeners->erase(it);
2170     listener->unregister_property(this);
2171     if (_listeners->empty()) {
2172       vector<SGPropertyChangeListener*>* tmp = _listeners;
2173       _listeners = 0;
2174       delete tmp;
2175     }
2176   }
2177 }
2178
2179 void
2180 SGPropertyNode::fireValueChanged ()
2181 {
2182   fireValueChanged(this);
2183 }
2184
2185 void
2186 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2187 {
2188   fireChildAdded(this, child);
2189 }
2190
2191 void
2192 SGPropertyNode::fireCreatedRecursive(bool fire_self)
2193 {
2194   if( fire_self )
2195   {
2196     _parent->fireChildAdded(this);
2197
2198     if( _children.empty() && getType() != simgear::props::NONE )
2199       return fireValueChanged();
2200   }
2201
2202   for(size_t i = 0; i < _children.size(); ++i)
2203     _children[i]->fireCreatedRecursive(true);
2204 }
2205
2206 void
2207 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2208 {
2209   fireChildRemoved(this, child);
2210 }
2211
2212 void
2213 SGPropertyNode::fireChildrenRemovedRecursive()
2214 {
2215   for(size_t i = 0; i < _children.size(); ++i)
2216   {
2217     SGPropertyNode* child = _children[i];
2218     fireChildRemoved(this, child);
2219     child->fireChildrenRemovedRecursive();
2220   }
2221 }
2222
2223 void
2224 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2225 {
2226   if (_listeners != 0) {
2227     for (unsigned int i = 0; i < _listeners->size(); i++) {
2228       (*_listeners)[i]->valueChanged(node);
2229     }
2230   }
2231   if (_parent != 0)
2232     _parent->fireValueChanged(node);
2233 }
2234
2235 void
2236 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2237                                 SGPropertyNode * child)
2238 {
2239   if (_listeners != 0) {
2240     for (unsigned int i = 0; i < _listeners->size(); i++) {
2241       (*_listeners)[i]->childAdded(parent, child);
2242     }
2243   }
2244   if (_parent != 0)
2245     _parent->fireChildAdded(parent, child);
2246 }
2247
2248 void
2249 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2250                                   SGPropertyNode * child)
2251 {
2252   if (_listeners != 0) {
2253     for (unsigned int i = 0; i < _listeners->size(); i++) {
2254       (*_listeners)[i]->childRemoved(parent, child);
2255     }
2256   }
2257   if (_parent != 0)
2258     _parent->fireChildRemoved(parent, child);
2259 }
2260
2261 //------------------------------------------------------------------------------
2262 SGPropertyNode_ptr
2263 SGPropertyNode::eraseChild(simgear::PropertyList::iterator child)
2264 {
2265   SGPropertyNode_ptr node = *child;
2266   node->setAttribute(REMOVED, true);
2267   node->clearValue();
2268   fireChildRemoved(node);
2269
2270   _children.erase(child);
2271   return node;
2272 }
2273
2274 ////////////////////////////////////////////////////////////////////////
2275 // Implementation of SGPropertyChangeListener.
2276 ////////////////////////////////////////////////////////////////////////
2277
2278 SGPropertyChangeListener::~SGPropertyChangeListener ()
2279 {
2280   for (int i = static_cast<int>(_properties.size() - 1); i >= 0; i--)
2281     _properties[i]->removeChangeListener(this);
2282 }
2283
2284 void
2285 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2286 {
2287   // NO-OP
2288 }
2289
2290 void
2291 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2292                                       SGPropertyNode * child)
2293 {
2294   // NO-OP
2295 }
2296
2297 void
2298 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2299                                         SGPropertyNode * child)
2300 {
2301   // NO-OP
2302 }
2303
2304 void
2305 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2306 {
2307   _properties.push_back(node);
2308 }
2309
2310 void
2311 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2312 {
2313   vector<SGPropertyNode *>::iterator it =
2314     find(_properties.begin(), _properties.end(), node);
2315   if (it != _properties.end())
2316     _properties.erase(it);
2317 }
2318
2319 template<>
2320 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2321 {
2322     const SGVec3d vec
2323         = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2324     for (int i = 0; i < 3; ++i) {
2325         stream << vec[i];
2326         if (i < 2)
2327             stream << ' ';
2328     }
2329     return stream;
2330 }
2331
2332 namespace simgear
2333 {
2334 template<>
2335 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2336 {
2337     for (int i = 0; i < 3; ++i) {
2338         stream >> result[i];
2339     }
2340     return stream;
2341 }
2342 }
2343 template<>
2344 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2345 {
2346     const SGVec4d vec
2347         = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();    
2348     for (int i = 0; i < 4; ++i) {
2349         stream << vec[i];
2350         if (i < 3)
2351             stream << ' ';
2352     }
2353     return stream;
2354 }
2355
2356 namespace simgear
2357 {
2358 template<>
2359 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2360 {
2361     for (int i = 0; i < 4; ++i) {
2362         stream >> result[i];
2363     }
2364     return stream;
2365 }
2366
2367 namespace
2368 {
2369 bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
2370 {
2371     props::Type ltype = lhs.getType();
2372     props::Type rtype = rhs.getType();
2373     if (ltype != rtype)
2374         return false;
2375     switch (ltype) {
2376     case props::NONE:
2377         return true;
2378     case props::ALIAS:
2379         return false;           // XXX Should we look in aliases?
2380     case props::BOOL:
2381         return lhs.getValue<bool>() == rhs.getValue<bool>();
2382     case props::INT:
2383         return lhs.getValue<int>() == rhs.getValue<int>();
2384     case props::LONG:
2385         return lhs.getValue<long>() == rhs.getValue<long>();
2386     case props::FLOAT:
2387         return lhs.getValue<float>() == rhs.getValue<float>();
2388     case props::DOUBLE:
2389         return lhs.getValue<double>() == rhs.getValue<double>();
2390     case props::STRING:
2391     case props::UNSPECIFIED:
2392         return !strcmp(lhs.getStringValue(), rhs.getStringValue());
2393     case props::VEC3D:
2394         return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
2395     case props::VEC4D:
2396         return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
2397     default:
2398         return false;
2399     }
2400 }
2401 }
2402 }
2403
2404 bool SGPropertyNode::compare(const SGPropertyNode& lhs,
2405                              const SGPropertyNode& rhs)
2406 {
2407     if (&lhs == &rhs)
2408         return true;
2409     int lhsChildren = lhs.nChildren();
2410     int rhsChildren = rhs.nChildren();
2411     if (lhsChildren != rhsChildren)
2412         return false;
2413     if (lhsChildren == 0)
2414         return compareNodeValue(lhs, rhs);
2415     for (size_t i = 0; i < lhs._children.size(); ++i) {
2416         const SGPropertyNode* lchild = lhs._children[i];
2417         const SGPropertyNode* rchild = rhs._children[i];
2418         // I'm guessing that the nodes will usually be in the same
2419         // order.
2420         if (lchild->getIndex() != rchild->getIndex()
2421             || lchild->getNameString() != rchild->getNameString()) {
2422             rchild = 0;
2423             for (PropertyList::const_iterator itr = rhs._children.begin(),
2424                      end = rhs._children.end();
2425                  itr != end;
2426                 ++itr)
2427                 if (lchild->getIndex() == (*itr)->getIndex()
2428                     && lchild->getNameString() == (*itr)->getNameString()) {
2429                     rchild = *itr;
2430                     break;
2431                 }
2432             if (!rchild)
2433                 return false;
2434         }
2435         if (!compare(*lchild, *rchild))
2436             return false;
2437     }
2438     return true;
2439 }
2440
2441 struct PropertyPlaceLess {
2442     typedef bool result_type;
2443     bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const
2444     {
2445         int comp = lhs->getNameString().compare(rhs->getNameString());
2446         if (comp == 0)
2447             return lhs->getIndex() < rhs->getIndex();
2448         else
2449             return comp < 0;
2450     }
2451 };
2452
2453 size_t hash_value(const SGPropertyNode& node)
2454 {
2455     using namespace boost;
2456
2457     if (node.nChildren() == 0) {
2458         switch (node.getType()) {
2459         case props::NONE:
2460             return 0;
2461
2462         case props::BOOL:
2463             return hash_value(node.getValue<bool>());
2464         case props::INT:
2465             return hash_value(node.getValue<int>());
2466         case props::LONG:
2467             return hash_value(node.getValue<long>());
2468         case props::FLOAT:
2469             return hash_value(node.getValue<float>());
2470         case props::DOUBLE:
2471             return hash_value(node.getValue<double>());
2472         case props::STRING:
2473         case props::UNSPECIFIED:
2474         {
2475             const char *val = node.getStringValue();
2476             return hash_range(val, val + strlen(val));
2477         }
2478         case props::VEC3D:
2479         {
2480             const SGVec3d val = node.getValue<SGVec3d>();
2481             return hash_range(&val[0], &val[3]);
2482         }
2483         case props::VEC4D:
2484         {
2485             const SGVec4d val = node.getValue<SGVec4d>();
2486             return hash_range(&val[0], &val[4]);
2487         }
2488         case props::ALIAS:      // XXX Should we look in aliases?
2489         default:
2490             return 0;
2491         }
2492     } else {
2493         size_t seed = 0;
2494         PropertyList children(node._children.begin(), node._children.end());
2495         sort(children.begin(), children.end(), PropertyPlaceLess());
2496         for (PropertyList::const_iterator itr  = children.begin(),
2497                  end = children.end();
2498              itr != end;
2499              ++itr) {
2500             hash_combine(seed, (*itr)->_name);
2501             hash_combine(seed, (*itr)->_index);
2502             hash_combine(seed, hash_value(**itr));
2503         }
2504         return seed;
2505     }
2506 }
2507
2508 // end of props.cxx