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); 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 /// 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) * If there are no target element, the link is permanent (removed at exit)
* NB : The target is not updated during this call. * 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. // 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(); static void updateAllLinks();
// force all trigered links to be updated // force all trigered links to be updated
@ -119,6 +124,7 @@ namespace NLGUI
* \return true if all targets are valid * \return true if all targets are valid
*/ */
static bool splitLinkTargets(const std::string &targets, CInterfaceGroup *parentGroup, std::vector<CInterfaceLink::CTargetInfo> &targetsVect); 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: private:
friend struct CRemoveTargetPred; friend struct CRemoveTargetPred;
@ -135,6 +141,7 @@ namespace NLGUI
typedef std::vector<NLMISC::ICDBNode *> TNodeVect; typedef std::vector<NLMISC::ICDBNode *> TNodeVect;
private: private:
std::vector<CTarget> _Targets; std::vector<CTarget> _Targets;
std::vector<CCDBTargetInfo> _CDBTargets;
TNodeVect _ObservedNodes; TNodeVect _ObservedNodes;
std::string _Expr; std::string _Expr;
CInterfaceExprNode *_ParseTree; CInterfaceExprNode *_ParseTree;

View file

@ -2325,7 +2325,8 @@ namespace NLGUI
_LUAOnDbChange[dbList]= newLink; _LUAOnDbChange[dbList]= newLink;
// Init and attach to list of untargeted links // Init and attach to list of untargeted links
std::vector<CInterfaceLink::CTargetInfo> noTargets; 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; CInterfaceExprValue result;
// Build the parse tree // 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 // 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)); _LinksWithNoTarget.push_back(TLinkSmartPtr(this));
} }
_CDBTargets = cdbTargets;
// create observers // create observers
createObservers(_ObservedNodes); 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 there's an action handler, execute it
if (!_ActionHandler.empty()) if (!_ActionHandler.empty())
{ {
// If there is a condition, test it. // If there is a condition, test it.
bool launch = _AHCond.empty(); bool launch = _AHCond.empty();
if (_AHCondParsed) if (_AHCondParsed) // todo: maybe makes more sense to make condition also cover target
{ {
CInterfaceExprValue result; CInterfaceExprValue result;
_AHCondParsed->eval(result); _AHCondParsed->eval(result);
@ -525,6 +555,11 @@ namespace NLGUI
continue; continue;
} }
std::string::size_type lastPos = targetNames[k].find_last_not_of(" "); 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)) 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() void CInterfaceLink::checkNbRefs()
{ {

View file

@ -997,6 +997,7 @@ namespace NLGUI
std::vector<CInterfaceLink::CTargetInfo> targets; std::vector<CInterfaceLink::CTargetInfo> targets;
std::vector<CInterfaceLink::CCDBTargetInfo> cdbTargets;
ptr = (char*) xmlGetProp (cur, (xmlChar*)"target"); ptr = (char*) xmlGetProp (cur, (xmlChar*)"target");
std::string target; std::string target;
@ -1004,7 +1005,7 @@ namespace NLGUI
{ {
target = std::string( (const char*)ptr ); target = std::string( (const char*)ptr );
if( !editorMode ) if( !editorMode )
CInterfaceLink::splitLinkTargets(std::string((const char*)ptr), parentGroup, targets); CInterfaceLink::splitLinkTargetsExt(std::string((const char*)ptr), parentGroup, targets, cdbTargets);
} }
// optional action handler // optional action handler
@ -1022,7 +1023,7 @@ namespace NLGUI
if( !editorMode ) if( !editorMode )
{ {
CInterfaceLink *il = new CInterfaceLink; 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 else
{ {

View file

@ -425,14 +425,15 @@ class CActionHandlerAddLink : public IActionHandler
} }
std::vector<CInterfaceLink::CTargetInfo> targetsVect; 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) if (!result)
{ {
nlwarning("<CActionHandlerAddLink> Couldn't parse all links"); nlwarning("<CActionHandlerAddLink> Couldn't parse all links");
} }
// add the link // add the link
CInterfaceLink *il = new CInterfaceLink; 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(); CInterfaceManager *im = CInterfaceManager::getInstance();
CWidgetManager::getInstance()->getParser()->addLink(il, id); CWidgetManager::getInstance()->getParser()->addLink(il, id);
il->update(); il->update();

View file

@ -558,7 +558,8 @@ void CPeopleInterraction::createTeamList()
{ {
CInterfaceLink *il = new CInterfaceLink; CInterfaceLink *il = new CInterfaceLink;
vector<CInterfaceLink::CTargetInfo> targets; 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());
} }
} }