Avoid having to use 'set' action handler, which parses the value expression on every use, in interface links by implementing use of cdb nodes as targets

This commit is contained in:
kaetemi 2013-07-28 05:10:07 +02:00
parent 22934d2b60
commit b09e28e9e0
6 changed files with 119 additions and 9 deletions

View file

@ -66,6 +66,11 @@ namespace NLGUI
*/
bool affect(const CInterfaceExprValue &value);
};
struct CCDBTargetInfo
{
NLMISC::CRefPtr<NLMISC::CCDBNodeLeaf> Leaf;
std::string LeafName;
};
/// Updates triggered interface links when triggered by the observed branch
@ -85,7 +90,7 @@ namespace NLGUI
* If there are no target element, the link is permanent (removed at exit)
* NB : The target is not updated during this call.
*/
bool init(const std::vector<CTargetInfo> &targets, const std::string &expr, const std::string &actionHandler, const std::string &ahParams, const std::string &ahCond, CInterfaceGroup *parent);
bool init(const std::vector<CTargetInfo> &targets, const std::vector<CCDBTargetInfo> &cdbTargets, const std::string &expr, const std::string &actionHandler, const std::string &ahParams, const std::string &ahCond, CInterfaceGroup *parent);
// force all the links that have been created to update their targets. This can be called when the interface has been loaded, and when the databse entries have been retrieved.
static void updateAllLinks();
// force all trigered links to be updated
@ -119,6 +124,7 @@ namespace NLGUI
* \return true if all targets are valid
*/
static bool splitLinkTargets(const std::string &targets, CInterfaceGroup *parentGroup, std::vector<CInterfaceLink::CTargetInfo> &targetsVect);
static bool splitLinkTargetsExt(const std::string &targets, CInterfaceGroup *parentGroup, std::vector<CInterfaceLink::CTargetInfo> &targetsVect, std::vector<CInterfaceLink::CCDBTargetInfo> &cdbTargetsVect);
////////////////////////////////////////////////////////////////////////////////////////////////////////
private:
friend struct CRemoveTargetPred;
@ -135,6 +141,7 @@ namespace NLGUI
typedef std::vector<NLMISC::ICDBNode *> TNodeVect;
private:
std::vector<CTarget> _Targets;
std::vector<CCDBTargetInfo> _CDBTargets;
TNodeVect _ObservedNodes;
std::string _Expr;
CInterfaceExprNode *_ParseTree;

View file

@ -2325,7 +2325,8 @@ namespace NLGUI
_LUAOnDbChange[dbList]= newLink;
// Init and attach to list of untargeted links
std::vector<CInterfaceLink::CTargetInfo> noTargets;
newLink->init(noTargets, NLMISC::toString("depends(%s)", dbList.c_str()), "lua", script, "", this);
std::vector<CInterfaceLink::CCDBTargetInfo> noCdbTargets;
newLink->init(noTargets, noCdbTargets, NLMISC::toString("depends(%s)", dbList.c_str()), "lua", script, "", this);
}
// ------------------------------------------------------------------------------------------------

View file

@ -194,7 +194,7 @@ namespace NLGUI
}
//===========================================================
bool CInterfaceLink::init(const std::vector<CTargetInfo> &targets, const std::string &expr, const std::string &actionHandler, const std::string &ahParams, const std::string &ahCond, CInterfaceGroup *parentGroup)
bool CInterfaceLink::init(const std::vector<CTargetInfo> &targets, const std::vector<CCDBTargetInfo> &cdbTargets, const std::string &expr, const std::string &actionHandler, const std::string &ahParams, const std::string &ahCond, CInterfaceGroup *parentGroup)
{
CInterfaceExprValue result;
// Build the parse tree
@ -240,6 +240,7 @@ namespace NLGUI
// There are no target for this link, so, put in a dedicated list to ensure that the link will be destroyed at exit
_LinksWithNoTarget.push_back(TLinkSmartPtr(this));
}
_CDBTargets = cdbTargets;
// create observers
createObservers(_ObservedNodes);
@ -365,12 +366,41 @@ namespace NLGUI
}
}
}
if (_CDBTargets.size())
{
CInterfaceExprValue resultCopy = result;
if (resultCopy.toInteger())
{
sint64 resultValue = resultCopy.getInteger();
for (uint k = 0; k < _CDBTargets.size(); ++k)
{
NLMISC::CCDBNodeLeaf *node = _CDBTargets[k].Leaf;
if (!node)
{
node = _CDBTargets[k].Leaf = NLGUI::CDBManager::getInstance()->getDbProp(_CDBTargets[k].LeafName, false);
}
if (node)
{
// assuming setvalue64 always works
node->setValue64(resultValue);
}
else
{
nlwarning("CInterfaceLink::update: Node does not exist: '%s'", _CDBTargets[k].LeafName.c_str());
}
}
}
else
{
nlwarning("CInterfaceLink::update: Result conversion to db target failed");
}
}
// if there's an action handler, execute it
if (!_ActionHandler.empty())
{
// If there is a condition, test it.
bool launch = _AHCond.empty();
if (_AHCondParsed)
if (_AHCondParsed) // todo: maybe makes more sense to make condition also cover target
{
CInterfaceExprValue result;
_AHCondParsed->eval(result);
@ -525,6 +555,11 @@ namespace NLGUI
continue;
}
std::string::size_type lastPos = targetNames[k].find_last_not_of(" ");
if (startPos >= lastPos)
{
nlwarning("<splitLinkTargets> empty target encountered");
continue;
}
if (!splitLinkTarget(targetNames[k].substr(startPos, lastPos - startPos+1), parentGroup, ti.PropertyName, ti.Elem))
{
@ -539,6 +574,70 @@ namespace NLGUI
}
// ***************************************************************************
bool CInterfaceLink::splitLinkTargetsExt(const std::string &targets, CInterfaceGroup *parentGroup,std::vector<CInterfaceLink::CTargetInfo> &targetsVect, std::vector<CInterfaceLink::CCDBTargetInfo> &cdbTargetsVect)
{
std::vector<std::string> targetNames;
NLMISC::splitString(targets, ",", targetNames);
targetsVect.clear();
targetsVect.reserve(targetNames.size());
cdbTargetsVect.clear(); // no reserve because less used
bool everythingOk = true;
for (uint k = 0; k < targetNames.size(); ++k)
{
std::string::size_type startPos = targetNames[k].find_first_not_of(" ");
if(startPos == std::string::npos)
{
// todo hulud interface syntax error
nlwarning("<splitLinkTargets> empty target encountered");
continue;
}
std::string::size_type lastPos = targetNames[k].find_last_not_of(" ");
if (startPos >= (lastPos+1))
{
nlwarning("<splitLinkTargets> empty target encountered");
continue;
}
if (targetNames[k][startPos] == '@')
{
CInterfaceLink::CCDBTargetInfo ti;
ti.LeafName = targetNames[k].substr((startPos+1), (lastPos+1) - (startPos+1));
// Do not allow Write on SERVER: or LOCAL:
static const std::string dbServer= "SERVER:";
static const std::string dbLocal= "LOCAL:";
static const std::string dbLocalR2= "LOCAL:R2";
if( (0==ti.LeafName.compare(0, dbServer.size(), dbServer)) ||
(0==ti.LeafName.compare(0, dbLocal.size(), dbLocal))
)
{
if (0!=ti.LeafName.compare(0, dbLocalR2.size(), dbLocalR2))
{
//nlwarning("You are not allowed to write on 'SERVER:...' or 'LOCAL:...' database");
nlstop;
return false;
}
}
ti.Leaf = NLGUI::CDBManager::getInstance()->getDbProp(ti.LeafName, false);
cdbTargetsVect.push_back(ti);
}
else
{
CInterfaceLink::CTargetInfo ti;
if (!splitLinkTarget(targetNames[k].substr(startPos, lastPos - startPos+1), parentGroup, ti.PropertyName, ti.Elem))
{
// todo hulud interface syntax error
nlwarning("<splitLinkTargets> Can't get link target");
everythingOk = false;
continue;
}
targetsVect.push_back(ti);
}
}
return everythingOk;
}
//===========================================================
void CInterfaceLink::checkNbRefs()
{

View file

@ -997,6 +997,7 @@ namespace NLGUI
std::vector<CInterfaceLink::CTargetInfo> targets;
std::vector<CInterfaceLink::CCDBTargetInfo> cdbTargets;
ptr = (char*) xmlGetProp (cur, (xmlChar*)"target");
std::string target;
@ -1004,7 +1005,7 @@ namespace NLGUI
{
target = std::string( (const char*)ptr );
if( !editorMode )
CInterfaceLink::splitLinkTargets(std::string((const char*)ptr), parentGroup, targets);
CInterfaceLink::splitLinkTargetsExt(std::string((const char*)ptr), parentGroup, targets, cdbTargets);
}
// optional action handler
@ -1022,7 +1023,7 @@ namespace NLGUI
if( !editorMode )
{
CInterfaceLink *il = new CInterfaceLink;
il->init(targets, expr, action, params, cond, parentGroup); // init will add 'il' in the list of link present in 'elm'
il->init(targets, cdbTargets, expr, action, params, cond, parentGroup); // init will add 'il' in the list of link present in 'elm'
}
else
{

View file

@ -425,14 +425,15 @@ class CActionHandlerAddLink : public IActionHandler
}
std::vector<CInterfaceLink::CTargetInfo> targetsVect;
bool result = CInterfaceLink::splitLinkTargets(targets, parentGroup, targetsVect);
std::vector<CInterfaceLink::CCDBTargetInfo> cdbTargetsVect;
bool result = CInterfaceLink::splitLinkTargetsExt(targets, parentGroup, targetsVect, cdbTargetsVect);
if (!result)
{
nlwarning("<CActionHandlerAddLink> Couldn't parse all links");
}
// add the link
CInterfaceLink *il = new CInterfaceLink;
il->init(targetsVect, expr, ah, ahparam, ahcond, parentGroup);
il->init(targetsVect, cdbTargetsVect, expr, ah, ahparam, ahcond, parentGroup);
CInterfaceManager *im = CInterfaceManager::getInstance();
CWidgetManager::getInstance()->getParser()->addLink(il, id);
il->update();

View file

@ -558,7 +558,8 @@ void CPeopleInterraction::createTeamList()
{
CInterfaceLink *il = new CInterfaceLink;
vector<CInterfaceLink::CTargetInfo> targets;
il->init(targets, sExpr, sAction, sParams, sCond, TeamChat->getContainer());
vector<CInterfaceLink::CCDBTargetInfo> cdbTargets;
il->init(targets, cdbTargets, sExpr, sAction, sParams, sCond, TeamChat->getContainer());
}
}