From 506840f28e9ee8b4c520230193bcb28835757f59 Mon Sep 17 00:00:00 2001 From: mpv Date: Mon, 25 May 2015 17:53:53 +0300 Subject: [PATCH] Fix for issue #562 : correct update by dependencies in the parameters --- src/Model/Model_AttributeDouble.cpp | 9 +- src/Model/Model_AttributeRefList.cpp | 10 ++ src/Model/Model_AttributeRefList.h | 3 + src/Model/Model_Update.cpp | 65 ++++++----- src/ModelAPI/ModelAPI_AttributeRefList.h | 3 + src/ModelAPI/ModelAPI_Tools.cpp | 8 +- src/ModelAPI/ModelAPI_Tools.h | 4 +- src/ModuleBase/ModuleBase_ParamSpinBox.cpp | 6 +- .../ModuleBase_WidgetDoubleValue.cpp | 7 -- .../ParametersPlugin_EvalListener.cpp | 4 +- .../ParametersPlugin_Parameter.cpp | 102 ++++++++++++------ .../ParametersPlugin_Parameter.h | 10 ++ 12 files changed, 153 insertions(+), 78 deletions(-) diff --git a/src/Model/Model_AttributeDouble.cpp b/src/Model/Model_AttributeDouble.cpp index c65748dee..3ef3e3c41 100644 --- a/src/Model/Model_AttributeDouble.cpp +++ b/src/Model/Model_AttributeDouble.cpp @@ -7,6 +7,7 @@ #include "Model_AttributeDouble.h" #include #include +#include #include #include @@ -46,6 +47,12 @@ void Model_AttributeDouble::setText(const std::string& theValue) if (myText->Get() != aValue) { myText->Set(aValue); owner()->data()->sendAttributeUpdated(this); + // Send it to evaluator to convert into the double and store in the attribute + static Events_ID anId = ModelAPI_AttributeEvalMessage::eventId(); + std::shared_ptr aMessage = + std::shared_ptr(new ModelAPI_AttributeEvalMessage(anId, this)); + aMessage->setAttribute(owner()->data()->attribute(id())); // to get shared pointer to this + Events_Loop::loop()->send(aMessage); } } @@ -67,5 +74,5 @@ void Model_AttributeDouble::setExpressionInvalid(const bool theFlag) bool Model_AttributeDouble::expressionInvalid() { - return myReal->Label().IsAttribute(kInvalidGUID); + return myReal->Label().IsAttribute(kInvalidGUID) == Standard_True; } diff --git a/src/Model/Model_AttributeRefList.cpp b/src/Model/Model_AttributeRefList.cpp index 3e4f5a21d..b7719ca78 100644 --- a/src/Model/Model_AttributeRefList.cpp +++ b/src/Model/Model_AttributeRefList.cpp @@ -50,6 +50,16 @@ void Model_AttributeRefList::remove(ObjectPtr theObject) owner()->data()->sendAttributeUpdated(this); } +void Model_AttributeRefList::clear() +{ + std::list anOldList = list(); + myRef->Clear(); + std::list::iterator anOldIter = anOldList.begin(); + for(; anOldIter != anOldList.end(); anOldIter++) { + REMOVE_BACK_REF((*anOldIter)); + } +} + int Model_AttributeRefList::size() const { return myRef->Extent(); diff --git a/src/Model/Model_AttributeRefList.h b/src/Model/Model_AttributeRefList.h index f59229a1a..ebf6ec9c6 100644 --- a/src/Model/Model_AttributeRefList.h +++ b/src/Model/Model_AttributeRefList.h @@ -31,6 +31,9 @@ class Model_AttributeRefList : public ModelAPI_AttributeRefList /// Returns number of features in the list MODEL_EXPORT virtual int size() const; + /// Removes all references from the list + MODEL_EXPORT virtual void clear(); + /// Returns the list of features MODEL_EXPORT virtual std::list list(); diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index be69043e9..502930d93 100644 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -110,11 +110,13 @@ void Model_Update::processEvent(const std::shared_ptr& theMessag isOperationChanged = true; } if (isOperationChanged) { - // remove all macros before clearing all created + // remove all macros before clearing all created and execute all not-previewed std::set::iterator aCreatedIter = myJustCreated.begin(); - for(; aCreatedIter != myJustCreated.end(); aCreatedIter++) { - FeaturePtr aFeature = - std::dynamic_pointer_cast(*aCreatedIter); + std::set::iterator anUpdatedIter = myJustUpdated.begin(); + for(; aCreatedIter != myJustCreated.end() || anUpdatedIter != myJustUpdated.end(); + aCreatedIter == myJustCreated.end() ? anUpdatedIter++ : aCreatedIter++) { + FeaturePtr aFeature = std::dynamic_pointer_cast(* + (aCreatedIter == myJustCreated.end() ? anUpdatedIter : aCreatedIter)); if (aFeature.get()) { // execute not-previewed feature on "apply" if (!aFeature->isPreviewNeeded() && (myJustCreated.find(aFeature) != myJustCreated.end() || @@ -267,8 +269,10 @@ void Model_Update::updateArguments(FeaturePtr theFeature) { for(; aDoubleIter != aDoubles.end(); aDoubleIter++) { AttributeDoublePtr aDouble = std::dynamic_pointer_cast(*aDoubleIter); - if (aDouble.get() && aDouble->expressionInvalid()) { - aState = ModelAPI_StateInvalidArgument; + if (aDouble.get() && !aDouble->text().empty()) { + if (aDouble->expressionInvalid()) { + aState = ModelAPI_StateInvalidArgument; + } } } @@ -371,31 +375,36 @@ void Model_Update::updateFeature(FeaturePtr theFeature) //std::cout<<"Update feature "<getKind()<<" must be updated = "<(theFeature->document())->executeFeatures() || - !theFeature->isPersistentResult()) && theFeature->isPreviewNeeded()) { - if (aFactory->validate(theFeature)) { - if (myIsAutomatic || !theFeature->isPersistentResult() /* execute quick, not persistent results */ - || (isUpdated(theFeature) && - theFeature == theFeature->document()->currentFeature(false))) // currently edited - { - if (aState == ModelAPI_StateDone || aState == ModelAPI_StateMustBeUpdated) { - executeFeature(theFeature); - } - } else { // must be updatet, but not updated yet - theFeature->data()->execState(ModelAPI_StateMustBeUpdated); - const std::list >& aResults = theFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - std::shared_ptr aRes = *aRIter; - aRes->data()->execState(ModelAPI_StateMustBeUpdated); + if (theFeature->isPreviewNeeded()) { + if (std::dynamic_pointer_cast(theFeature->document())->executeFeatures() || + !theFeature->isPersistentResult()) { + if (aFactory->validate(theFeature)) { + if (myIsAutomatic || !theFeature->isPersistentResult() /* execute quick, not persistent results */ + || (isUpdated(theFeature) && + theFeature == theFeature->document()->currentFeature(false))) // currently edited + { + if (aState == ModelAPI_StateDone || aState == ModelAPI_StateMustBeUpdated) { + executeFeature(theFeature); + } + } else { // must be updatet, but not updated yet + theFeature->data()->execState(ModelAPI_StateMustBeUpdated); + const std::list >& aResults = theFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { + std::shared_ptr aRes = *aRIter; + aRes->data()->execState(ModelAPI_StateMustBeUpdated); + } } + } else { + theFeature->eraseResults(); + redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated } - } else { - theFeature->eraseResults(); - redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated + } else { // for automatically updated features (on abort, etc) it is necessary to redisplay anyway + redisplayWithResults(theFeature, ModelAPI_StateNothing); } - } else { // for automatically updated features (on abort, etc) it is necessary to redisplay anyway - redisplayWithResults(theFeature, ModelAPI_StateNothing); + } else { // preview is not needed => make state Done + if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) + theFeature->data()->execState(ModelAPI_StateDone); } } } diff --git a/src/ModelAPI/ModelAPI_AttributeRefList.h b/src/ModelAPI/ModelAPI_AttributeRefList.h index 12235c5b8..37e9f68de 100644 --- a/src/ModelAPI/ModelAPI_AttributeRefList.h +++ b/src/ModelAPI/ModelAPI_AttributeRefList.h @@ -34,6 +34,9 @@ class ModelAPI_AttributeRefList : public ModelAPI_Attribute /// Erases the first meet of the feature in the list MODELAPI_EXPORT virtual void remove(ObjectPtr theObject) = 0; + /// Removes all references from the list + MODELAPI_EXPORT virtual void clear() = 0; + /// Returns number of features in the list MODELAPI_EXPORT virtual int size() const = 0; diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index 1073922ee..3a1623576 100644 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -36,7 +36,7 @@ std::shared_ptr shape(const ResultPtr& theResult) return theResult->shape(); } -bool findVariable(const std::string& theName, double& outValue) +bool findVariable(const std::string& theName, double& outValue, ResultParameterPtr& theParam) { SessionPtr aSession = ModelAPI_Session::get(); std::list aDocList; @@ -48,10 +48,10 @@ bool findVariable(const std::string& theName, double& outValue) } for(std::list::const_iterator it = aDocList.begin(); it != aDocList.end(); ++it) { ObjectPtr aParamObj = (*it)->objectByName(ModelAPI_ResultParameter::group(), theName); - ResultParameterPtr aParam = std::dynamic_pointer_cast(aParamObj); - if(!aParam.get()) + theParam = std::dynamic_pointer_cast(aParamObj); + if(!theParam.get()) continue; - AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE()); + AttributeDoublePtr aValueAttribute = theParam->data()->real(ModelAPI_ResultParameter::VALUE()); outValue = aValueAttribute->value(); return true; } diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index e89a713ce..9bea2d9cd 100644 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -9,6 +9,7 @@ #include "ModelAPI.h" #include +#include #include #include @@ -22,7 +23,8 @@ MODELAPI_EXPORT std::shared_ptr shape(const ResultPtr& theResult) * in the root document (PartSet). If found, set it value in the \param outValue * and returns true. */ -MODELAPI_EXPORT bool findVariable(const std::string& theName, double& outValue); +MODELAPI_EXPORT bool findVariable(const std::string& theName, double& outValue, + ResultParameterPtr& theParam); /*! * Returns the values of the next random color. The values are in range [0, 255] diff --git a/src/ModuleBase/ModuleBase_ParamSpinBox.cpp b/src/ModuleBase/ModuleBase_ParamSpinBox.cpp index 5501b2655..5b88af890 100644 --- a/src/ModuleBase/ModuleBase_ParamSpinBox.cpp +++ b/src/ModuleBase/ModuleBase_ParamSpinBox.cpp @@ -164,7 +164,7 @@ bool ModuleBase_ParamSpinBox::hasVariable() const bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const { - QRegExp varNameMask("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"); + QRegExp varNameMask("[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?"); return !varNameMask.exactMatch(theText); } @@ -205,8 +205,8 @@ bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const bool ModuleBase_ParamSpinBox::findVariable(const QString& theName, double& outValue) const { - - return ModelAPI_Tools::findVariable(theName.toStdString(), outValue); + ResultParameterPtr aParam; + return ModelAPI_Tools::findVariable(theName.toStdString(), outValue, aParam); } /*! diff --git a/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp b/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp index 904df9408..d0e7a9c20 100644 --- a/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp +++ b/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -125,12 +124,6 @@ bool ModuleBase_WidgetDoubleValue::storeValueCustom() const // Here is a text of a real value or an expression. std::string aText = mySpinBox->text().toStdString(); aReal->setText(aText); - // Send it to evaluator to convert into the double and store in the attribute - static Events_ID anId = ModelAPI_AttributeEvalMessage::eventId(); - std::shared_ptr aMessage = - std::shared_ptr(new ModelAPI_AttributeEvalMessage(anId, this)); - aMessage->setAttribute(aData->attribute(attributeID())); - Events_Loop::loop()->send(aMessage); } updateObject(myFeature); return true; diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp index 06f2ecfa1..8fa3af26d 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp @@ -66,7 +66,8 @@ double ParametersPlugin_EvalListener::evaluate(const std::string& theExpression, std::list::iterator it = anExprParams.begin(); for ( ; it != anExprParams.end(); it++) { double aValue; - if (!ModelAPI_Tools::findVariable(*it, aValue)) continue; + ResultParameterPtr aParamRes; + if (!ModelAPI_Tools::findVariable(*it, aValue, aParamRes)) continue; std::ostringstream sstream; sstream << aValue; @@ -78,4 +79,3 @@ double ParametersPlugin_EvalListener::evaluate(const std::string& theExpression, myInterp->clearLocalContext(); return result; } - diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp index f9fdc7c6d..58280994c 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp @@ -10,7 +10,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -27,10 +30,10 @@ ParametersPlugin_Parameter::~ParametersPlugin_Parameter() void ParametersPlugin_Parameter::initAttributes() { - data()->addAttribute(ParametersPlugin_Parameter::VARIABLE_ID(), - ModelAPI_AttributeString::typeId()); - data()->addAttribute(ParametersPlugin_Parameter::EXPRESSION_ID(), - ModelAPI_AttributeString::typeId()); + data()->addAttribute(VARIABLE_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(EXPRESSION_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(ARGUMENTS_ID(), ModelAPI_AttributeRefList::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ARGUMENTS_ID()); } bool ParametersPlugin_Parameter::isInHistory() @@ -38,40 +41,47 @@ bool ParametersPlugin_Parameter::isInHistory() return false; } -void ParametersPlugin_Parameter::attributeChanged(const std::string&) +void ParametersPlugin_Parameter::attributeChanged(const std::string& theID) { - ResultParameterPtr aParam = document()->createParameter(data()); + if (theID == EXPRESSION_ID()) { // recompute only on change of the expression + ResultParameterPtr aParam = document()->createParameter(data()); - std::string anExpression = string(ParametersPlugin_Parameter::EXPRESSION_ID())->value(); - if(anExpression.empty()) { - // clear error/result if the expression is empty - setError("", false); - return; + std::string anExpression = string(EXPRESSION_ID())->value(); + if(anExpression.empty()) { + // clear error/result if the expression is empty + setError("", false); + return; + } + std::string outErrorMessage; + double aValue = evaluate(anExpression, outErrorMessage); + // Name + std::string aName = string(VARIABLE_ID())->value(); + std::ostringstream sstream; + sstream << aValue; + std::string aParamValue = sstream.str(); + data()->setName(aName); + aParam->data()->setName(aName); + // Error + if (!outErrorMessage.empty()) { + std::string aStateMsg("Error: " + outErrorMessage); + data()->execState(ModelAPI_StateExecFailed); + setError(aStateMsg, false); + } else { + static const std::string anEmptyMsg(""); // it is checked in the validator by the empty message + setError(anEmptyMsg, false); + data()->execState(ModelAPI_StateDone); + } + // Value + AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE()); + aValueAttribute->setValue(aValue); + setResult(aParam); } - std::string outErrorMessage; - double aValue = evaluate(anExpression, outErrorMessage); - // Name - std::string aName = string(ParametersPlugin_Parameter::VARIABLE_ID())->value(); - std::ostringstream sstream; - sstream << aValue; - std::string aParamValue = sstream.str(); - data()->setName(aName); - aParam->data()->setName(aName); - // Error - std::string aStateMsg; - if (!outErrorMessage.empty()) { - aStateMsg = "Error: " + outErrorMessage; - data()->execState(ModelAPI_StateExecFailed); - } - setError(aStateMsg, false); - // Value - AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE()); - aValueAttribute->setValue(aValue); - setResult(aParam); } void ParametersPlugin_Parameter::execute() { + // just call recompute + attributeChanged(EXPRESSION_ID()); } double ParametersPlugin_Parameter::evaluate(const std::string& theExpression, std::string& theError) @@ -81,17 +91,45 @@ double ParametersPlugin_Parameter::evaluate(const std::string& theExpression, st // find expression's params in the model std::list aContext; std::list::iterator it = anExprParams.begin(); + std::list aParamsList; for ( ; it != anExprParams.end(); it++) { double aValue; - if (!ModelAPI_Tools::findVariable(*it, aValue)) continue; + ResultParameterPtr aParamRes; + if (!ModelAPI_Tools::findVariable(*it, aValue, aParamRes)) continue; + aParamsList.push_back(aParamRes); std::ostringstream sstream; sstream << aValue; std::string aParamValue = sstream.str(); aContext.push_back(*it + "=" + aParamValue); } + // compare the list of parameters to store if changed + AttributeRefListPtr aParams = reflist(ARGUMENTS_ID()); + bool aDifferent = aParams->size() != aParamsList.size(); + if (!aDifferent) { + std::list::iterator aNewIter = aParamsList.begin(); + std::list anOldList = aParams->list(); + std::list::iterator anOldIter = anOldList.begin(); + for(; !aDifferent && aNewIter != aParamsList.end(); aNewIter++, anOldIter++) { + if (*aNewIter != *anOldIter) + aDifferent = true; + } + } + if (aDifferent) { + aParams->clear(); + std::list::iterator aNewIter = aParamsList.begin(); + for(; aNewIter != aParamsList.end(); aNewIter++) { + aParams->append(*aNewIter); + } + } + myInterp->extendLocalContext(aContext); double result = myInterp->evaluate(theExpression, theError); myInterp->clearLocalContext(); return result; } + +bool ParametersPlugin_Parameter::isPreviewNeeded() const +{ + return false; +} diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.h b/src/ParametersPlugin/ParametersPlugin_Parameter.h index a65a5ff38..c348d0f73 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.h +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.h @@ -40,6 +40,13 @@ class ParametersPlugin_Parameter : public ModelAPI_Feature return MY_EXPRESSION_ID; } + /// list of references to the arguments of this expression + inline static const std::string& ARGUMENTS_ID() + { + static const std::string MY_VARIABLE_ID("arguments"); + return MY_VARIABLE_ID; + } + /// Returns the kind of a feature PARAMETERSPLUGIN_EXPORT virtual const std::string& getKind() { @@ -47,6 +54,9 @@ class ParametersPlugin_Parameter : public ModelAPI_Feature return MY_KIND; } + /// Pre-execution is not needed for parameter + PARAMETERSPLUGIN_EXPORT virtual bool isPreviewNeeded() const; + /// Creates a new part document if needed PARAMETERSPLUGIN_EXPORT virtual void execute(); -- 2.39.2