]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropertyManager.h
More tweaks to the automake/conf configuration scripts.
[flightgear.git] / src / FDM / JSBSim / FGPropertyManager.h
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2  
3  Header:       FGPropertyManager.h
4  Author:       Tony Peden
5                Based on work originally by David Megginson
6  Date:         2/2002
7  
8  ------------- Copyright (C) 2002 -------------
9  
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14  
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  details.
19  
20  You should have received a copy of the GNU General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26  
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 SENTRY
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30
31 #ifndef FGPROPERTYMANAGER_H
32 #define FGPROPERTYMANAGER_H
33
34 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 INCLUDES
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
37
38 #include <simgear/misc/props.hxx>
39
40 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 DEFINITIONS
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
43
44 #define ID_PROPERTYMANAGER "$Id$"
45
46 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
47 FORWARD DECLARATIONS
48 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
49
50 using namespace std;
51
52 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55
56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 CLASS DOCUMENTATION
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59
60 /** Class wrapper for property handling.
61     @author David Megginson, Tony Peden
62     @see <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jsbsim/JSBSim/FGPropertyManager.h?rev=HEAD&content-type=text/vnd.viewcvs-markup">
63          Header File </a>
64     @see <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jsbsim/JSBSim/FGPropertyManager.cpp?rev=HEAD&content-type=text/vnd.viewcvs-markup">
65          Source File </a>
66   */
67   
68 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 CLASS DECLARATION
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
71
72 class FGPropertyManager:public SGPropertyNode {
73   public:
74     /// Constructor
75     FGPropertyManager(void) {
76       
77     }
78     /// Destructor
79     ~FGPropertyManager(void) {
80       
81     }   
82     /**
83      * Get a property node.
84      *
85      * @param path The path of the node, relative to root.
86      * @param create true to create the node if it doesn't exist.
87      * @return The node, or 0 if none exists and none was created.
88      */
89     inline FGPropertyManager* 
90     GetNode (const string &path, bool create = false)
91     {
92       SGPropertyNode* node=this->getNode(path.c_str(), create);
93       if(node == 0) 
94         cout << "FGPropertyManager::GetNode() No node found for " 
95              << path << endl;
96       return (FGPropertyManager*)node;
97     }
98   
99     inline FGPropertyManager* 
100     GetNode (const string &relpath, int index, bool create = false)
101     {
102         return (FGPropertyManager*)getNode(relpath.c_str(),index,create);
103     }    
104
105
106     /**
107      * Test whether a given node exists.
108      *
109      * @param path The path of the node, relative to root.
110      * @return true if the node exists, false otherwise.
111      */
112     inline bool
113     HasNode (const string &path)
114     {
115       return (GetNode(path, false) != 0);
116     }
117
118     /**
119      * Get the name of a node
120      */
121     inline string
122     GetName( void ) {
123       return string( getName() );
124     }  
125
126     /**
127      * Get a bool value for a property.
128      *
129      * This method is convenient but inefficient.  It should be used
130      * infrequently (i.e. for initializing, loading, saving, etc.),
131      * not in the main loop.  If you need to get a value frequently,
132      * it is better to look up the node itself using GetNode and then
133      * use the node's getBoolValue() method, to avoid the lookup overhead.
134      *
135      * @param name The property name.
136      * @param defaultValue The default value to return if the property
137      *        does not exist.
138      * @return The property's value as a bool, or the default value provided.
139      */
140     inline bool GetBool (const string &name, bool defaultValue = false)
141     {
142       return getBoolValue(name.c_str(), defaultValue);
143     }
144
145
146     /**
147      * Get an int value for a property.
148      *
149      * This method is convenient but inefficient.  It should be used
150      * infrequently (i.e. for initializing, loading, saving, etc.),
151      * not in the main loop.  If you need to get a value frequently,
152      * it is better to look up the node itself using GetNode and then
153      * use the node's getIntValue() method, to avoid the lookup overhead.
154      *
155      * @param name The property name.
156      * @param defaultValue The default value to return if the property
157      *        does not exist.
158      * @return The property's value as an int, or the default value provided.
159      */
160     inline int GetInt (const string &name, int defaultValue = 0)
161     {
162       return getIntValue(name.c_str(), defaultValue);
163     }
164
165
166     /**
167      * Get a long value for a property.
168      *
169      * This method is convenient but inefficient.  It should be used
170      * infrequently (i.e. for initializing, loading, saving, etc.),
171      * not in the main loop.  If you need to get a value frequently,
172      * it is better to look up the node itself using GetNode and then
173      * use the node's getLongValue() method, to avoid the lookup overhead.
174      *
175      * @param name The property name.
176      * @param defaultValue The default value to return if the property
177      *        does not exist.
178      * @return The property's value as a long, or the default value provided.
179      */
180     inline int GetLong (const string &name, long defaultValue = 0L)
181     {
182       return getLongValue(name.c_str(), defaultValue);
183     }
184
185
186     /**
187      * Get a float value for a property.
188      *
189      * This method is convenient but inefficient.  It should be used
190      * infrequently (i.e. for initializing, loading, saving, etc.),
191      * not in the main loop.  If you need to get a value frequently,
192      * it is better to look up the node itself using GetNode and then
193      * use the node's getFloatValue() method, to avoid the lookup overhead.
194      *
195      * @param name The property name.
196      * @param defaultValue The default value to return if the property
197      *        does not exist.
198      * @return The property's value as a float, or the default value provided.
199      */
200     inline float GetFloat (const string &name, float defaultValue = 0.0)
201     {
202       return getFloatValue(name.c_str(), defaultValue);
203     }
204
205
206     /**
207      * Get a double value for a property.
208      *
209      * This method is convenient but inefficient.  It should be used
210      * infrequently (i.e. for initializing, loading, saving, etc.),
211      * not in the main loop.  If you need to get a value frequently,
212      * it is better to look up the node itself using GetNode and then
213      * use the node's getDoubleValue() method, to avoid the lookup overhead.
214      *
215      * @param name The property name.
216      * @param defaultValue The default value to return if the property
217      *        does not exist.
218      * @return The property's value as a double, or the default value provided.
219      */
220     inline double GetDouble (const string &name, double defaultValue = 0.0)
221     {
222       return getDoubleValue(name.c_str(), defaultValue);
223     }
224
225
226     /**
227      * Get a string value for a property.
228      *
229      * This method is convenient but inefficient.  It should be used
230      * infrequently (i.e. for initializing, loading, saving, etc.),
231      * not in the main loop.  If you need to get a value frequently,
232      * it is better to look up the node itself using GetNode and then
233      * use the node's getStringValue() method, to avoid the lookup overhead.
234      *
235      * @param name The property name.
236      * @param defaultValue The default value to return if the property
237      *        does not exist.
238      * @return The property's value as a string, or the default value provided.
239      */
240     inline string GetString (const string &name, string defaultValue = "")
241     {
242       return string(getStringValue(name.c_str(), defaultValue.c_str()));
243     }
244
245
246     /**
247      * Set a bool value for a property.
248      *
249      * Assign a bool value to a property.  If the property does not
250      * yet exist, it will be created and its type will be set to
251      * BOOL; if it has a type of UNKNOWN, the type will also be set to
252      * BOOL; otherwise, the bool value will be converted to the property's
253      * type.
254      *
255      * @param name The property name.
256      * @param val The new value for the property.
257      * @return true if the assignment succeeded, false otherwise.
258      */
259     inline bool SetBool (const string &name, bool val)
260     {
261       return setBoolValue(name.c_str(), val);
262     }
263
264
265     /**
266      * Set an int value for a property.
267      *
268      * Assign an int value to a property.  If the property does not
269      * yet exist, it will be created and its type will be set to
270      * INT; if it has a type of UNKNOWN, the type will also be set to
271      * INT; otherwise, the bool value will be converted to the property's
272      * type.
273      *
274      * @param name The property name.
275      * @param val The new value for the property.
276      * @return true if the assignment succeeded, false otherwise.
277      */
278     inline bool SetInt (const string &name, int val)
279     {
280       return setIntValue(name.c_str(), val);
281     }
282
283
284     /**
285      * Set a long value for a property.
286      *
287      * Assign a long value to a property.  If the property does not
288      * yet exist, it will be created and its type will be set to
289      * LONG; if it has a type of UNKNOWN, the type will also be set to
290      * LONG; otherwise, the bool value will be converted to the property's
291      * type.
292      *
293      * @param name The property name.
294      * @param val The new value for the property.
295      * @return true if the assignment succeeded, false otherwise.
296      */
297     inline bool SetLong (const string &name, long val)
298     {
299       return setLongValue(name.c_str(), val);
300     }
301
302
303     /**
304      * Set a float value for a property.
305      *
306      * Assign a float value to a property.  If the property does not
307      * yet exist, it will be created and its type will be set to
308      * FLOAT; if it has a type of UNKNOWN, the type will also be set to
309      * FLOAT; otherwise, the bool value will be converted to the property's
310      * type.
311      *
312      * @param name The property name.
313      * @param val The new value for the property.
314      * @return true if the assignment succeeded, false otherwise.
315      */
316     inline bool SetFloat (const string &name, float val)
317     {
318       return setFloatValue(name.c_str(), val);
319     }
320
321
322     /**
323      * Set a double value for a property.
324      *
325      * Assign a double value to a property.  If the property does not
326      * yet exist, it will be created and its type will be set to
327      * DOUBLE; if it has a type of UNKNOWN, the type will also be set to
328      * DOUBLE; otherwise, the double value will be converted to the property's
329      * type.
330      *
331      * @param name The property name.
332      * @param val The new value for the property.
333      * @return true if the assignment succeeded, false otherwise.
334      */
335     inline bool SetDouble (const string &name, double val)
336     {
337       return setDoubleValue(name.c_str(), val);
338     }
339
340
341     /**
342      * Set a string value for a property.
343      *
344      * Assign a string value to a property.  If the property does not
345      * yet exist, it will be created and its type will be set to
346      * STRING; if it has a type of UNKNOWN, the type will also be set to
347      * STRING; otherwise, the string value will be converted to the property's
348      * type.
349      *
350      * @param name The property name.
351      * @param val The new value for the property.
352      * @return true if the assignment succeeded, false otherwise.
353      */
354     inline bool SetString (const string &name, const string &val)
355     {
356       return setStringValue(name.c_str(), val.c_str());
357     }
358
359
360     ////////////////////////////////////////////////////////////////////////
361     // Convenience functions for setting property attributes.
362     ////////////////////////////////////////////////////////////////////////
363
364
365     /**
366      * Set the state of the archive attribute for a property.
367      *
368      * If the archive attribute is true, the property will be written
369      * when a flight is saved; if it is false, the property will be
370      * skipped.
371      *
372      * A warning message will be printed if the property does not exist.
373      *
374      * @param name The property name.
375      * @param state The state of the archive attribute (defaults to true).
376      */
377     inline void
378     SetArchivable (const string &name, bool state = true)
379     {
380       SGPropertyNode * node = getNode(name.c_str());
381       if (node == 0)
382         cout <<
383                "Attempt to set archive flag for non-existant property "
384                << name << endl;
385       else
386         node->setAttribute(SGPropertyNode::ARCHIVE, state);
387     }
388
389
390     /**
391      * Set the state of the read attribute for a property.
392      *
393      * If the read attribute is true, the property value will be readable;
394      * if it is false, the property value will always be the default value
395      * for its type.
396      *
397      * A warning message will be printed if the property does not exist.
398      *
399      * @param name The property name.
400      * @param state The state of the read attribute (defaults to true).
401      */
402     inline void
403     SetReadable (const string &name, bool state = true)
404     {
405       SGPropertyNode * node = getNode(name.c_str());
406       if (node == 0)
407         cout <<
408                "Attempt to set read flag for non-existant property "
409                << name << endl;
410       else
411         node->setAttribute(SGPropertyNode::READ, state);
412     }
413
414
415     /**
416      * Set the state of the write attribute for a property.
417      *
418      * If the write attribute is true, the property value may be modified
419      * (depending on how it is tied); if the write attribute is false, the
420      * property value may not be modified.
421      *
422      * A warning message will be printed if the property does not exist.
423      *
424      * @param name The property name.
425      * @param state The state of the write attribute (defaults to true).
426      */
427     inline void
428     SetWritable (const string &name, bool state = true)
429     {
430       SGPropertyNode * node = getNode(name.c_str());
431       if (node == 0)
432         cout <<
433                "Attempt to set write flag for non-existant property "
434                << name << endl;
435       else
436         node->setAttribute(SGPropertyNode::WRITE, state);
437     }
438
439
440     ////////////////////////////////////////////////////////////////////////
441     // Convenience functions for tying properties, with logging.
442     ////////////////////////////////////////////////////////////////////////
443
444
445     /**
446      * Untie a property from an external data source.
447      *
448      * Classes should use this function to release control of any
449      * properties they are managing.
450      */
451     inline void
452     Untie (const string &name)
453     {
454       if (!untie(name.c_str()))
455         cout << "Failed to untie property " << name << endl;
456     }
457
458
459                                     // Templates cause ambiguity here
460
461     /**
462      * Tie a property to an external bool variable.
463      *
464      * The property's value will automatically mirror the variable's
465      * value, and vice-versa, until the property is untied.
466      *
467      * @param name The property name to tie (full path).
468      * @param pointer A pointer to the variable.
469      * @param useDefault true if any existing property value should be
470      *        copied to the variable; false if the variable should not
471      *        be modified; defaults to true.
472      */
473     inline void
474     Tie (const string &name, bool *pointer, bool useDefault = true)
475     {
476       if (!tie(name.c_str(), SGRawValuePointer<bool>(pointer),
477                                      useDefault))
478         cout <<
479                "Failed to tie property " << name << " to a pointer" << endl;
480     }
481
482
483     /**
484      * Tie a property to an external int variable.
485      *
486      * The property's value will automatically mirror the variable's
487      * value, and vice-versa, until the property is untied.
488      *
489      * @param name The property name to tie (full path).
490      * @param pointer A pointer to the variable.
491      * @param useDefault true if any existing property value should be
492      *        copied to the variable; false if the variable should not
493      *        be modified; defaults to true.
494      */
495     inline void
496     Tie (const string &name, int *pointer, bool useDefault = true)
497     {
498       if (!tie(name.c_str(), SGRawValuePointer<int>(pointer),
499                                      useDefault))
500         cout <<
501                "Failed to tie property " << name << " to a pointer" << endl;
502     }
503
504
505     /**
506      * Tie a property to an external long variable.
507      *
508      * The property's value will automatically mirror the variable's
509      * value, and vice-versa, until the property is untied.
510      *
511      * @param name The property name to tie (full path).
512      * @param pointer A pointer to the variable.
513      * @param useDefault true if any existing property value should be
514      *        copied to the variable; false if the variable should not
515      *        be modified; defaults to true.
516      */
517     inline void
518     Tie (const string &name, long *pointer, bool useDefault = true)
519     {
520       if (!tie(name.c_str(), SGRawValuePointer<long>(pointer),
521                                      useDefault))
522         cout <<
523                "Failed to tie property " << name << " to a pointer" << endl;
524     }
525
526
527     /**
528      * Tie a property to an external float variable.
529      *
530      * The property's value will automatically mirror the variable's
531      * value, and vice-versa, until the property is untied.
532      *
533      * @param name The property name to tie (full path).
534      * @param pointer A pointer to the variable.
535      * @param useDefault true if any existing property value should be
536      *        copied to the variable; false if the variable should not
537      *        be modified; defaults to true.
538      */
539     inline void
540     Tie (const string &name, float *pointer, bool useDefault = true)
541     {
542       if (!tie(name.c_str(), SGRawValuePointer<float>(pointer),
543                                      useDefault))
544         cout <<
545                "Failed to tie property " << name << " to a pointer" << endl;
546     }
547
548
549     /**
550      * Tie a property to an external double variable.
551      *
552      * The property's value will automatically mirror the variable's
553      * value, and vice-versa, until the property is untied.
554      *
555      * @param name The property name to tie (full path).
556      * @param pointer A pointer to the variable.
557      * @param useDefault true if any existing property value should be
558      *        copied to the variable; false if the variable should not
559      *        be modified; defaults to true.
560      */
561     inline void
562     Tie (const string &name, double *pointer, bool useDefault = true)
563     {
564       if (!tie(name.c_str(), SGRawValuePointer<double>(pointer),
565                                      useDefault))
566         cout <<
567                "Failed to tie property " << name << " to a pointer" << endl;
568     }
569
570     /* template <class V> void
571     Tie (const string &name, V (*getter)(), void (*setter)(V) = 0,
572            bool useDefault = true);
573     
574     template <class V> void
575     Tie (const string &name, int index, V (*getter)(int),
576            void (*setter)(int, V) = 0, bool useDefault = true);
577     
578     template <class T, class V> void
579     Tie (const string &name, T * obj, V (T::*getter)() const,
580            void (T::*setter)(V) = 0, bool useDefault = true);
581
582     template <class T, class V> void 
583     Tie (const string &name, T * obj, int index,
584            V (T::*getter)(int) const, void (T::*setter)(int, V) = 0,
585            bool useDefault = true); */
586
587 /**
588      * Tie a property to a pair of simple functions.
589      *
590      * Every time the property value is queried, the getter (if any) will
591      * be invoked; every time the property value is modified, the setter
592      * (if any) will be invoked.  The getter can be 0 to make the property
593      * unreadable, and the setter can be 0 to make the property
594      * unmodifiable.
595      *
596      * @param name The property name to tie (full path).
597      * @param getter The getter function, or 0 if the value is unreadable.
598      * @param setter The setter function, or 0 if the value is unmodifiable.
599      * @param useDefault true if the setter should be invoked with any existing 
600      *        property value should be; false if the old value should be
601      *        discarded; defaults to true.
602      */
603     template <class V>
604     inline void
605     Tie (const string &name, V (*getter)(), void (*setter)(V) = 0,
606            bool useDefault = true)
607     {
608       if (!tie(name.c_str(), SGRawValueFunctions<V>(getter, setter),
609                                      useDefault))
610         cout <<
611                "Failed to tie property " << name << " to functions" << endl;
612     }
613
614
615     /**
616      * Tie a property to a pair of indexed functions.
617      *
618      * Every time the property value is queried, the getter (if any) will
619      * be invoked with the index provided; every time the property value
620      * is modified, the setter (if any) will be invoked with the index
621      * provided.  The getter can be 0 to make the property unreadable, and
622      * the setter can be 0 to make the property unmodifiable.
623      *
624      * @param name The property name to tie (full path).
625      * @param index The integer argument to pass to the getter and
626      *        setter functions.
627      * @param getter The getter function, or 0 if the value is unreadable.
628      * @param setter The setter function, or 0 if the value is unmodifiable.
629      * @param useDefault true if the setter should be invoked with any existing 
630      *        property value should be; false if the old value should be
631      *        discarded; defaults to true.
632      */
633     template <class V>
634     inline void
635     Tie (const string &name, int index, V (*getter)(int),
636            void (*setter)(int, V) = 0, bool useDefault = true)
637     {
638       if (!tie(name.c_str(),
639                                      SGRawValueFunctionsIndexed<V>(index,
640                                                                    getter,
641                                                                    setter),
642                                      useDefault))
643         cout <<
644                "Failed to tie property " << name << " to indexed functions" << endl;
645     }
646
647
648     /**
649      * Tie a property to a pair of object methods.
650      *
651      * Every time the property value is queried, the getter (if any) will
652      * be invoked; every time the property value is modified, the setter
653      * (if any) will be invoked.  The getter can be 0 to make the property
654      * unreadable, and the setter can be 0 to make the property
655      * unmodifiable.
656      *
657      * @param name The property name to tie (full path).
658      * @param obj The object whose methods should be invoked.
659      * @param getter The object's getter method, or 0 if the value is
660      *        unreadable.
661      * @param setter The object's setter method, or 0 if the value is
662      *        unmodifiable.
663      * @param useDefault true if the setter should be invoked with any existing 
664      *        property value should be; false if the old value should be
665      *        discarded; defaults to true.
666      */
667     template <class T, class V>
668     inline void
669     Tie (const string &name, T * obj, V (T::*getter)() const,
670            void (T::*setter)(V) = 0, bool useDefault = true)
671     {
672       if (!tie(name.c_str(),
673                                      SGRawValueMethods<T,V>(*obj, getter, setter),
674                                      useDefault))
675         cout <<
676                "Failed to tie property " << name << " to object methods" << endl;
677     }
678
679
680     /**
681      * Tie a property to a pair of indexed object methods.
682      *
683      * Every time the property value is queried, the getter (if any) will
684      * be invoked with the index provided; every time the property value
685      * is modified, the setter (if any) will be invoked with the index
686      * provided.  The getter can be 0 to make the property unreadable, and
687      * the setter can be 0 to make the property unmodifiable.
688      *
689      * @param name The property name to tie (full path).
690      * @param obj The object whose methods should be invoked.
691      * @param index The integer argument to pass to the getter and
692      *        setter methods.
693      * @param getter The getter method, or 0 if the value is unreadable.
694      * @param setter The setter method, or 0 if the value is unmodifiable.
695      * @param useDefault true if the setter should be invoked with any existing 
696      *        property value should be; false if the old value should be
697      *        discarded; defaults to true.
698      */
699     template <class T, class V>
700     inline void 
701     Tie (const string &name, T * obj, int index,
702            V (T::*getter)(int) const, void (T::*setter)(int, V) = 0,
703            bool useDefault = true)
704     {
705       if (!tie(name.c_str(),
706                                      SGRawValueMethodsIndexed<T,V>(*obj,
707                                                                    index,
708                                                                    getter,
709                                                                    setter),
710                                      useDefault))
711         cout <<
712                "Failed to tie property " << name << " to indexed object methods" << endl;
713     }
714
715 };        
716
717 #endif // FGPROPERTYMANAGER_H
718