From b09e28e9e026fb93d6a9b1a852f625127c8528be Mon Sep 17 00:00:00 2001 From: kaetemi Date: Sun, 28 Jul 2013 05:10:07 +0200 Subject: [PATCH] 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 --- code/nel/include/nel/gui/interface_link.h | 9 +- code/nel/src/gui/interface_group.cpp | 3 +- code/nel/src/gui/interface_link.cpp | 103 +++++++++++++++++- code/nel/src/gui/interface_parser.cpp | 5 +- .../src/interface_v3/action_handler_misc.cpp | 5 +- .../src/interface_v3/people_interraction.cpp | 3 +- 6 files changed, 119 insertions(+), 9 deletions(-) diff --git a/code/nel/include/nel/gui/interface_link.h b/code/nel/include/nel/gui/interface_link.h index 87389a185..42fb2bbcf 100644 --- a/code/nel/include/nel/gui/interface_link.h +++ b/code/nel/include/nel/gui/interface_link.h @@ -66,6 +66,11 @@ namespace NLGUI */ bool affect(const CInterfaceExprValue &value); }; + struct CCDBTargetInfo + { + NLMISC::CRefPtr 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 &targets, const std::string &expr, const std::string &actionHandler, const std::string &ahParams, const std::string &ahCond, CInterfaceGroup *parent); + bool init(const std::vector &targets, const std::vector &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 &targetsVect); + static bool splitLinkTargetsExt(const std::string &targets, CInterfaceGroup *parentGroup, std::vector &targetsVect, std::vector &cdbTargetsVect); //////////////////////////////////////////////////////////////////////////////////////////////////////// private: friend struct CRemoveTargetPred; @@ -135,6 +141,7 @@ namespace NLGUI typedef std::vector TNodeVect; private: std::vector _Targets; + std::vector _CDBTargets; TNodeVect _ObservedNodes; std::string _Expr; CInterfaceExprNode *_ParseTree; diff --git a/code/nel/src/gui/interface_group.cpp b/code/nel/src/gui/interface_group.cpp index f981814ba..4e8919e5c 100644 --- a/code/nel/src/gui/interface_group.cpp +++ b/code/nel/src/gui/interface_group.cpp @@ -2325,7 +2325,8 @@ namespace NLGUI _LUAOnDbChange[dbList]= newLink; // Init and attach to list of untargeted links std::vector noTargets; - newLink->init(noTargets, NLMISC::toString("depends(%s)", dbList.c_str()), "lua", script, "", this); + std::vector noCdbTargets; + newLink->init(noTargets, noCdbTargets, NLMISC::toString("depends(%s)", dbList.c_str()), "lua", script, "", this); } // ------------------------------------------------------------------------------------------------ diff --git a/code/nel/src/gui/interface_link.cpp b/code/nel/src/gui/interface_link.cpp index c40788040..282199ee7 100644 --- a/code/nel/src/gui/interface_link.cpp +++ b/code/nel/src/gui/interface_link.cpp @@ -194,7 +194,7 @@ namespace NLGUI } //=========================================================== - bool CInterfaceLink::init(const std::vector &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 &targets, const std::vector &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(" 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 &targetsVect, std::vector &cdbTargetsVect) + { + std::vector 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(" empty target encountered"); + continue; + } + std::string::size_type lastPos = targetNames[k].find_last_not_of(" "); + if (startPos >= (lastPos+1)) + { + nlwarning(" 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(" Can't get link target"); + everythingOk = false; + continue; + } + targetsVect.push_back(ti); + } + } + return everythingOk; + } + + //=========================================================== void CInterfaceLink::checkNbRefs() { diff --git a/code/nel/src/gui/interface_parser.cpp b/code/nel/src/gui/interface_parser.cpp index 76f5df1ed..da8bd1e52 100644 --- a/code/nel/src/gui/interface_parser.cpp +++ b/code/nel/src/gui/interface_parser.cpp @@ -997,6 +997,7 @@ namespace NLGUI std::vector targets; + std::vector 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 { diff --git a/code/ryzom/client/src/interface_v3/action_handler_misc.cpp b/code/ryzom/client/src/interface_v3/action_handler_misc.cpp index 6a21858f5..54c8b6fac 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_misc.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_misc.cpp @@ -425,14 +425,15 @@ class CActionHandlerAddLink : public IActionHandler } std::vector targetsVect; - bool result = CInterfaceLink::splitLinkTargets(targets, parentGroup, targetsVect); + std::vector cdbTargetsVect; + bool result = CInterfaceLink::splitLinkTargetsExt(targets, parentGroup, targetsVect, cdbTargetsVect); if (!result) { nlwarning(" 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(); diff --git a/code/ryzom/client/src/interface_v3/people_interraction.cpp b/code/ryzom/client/src/interface_v3/people_interraction.cpp index b0a050f29..95b091c22 100644 --- a/code/ryzom/client/src/interface_v3/people_interraction.cpp +++ b/code/ryzom/client/src/interface_v3/people_interraction.cpp @@ -558,7 +558,8 @@ void CPeopleInterraction::createTeamList() { CInterfaceLink *il = new CInterfaceLink; vector targets; - il->init(targets, sExpr, sAction, sParams, sCond, TeamChat->getContainer()); + vector cdbTargets; + il->init(targets, cdbTargets, sExpr, sAction, sParams, sCond, TeamChat->getContainer()); } }