]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
93c205d1e7f80cd1878c34ba99aeabaad7382ba6
[flightgear.git] / src / Main / fg_props.cxx
1 // fg_props.cxx -- support for FlightGear properties.
2 //
3 // Written by David Megginson, started 2000.
4 //
5 // Copyright (C) 2000, 2001 David Megginson - david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear/compiler.h>
25 #endif
26
27 #include <simgear/misc/exception.hxx>
28 #include <simgear/magvar/magvar.hxx>
29 #include <simgear/timing/sg_time.hxx>
30 #include <simgear/misc/sg_path.hxx>
31
32 #include STL_IOSTREAM
33
34 #include <ATC/ATCdisplay.hxx>
35 #include <Aircraft/aircraft.hxx>
36 #include <Time/tmp.hxx>
37 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
38 #ifdef FG_WEATHERCM
39 #  include <WeatherCM/FGLocalWeatherDatabase.h>
40 #else
41 #  include <Environment/environment.hxx>
42 #endif // FG_WEATHERCM
43 #include <Objects/matlib.hxx>
44
45 #include <GUI/gui.h>
46 #include <Sound/soundmgr.hxx>
47
48 #include "globals.hxx"
49 #include "fgfs.hxx"
50 #include "fg_props.hxx"
51
52 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
53 SG_USING_STD(istream);
54 SG_USING_STD(ostream);
55 #endif
56
57 #ifdef FG_WEATHERCM
58 static double getWindNorth ();
59 static double getWindEast ();
60 static double getWindDown ();
61 #endif // FG_WEATHERCM
62
63 static bool winding_ccw = true; // FIXME: temporary
64
65 static bool fdm_data_logging = false; // FIXME: temporary
66
67 static bool frozen = false;     // FIXME: temporary
68
69
70 \f
71 ////////////////////////////////////////////////////////////////////////
72 // Default property bindings (not yet handled by any module).
73 ////////////////////////////////////////////////////////////////////////
74
75 struct LogClassMapping {
76   sgDebugClass c;
77   string name;
78   LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
79 };
80
81 LogClassMapping log_class_mappings [] = {
82   LogClassMapping(SG_NONE, "none"),
83   LogClassMapping(SG_TERRAIN, "terrain"),
84   LogClassMapping(SG_ASTRO, "astro"),
85   LogClassMapping(SG_FLIGHT, "flight"),
86   LogClassMapping(SG_INPUT, "input"),
87   LogClassMapping(SG_GL, "gl"),
88   LogClassMapping(SG_VIEW, "view"),
89   LogClassMapping(SG_COCKPIT, "cockpit"),
90   LogClassMapping(SG_GENERAL, "general"),
91   LogClassMapping(SG_MATH, "math"),
92   LogClassMapping(SG_EVENT, "event"),
93   LogClassMapping(SG_AIRCRAFT, "aircraft"),
94   LogClassMapping(SG_AUTOPILOT, "autopilot"),
95   LogClassMapping(SG_IO, "io"),
96   LogClassMapping(SG_CLIPPER, "clipper"),
97   LogClassMapping(SG_NETWORK, "network"),
98   LogClassMapping(SG_UNDEFD, "")
99 };
100
101
102 /**
103  * Get the logging classes.
104  */
105 static const char *
106 getLoggingClasses ()
107 {
108   sgDebugClass classes = logbuf::get_log_classes();
109   static string result = "";    // FIXME
110   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
111     if ((classes&log_class_mappings[i].c) > 0) {
112       if (!result.empty())
113         result += '|';
114       result += log_class_mappings[i].name;
115     }
116   }
117   return result.c_str();
118 }
119
120
121 static void
122 addLoggingClass (const string &name)
123 {
124   sgDebugClass classes = logbuf::get_log_classes();
125   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
126     if (name == log_class_mappings[i].name) {
127       logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
128       return;
129     }
130   }
131   SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
132 }
133
134
135 /**
136  * Set the logging classes.
137  */
138 static void
139 setLoggingClasses (const char * c)
140 {
141   string classes = c;
142   logbuf::set_log_classes(SG_NONE);
143
144   if (classes == "none") {
145     SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
146     return;
147   }
148
149   if (classes.empty() || classes == "all") { // default
150     logbuf::set_log_classes(SG_ALL);
151     SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
152            << getLoggingClasses());
153     return;
154   }
155
156   string rest = classes;
157   string name = "";
158   int sep = rest.find('|');
159   while (sep > 0) {
160     name = rest.substr(0, sep);
161     rest = rest.substr(sep+1);
162     addLoggingClass(name);
163     sep = rest.find('|');
164   }
165   addLoggingClass(rest);
166   SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
167          << getLoggingClasses());
168 }
169
170
171 /**
172  * Get the logging priority.
173  */
174 static const char *
175 getLoggingPriority ()
176 {
177   switch (logbuf::get_log_priority()) {
178   case SG_BULK:
179     return "bulk";
180   case SG_DEBUG:
181     return "debug";
182   case SG_INFO:
183     return "info";
184   case SG_WARN:
185     return "warn";
186   case SG_ALERT:
187     return "alert";
188   default:
189     SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
190            << logbuf::get_log_priority());
191     return "unknown";
192   }
193 }
194
195
196 /**
197  * Set the logging priority.
198  */
199 static void
200 setLoggingPriority (const char * p)
201 {
202   string priority = p;
203   if (priority == "bulk") {
204     logbuf::set_log_priority(SG_BULK);
205   } else if (priority == "debug") {
206     logbuf::set_log_priority(SG_DEBUG);
207   } else if (priority.empty() || priority == "info") { // default
208     logbuf::set_log_priority(SG_INFO);
209   } else if (priority == "warn") {
210     logbuf::set_log_priority(SG_WARN);
211   } else if (priority == "alert") {
212     logbuf::set_log_priority(SG_ALERT);
213   } else {
214     SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
215   }
216   SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
217 }
218
219
220 /**
221  * Return the current frozen state.
222  */
223 static bool
224 getFreeze ()
225 {
226   return frozen;
227 }
228
229
230 /**
231  * Set the current frozen state.
232  */
233 static void
234 setFreeze (bool f)
235 {
236     frozen = f;
237
238     // Stop sound on a pause
239     FGSoundMgr *s = globals->get_soundmgr();
240     if ( s != NULL ) {
241         if ( f ) {
242             s->pause();
243         } else {
244             s->resume();
245         }
246     }
247 }
248
249
250 /**
251  * Return the current aircraft directory (UIUC) as a string.
252  */
253 static const char *
254 getAircraftDir ()
255 {
256   return aircraft_dir.c_str();
257 }
258
259
260 /**
261  * Set the current aircraft directory (UIUC).
262  */
263 static void
264 setAircraftDir (const char * dir)
265 {
266   aircraft_dir = dir;
267 }
268
269
270 /**
271  * Return the number of milliseconds elapsed since simulation started.
272  */
273 static double
274 getElapsedTime_sec ()
275 {
276   return globals->get_sim_time_sec();
277 }
278
279
280 /**
281  * Return the current Zulu time.
282  */
283 static const char *
284 getDateString ()
285 {
286   static char buf[64];          // FIXME
287   struct tm * t = globals->get_time_params()->getGmt();
288   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
289           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
290           t->tm_hour, t->tm_min, t->tm_sec);
291   return buf;
292 }
293
294
295 /**
296  * Set the current Zulu time.
297  */
298 static void
299 setDateString (const char * date_string)
300 {
301   static const SGPropertyNode *cur_time_override
302         = fgGetNode("/sim/time/cur-time-override", true);
303
304   SGTime * st = globals->get_time_params();
305   struct tm * current_time = st->getGmt();
306   struct tm new_time;
307
308                                 // Scan for basic ISO format
309                                 // YYYY-MM-DDTHH:MM:SS
310   int ret = sscanf(date_string, "%d-%d-%dT%d:%d:%d",
311                    &(new_time.tm_year), &(new_time.tm_mon),
312                    &(new_time.tm_mday), &(new_time.tm_hour),
313                    &(new_time.tm_min), &(new_time.tm_sec));
314
315                                 // Be pretty picky about this, so
316                                 // that strange things don't happen
317                                 // if the save file has been edited
318                                 // by hand.
319   if (ret != 6) {
320     SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
321            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
322     return;
323   }
324
325                                 // OK, it looks like we got six
326                                 // values, one way or another.
327   new_time.tm_year -= 1900;
328   new_time.tm_mon -= 1;
329
330                                 // Now, tell flight gear to use
331                                 // the new time.  This was far
332                                 // too difficult, by the way.
333   long int warp =
334     mktime(&new_time) - mktime(current_time) + globals->get_warp();
335   double lon = current_aircraft.fdm_state->get_Longitude();
336   double lat = current_aircraft.fdm_state->get_Latitude();
337   globals->set_warp(warp);
338   st->update(lon, lat, cur_time_override->getLongValue(), warp);
339   fgUpdateSkyAndLightingParams();
340 }
341
342 /**
343  * Return the GMT as a string.
344  */
345 static const char *
346 getGMTString ()
347 {
348   static char buf[16];          // FIXME
349   struct tm *t = globals->get_time_params()->getGmt();
350   sprintf(buf, " %.2d:%.2d:%.2d",
351           t->tm_hour, t->tm_min, t->tm_sec);
352   // cout << t << " " << buf << endl;
353   return buf;
354 }
355
356
357 /**
358  * Get the texture rendering state.
359  */
360 static bool
361 getTextures ()
362 {
363   return (material_lib.get_step() == 0);
364 }
365
366
367 /**
368  * Set the texture rendering state.
369  */
370 static void
371 setTextures (bool textures)
372 {
373   if (textures)
374     material_lib.set_step(0);
375   else
376     material_lib.set_step(1);
377 }
378
379
380 /**
381  * Return the magnetic variation
382  */
383 static double
384 getMagVar ()
385 {
386   return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
387 }
388
389
390 /**
391  * Return the magnetic dip
392  */
393 static double
394 getMagDip ()
395 {
396   return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
397 }
398
399
400 /**
401  * Return the current heading in degrees.
402  */
403 static double
404 getHeadingMag ()
405 {
406   return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
407 }
408
409
410 #ifdef FG_WEATHERCM
411
412 /**
413  * Get the current visibility (meters).
414  */
415 static double
416 getVisibility ()
417 {
418   return WeatherDatabase->getWeatherVisibility();
419 }
420
421
422 /**
423  * Set the current visibility (meters).
424  */
425 static void
426 setVisibility (double visibility)
427 {
428   WeatherDatabase->setWeatherVisibility(visibility);
429 }
430
431 /**
432  * Get the current wind north velocity (feet/second).
433  */
434 static double
435 getWindNorth ()
436 {
437   return current_aircraft.fdm_state->get_V_north_airmass();
438 }
439
440
441 /**
442  * Set the current wind north velocity (feet/second).
443  */
444 static void
445 setWindNorth (double speed)
446 {
447   current_aircraft.fdm_state
448     ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
449 }
450
451
452 /**
453  * Get the current wind east velocity (feet/second).
454  */
455 static double
456 getWindEast ()
457 {
458   return current_aircraft.fdm_state->get_V_east_airmass();
459 }
460
461
462 /**
463  * Set the current wind east velocity (feet/second).
464  */
465 static void
466 setWindEast (double speed)
467 {
468   cout << "Set wind-east to " << speed << endl;
469   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
470                                                            speed,
471                                                            getWindDown());
472 }
473
474
475 /**
476  * Get the current wind down velocity (feet/second).
477  */
478 static double
479 getWindDown ()
480 {
481   return current_aircraft.fdm_state->get_V_down_airmass();
482 }
483
484
485 /**
486  * Set the current wind down velocity (feet/second).
487  */
488 static void
489 setWindDown (double speed)
490 {
491   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
492                                                            getWindEast(),
493                                                            speed);
494 }
495
496 #endif // FG_WEATHERCM
497
498 static long
499 getWarp ()
500 {
501   return globals->get_warp();
502 }
503
504 static void
505 setWarp (long warp)
506 {
507   globals->set_warp(warp);
508 }
509
510 static long
511 getWarpDelta ()
512 {
513   return globals->get_warp_delta();
514 }
515
516 static void
517 setWarpDelta (long delta)
518 {
519   globals->set_warp_delta(delta);
520 }
521
522 static bool
523 getWindingCCW ()
524 {
525   return winding_ccw;
526 }
527
528 static void
529 setWindingCCW (bool state)
530 {
531   winding_ccw = state;
532   if ( winding_ccw )
533     glFrontFace ( GL_CCW );
534   else
535     glFrontFace ( GL_CW );
536 }
537
538 static bool
539 getFullScreen ()
540 {
541 #if defined(FX) && !defined(WIN32)
542   return globals->get_fullscreen();
543 #else
544   return false;
545 #endif
546 }
547
548 static void
549 setFullScreen (bool state)
550 {
551 #if defined(FX) && !defined(WIN32)
552   globals->set_fullscreen(state);
553 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
554   XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
555 #  endif
556 #endif
557 }
558
559 static bool
560 getFDMDataLogging ()
561 {
562   return fdm_data_logging;
563 }
564
565 static void
566 setFDMDataLogging (bool state)
567 {
568                                 // kludge; no getter or setter available
569   if (state != fdm_data_logging) {
570     fgToggleFDMdataLogging();
571     fdm_data_logging = state;
572   }
573 }
574
575 \f
576 ////////////////////////////////////////////////////////////////////////
577 // Tie the properties.
578 ////////////////////////////////////////////////////////////////////////
579
580 void
581 fgInitProps ()
582 {
583   cout << "start of fgInitProps()" << endl;
584                                 // Simulation
585   fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
586   fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
587   fgTie("/sim/freeze/master", getFreeze, setFreeze);
588   fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
589
590   fgTie("/sim/time/elapsed-sec", getElapsedTime_sec);
591   fgTie("/sim/time/gmt", getDateString, setDateString);
592   fgSetArchivable("/sim/time/gmt");
593   fgTie("/sim/time/gmt-string", getGMTString);
594   fgTie("/sim/rendering/textures", getTextures, setTextures);
595
596                                 // Orientation
597   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
598
599                                 // Environment
600 #ifdef FG_WEATHERCM
601   fgTie("/environment/visibility-m", getVisibility, setVisibility);
602   fgSetArchivable("/environment/visibility-m");
603   fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
604   fgSetArchivable("/environment/wind-from-north-fps");
605   fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
606   fgSetArchivable("/environment/wind-from-east-fps");
607   fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
608   fgSetArchivable("/environment/wind-from-down-fps");
609 #endif
610
611   fgTie("/environment/magnetic-variation-deg", getMagVar);
612   fgTie("/environment/magnetic-dip-deg", getMagDip);
613
614   fgTie("/sim/time/warp", getWarp, setWarp, false);
615   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
616
617                                 // Misc. Temporary junk.
618   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
619   fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
620   fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
621
622   cout << "end of fgInitProps()" << endl;
623 }
624
625
626 void
627 fgUpdateProps ()
628 {
629 }
630
631
632 \f
633 ////////////////////////////////////////////////////////////////////////
634 // Save and restore.
635 ////////////////////////////////////////////////////////////////////////
636
637
638 /**
639  * Save the current state of the simulator to a stream.
640  */
641 bool
642 fgSaveFlight (ostream &output, bool write_all)
643 {
644
645   fgSetBool("/sim/presets/onground", false);
646   fgSetArchivable("/sim/presets/onground");
647   fgSetBool("/sim/presets/trim", false);
648   fgSetArchivable("/sim/presets/trim");
649   fgSetString("/sim/presets/speed-set", "UVW");
650   fgSetArchivable("/sim/presets/speed-set");
651
652   try {
653     writeProperties(output, globals->get_props(), write_all);
654   } catch (const sg_exception &e) {
655     guiErrorMessage("Error saving flight: ", e);
656     return false;
657   }
658   return true;
659 }
660
661
662 /**
663  * Restore the current state of the simulator from a stream.
664  */
665 bool
666 fgLoadFlight (istream &input)
667 {
668   SGPropertyNode props;
669   try {
670     readProperties(input, &props);
671   } catch (const sg_exception &e) {
672     guiErrorMessage("Error reading saved flight: ", e);
673     return false;
674   }
675
676   fgSetBool("/sim/presets/onground", false);
677   fgSetBool("/sim/presets/trim", false);
678   fgSetString("/sim/presets/speed-set", "UVW");
679
680   copyProperties(&props, globals->get_props());
681   // When loading a flight, make it the
682   // new initial state.
683   globals->saveInitialState();
684   return true;
685 }
686
687
688 void
689 fgLoadProps (const char * path, SGPropertyNode * props)
690 {
691     SGPath loadpath(globals->get_fg_root());
692     loadpath.append(path);
693     readProperties(loadpath.c_str(), props);
694 }
695
696
697 \f
698 ////////////////////////////////////////////////////////////////////////
699 // Property convenience functions.
700 ////////////////////////////////////////////////////////////////////////
701
702 SGPropertyNode *
703 fgGetNode (const char * path, bool create)
704 {
705   return globals->get_props()->getNode(path, create);
706 }
707
708 SGPropertyNode * 
709 fgGetNode (const char * path, int index, bool create)
710 {
711   return globals->get_props()->getNode(path, index, create);
712 }
713
714 bool
715 fgHasNode (const char * path)
716 {
717   return (fgGetNode(path, false) != 0);
718 }
719
720 void
721 fgAddChangeListener (SGPropertyChangeListener * listener, const char * path)
722 {
723   fgGetNode(path, true)->addChangeListener(listener);
724 }
725
726 void
727 fgAddChangeListener (SGPropertyChangeListener * listener,
728                      const char * path, int index)
729 {
730   fgGetNode(path, index, true)->addChangeListener(listener);
731 }
732
733 bool
734 fgGetBool (const char * name, bool defaultValue)
735 {
736   return globals->get_props()->getBoolValue(name, defaultValue);
737 }
738
739 int
740 fgGetInt (const char * name, int defaultValue)
741 {
742   return globals->get_props()->getIntValue(name, defaultValue);
743 }
744
745 int
746 fgGetLong (const char * name, long defaultValue)
747 {
748   return globals->get_props()->getLongValue(name, defaultValue);
749 }
750
751 float
752 fgGetFloat (const char * name, float defaultValue)
753 {
754   return globals->get_props()->getFloatValue(name, defaultValue);
755 }
756
757 double
758 fgGetDouble (const char * name, double defaultValue)
759 {
760   return globals->get_props()->getDoubleValue(name, defaultValue);
761 }
762
763 const char *
764 fgGetString (const char * name, const char * defaultValue)
765 {
766   return globals->get_props()->getStringValue(name, defaultValue);
767 }
768
769 bool
770 fgSetBool (const char * name, bool val)
771 {
772   return globals->get_props()->setBoolValue(name, val);
773 }
774
775 bool
776 fgSetInt (const char * name, int val)
777 {
778   return globals->get_props()->setIntValue(name, val);
779 }
780
781 bool
782 fgSetLong (const char * name, long val)
783 {
784   return globals->get_props()->setLongValue(name, val);
785 }
786
787 bool
788 fgSetFloat (const char * name, float val)
789 {
790   return globals->get_props()->setFloatValue(name, val);
791 }
792
793 bool
794 fgSetDouble (const char * name, double val)
795 {
796   return globals->get_props()->setDoubleValue(name, val);
797 }
798
799 bool
800 fgSetString (const char * name, const char * val)
801 {
802   return globals->get_props()->setStringValue(name, val);
803 }
804
805 void
806 fgSetArchivable (const char * name, bool state)
807 {
808   SGPropertyNode * node = globals->get_props()->getNode(name);
809   if (node == 0)
810     SG_LOG(SG_GENERAL, SG_ALERT,
811            "Attempt to set archive flag for non-existant property "
812            << name);
813   else
814     node->setAttribute(SGPropertyNode::ARCHIVE, state);
815 }
816
817 void
818 fgSetReadable (const char * name, bool state)
819 {
820   SGPropertyNode * node = globals->get_props()->getNode(name);
821   if (node == 0)
822     SG_LOG(SG_GENERAL, SG_ALERT,
823            "Attempt to set read flag for non-existant property "
824            << name);
825   else
826     node->setAttribute(SGPropertyNode::READ, state);
827 }
828
829 void
830 fgSetWritable (const char * name, bool state)
831 {
832   SGPropertyNode * node = globals->get_props()->getNode(name);
833   if (node == 0)
834     SG_LOG(SG_GENERAL, SG_ALERT,
835            "Attempt to set write flag for non-existant property "
836            << name);
837   else
838     node->setAttribute(SGPropertyNode::WRITE, state);
839 }
840
841 void
842 fgUntie (const char * name)
843 {
844   if (!globals->get_props()->untie(name))
845     SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
846 }
847
848
849
850 \f
851 ////////////////////////////////////////////////////////////////////////
852 // Implementation of FGCondition.
853 ////////////////////////////////////////////////////////////////////////
854
855 FGCondition::FGCondition ()
856 {
857 }
858
859 FGCondition::~FGCondition ()
860 {
861 }
862
863
864 \f
865 ////////////////////////////////////////////////////////////////////////
866 // Implementation of FGPropertyCondition.
867 ////////////////////////////////////////////////////////////////////////
868
869 FGPropertyCondition::FGPropertyCondition (const char * propname)
870   : _node(fgGetNode(propname, true))
871 {
872 }
873
874 FGPropertyCondition::~FGPropertyCondition ()
875 {
876 }
877
878
879 \f
880 ////////////////////////////////////////////////////////////////////////
881 // Implementation of FGNotCondition.
882 ////////////////////////////////////////////////////////////////////////
883
884 FGNotCondition::FGNotCondition (FGCondition * condition)
885   : _condition(condition)
886 {
887 }
888
889 FGNotCondition::~FGNotCondition ()
890 {
891   delete _condition;
892 }
893
894 bool
895 FGNotCondition::test () const
896 {
897   return !(_condition->test());
898 }
899
900
901 \f
902 ////////////////////////////////////////////////////////////////////////
903 // Implementation of FGAndCondition.
904 ////////////////////////////////////////////////////////////////////////
905
906 FGAndCondition::FGAndCondition ()
907 {
908 }
909
910 FGAndCondition::~FGAndCondition ()
911 {
912   for (unsigned int i = 0; i < _conditions.size(); i++)
913     delete _conditions[i];
914 }
915
916 bool
917 FGAndCondition::test () const
918 {
919   int nConditions = _conditions.size();
920   for (int i = 0; i < nConditions; i++) {
921     if (!_conditions[i]->test())
922       return false;
923   }
924   return true;
925 }
926
927 void
928 FGAndCondition::addCondition (FGCondition * condition)
929 {
930   _conditions.push_back(condition);
931 }
932
933
934 \f
935 ////////////////////////////////////////////////////////////////////////
936 // Implementation of FGOrCondition.
937 ////////////////////////////////////////////////////////////////////////
938
939 FGOrCondition::FGOrCondition ()
940 {
941 }
942
943 FGOrCondition::~FGOrCondition ()
944 {
945   for (unsigned int i = 0; i < _conditions.size(); i++)
946     delete _conditions[i];
947 }
948
949 bool
950 FGOrCondition::test () const
951 {
952   int nConditions = _conditions.size();
953   for (int i = 0; i < nConditions; i++) {
954     if (_conditions[i]->test())
955       return true;
956   }
957   return false;
958 }
959
960 void
961 FGOrCondition::addCondition (FGCondition * condition)
962 {
963   _conditions.push_back(condition);
964 }
965
966
967 \f
968 ////////////////////////////////////////////////////////////////////////
969 // Implementation of FGComparisonCondition.
970 ////////////////////////////////////////////////////////////////////////
971
972 static int
973 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
974 {
975   switch (left->getType()) {
976   case SGPropertyNode::BOOL: {
977     bool v1 = left->getBoolValue();
978     bool v2 = right->getBoolValue();
979     if (v1 < v2)
980       return FGComparisonCondition::LESS_THAN;
981     else if (v1 > v2)
982       return FGComparisonCondition::GREATER_THAN;
983     else
984       return FGComparisonCondition::EQUALS;
985     break;
986   }
987   case SGPropertyNode::INT: {
988     int v1 = left->getIntValue();
989     int v2 = right->getIntValue();
990     if (v1 < v2)
991       return FGComparisonCondition::LESS_THAN;
992     else if (v1 > v2)
993       return FGComparisonCondition::GREATER_THAN;
994     else
995       return FGComparisonCondition::EQUALS;
996     break;
997   }
998   case SGPropertyNode::LONG: {
999     long v1 = left->getLongValue();
1000     long v2 = right->getLongValue();
1001     if (v1 < v2)
1002       return FGComparisonCondition::LESS_THAN;
1003     else if (v1 > v2)
1004       return FGComparisonCondition::GREATER_THAN;
1005     else
1006       return FGComparisonCondition::EQUALS;
1007     break;
1008   }
1009   case SGPropertyNode::FLOAT: {
1010     float v1 = left->getFloatValue();
1011     float v2 = right->getFloatValue();
1012     if (v1 < v2)
1013       return FGComparisonCondition::LESS_THAN;
1014     else if (v1 > v2)
1015       return FGComparisonCondition::GREATER_THAN;
1016     else
1017       return FGComparisonCondition::EQUALS;
1018     break;
1019   }
1020   case SGPropertyNode::DOUBLE: {
1021     double v1 = left->getDoubleValue();
1022     double v2 = right->getDoubleValue();
1023     if (v1 < v2)
1024       return FGComparisonCondition::LESS_THAN;
1025     else if (v1 > v2)
1026       return FGComparisonCondition::GREATER_THAN;
1027     else
1028       return FGComparisonCondition::EQUALS;
1029     break;
1030   }
1031   case SGPropertyNode::STRING: 
1032   case SGPropertyNode::NONE:
1033   case SGPropertyNode::UNSPECIFIED: {
1034     string v1 = left->getStringValue();
1035     string v2 = right->getStringValue();
1036     if (v1 < v2)
1037       return FGComparisonCondition::LESS_THAN;
1038     else if (v1 > v2)
1039       return FGComparisonCondition::GREATER_THAN;
1040     else
1041       return FGComparisonCondition::EQUALS;
1042     break;
1043   }
1044   }
1045   throw sg_exception("Unrecognized node type");
1046   return 0;
1047 }
1048
1049
1050 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
1051   : _type(type),
1052     _reverse(reverse),
1053     _left_property(0),
1054     _right_property(0),
1055     _right_value(0)
1056 {
1057 }
1058
1059 FGComparisonCondition::~FGComparisonCondition ()
1060 {
1061   delete _right_value;
1062 }
1063
1064 bool
1065 FGComparisonCondition::test () const
1066 {
1067                                 // Always fail if incompletely specified
1068   if (_left_property == 0 ||
1069       (_right_property == 0 && _right_value == 0))
1070     return false;
1071
1072                                 // Get LESS_THAN, EQUALS, or GREATER_THAN
1073   int cmp =
1074     doComparison(_left_property,
1075                  (_right_property != 0 ? _right_property : _right_value));
1076   if (!_reverse)
1077     return (cmp == _type);
1078   else
1079     return (cmp != _type);
1080 }
1081
1082 void
1083 FGComparisonCondition::setLeftProperty (const char * propname)
1084 {
1085   _left_property = fgGetNode(propname, true);
1086 }
1087
1088 void
1089 FGComparisonCondition::setRightProperty (const char * propname)
1090 {
1091   delete _right_value;
1092   _right_value = 0;
1093   _right_property = fgGetNode(propname, true);
1094 }
1095
1096 void
1097 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
1098 {
1099   _right_property = 0;
1100   delete _right_value;
1101   _right_value = new SGPropertyNode(*node);
1102 }
1103
1104
1105 \f
1106 ////////////////////////////////////////////////////////////////////////
1107 // Read a condition and use it if necessary.
1108 ////////////////////////////////////////////////////////////////////////
1109
1110                                 // Forward declaration
1111 static FGCondition * readCondition (const SGPropertyNode * node);
1112
1113 static FGCondition *
1114 readPropertyCondition (const SGPropertyNode * node)
1115 {
1116   return new FGPropertyCondition(node->getStringValue());
1117 }
1118
1119 static FGCondition *
1120 readNotCondition (const SGPropertyNode * node)
1121 {
1122   int nChildren = node->nChildren();
1123   for (int i = 0; i < nChildren; i++) {
1124     const SGPropertyNode * child = node->getChild(i);
1125     FGCondition * condition = readCondition(child);
1126     if (condition != 0)
1127       return new FGNotCondition(condition);
1128   }
1129   SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
1130   return 0;
1131 }
1132
1133 static FGCondition *
1134 readAndConditions (const SGPropertyNode * node)
1135 {
1136   FGAndCondition * andCondition = new FGAndCondition;
1137   int nChildren = node->nChildren();
1138   for (int i = 0; i < nChildren; i++) {
1139     const SGPropertyNode * child = node->getChild(i);
1140     FGCondition * condition = readCondition(child);
1141     if (condition != 0)
1142       andCondition->addCondition(condition);
1143   }
1144   return andCondition;
1145 }
1146
1147 static FGCondition *
1148 readOrConditions (const SGPropertyNode * node)
1149 {
1150   FGOrCondition * orCondition = new FGOrCondition;
1151   int nChildren = node->nChildren();
1152   for (int i = 0; i < nChildren; i++) {
1153     const SGPropertyNode * child = node->getChild(i);
1154     FGCondition * condition = readCondition(child);
1155     if (condition != 0)
1156       orCondition->addCondition(condition);
1157   }
1158   return orCondition;
1159 }
1160
1161 static FGCondition *
1162 readComparison (const SGPropertyNode * node,
1163                 FGComparisonCondition::Type type,
1164                 bool reverse)
1165 {
1166   FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1167   condition->setLeftProperty(node->getStringValue("property[0]"));
1168   if (node->hasValue("property[1]"))
1169     condition->setRightProperty(node->getStringValue("property[1]"));
1170   else
1171     condition->setRightValue(node->getChild("value", 0));
1172
1173   return condition;
1174 }
1175
1176 static FGCondition *
1177 readCondition (const SGPropertyNode * node)
1178 {
1179   const string &name = node->getName();
1180   if (name == "property")
1181     return readPropertyCondition(node);
1182   else if (name == "not")
1183     return readNotCondition(node);
1184   else if (name == "and")
1185     return readAndConditions(node);
1186   else if (name == "or")
1187     return readOrConditions(node);
1188   else if (name == "less-than")
1189     return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1190   else if (name == "less-than-equals")
1191     return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1192   else if (name == "greater-than")
1193     return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1194   else if (name == "greater-than-equals")
1195     return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1196   else if (name == "equals")
1197     return readComparison(node, FGComparisonCondition::EQUALS, false);
1198   else if (name == "not-equals")
1199     return readComparison(node, FGComparisonCondition::EQUALS, true);
1200   else
1201     return 0;
1202 }
1203
1204
1205 \f
1206 ////////////////////////////////////////////////////////////////////////
1207 // Implementation of FGConditional.
1208 ////////////////////////////////////////////////////////////////////////
1209
1210 FGConditional::FGConditional ()
1211   : _condition (0)
1212 {
1213 }
1214
1215 FGConditional::~FGConditional ()
1216 {
1217   delete _condition;
1218 }
1219
1220 void
1221 FGConditional::setCondition (FGCondition * condition)
1222 {
1223   delete _condition;
1224   _condition = condition;
1225 }
1226
1227 bool
1228 FGConditional::test () const
1229 {
1230   return ((_condition == 0) || _condition->test());
1231 }
1232
1233
1234 \f
1235 // The top-level is always an implicit 'and' group
1236 FGCondition *
1237 fgReadCondition (const SGPropertyNode * node)
1238 {
1239   return readAndConditions(node);
1240 }
1241
1242
1243 // end of fg_props.cxx