wpn->getChild("eta", 0, true);
_pathNode = fgGetNode(RM "file-path", 0, true);
- setFlightPlan(new FlightPlan());
}
void FGRouteMgr::postinit()
{
+ setFlightPlan(new FlightPlan());
+
SGPath path(_pathNode->getStringValue());
if (!path.isNull()) {
SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from: " << path.str());
}
if (_plan) {
+ _plan->removeDelegate(this);
delete _plan;
active->setBoolValue(false);
}
_plan = plan;
- _plan->setDelegate(this);
+ _plan->addDelegate(this);
_flightplanChanged->fireValueChanged();
namespace flightgear {
+typedef std::vector<FlightPlan::DelegateFactory*> FPDelegateFactoryVec;
+static FPDelegateFactoryVec static_delegateFactories;
+
FlightPlan::FlightPlan() :
_currentIndex(-1),
_departureRunway(NULL),
_approach(NULL),
_delegate(NULL)
{
-
+ BOOST_FOREACH(DelegateFactory* factory, static_delegateFactories) {
+ Delegate* d = factory->createFlightPlanDelegate(this);
+ if (d) { // factory might not always create a delegate
+ d->_deleteWithPlan = true;
+ addDelegate(d);
+ }
+ }
}
FlightPlan::~FlightPlan()
{
-
+// delete all delegates which we own.
+ Delegate* d = _delegate;
+ while (d) {
+ Delegate* cur = d;
+ d = d->_inner;
+ if (cur->_deleteWithPlan) {
+ delete cur;
+ }
+ }
}
FlightPlan* FlightPlan::clone(const string& newIdent) const
} // of legs iteration
}
-void FlightPlan::setDelegate(Delegate* d)
+void FlightPlan::registerDelegateFactory(DelegateFactory* df)
+{
+ FPDelegateFactoryVec::iterator it = std::find(static_delegateFactories.begin(),
+ static_delegateFactories.end(), df);
+ if (it != static_delegateFactories.end()) {
+ throw sg_exception("duplicate delegate factory registration");
+ }
+
+ static_delegateFactories.push_back(df);
+}
+
+void FlightPlan::unregisterDelegateFactory(DelegateFactory* df)
+{
+ FPDelegateFactoryVec::iterator it = std::find(static_delegateFactories.begin(),
+ static_delegateFactories.end(), df);
+ if (it == static_delegateFactories.end()) {
+ return;
+ }
+
+ static_delegateFactories.erase(it);
+}
+
+void FlightPlan::addDelegate(Delegate* d)
{
// wrap any existing delegate(s) in the new one
d->_inner = _delegate;
}
FlightPlan::Delegate::Delegate() :
+ _deleteWithPlan(false),
_inner(NULL)
{
{
public:
virtual ~Delegate();
-
+
virtual void departureChanged() { }
virtual void arrivalChanged() { }
virtual void waypointsChanged() { }
friend class FlightPlan;
+ bool _deleteWithPlan;
Delegate* _inner;
};
*/
WayptRef waypointFromString(const std::string& target);
- void setDelegate(Delegate* d);
+ /**
+ * abstract interface for creating delegates automatically when a
+ * flight-plan is created or loaded
+ */
+ class DelegateFactory
+ {
+ public:
+ virtual Delegate* createFlightPlanDelegate(FlightPlan* fp) = 0;
+ };
+
+ static void registerDelegateFactory(DelegateFactory* df);
+ static void unregisterDelegateFactory(DelegateFactory* df);
+
+ void addDelegate(Delegate* d);
void removeDelegate(Delegate* d);
private:
return ghostForProcedure(c, apt->findApproachWithIdent(ident));
}
+static naRef f_airport_toString(naContext c, naRef me, int argc, naRef* args)
+{
+ FGAirport* apt = airportGhost(me);
+ if (!apt) {
+ naRuntimeError(c, "airport.tostring called on non-airport object");
+ }
+
+ return stringToNasal(c, "an airport " + apt->ident());
+}
+
// Returns vector of data hash for navaid of a <type>, nil on error
// navaids sorted by ascending distance
// navinfo([<lat>,<lon>],[<type>],[<id>])
return naNil();
}
+class NasalFPDelegate : public FlightPlan::Delegate
+{
+public:
+ NasalFPDelegate(FlightPlan* fp, FGNasalSys* sys, naRef ins) :
+ _nasal(sys),
+ _plan(fp),
+ _instance(ins)
+ {
+ SG_LOG(SG_NASAL, SG_INFO, "created Nasal delegate for " << fp);
+ _gcSaveKey = _nasal->gcSave(ins);
+ }
+
+ virtual ~NasalFPDelegate()
+ {
+ SG_LOG(SG_NASAL, SG_INFO, "destroying Nasal delegate for " << _plan);
+ _nasal->gcRelease(_gcSaveKey);
+ }
+
+ virtual void departureChanged()
+ {
+ callDelegateMethod("departureChanged");
+ }
+
+ virtual void arrivalChanged()
+ {
+ callDelegateMethod("arrivalChanged");
+ }
+
+ virtual void waypointsChanged()
+ {
+ callDelegateMethod("waypointsChanged");
+ }
+
+ virtual void currentWaypointChanged()
+ {
+ callDelegateMethod("currentWaypointChanged");
+ }
+private:
+
+ void callDelegateMethod(const char* method)
+ {
+ naRef f;
+ naMember_cget(_nasal->context(), _instance, method, &f);
+ if (naIsNil(f)) {
+ return; // no method on the delegate
+ }
+
+ naRef arg[1];
+ arg[0] = ghostForFlightPlan(_nasal->context(), _plan);
+ _nasal->callMethod(f, _instance, 1, arg, naNil());
+ }
+
+ FGNasalSys* _nasal;
+ FlightPlan* _plan;
+ naRef _instance;
+ int _gcSaveKey;
+};
+
+class NasalFPDelegateFactory : public FlightPlan::DelegateFactory
+{
+public:
+ NasalFPDelegateFactory(naRef code)
+ {
+ _nasal = (FGNasalSys*) globals->get_subsystem("nasal");
+ _func = code;
+ _gcSaveKey = _nasal->gcSave(_func);
+ }
+
+ ~NasalFPDelegateFactory()
+ {
+ _nasal->gcRelease(_gcSaveKey);
+ }
+
+ virtual FlightPlan::Delegate* createFlightPlanDelegate(FlightPlan* fp)
+ {
+ naRef args[1];
+ args[0] = ghostForFlightPlan(_nasal->context(), fp);
+ naRef instance = _nasal->call(_func, 1, args, naNil());
+ if (naIsNil(instance)) {
+ return NULL;
+ }
+
+ return new NasalFPDelegate(fp, _nasal, instance);
+ }
+private:
+ FGNasalSys* _nasal;
+ naRef _func;
+ int _gcSaveKey;
+};
+
+static naRef f_registerFPDelegate(naContext c, naRef me, int argc, naRef* args)
+{
+ if ((argc < 1) || !naIsFunc(args[0])) {
+ naRuntimeError(c, "non-function argument to registerFlightPlanDelegate");
+ }
+
+ NasalFPDelegateFactory* factory = new NasalFPDelegateFactory(args[0]);
+ FlightPlan::registerDelegateFactory(factory);
+
+ return naNil();
+}
+
static WayptRef wayptFromArg(naRef arg)
{
WayptRef r = wayptGhost(arg);
{ "findNavaidsByID", f_findNavaidsByIdent },
{ "findFixesByID", f_findFixesByIdent },
{ "flightplan", f_route },
+ { "registerFlightPlanDelegate", f_registerFPDelegate },
{ "createWP", f_createWP },
{ "createWPFrom", f_createWPFrom },
{ "airwaysRoute", f_airwaySearch },
hashset(c, airportPrototype, "getSid", naNewFunc(c, naNewCCode(c, f_airport_getSid)));
hashset(c, airportPrototype, "getStar", naNewFunc(c, naNewCCode(c, f_airport_getStar)));
hashset(c, airportPrototype, "getIAP", naNewFunc(c, naNewCCode(c, f_airport_getApproach)));
+ hashset(c, airportPrototype, "tostring", naNewFunc(c, naNewCCode(c, f_airport_toString)));
flightplanPrototype = naNewHash(c);
hashset(c, gcSave, "flightplanProto", flightplanPrototype);
_callCount = 0;
}
+naRef FGNasalSys::call(naRef code, int argc, naRef* args, naRef locals)
+{
+ return callMethod(code, naNil(), argc, args, locals);
+}
+
// Does a naCall() in a new context. Wrapped here to make lock
// tracking easier. Extension functions are called with the lock, but
// we have to release it before making a new naCall(). So rather than
// drop the lock in every extension function that might call back into
// Nasal, we keep a stack depth counter here and only unlock/lock
// around the naCall if it isn't the first one.
-naRef FGNasalSys::call(naRef code, int argc, naRef* args, naRef locals)
+
+naRef FGNasalSys::callMethod(naRef code, naRef self, int argc, naRef* args, naRef locals)
{
naContext ctx = naNewContext();
if(_callCount) naModUnlock();
_callCount++;
- naRef result = naCall(ctx, code, argc, args, naNil(), locals);
+ naRef result = naCall(ctx, code, argc, args, self, locals);
if(naGetError(ctx))
logError(ctx);
_callCount--;
void deleteModule(const char* moduleName);
naRef call(naRef code, int argc, naRef* args, naRef locals);
+
+ naRef callMethod(naRef code, naRef self, int argc, naRef* args, naRef locals);
+
naRef propNodeGhost(SGPropertyNode* handle);
void registerToLoad(FGNasalModelData* data) { _loadList.push(data);}
void registerToUnload(FGNasalModelData* data) { _unloadList.push(data);}
+ // can't call this 'globals' due to naming clash
+ naRef nasalGlobals() const
+ { return _globals; }
+
+ naContext context() const
+ { return _context; }
+
+ // This mechanism is here to allow naRefs to be passed to
+ // locations "outside" the interpreter. Normally, such a
+ // reference would be garbage collected unexpectedly. By passing
+ // it to gcSave and getting a key/handle, it can be cached in a
+ // globals.__gcsave hash. Be sure to release it with gcRelease
+ // when done.
+ int gcSave(naRef r);
+ void gcRelease(int key);
private:
friend class FGNasalScript;
friend class FGNasalListener;
naRef parse(const char* filename, const char* buf, int len);
naRef genPropsModule();
- // This mechanism is here to allow naRefs to be passed to
- // locations "outside" the interpreter. Normally, such a
- // reference would be garbage collected unexpectedly. By passing
- // it to gcSave and getting a key/handle, it can be cached in a
- // globals.__gcsave hash. Be sure to release it with gcRelease
- // when done.
- int gcSave(naRef r);
- void gcRelease(int key);
-
naContext _context;
naRef _globals;