Expose FlightPlan delegates to Nasal, finally.
This will permit Nasal (e.g., FMS) to update nicely when the FlightPlan is modified from anywhere else.
This commit is contained in:
parent
acadbdeee1
commit
ce92730ef6
6 changed files with 203 additions and 18 deletions
|
@ -326,12 +326,13 @@ void FGRouteMgr::init() {
|
||||||
wpn->getChild("eta", 0, true);
|
wpn->getChild("eta", 0, true);
|
||||||
|
|
||||||
_pathNode = fgGetNode(RM "file-path", 0, true);
|
_pathNode = fgGetNode(RM "file-path", 0, true);
|
||||||
setFlightPlan(new FlightPlan());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FGRouteMgr::postinit()
|
void FGRouteMgr::postinit()
|
||||||
{
|
{
|
||||||
|
setFlightPlan(new FlightPlan());
|
||||||
|
|
||||||
SGPath path(_pathNode->getStringValue());
|
SGPath path(_pathNode->getStringValue());
|
||||||
if (!path.isNull()) {
|
if (!path.isNull()) {
|
||||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from: " << path.str());
|
SG_LOG(SG_AUTOPILOT, SG_INFO, "loading flight-plan from: " << path.str());
|
||||||
|
@ -402,12 +403,13 @@ void FGRouteMgr::setFlightPlan(FlightPlan* plan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_plan) {
|
if (_plan) {
|
||||||
|
_plan->removeDelegate(this);
|
||||||
delete _plan;
|
delete _plan;
|
||||||
active->setBoolValue(false);
|
active->setBoolValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_plan = plan;
|
_plan = plan;
|
||||||
_plan->setDelegate(this);
|
_plan->addDelegate(this);
|
||||||
|
|
||||||
_flightplanChanged->fireValueChanged();
|
_flightplanChanged->fireValueChanged();
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,9 @@ using std::fstream;
|
||||||
|
|
||||||
namespace flightgear {
|
namespace flightgear {
|
||||||
|
|
||||||
|
typedef std::vector<FlightPlan::DelegateFactory*> FPDelegateFactoryVec;
|
||||||
|
static FPDelegateFactoryVec static_delegateFactories;
|
||||||
|
|
||||||
FlightPlan::FlightPlan() :
|
FlightPlan::FlightPlan() :
|
||||||
_currentIndex(-1),
|
_currentIndex(-1),
|
||||||
_departureRunway(NULL),
|
_departureRunway(NULL),
|
||||||
|
@ -64,12 +67,26 @@ FlightPlan::FlightPlan() :
|
||||||
_approach(NULL),
|
_approach(NULL),
|
||||||
_delegate(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()
|
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
|
FlightPlan* FlightPlan::clone(const string& newIdent) const
|
||||||
|
@ -986,7 +1003,29 @@ void FlightPlan::rebuildLegData()
|
||||||
} // of legs iteration
|
} // 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
|
// wrap any existing delegate(s) in the new one
|
||||||
d->_inner = _delegate;
|
d->_inner = _delegate;
|
||||||
|
@ -1003,6 +1042,7 @@ void FlightPlan::removeDelegate(Delegate* d)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlightPlan::Delegate::Delegate() :
|
FlightPlan::Delegate::Delegate() :
|
||||||
|
_deleteWithPlan(false),
|
||||||
_inner(NULL)
|
_inner(NULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,7 @@ public:
|
||||||
|
|
||||||
friend class FlightPlan;
|
friend class FlightPlan;
|
||||||
|
|
||||||
|
bool _deleteWithPlan;
|
||||||
Delegate* _inner;
|
Delegate* _inner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -207,7 +208,20 @@ public:
|
||||||
*/
|
*/
|
||||||
WayptRef waypointFromString(const std::string& target);
|
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);
|
void removeDelegate(Delegate* d);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -1308,6 +1308,16 @@ static naRef f_airport_getApproach(naContext c, naRef me, int argc, naRef* args)
|
||||||
return ghostForProcedure(c, apt->findApproachWithIdent(ident));
|
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
|
// Returns vector of data hash for navaid of a <type>, nil on error
|
||||||
// navaids sorted by ascending distance
|
// navaids sorted by ascending distance
|
||||||
// navinfo([<lat>,<lon>],[<type>],[<id>])
|
// navinfo([<lat>,<lon>],[<type>],[<id>])
|
||||||
|
@ -1617,6 +1627,108 @@ static naRef f_route(naContext c, naRef me, int argc, naRef* args)
|
||||||
return naNil();
|
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)
|
static WayptRef wayptFromArg(naRef arg)
|
||||||
{
|
{
|
||||||
WayptRef r = wayptGhost(arg);
|
WayptRef r = wayptGhost(arg);
|
||||||
|
@ -2077,6 +2189,7 @@ static struct { const char* name; naCFunction func; } funcs[] = {
|
||||||
{ "findNavaidsByID", f_findNavaidsByIdent },
|
{ "findNavaidsByID", f_findNavaidsByIdent },
|
||||||
{ "findFixesByID", f_findFixesByIdent },
|
{ "findFixesByID", f_findFixesByIdent },
|
||||||
{ "flightplan", f_route },
|
{ "flightplan", f_route },
|
||||||
|
{ "registerFlightPlanDelegate", f_registerFPDelegate },
|
||||||
{ "createWP", f_createWP },
|
{ "createWP", f_createWP },
|
||||||
{ "createWPFrom", f_createWPFrom },
|
{ "createWPFrom", f_createWPFrom },
|
||||||
{ "airwaysRoute", f_airwaySearch },
|
{ "airwaysRoute", f_airwaySearch },
|
||||||
|
@ -2104,6 +2217,7 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave)
|
||||||
hashset(c, airportPrototype, "getSid", naNewFunc(c, naNewCCode(c, f_airport_getSid)));
|
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, "getStar", naNewFunc(c, naNewCCode(c, f_airport_getStar)));
|
||||||
hashset(c, airportPrototype, "getIAP", naNewFunc(c, naNewCCode(c, f_airport_getApproach)));
|
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);
|
flightplanPrototype = naNewHash(c);
|
||||||
hashset(c, gcSave, "flightplanProto", flightplanPrototype);
|
hashset(c, gcSave, "flightplanProto", flightplanPrototype);
|
||||||
|
|
|
@ -99,18 +99,24 @@ FGNasalSys::FGNasalSys()
|
||||||
_callCount = 0;
|
_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
|
// Does a naCall() in a new context. Wrapped here to make lock
|
||||||
// tracking easier. Extension functions are called with the lock, but
|
// tracking easier. Extension functions are called with the lock, but
|
||||||
// we have to release it before making a new naCall(). So rather than
|
// 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
|
// drop the lock in every extension function that might call back into
|
||||||
// Nasal, we keep a stack depth counter here and only unlock/lock
|
// Nasal, we keep a stack depth counter here and only unlock/lock
|
||||||
// around the naCall if it isn't the first one.
|
// 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();
|
naContext ctx = naNewContext();
|
||||||
if(_callCount) naModUnlock();
|
if(_callCount) naModUnlock();
|
||||||
_callCount++;
|
_callCount++;
|
||||||
naRef result = naCall(ctx, code, argc, args, naNil(), locals);
|
naRef result = naCall(ctx, code, argc, args, self, locals);
|
||||||
if(naGetError(ctx))
|
if(naGetError(ctx))
|
||||||
logError(ctx);
|
logError(ctx);
|
||||||
_callCount--;
|
_callCount--;
|
||||||
|
|
|
@ -111,11 +111,29 @@ public:
|
||||||
void deleteModule(const char* moduleName);
|
void deleteModule(const char* moduleName);
|
||||||
|
|
||||||
naRef call(naRef code, int argc, naRef* args, naRef locals);
|
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);
|
naRef propNodeGhost(SGPropertyNode* handle);
|
||||||
|
|
||||||
void registerToLoad(FGNasalModelData* data) { _loadList.push(data);}
|
void registerToLoad(FGNasalModelData* data) { _loadList.push(data);}
|
||||||
void registerToUnload(FGNasalModelData* data) { _unloadList.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:
|
private:
|
||||||
friend class FGNasalScript;
|
friend class FGNasalScript;
|
||||||
friend class FGNasalListener;
|
friend class FGNasalListener;
|
||||||
|
@ -151,15 +169,6 @@ private:
|
||||||
naRef parse(const char* filename, const char* buf, int len);
|
naRef parse(const char* filename, const char* buf, int len);
|
||||||
naRef genPropsModule();
|
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;
|
naContext _context;
|
||||||
naRef _globals;
|
naRef _globals;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue