From 3c3d2b36e230e15ee8384554118ea13ca1415772 Mon Sep 17 00:00:00 2001 From: mpv Date: Fri, 21 Nov 2014 14:24:04 +0300 Subject: [PATCH] Task #267: initial implementation of errors management --- .../ExchangePlugin_ImportFeature.cpp | 23 +- src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp | 24 +- .../FeaturesPlugin_Extrusion.cpp | 22 +- src/FeaturesPlugin/FeaturesPlugin_Group.h | 2 +- src/Model/Model_Data.cpp | 213 ++++-------------- src/Model/Model_Data.h | 13 +- src/Model/Model_FeatureValidator.cpp | 6 + src/Model/Model_FeatureValidator.h | 5 +- src/Model/Model_Update.cpp | 140 ++++++++---- src/Model/Model_Update.h | 4 +- src/Model/Model_Validator.cpp | 13 ++ src/Model/Model_Validator.h | 3 + src/ModelAPI/ModelAPI_Data.h | 21 +- src/ModelAPI/ModelAPI_Feature.h | 5 + src/ModelAPI/ModelAPI_FeatureValidator.h | 3 + src/ModelAPI/ModelAPI_Validator.h | 3 + src/XGUI/XGUI_PartDataModel.cpp | 3 +- 17 files changed, 222 insertions(+), 281 deletions(-) diff --git a/src/ExchangePlugin/ExchangePlugin_ImportFeature.cpp b/src/ExchangePlugin/ExchangePlugin_ImportFeature.cpp index 6493870df..5a31c28f9 100644 --- a/src/ExchangePlugin/ExchangePlugin_ImportFeature.cpp +++ b/src/ExchangePlugin/ExchangePlugin_ImportFeature.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -100,12 +99,9 @@ bool ExchangePlugin_ImportFeature::importFile(const std::string& theFileName) anUnknownLabel); // Check if shape is valid if ( aShape.IsNull() ) { - std::string aShapeError = "An error occurred while importing " + theFileName + ": "; - aShapeError = aShapeError + std::string(anError.ToCString()); - Events_Error::send(aShapeError, this); - #ifdef _DEBUG - std::cerr << aShapeError << std::endl; - #endif + const static std::string aShapeError = + "An error occurred while importing " + theFileName + ": " + anError.ToCString(); + setError(aShapeError); return false; } // @@ -154,20 +150,15 @@ LibHandle ExchangePlugin_ImportFeature::loadImportPlugin(const std::string& theF #else anImportError = anImportError + std::string(dlerror()); #endif - Events_Error::send(anImportError, this); -#ifdef _DEBUG - std::cerr << anImportError << std::endl; -#endif + setError(anImportError); return false; } // Test loaded plugin for existence of valid "Import" function: importFunctionPointer fp = (importFunctionPointer) GetProc(anImportLib, "Import"); if (!fp) { - std::string aFunctionError = "No valid \"Import\" function was found in the " + aLibName; - Events_Error::send(aFunctionError, this); -#ifdef _DEBUG - std::cerr << aFunctionError << std::endl; -#endif + const static std::string aFunctionError = + "No valid \"Import\" function was found in the " + aLibName; + setError(aFunctionError); UnLoadLib(anImportLib) return NULL; } diff --git a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp index d8b8198ed..025f63bab 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp @@ -10,12 +10,7 @@ #include #include #include -#include using namespace std; -#ifdef _DEBUG -#include -#include -#endif #define FACE 4 #define _MODIFY_TAG 1 @@ -65,29 +60,26 @@ void FeaturesPlugin_Boolean::execute() GeomAlgoAPI_Boolean* aFeature = new GeomAlgoAPI_Boolean(anObject, aTool, aType); if(aFeature && !aFeature->isDone()) { - std::string aFeatureError = "Boolean feature: algorithm failed"; - Events_Error::send(aFeatureError, this); + static const std::string aFeatureError = "Boolean feature: algorithm failed"; + setError(aFeatureError); return; } // Check if shape is valid if (aFeature->shape()->isNull()) { - std::string aShapeError = "Boolean feature: resulting shape is Null"; - Events_Error::send(aShapeError, this); -#ifdef _DEBUG - std::cerr << aShapeError << std::endl; -#endif + static const std::string aShapeError = "Boolean feature: resulting shape is Null"; + setError(aShapeError); return; } if(!aFeature->isValid()) { - std::string aFeatureError = "Boolean feature: resulting shape is not valid"; - Events_Error::send(aFeatureError, this); + static const std::string aFeatureError = "Boolean feature: resulting shape is not valid"; + setError(aFeatureError); return; } // if result of Boolean operation is same as was before it means that Boolean operation has no sence // and naming provides no result, so, generate an error in this case if (anObject->isEqual(aFeature->shape())) { - std::string aFeatureError = "Boolean feature: operation was not performed"; - Events_Error::send(aFeatureError, this); + static const std::string aFeatureError = "Boolean feature: operation was not performed"; + setError(aFeatureError); return; } //LoadNamingDS diff --git a/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp b/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp index 55bc605c1..cebc0bb44 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include using namespace std; @@ -19,10 +18,6 @@ using namespace std; #define _FIRST_TAG 2 #define _LAST_TAG 3 #define EDGE 6 -#ifdef _DEBUG -#include -#include -#endif FeaturesPlugin_Extrusion::FeaturesPlugin_Extrusion() { @@ -56,8 +51,8 @@ void FeaturesPlugin_Extrusion::execute() aContext = std::dynamic_pointer_cast(aContextRes)->shape(); } if (!aContext) { - std::string aContextError = "The selection context is bad"; - Events_Error::send(aContextError, this); + static const std::string aContextError = "The selection context is bad"; + setError(aContextError); return; } @@ -68,23 +63,20 @@ void FeaturesPlugin_Extrusion::execute() std::shared_ptr aResultBody = document()->createBody(data()); GeomAlgoAPI_Extrusion aFeature(aFace, aSize); if(!aFeature.isDone()) { - std::string aFeatureError = "Extrusion algorithm failed"; - Events_Error::send(aFeatureError, this); + static const std::string aFeatureError = "Extrusion algorithm failed"; + setError(aFeatureError); return; } // Check if shape is valid if (aFeature.shape()->isNull()) { - std::string aShapeError = "Resulting shape is Null"; - Events_Error::send(aShapeError, this); -#ifdef _DEBUG - std::cerr << aShapeError << std::endl; -#endif + static const std::string aShapeError = "Resulting shape is Null"; + setError(aShapeError); return; } if(!aFeature.isValid()) { std::string aFeatureError = "Warning: resulting shape is not valid"; - Events_Error::send(aFeatureError, this); + setError(aFeatureError); return; } //LoadNamingDS diff --git a/src/FeaturesPlugin/FeaturesPlugin_Group.h b/src/FeaturesPlugin/FeaturesPlugin_Group.h index 7138c1241..e306842a5 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Group.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Group.h @@ -45,7 +45,7 @@ class FeaturesPlugin_Group : public ModelAPI_Feature FEATURESPLUGIN_EXPORT virtual void initAttributes(); /// Result of groups is created on the fly and don't stored to the document - FEATURESPLUGIN_EXPORT virtual bool isPersistentResult() {return false;} + FEATURESPLUGIN_EXPORT virtual bool isPersistentResult() {return true;} /// Use plugin manager for features creation FeaturesPlugin_Group(); diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index 77b834ada..5dcc138de 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -26,10 +26,13 @@ #include #include -#include #include +// myLab contains: +// TDataStd_Name - name of the object +// TDataStd_Integer - state of the object execution + Model_Data::Model_Data() { } @@ -85,7 +88,9 @@ void Model_Data::addAttribute(const std::string& theID, const std::string theAtt anAttr = new Model_AttributeRefAttr(anAttrLab); } else if (theAttrType == ModelAPI_AttributeRefList::type()) { anAttr = new Model_AttributeRefList(anAttrLab); - } else if (theAttrType == GeomData_Point::type()) { + } + // create also GeomData attributes here because only here the OCAF strucure is known + else if (theAttrType == GeomData_Point::type()) { anAttr = new GeomData_Point(anAttrLab); } else if (theAttrType == GeomData_Dir::type()) { anAttr = new GeomData_Dir(anAttrLab); @@ -100,167 +105,28 @@ void Model_Data::addAttribute(const std::string& theID, const std::string theAtt } } -std::shared_ptr Model_Data::document(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeDocRef>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr Model_Data::real(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr Model_Data::integer(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeInteger>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request +// macro for gthe generic returning of the attribute by the ID +#define GET_ATTRIBUTE_BY_ID(ATTR_TYPE, METHOD_NAME) \ + std::shared_ptr Model_Data::METHOD_NAME(const std::string& theID) { \ + std::shared_ptr aRes; \ + std::map::iterator aFound = \ + myAttrs.find(theID); \ + if (aFound != myAttrs.end()) { \ + aRes = std::dynamic_pointer_cast(aFound->second); \ + } \ + return aRes; \ } - return aRes; -} - -std::shared_ptr Model_Data::boolean(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeBoolean>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr Model_Data::string(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = - std::dynamic_pointer_cast(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; - -} - -std::shared_ptr Model_Data::reference(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeReference>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr Model_Data::selection(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = - std::dynamic_pointer_cast(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr - Model_Data::selectionList(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = - std::dynamic_pointer_cast(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr Model_Data::refattr(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} - -std::shared_ptr Model_Data::reflist(const std::string& theID) -{ - std::map >::iterator aFound = - myAttrs.find(theID); - if (aFound == myAttrs.end()) { - // TODO: generate error on unknown attribute request and/or add mechanism for customization - return std::shared_ptr(); - } - std::shared_ptr aRes = std::dynamic_pointer_cast< - ModelAPI_AttributeRefList>(aFound->second); - if (!aRes) { - // TODO: generate error on invalid attribute type request - } - return aRes; -} +// implement nice getting methods for all ModelAPI attributes +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeDocRef, document); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeDouble, real); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeInteger, integer); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeBoolean, boolean); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeString, string); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeReference, reference); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeSelection, selection); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeSelectionList, selectionList); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeRefAttr, refattr); +GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeRefList, reflist); std::shared_ptr Model_Data::attribute(const std::string& theID) { @@ -340,20 +206,25 @@ void Model_Data::erase() myLab.ForgetAllAttributes(); } -/// identifeir of the "must be updated" flag in the data tree -Standard_GUID kMustBeUpdatedGUID("baede74c-31a6-4416-9c4d-e48ce65f2005"); +void Model_Data::execState(const ModelAPI_ExecState theState) +{ + if (theState != ModelAPI_StateNothing) + TDataStd_Integer::Set(myLab, (int)theState); +} -void Model_Data::mustBeUpdated(const bool theFlag) +ModelAPI_ExecState Model_Data::execState() { - if (theFlag) - TDataStd_UAttribute::Set(myLab, kMustBeUpdatedGUID); - else - myLab.ForgetAttribute(kMustBeUpdatedGUID); + Handle(TDataStd_Integer) aStateAttr; + if (myLab.FindAttribute(TDataStd_Integer::GetID(), aStateAttr)) { + return ModelAPI_ExecState(aStateAttr->Get()); + } + return ModelAPI_StateMustBeUpdated; // default value } -bool Model_Data::mustBeUpdated() +void Model_Data::setError(const std::string& theError) { - return myLab.IsAttribute(kMustBeUpdatedGUID) == Standard_True; + execState(ModelAPI_StateExecFailed); + Events_Error::send(theError); } int Model_Data::featureId() const diff --git a/src/Model/Model_Data.h b/src/Model/Model_Data.h index 1d82ad14b..05068cd65 100644 --- a/src/Model/Model_Data.h +++ b/src/Model/Model_Data.h @@ -140,14 +140,17 @@ class Model_Data : public ModelAPI_Data myObject = theObject; } + /// Erases all the data from the data model MODEL_EXPORT virtual void erase(); - /// Makes feature must be updated later (on rebuild). Normally the Updater must call it - /// in case of not-automatic update to true - MODEL_EXPORT virtual void mustBeUpdated(const bool theFlag); + /// Stores the state of the object to execute it later accordingly + MODEL_EXPORT virtual void execState(const ModelAPI_ExecState theState); - /// Returns true if feature must be updated (re-executed) on rebuild - MODEL_EXPORT virtual bool mustBeUpdated(); + /// Returns the state of the latest execution of the feature + MODEL_EXPORT virtual ModelAPI_ExecState execState(); + + /// Registers error during the execution, causes the ExecutionFailed state + MODEL_EXPORT virtual void setError(const std::string& theError); /// Returns the identifier of feature-owner, unique in this document MODEL_EXPORT virtual int featureId() const; diff --git a/src/Model/Model_FeatureValidator.cpp b/src/Model/Model_FeatureValidator.cpp index 6e609dd5d..2bbad12d1 100644 --- a/src/Model/Model_FeatureValidator.cpp +++ b/src/Model/Model_FeatureValidator.cpp @@ -41,3 +41,9 @@ void Model_FeatureValidator::registerNotObligatory(std::string theFeature, std:: std::set& anAttrs = myNotObligatory[theFeature]; anAttrs.insert(theAttribute); } + +bool Model_FeatureValidator::isNotObligatory(std::string theFeature, std::string theAttribute) +{ + std::set& anAttrs = myNotObligatory[theFeature]; + return anAttrs.find(theAttribute) != anAttrs.end(); +} diff --git a/src/Model/Model_FeatureValidator.h b/src/Model/Model_FeatureValidator.h index b262ff0ea..dddfb2a31 100644 --- a/src/Model/Model_FeatureValidator.h +++ b/src/Model/Model_FeatureValidator.h @@ -24,7 +24,10 @@ class Model_FeatureValidator : public ModelAPI_FeatureValidator const std::list& theArguments) const; // sets not obligatory attributes, not checked for initialization - void registerNotObligatory(std::string theFeature, std::string theAttribute); + virtual void registerNotObligatory(std::string theFeature, std::string theAttribute); + + /// Returns true if the attribute in feature is not obligatory for the feature execution + virtual bool isNotObligatory(std::string theFeature, std::string theAttribute); }; #endif diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index 8aa00217e..ca900b86b 100644 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -160,20 +160,35 @@ void Model_Update::processEvent(const std::shared_ptr& theMessag isExecuted = false; } -void Model_Update::redisplayWithResults(FeaturePtr theFeature) { +void Model_Update::redisplayWithResults(FeaturePtr theFeature, const ModelAPI_ExecState theState) +{ // maske updated and redisplay all results static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); 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()->mustBeUpdated(false); + aRes->data()->execState(theState); myUpdated[aRes] = true; ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP); } // to redisplay "presentable" feature (for ex. distance constraint) ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP); - theFeature->data()->mustBeUpdated(false); + theFeature->data()->execState(theState); +} + +/// Updates the state by the referenced object: if something bad with it, set state for this one +ModelAPI_ExecState stateByReference(ObjectPtr theTarget, const ModelAPI_ExecState theCurrent) +{ + if (theTarget) { + ModelAPI_ExecState aRefState = theTarget->data()->execState(); + if (aRefState == ModelAPI_StateMustBeUpdated) { + return ModelAPI_StateMustBeUpdated; + } else if (aRefState != ModelAPI_StateDone) { + return ModelAPI_StateInvalidArgument; + } + } + return theCurrent; } bool Model_Update::updateFeature(FeaturePtr theFeature) @@ -185,7 +200,8 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); bool aMustbeUpdated = myInitial.find(theFeature) != myInitial.end(); if (theFeature) { // only real feature contains references to other objects - if (theFeature->data()->mustBeUpdated()) aMustbeUpdated = true; + if (theFeature->data()->execState() != ModelAPI_StateDone) + aMustbeUpdated = true; // composite feature must be executed after sub-features execution CompositeFeaturePtr aComposite = @@ -197,7 +213,9 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) aMustbeUpdated = true; } } + ModelAPI_ExecState aState = ModelAPI_StateDone; // check all references: if referenced objects are updated, this object also must be updated + // also check state of referenced objects: if they are not ready, inherit corresponding state std::list > > aRefs; std::shared_ptr aData = std::dynamic_pointer_cast(theFeature->data()); @@ -209,6 +227,7 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) if (updateObject(*aRefObj)) { aMustbeUpdated = true; } + aState = stateByReference(*aRefObj, aState); } } @@ -218,71 +237,94 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) if (std::dynamic_pointer_cast(theFeature->document())->executeFeatures() || !theFeature->isPersistentResult()) { if (aFactory->validate(theFeature)) { - if (isAutomatic || (myJustCreatedOrUpdated.find(theFeature) != myJustCreatedOrUpdated.end()) || - !theFeature->isPersistentResult() /* execute quick, not persistent results */) + if (isAutomatic || + (myJustCreatedOrUpdated.find(theFeature) != myJustCreatedOrUpdated.end()) || + !theFeature->isPersistentResult() /* execute quick, not persistent results */) { - //std::cout<<"Execute feature "<getKind()< aRefs = - theFeature->data()->attributes(ModelAPI_AttributeSelection::type()); - list::iterator aRefsIter = aRefs.begin(); - for (; aRefsIter != aRefs.end(); aRefsIter++) { - std::shared_ptr aSel = - std::dynamic_pointer_cast(*aRefsIter); - aSel->update(); // this must be done on execution since it may be long operation - } - aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::type()); - for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) { - std::shared_ptr aSel = - std::dynamic_pointer_cast(*aRefsIter); - for(int a = aSel->size() - 1; a >= 0; a--) { - aSel->value(a)->update(); + if (aState == ModelAPI_StateDone) {// all referenced objects are ready to be used + //std::cout<<"Execute feature "<getKind()< aRefs = + theFeature->data()->attributes(ModelAPI_AttributeSelection::type()); + list::iterator aRefsIter = aRefs.begin(); + for (; aRefsIter != aRefs.end(); aRefsIter++) { + std::shared_ptr aSel = + std::dynamic_pointer_cast(*aRefsIter); + if (!aSel->update()) { // this must be done on execution since it may be long operation + if (!aFactory->isNotObligatory(theFeature->getKind(), theFeature->data()->id(aSel))) + aState = ModelAPI_StateInvalidArgument; + } } - } - // for sketch after update of plane (by update of selection attribute) - // but before execute, all sub-elements also must be updated (due to the plane changes) - if (aComposite) { - int aSubsNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubsNum; a++) { - FeaturePtr aSub = aComposite->subFeature(a); - bool aWasModified = myUpdated[aSub]; - myUpdated.erase(myUpdated.find(aSub)); // erase to update for sure (plane may be changed) - myInitial.insert(aSub); - updateFeature(aSub); - myUpdated[aSub] = aWasModified; // restore value + aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::type()); + for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) { + std::shared_ptr aSel = + std::dynamic_pointer_cast(*aRefsIter); + for(int a = aSel->size() - 1; a >= 0; a--) { + std::shared_ptr aSelAttr = + std::dynamic_pointer_cast(aSel->value(a)); + if (aSelAttr) { + if (!aSelAttr->update()) { + if (!aFactory->isNotObligatory( + theFeature->getKind(), theFeature->data()->id(aSel))) + aState = ModelAPI_StateInvalidArgument; + } + } + } } - // re-execute after update: solver may update the previous values, so, shapes must be - // updated - for(int a = 0; a < aSubsNum; a++) { - if (aComposite->subFeature(a) && aFactory->validate(aComposite->subFeature(a))) - aComposite->subFeature(a)->execute(); + // for sketch after update of plane (by update of selection attribute) + // but before execute, all sub-elements also must be updated (due to the plane changes) + if (aComposite) { + int aSubsNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubsNum; a++) { + FeaturePtr aSub = aComposite->subFeature(a); + bool aWasModified = myUpdated[aSub]; + myUpdated.erase(myUpdated.find(aSub)); // erase to update for sure (plane may be changed) + myInitial.insert(aSub); + updateFeature(aSub); + myUpdated[aSub] = aWasModified; // restore value + } + // re-execute after update: solver may update the previous values, so, shapes must be + // updated + for(int a = 0; a < aSubsNum; a++) { + if (aComposite->subFeature(a) && aFactory->validate(aComposite->subFeature(a))) + aComposite->subFeature(a)->execute(); + } } } // execute in try-catch to avoid internal problems of the feature - try { - theFeature->execute(); - } catch(...) { - Events_Error::send( - "Feature " + theFeature->getKind() + " has failed during the execution"); + if (aState == ModelAPI_StateDone) { + theFeature->data()->execState(ModelAPI_StateDone); + try { + theFeature->execute(); + if (theFeature->data()->execState() != ModelAPI_StateDone) { + aState = ModelAPI_StateExecFailed; + } + } catch(...) { + aState = ModelAPI_StateExecFailed; + Events_Error::send( + "Feature " + theFeature->getKind() + " has failed during the execution"); + } + } + if (aState != ModelAPI_StateDone) { theFeature->eraseResults(); } - redisplayWithResults(theFeature); + redisplayWithResults(theFeature, aState); } else { // must be updatet, but not updated yet - theFeature->data()->mustBeUpdated(true); + 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()->mustBeUpdated(true); + aRes->data()->execState(ModelAPI_StateMustBeUpdated); } } } else { theFeature->eraseResults(); - redisplayWithResults(theFeature); // result also must be updated + 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); + redisplayWithResults(theFeature, ModelAPI_StateNothing); } } else { // returns also true is results were updated: for sketch that refers to sub-features but results of sub-features were changed const std::list >& aResults = theFeature->results(); diff --git a/src/Model/Model_Update.h b/src/Model/Model_Update.h index 31d532da5..bc4c2be68 100644 --- a/src/Model/Model_Update.h +++ b/src/Model/Model_Update.h @@ -6,6 +6,7 @@ #define Model_Update_H_ #include "Model.h" +#include #include "Events_Listener.h" #include #include @@ -48,7 +49,8 @@ class Model_Update : public Events_Listener /// Returns true if object was updated. bool updateObject(std::shared_ptr theObject, const bool theCyclic = true); /// Sends the redisplay events for feature and results, updates the updated status - void redisplayWithResults(std::shared_ptr theFeature); + void redisplayWithResults(std::shared_ptr theFeature, + const ModelAPI_ExecState theState); }; #endif diff --git a/src/Model/Model_Validator.cpp b/src/Model/Model_Validator.cpp index cc3a612a5..501b91b2f 100644 --- a/src/Model/Model_Validator.cpp +++ b/src/Model/Model_Validator.cpp @@ -224,6 +224,19 @@ void Model_ValidatorsFactory::registerNotObligatory(std::string theFeature, std: } } +bool Model_ValidatorsFactory::isNotObligatory(std::string theFeature, std::string theAttribute) +{ + const static std::string kDefaultId = "Model_FeatureValidator"; + std::map::const_iterator it = myIDs.find(kDefaultId); + if (it != myIDs.end()) { + Model_FeatureValidator* aValidator = dynamic_cast(it->second); + if (aValidator) { + return aValidator->isNotObligatory(theFeature, theAttribute); + } + } + return false; // default +} + void Model_ValidatorsFactory::registerConcealment(std::string theFeature, std::string theAttribute) { std::map >::iterator aFind = myConcealed.find(theFeature); diff --git a/src/Model/Model_Validator.h b/src/Model/Model_Validator.h index a6d369963..a739a7978 100644 --- a/src/Model/Model_Validator.h +++ b/src/Model/Model_Validator.h @@ -76,6 +76,9 @@ class Model_ValidatorsFactory : public ModelAPI_ValidatorsFactory /// so, it is not needed for the standard validation mechanism virtual void registerNotObligatory(std::string theFeature, std::string theAttribute); + /// Returns true if the attribute in feature is not obligatory for the feature execution + virtual bool isNotObligatory(std::string theFeature, std::string theAttribute); + /// register that this attribute conceals in the object browser /// all referenced features after execution virtual void registerConcealment(std::string theFeature, std::string theAttribute); diff --git a/src/ModelAPI/ModelAPI_Data.h b/src/ModelAPI/ModelAPI_Data.h index 8cc137477..8e33c85ff 100644 --- a/src/ModelAPI/ModelAPI_Data.h +++ b/src/ModelAPI/ModelAPI_Data.h @@ -26,6 +26,15 @@ class ModelAPI_AttributeSelection; class ModelAPI_AttributeSelectionList; class GeomAPI_Shape; +/// Enumeration that contains the execution status of the Object +enum ModelAPI_ExecState { + ModelAPI_StateDone, ///< execution was performed and result is up to date + ModelAPI_StateMustBeUpdated, ///< execution must be performed to obtain the up to date result + ModelAPI_StateExecFailed, ///< execution was failed (results are deleted in this case) + ModelAPI_StateInvalidArgument, ///< execution was not performed (results are deleted in this case) + ModelAPI_StateNothing ///< internal state that actually means that nothing must be changed +}; + /**\class ModelAPI_Data * \ingroup DataModel * \brief General object of the application that allows @@ -100,12 +109,14 @@ class MODELAPI_EXPORT ModelAPI_Data { } - /// Makes feature must be updated later (on rebuild). Normally the Updater must call it - /// in case of not-automatic update to true - virtual void mustBeUpdated(const bool theFlag) = 0; + /// Stores the state of the object to execute it later accordingly + virtual void execState(const ModelAPI_ExecState theState) = 0; + + /// Returns the state of the latest execution of the feature + virtual ModelAPI_ExecState execState() = 0; - /// Returns true if feature must be updated (re-executed) on rebuild - virtual bool mustBeUpdated() = 0; + /// Registers error during the execution, causes the ExecutionFailed state + virtual void setError(const std::string& theError) = 0; /// Returns the identifier of feature-owner, unique in this document virtual int featureId() const = 0; diff --git a/src/ModelAPI/ModelAPI_Feature.h b/src/ModelAPI/ModelAPI_Feature.h index 431b065b7..6ea57af29 100644 --- a/src/ModelAPI/ModelAPI_Feature.h +++ b/src/ModelAPI/ModelAPI_Feature.h @@ -53,6 +53,11 @@ class ModelAPI_Feature : public ModelAPI_Object /// Computes or recomputes the results virtual void execute() = 0; + /// Registers error during the execution, causes the ExecutionFailed state + virtual void setError(const std::string& theError) { + data()->setError(theError); + } + /// returns the current results of the feature MODELAPI_EXPORT const std::list >& results(); /// returns the first result in the list or NULL reference diff --git a/src/ModelAPI/ModelAPI_FeatureValidator.h b/src/ModelAPI/ModelAPI_FeatureValidator.h index 6d44a735a..b29fda799 100644 --- a/src/ModelAPI/ModelAPI_FeatureValidator.h +++ b/src/ModelAPI/ModelAPI_FeatureValidator.h @@ -17,6 +17,9 @@ class ModelAPI_FeatureValidator : public ModelAPI_Validator /// \param theArguments list of string, feature attribute names: dependent attributes virtual bool isValid(const std::shared_ptr& theFeature, const std::list& theArguments) const = 0; + + /// Returns true if the attribute in feature is not obligatory for the feature execution + virtual bool isNotObligatory(std::string theFeature, std::string theAttribute) = 0; }; #endif diff --git a/src/ModelAPI/ModelAPI_Validator.h b/src/ModelAPI/ModelAPI_Validator.h index a4eb79416..3dfb14f10 100644 --- a/src/ModelAPI/ModelAPI_Validator.h +++ b/src/ModelAPI/ModelAPI_Validator.h @@ -83,6 +83,9 @@ class MODELAPI_EXPORT ModelAPI_ValidatorsFactory /// so, it is not needed for the standard validation mechanism virtual void registerNotObligatory(std::string theFeature, std::string theAttribute) = 0; + /// Returns true if the attribute in feature is not obligatory for the feature execution + virtual bool isNotObligatory(std::string theFeature, std::string theAttribute) = 0; + /// register that this attribute conceals in the object browser /// all referenced features after execution virtual void registerConcealment(std::string theFeature, std::string theAttribute) = 0; diff --git a/src/XGUI/XGUI_PartDataModel.cpp b/src/XGUI/XGUI_PartDataModel.cpp index c7f1b81a2..f80e5ae9f 100644 --- a/src/XGUI/XGUI_PartDataModel.cpp +++ b/src/XGUI/XGUI_PartDataModel.cpp @@ -319,7 +319,8 @@ QVariant XGUI_PartDataModel::data(const QModelIndex& theIndex, int theRole) cons std::string aGroup = theIndex.internalId() == ConstructObject ? ModelAPI_ResultConstruction::group() : ModelAPI_ResultBody::group(); ObjectPtr anObject = partDocument()->object(aGroup, theIndex.row()); - if (anObject && anObject->data() && anObject->data()->mustBeUpdated()) { + if (anObject && anObject->data() && + anObject->data()->execState() == ModelAPI_StateMustBeUpdated) { return QIcon(":pictures/constr_object_modified.png"); } return QIcon(":pictures/constr_object.png"); -- 2.39.2