From 298e667eb49d3d1441664d76c1ab4f5fdc80645e Mon Sep 17 00:00:00 2001 From: mpv Date: Tue, 30 Jun 2015 13:12:54 +0300 Subject: [PATCH] Update the management of the updates: use transactions ID to detect correctly dependencies that must be updated. --- src/Model/Model_Data.cpp | 57 +++- src/Model/Model_Data.h | 7 + src/Model/Model_Document.cpp | 23 ++ src/Model/Model_Document.h | 7 + src/Model/Model_ResultPart.cpp | 16 +- src/Model/Model_ResultPart.h | 2 + src/Model/Model_Session.cpp | 5 + src/Model/Model_Session.h | 3 + src/Model/Model_Update.cpp | 316 ++++++++++------------- src/Model/Model_Update.h | 13 +- src/ModelAPI/ModelAPI_Data.h | 7 + src/ModelAPI/ModelAPI_Feature.cpp | 2 +- src/ModelAPI/ModelAPI_Feature.h | 2 +- src/ModelAPI/ModelAPI_ResultPart.h | 2 + src/ModelAPI/ModelAPI_Session.h | 3 + src/PartSetPlugin/PartSetPlugin_Part.cpp | 69 +++++ src/PartSetPlugin/PartSetPlugin_Part.h | 26 +- 17 files changed, 343 insertions(+), 217 deletions(-) diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index 9228db8ab..4546128eb 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,7 @@ #include #include +#include #include #include #include @@ -38,7 +40,7 @@ // myLab contains: // TDataStd_Name - name of the object -// TDataStd_Integer - state of the object execution +// TDataStd_IntegerArray - state of the object execution, transaction ID of update // TDataStd_BooleanArray - array of flags of this data: // 0 - is in history or not static const int kFlagInHistory = 0; @@ -240,19 +242,44 @@ void Model_Data::erase() myLab.ForgetAllAttributes(); } +// indexes in the state array +enum StatesIndexes { + STATE_INDEX_STATE = 1, // the state type itself + STATE_INDEX_TRANSACTION = 2, // transaction ID +}; + +/// Returns the label array, initialises it by default values if not exists +static Handle(TDataStd_IntegerArray) stateArray(TDF_Label& theLab) +{ + Handle(TDataStd_IntegerArray) aStateArray; + if (!theLab.FindAttribute(TDataStd_IntegerArray::GetID(), aStateArray)) { + aStateArray = TDataStd_IntegerArray::Set(theLab, 1, 2); + aStateArray->SetValue(STATE_INDEX_STATE, ModelAPI_StateMustBeUpdated); // default state + aStateArray->SetValue(STATE_INDEX_TRANSACTION, 0); // default transaction ID (not existing) + } + return aStateArray; +} + void Model_Data::execState(const ModelAPI_ExecState theState) { - if (theState != ModelAPI_StateNothing) - TDataStd_Integer::Set(myLab, (int)theState); + if (theState != ModelAPI_StateNothing) { + stateArray(myLab)->SetValue(STATE_INDEX_STATE, (int)theState); + } } ModelAPI_ExecState Model_Data::execState() { - Handle(TDataStd_Integer) aStateAttr; - if (myLab.FindAttribute(TDataStd_Integer::GetID(), aStateAttr)) { - return ModelAPI_ExecState(aStateAttr->Get()); - } - return ModelAPI_StateMustBeUpdated; // default value + return ModelAPI_ExecState(stateArray(myLab)->Value(STATE_INDEX_STATE)); +} + +int Model_Data::updateID() +{ + return stateArray(myLab)->Value(STATE_INDEX_TRANSACTION); +} + +void Model_Data::setUpdateID(const int theID) +{ + stateArray(myLab)->SetValue(STATE_INDEX_TRANSACTION, theID); } void Model_Data::setError(const std::string& theError, bool theSend) @@ -400,10 +427,16 @@ void Model_Data::setIsInHistory(const bool theFlag) bool Model_Data::isDisplayed() { - return myObject.get() && myObject->document().get() && - (myObject->document()->isActive() || - myObject->document() == ModelAPI_Session::get()->moduleDocument()) && // root is accessible allways - myFlags->Value(kFlagDisplayed) == Standard_True; + if (!myObject.get() || !myObject->document().get() || // object is in valid + myFlags->Value(kFlagDisplayed) != Standard_True) // or it was not displayed before + return false; + if (myObject->document()->isActive()) // for active documents it must be ok anyway + return true; + // any object from the root document except part result may be displayed + if (myObject->document() == ModelAPI_Session::get()->moduleDocument() && + myObject->groupName() != ModelAPI_ResultPart::group()) + return true; + return false; } void Model_Data::setDisplayed(const bool theDisplay) diff --git a/src/Model/Model_Data.h b/src/Model/Model_Data.h index 38733fb72..fba3cd500 100644 --- a/src/Model/Model_Data.h +++ b/src/Model/Model_Data.h @@ -192,6 +192,13 @@ class Model_Data : public ModelAPI_Data /// Returns the invalid data pointer: static method static std::shared_ptr invalidData(); + /// Identifier of the transaction when object (feature or result) was updated last time. + MODEL_EXPORT virtual int updateID(); + + /// Identifier of the transaction when object (feature or result) was updated last time. + /// This method is called by the updater. + MODEL_EXPORT virtual void setUpdateID(const int theID); + protected: /// Returns true if "is in history" custom behaviors is defined for the feature MODEL_EXPORT virtual bool isInHistory(); diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 75cfb1de8..a18375f86 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -46,6 +46,7 @@ static const int TAG_GENERAL = 1; // general properties tag // general sub-labels static const int TAG_CURRENT_FEATURE = 1; ///< where the reference to the current feature label is located (or no attribute if null feature) +static const int TAG_CURRENT_TRANSACTION = 2; ///< integer, index of the cransaction Model_Document::Model_Document(const std::string theID, const std::string theKind) : myID(theID), myKind(theKind), myIsActive(false), @@ -292,6 +293,7 @@ void Model_Document::startOperation() myDoc->NewCommand(); } // starts a new operation + incrementTransactionID(); myTransactions.push_back(Transaction()); if (!myNestedNum.empty()) (*myNestedNum.rbegin())++; @@ -862,3 +864,24 @@ bool Model_Document::isActive() const { return myIsActive; } + +int Model_Document::transactionID() +{ + Handle(TDataStd_Integer) anIndex; + if (!generalLabel().FindChild(TAG_CURRENT_TRANSACTION). + FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + anIndex = TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), 1); + } + return anIndex->Get(); +} + +void Model_Document::incrementTransactionID() +{ + int aNewVal = transactionID() + 1; + TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal); +} +void Model_Document::decrementTransactionID() +{ + int aNewVal = transactionID() - 1; + TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal); +} diff --git a/src/Model/Model_Document.h b/src/Model/Model_Document.h index bc414a156..1aaca02ac 100644 --- a/src/Model/Model_Document.h +++ b/src/Model/Model_Document.h @@ -172,6 +172,13 @@ class Model_Document : public ModelAPI_Document ///! history. Not very fast method, for calling once, not in big cycles. MODEL_EXPORT virtual std::list > allFeatures(); + /// Returns the global identifier of the current transaction (needed for the update algo) + MODEL_EXPORT virtual int transactionID(); + /// Increases the transaction ID + MODEL_EXPORT virtual void incrementTransactionID(); + /// Decreases the transaction ID + MODEL_EXPORT virtual void decrementTransactionID(); + protected: //! Returns (creates if needed) the general label TDF_Label generalLabel() const; diff --git a/src/Model/Model_ResultPart.cpp b/src/Model/Model_ResultPart.cpp index e49604794..5216e6107 100644 --- a/src/Model/Model_ResultPart.cpp +++ b/src/Model/Model_ResultPart.cpp @@ -10,7 +10,12 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -122,12 +127,6 @@ std::shared_ptr Model_ResultPart::shape() return aResult; } -#include -#include -#include -#include -#include - std::string Model_ResultPart::nameInPart(const std::shared_ptr& theShape) { TopoDS_Shape aShape = theShape->impl(); @@ -176,3 +175,8 @@ void Model_ResultPart::colorConfigInfo(std::string& theSection, std::string& the theName = "result_part_color"; theDefault = DEFAULT_COLOR(); } + +void Model_ResultPart::updateShape() +{ + myShape.Nullify(); +} diff --git a/src/Model/Model_ResultPart.h b/src/Model/Model_ResultPart.h index fe00a84bd..11f813388 100644 --- a/src/Model/Model_ResultPart.h +++ b/src/Model/Model_ResultPart.h @@ -41,6 +41,8 @@ class Model_ResultPart : public ModelAPI_ResultPart MODEL_EXPORT virtual std::string nameInPart(const std::shared_ptr& theShape); /// Returns the shape by the name in the part MODEL_EXPORT virtual std::shared_ptr shapeInPart(const std::string& theName); + /// Updates the shape-result of the part (called on Part feature execution) + MODEL_EXPORT virtual void updateShape(); /// Returns the parameters of color definition in the resources config manager MODEL_EXPORT virtual void colorConfigInfo(std::string& theSection, std::string& theName, diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index 9d76861f6..daae187f0 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -425,3 +425,8 @@ ModelAPI_ValidatorsFactory* Model_Session::validators() static Model_ValidatorsFactory* aFactory = new Model_ValidatorsFactory; return aFactory; } + +int Model_Session::transactionID() +{ + return ROOT_DOC->transactionID(); +} diff --git a/src/Model/Model_Session.h b/src/Model/Model_Session.h index 2584a2e20..62d69e5be 100644 --- a/src/Model/Model_Session.h +++ b/src/Model/Model_Session.h @@ -117,6 +117,9 @@ class Model_Session : public ModelAPI_Session, public Events_Listener /// Is called only once, on startup of the application Model_Session(); + /// Returns the global identifier of the current transaction (needed for the update algo) + MODEL_EXPORT virtual int transactionID(); + protected: /// Loads (if not done yet) the information about the features and plugins void LoadPluginsInfo(); diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index d3cc6c9c1..5aa0e18f7 100644 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -99,13 +99,9 @@ void Model_Update::processEvent(const std::shared_ptr& theMessag } // created objects are always must be up to date (python box feature) // and updated not in internal uptation chain - if (theMessage->eventID() == kCreatedEvent) { - myJustCreated.insert(*anObjIter); - } else if (myJustCreated.find(*anObjIter) == myJustCreated.end()) { // moved and updated - myJustUpdated.insert(*anObjIter); - } + myJustUpdated.insert(*anObjIter); } - // this event is for solver update, not here, do not react immideately + // this event is for solver update, not here, do not react immideately if (!isOnlyResults && !(theMessage->eventID() == kMovedEvent)) processOperation(false); } else if (theMessage->eventID() == kOpStartEvent) { @@ -117,16 +113,12 @@ void Model_Update::processEvent(const std::shared_ptr& theMessag } if (isOperationChanged) { // remove all macros before clearing all created and execute all not-previewed - std::set::iterator aCreatedIter = myJustCreated.begin(); 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)); + for(; anUpdatedIter != myJustUpdated.end(); anUpdatedIter++) { + FeaturePtr aFeature = std::dynamic_pointer_cast(*anUpdatedIter); if (aFeature.get()) { // execute not-previewed feature on "apply" - if (!aFeature->isPreviewNeeded() && (myJustCreated.find(aFeature) != myJustCreated.end() || - myJustUpdated.find(aFeature) != myJustUpdated.end())) { + if (!aFeature->isPreviewNeeded() && myJustUpdated.find(aFeature) != myJustUpdated.end()) { static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); if (aFactory->validate(aFeature)) { executeFeature(aFeature); @@ -138,8 +130,6 @@ void Model_Update::processEvent(const std::shared_ptr& theMessag } } } - myJustCreated.clear(); - myJustUpdated.clear(); myIsParamUpdated = false; } } @@ -149,7 +139,7 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin if (theFinish) { // the hardcode (DBC asked): hide the sketch referenced by extrusion on apply std::set >::iterator aFIter; - for(aFIter = myJustCreated.begin(); aFIter != myJustCreated.end(); aFIter++) + for(aFIter = myJustUpdated.begin(); aFIter != myJustUpdated.end(); aFIter++) { FeaturePtr aF = std::dynamic_pointer_cast(*aFIter); if (aF && aF->data()->isValid() && aF->getKind() == "Extrusion") { @@ -176,9 +166,20 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin myIsAutomatic = true; } - updateInDoc(ModelAPI_Session::get()->moduleDocument()); + // iterate all features in the root document to update each + DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); + Model_Objects* anObjs = std::dynamic_pointer_cast(aRootDoc)->objects(); + if (!anObjs) return; + FeaturePtr aFeatureIter = anObjs->firstFeature(); + std::set aProcessedFeatures; // to avoid processing twice + for (; aFeatureIter.get(); aFeatureIter = anObjs->nextFeature(aFeatureIter)) { + updateFeature(aFeatureIter, aProcessedFeatures); + } if (isAutomaticChanged) myIsAutomatic = false; + // make just updated clear after each processing: it is not needed anymore, update causes + // execute immideately + //myJustUpdated.clear(); // just before myIsExecuted = false because after myJustUpdated will be processed again myIsExecuted = false; // flush to update display @@ -188,44 +189,64 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin } } -void Model_Update::updateInDoc(std::shared_ptr theDoc) +void Model_Update::updateFeature(FeaturePtr theFeature, std::set& theProcessed) { - std::set alreadyProcessed; // features that are processed before others - // all features one by one - Model_Objects* anObjs = std::dynamic_pointer_cast(theDoc)->objects(); - if (!anObjs) return; - FeaturePtr aFeatureIter = anObjs->firstFeature(); - for (; aFeatureIter.get(); aFeatureIter = anObjs->nextFeature(aFeatureIter)) { - if (!aFeatureIter->data()->isValid()) // this may be on close of the document - continue; - if (aFeatureIter && alreadyProcessed.find(aFeatureIter) == alreadyProcessed.end()) { - // update selection and parameters attributes first, before sub-features analysis (sketch plane) - updateArguments(aFeatureIter); - // composite feature must be executed after sub-features execution - CompositeFeaturePtr aComposite = - std::dynamic_pointer_cast(aFeatureIter); - if (aComposite) { - // number of subs can be changed in execution: like fillet - for(int a = 0; a < aComposite->numberOfSubs(); a++) { - FeaturePtr aSub = aComposite->subFeature(a); - updateArguments(aSub); - updateFeature(aSub); - alreadyProcessed.insert(aSub); - } - } + // check all features this feature depended on (recursive call of updateFeature) + static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); - updateFeature(aFeatureIter); - // update the document results recursively - const std::list >& aResults = aFeatureIter->results(); - std::list >::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - ResultPartPtr aPart = std::dynamic_pointer_cast(*aRIter); - if (aPart.get()) { - if (!aPart->isDisabled() && aPart->partDoc().get()) { - updateInDoc(aPart->partDoc()); - } + if (theProcessed.find(theFeature) != theProcessed.end()) + return; + theProcessed.insert(theFeature); + if (theFeature->isDisabled()) + return; + + CompositeFeaturePtr aCompos = std::dynamic_pointer_cast(theFeature); + // If automatice update is not needed and feature attributes were not updated right now, + // do not execute it and do not update arguments. + if (!myIsAutomatic && myJustUpdated.find(theFeature) == myJustUpdated.end() && !aCompos.get()) { + // execute will be performed later, but some features may have not-result + // presentations, so call update for them (like coincidence in the sketcher) + static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); + ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP); + return; + } + + // Update selection and parameters attributes first, before sub-features analysis (sketch plane). + updateArguments(theFeature); + + // composite feature must be executed after sub-features execution + if (aCompos) { + // number of subs can be changed in execution: like fillet + for(int a = 0; a < aCompos->numberOfSubs(); a++) { + FeaturePtr aSub = aCompos->subFeature(a); + updateFeature(aSub, theProcessed); + } + } + // this checking must be after the composite feature sub-elements processing: + // composite feature status may depend on it's subelements + if (theFeature->data()->execState() == ModelAPI_StateInvalidArgument) + return; + + bool aJustUpdated = myJustUpdated.find(theFeature) != myJustUpdated.end(); + + if (myIsAutomatic && theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) + aJustUpdated = true; + + // execute feature if it must be updated + if (theFeature->isPreviewNeeded()) { + if ((myIsAutomatic || aJustUpdated) && + std::dynamic_pointer_cast(theFeature->document())->executeFeatures()) { + ModelAPI_ExecState aState = theFeature->data()->execState(); + if (aFactory->validate(theFeature)) { + executeFeature(theFeature); + } else { + theFeature->eraseResults(); + redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated } - } + } + } else { // preview is not needed => make state Done + if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) { + theFeature->data()->execState(ModelAPI_StateDone); } } } @@ -239,7 +260,10 @@ void Model_Update::redisplayWithResults(FeaturePtr theFeature, const ModelAPI_Ex for (; aRIter != aResults.cend(); aRIter++) { std::shared_ptr aRes = *aRIter; aRes->data()->execState(theState); - myJustUpdated.insert(aRes); + if (theFeature->data()->updateID() > aRes->data()->updateID()) { + myJustUpdated.insert(aRes); + aRes->data()->setUpdateID(theFeature->data()->updateID()); + } ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP); } // to redisplay "presentable" feature (for ex. distance constraint) @@ -267,7 +291,6 @@ void Model_Update::updateArguments(FeaturePtr theFeature) { static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); - bool aJustUpdated = false; ModelAPI_ExecState aState = theFeature->data()->execState(); if (aState == ModelAPI_StateInvalidArgument) // a chance to be corrected aState = ModelAPI_StateMustBeUpdated; @@ -301,8 +324,8 @@ void Model_Update::updateArguments(FeaturePtr theFeature) { ModelAPI_AttributeEvalMessage::send(aPointAttribute, this); } if ((!aPointAttribute->textX().empty() && aPointAttribute->expressionInvalid(0)) || - (!aPointAttribute->textY().empty() && aPointAttribute->expressionInvalid(1)) || - (!aPointAttribute->textZ().empty() && aPointAttribute->expressionInvalid(2))) + (!aPointAttribute->textY().empty() && aPointAttribute->expressionInvalid(1)) || + (!aPointAttribute->textZ().empty() && aPointAttribute->expressionInvalid(2))) aState = ModelAPI_StateInvalidArgument; } } @@ -320,44 +343,46 @@ void Model_Update::updateArguments(FeaturePtr theFeature) { ModelAPI_AttributeEvalMessage::send(aPoint2DAttribute, this); } if ((!aPoint2DAttribute->textX().empty() && aPoint2DAttribute->expressionInvalid(0)) || - (!aPoint2DAttribute->textY().empty() && aPoint2DAttribute->expressionInvalid(1))) + (!aPoint2DAttribute->textY().empty() && aPoint2DAttribute->expressionInvalid(1))) aState = ModelAPI_StateInvalidArgument; } } } //if (aState == ModelAPI_StateDone) {// all referenced objects are ready to be used - //std::cout<<"Execute feature "<getKind()< aRefs = - theFeature->data()->attributes(ModelAPI_AttributeSelection::typeId()); - list::iterator aRefsIter = aRefs.begin(); - for (; aRefsIter != aRefs.end(); aRefsIter++) { - std::shared_ptr aSel = - std::dynamic_pointer_cast(*aRefsIter); - ObjectPtr aContext = aSel->context(); - // update argument onlt if the referenced object is changed - if (aContext.get() && isUpdated(aContext) && !aContext->isDisabled()) { + //std::cout<<"Execute feature "<getKind()< aRefs = + theFeature->data()->attributes(ModelAPI_AttributeSelection::typeId()); + list::iterator aRefsIter = aRefs.begin(); + for (; aRefsIter != aRefs.end(); aRefsIter++) { + std::shared_ptr aSel = + std::dynamic_pointer_cast(*aRefsIter); + ObjectPtr aContext = aSel->context(); + // update argument onlt if the referenced object is changed + if (aContext.get() && !aContext->isDisabled() && + aContext->data()->updateID() > theFeature->data()->updateID()) { if (aState == ModelAPI_StateDone) aState = ModelAPI_StateMustBeUpdated; if (!aSel->update()) { // this must be done on execution since it may be long operation if (!aFactory->isNotObligatory(theFeature->getKind(), theFeature->data()->id(aSel)) && - aFactory->isCase(theFeature, theFeature->data()->id(aSel))) + aFactory->isCase(theFeature, theFeature->data()->id(aSel))) aState = ModelAPI_StateInvalidArgument; } - } } - aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId()); - 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) { - ObjectPtr aContext = aSelAttr->context(); - // update argument onlt if the referenced object is changed - if (aContext.get() && isUpdated(aContext) && !aContext->isDisabled()) { + } + aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId()); + 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) { + ObjectPtr aContext = aSelAttr->context(); + // update argument onlt if the referenced object is changed + if (aContext.get() && !aContext->isDisabled() && + aContext->data()->updateID() > theFeature->data()->updateID()) { if (aState == ModelAPI_StateDone) aState = ModelAPI_StateMustBeUpdated; if (!aSelAttr->update()) { @@ -366,111 +391,34 @@ void Model_Update::updateArguments(FeaturePtr theFeature) { aFactory->isCase(theFeature, theFeature->data()->id(aSel))) aState = ModelAPI_StateInvalidArgument; } - } - } - } - } - //} - if (aJustUpdated && myJustCreated.find(theFeature) == myJustCreated.end()) - myJustUpdated.insert(theFeature); - if (aState != ModelAPI_StateDone) - theFeature->data()->execState(aState); -} - -void Model_Update::updateFeature(FeaturePtr theFeature) -{ - // check all features this feature depended on (recursive call of updateFeature) - static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); - - if (theFeature->data()->execState() == ModelAPI_StateInvalidArgument) - return; - bool aJustUpdated = false; - - if (theFeature) { - if (myIsAutomatic && theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) - aJustUpdated = 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()); - aData->referencesToObjects(aRefs); - std::list > >::iterator aRef = aRefs.begin(); - for(; aRef != aRefs.end(); aRef++) { - std::list::iterator aRefObj = aRef->second.begin(); - for(; aRefObj != aRef->second.end(); aRefObj++) { - // if reference is null, it may mean that this reference is to other document - // the does not supported by RefList: peremeters may be recomputed - if (!aRefObj->get() && theFeature->firstResult().get() && - theFeature->firstResult()->groupName() == ModelAPI_ResultParameter::group()) { - aJustUpdated = true; - } else if (myJustCreated.find(*aRefObj) != myJustCreated.end() || - myJustUpdated.find(*aRefObj) != myJustUpdated.end()) { - aJustUpdated = true; } - aState = stateByReference(*aRefObj, aState); } } - - // some arguments were changed, so, this feature must be updated - if (myJustCreated.find(theFeature) != myJustCreated.end()) { - aJustUpdated = true; - } else { - if (aJustUpdated) { - if (myJustUpdated.find(theFeature) == myJustUpdated.end()) - myJustUpdated.insert(theFeature); - } else { - aJustUpdated = myJustUpdated.find(theFeature) != myJustUpdated.end(); - } - } - //std::cout<<"Update feature "<getKind()<<" must be updated = "<isDisabled()) { // do not execute the disabled feature - // the disabled features must be updated after enabling anyway if their arguments were changed - if (theFeature->data()->execState() == ModelAPI_StateDone && - aState == ModelAPI_StateMustBeUpdated) - theFeature->data()->execState(ModelAPI_StateMustBeUpdated); - } else { - if (theFeature->isPreviewNeeded()) { - if (std::dynamic_pointer_cast(theFeature->document())->executeFeatures() || - !theFeature->isPersistentResult()) { - if (aFactory->validate(theFeature)) { - FeaturePtr aCurrent = theFeature->document()->currentFeature(false); - if (myIsAutomatic || !theFeature->isPersistentResult() /* execute quick, not persistent results */ - || (isUpdated(theFeature) && - (theFeature == aCurrent || - (aCurrent.get() && aCurrent->isMacro())))) // 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 { // 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); - } + } + // 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 > > aRefsObj; + std::shared_ptr aData = std::dynamic_pointer_cast(theFeature->data()); + aData->referencesToObjects(aRefsObj); + std::list > >::iterator aRef = aRefsObj.begin(); + for(; aRef != aRefsObj.end(); aRef++) { + std::list::iterator aRefObj = aRef->second.begin(); + for(; aRefObj != aRef->second.end(); aRefObj++) { + // if reference is null, it may mean that this reference is to other document + // the does not supported by RefList: parameters may be recomputed + if (!aRefObj->get() && theFeature->firstResult().get() && + theFeature->firstResult()->groupName() == ModelAPI_ResultParameter::group()) { + aState = ModelAPI_StateMustBeUpdated; + } else if (myJustUpdated.find(*aRefObj) != myJustUpdated.end() || + (aRefObj->get() && (*aRefObj)->data()->updateID() > theFeature->data()->updateID())) { + aState = ModelAPI_StateMustBeUpdated; } + aState = stateByReference(*aRefObj, aState); } } + + if (aState != ModelAPI_StateDone) + theFeature->data()->execState(aState); } void Model_Update::executeFeature(FeaturePtr theFeature) @@ -480,6 +428,7 @@ void Model_Update::executeFeature(FeaturePtr theFeature) theFeature->data()->execState(ModelAPI_StateDone); try { theFeature->execute(); + myJustUpdated.erase(theFeature); if (theFeature->data()->execState() != ModelAPI_StateDone) { aState = ModelAPI_StateExecFailed; } else { @@ -493,11 +442,6 @@ void Model_Update::executeFeature(FeaturePtr theFeature) if (aState != ModelAPI_StateDone) { theFeature->eraseResults(); } + theFeature->data()->setUpdateID(ModelAPI_Session::get()->transactionID()); redisplayWithResults(theFeature, aState); } - -bool Model_Update::isUpdated(const ObjectPtr& theObj) -{ - return myJustCreated.find(theObj) != myJustCreated.end() || - myJustUpdated.find(theObj) != myJustUpdated.end(); -} diff --git a/src/Model/Model_Update.h b/src/Model/Model_Update.h index c28d30b25..56a16cbd2 100644 --- a/src/Model/Model_Update.h +++ b/src/Model/Model_Update.h @@ -23,9 +23,7 @@ class ModelAPI_Feature; */ class Model_Update : public Events_Listener { - /// created features during this transaction: must be updated all the time - std::set > myJustCreated; - /// updated features during this transaction: must be updated in the end of transaction + /// updated features during this transaction: must be updated immediately std::set > myJustUpdated; /// to know that all next updates are caused by this execution bool myIsExecuted; @@ -42,13 +40,13 @@ class Model_Update : public Events_Listener MODEL_EXPORT virtual void processEvent(const std::shared_ptr& theMessage); protected: - /// updates all features in the document and then - in sub-documents - void updateInDoc(std::shared_ptr theDoc); /// Recoursively checks and updates the feature if needed (calls the execute method) /// Returns true if feature was updated. - void updateFeature(std::shared_ptr theFeature); + void updateFeature(std::shared_ptr theFeature, + std::set >& theProcessed); /// Updates the selection and parametrical arguments before the later feature analysis + /// Returns true if something really was updated void updateArguments(std::shared_ptr theFeature); /// Sends the redisplay events for feature and results, updates the updated status @@ -62,9 +60,6 @@ protected: /// Performs the feature execution /// \returns the status of execution void executeFeature(std::shared_ptr theFeature); - - /// returns true if the object was created or updated - bool isUpdated(const std::shared_ptr& theObj); }; #endif diff --git a/src/ModelAPI/ModelAPI_Data.h b/src/ModelAPI/ModelAPI_Data.h index e57aaec10..0cd4631e6 100644 --- a/src/ModelAPI/ModelAPI_Data.h +++ b/src/ModelAPI/ModelAPI_Data.h @@ -147,6 +147,13 @@ class MODELAPI_EXPORT ModelAPI_Data /// Returns the invalid data pointer (to avoid working with NULL shared ptrs in swig) virtual std::shared_ptr invalidPtr() = 0; + /// Identifier of the transaction when object (feature or result) was updated last time. + virtual int updateID() = 0; + + /// Identifier of the transaction when object (feature or result) was updated last time. + /// This method is called by the updater. + virtual void setUpdateID(const int theID) = 0; + protected: /// Objects are created for features automatically ModelAPI_Data(); diff --git a/src/ModelAPI/ModelAPI_Feature.cpp b/src/ModelAPI/ModelAPI_Feature.cpp index 3c78c82d0..e7f96587c 100644 --- a/src/ModelAPI/ModelAPI_Feature.cpp +++ b/src/ModelAPI/ModelAPI_Feature.cpp @@ -17,7 +17,7 @@ const std::list >& ModelAPI_Feature::results() return myResults; } -std::shared_ptr ModelAPI_Feature::firstResult() +std::shared_ptr ModelAPI_Feature::firstResult() const { return myResults.empty() ? std::shared_ptr() : *(myResults.begin()); } diff --git a/src/ModelAPI/ModelAPI_Feature.h b/src/ModelAPI/ModelAPI_Feature.h index 8631c3e08..85ce31df2 100644 --- a/src/ModelAPI/ModelAPI_Feature.h +++ b/src/ModelAPI/ModelAPI_Feature.h @@ -72,7 +72,7 @@ class ModelAPI_Feature : public ModelAPI_Object /// returns the current results of the feature MODELAPI_EXPORT const std::list >& results(); /// returns the first result in the list or NULL reference - MODELAPI_EXPORT std::shared_ptr firstResult(); + MODELAPI_EXPORT std::shared_ptr firstResult() const; /// returns the last result in the list or NULL reference MODELAPI_EXPORT std::shared_ptr lastResult(); /// sets the alone result diff --git a/src/ModelAPI/ModelAPI_ResultPart.h b/src/ModelAPI/ModelAPI_ResultPart.h index fec934216..74d86953f 100644 --- a/src/ModelAPI/ModelAPI_ResultPart.h +++ b/src/ModelAPI/ModelAPI_ResultPart.h @@ -58,6 +58,8 @@ class ModelAPI_ResultPart : public ModelAPI_Result virtual std::string nameInPart(const std::shared_ptr& theShape) = 0; /// Returns the shape by the name in the part virtual std::shared_ptr shapeInPart(const std::string& theName) = 0; + /// Updates the shape-result of the part (called on Part feature execution) + virtual void updateShape() = 0; }; //! Pointer on feature object diff --git a/src/ModelAPI/ModelAPI_Session.h b/src/ModelAPI/ModelAPI_Session.h index 47f607181..33aa5a67d 100644 --- a/src/ModelAPI/ModelAPI_Session.h +++ b/src/ModelAPI/ModelAPI_Session.h @@ -108,6 +108,9 @@ class MODELAPI_EXPORT ModelAPI_Session { } + /// Returns the global identifier of the current transaction (needed for the update algo) + virtual int transactionID() = 0; + protected: /// Sets the session interface implementation (once per application launch) static void setSession(std::shared_ptr theManager); diff --git a/src/PartSetPlugin/PartSetPlugin_Part.cpp b/src/PartSetPlugin/PartSetPlugin_Part.cpp index fda4e53a1..04b6ddd6e 100644 --- a/src/PartSetPlugin/PartSetPlugin_Part.cpp +++ b/src/PartSetPlugin/PartSetPlugin_Part.cpp @@ -39,6 +39,8 @@ void PartSetPlugin_Part::execute() aResult->activate(); } + } else { // execute is called for result update anyway + aResult->updateShape(); } } @@ -47,3 +49,70 @@ const std::string& PartSetPlugin_Part::documentToAdd() // part must be added only to the module document return ModelAPI_Session::get()->moduleDocument()->kind(); } + +std::shared_ptr PartSetPlugin_Part::addFeature(std::string theID) +{ + ResultPartPtr aResult = std::dynamic_pointer_cast(firstResult()); + if (aResult.get()) { + DocumentPtr aDoc = aResult->partDoc(); + if (aDoc.get()) + return aDoc->addFeature(theID); + } + return FeaturePtr(); +} + +int PartSetPlugin_Part::numberOfSubs() const +{ + ResultPartPtr aResult = std::dynamic_pointer_cast(firstResult()); + if (aResult.get()) { + DocumentPtr aDoc = aResult->partDoc(); + if (aDoc.get()) + return aDoc->size(ModelAPI_Feature::group()); + } + return 0; +} + +std::shared_ptr PartSetPlugin_Part::subFeature(const int theIndex) const +{ + ResultPartPtr aResult = std::dynamic_pointer_cast(firstResult()); + if (aResult.get()) { + DocumentPtr aDoc = aResult->partDoc(); + if (aDoc.get()) { + return std::dynamic_pointer_cast( + aDoc->object(ModelAPI_Feature::group(), theIndex)); + } + } + return FeaturePtr(); +} + +int PartSetPlugin_Part::subFeatureId(const int theIndex) const +{ + ResultPartPtr aResult = std::dynamic_pointer_cast(firstResult()); + if (aResult.get()) { + DocumentPtr aDoc = aResult->partDoc(); + if (aDoc.get()) { + return aDoc->object(ModelAPI_Feature::group(), theIndex)->data()->featureId(); + } + } + return 0; // none +} + +bool PartSetPlugin_Part::isSub(ObjectPtr theObject) const +{ + ResultPartPtr aResult = std::dynamic_pointer_cast(firstResult()); + if (aResult.get()) { + DocumentPtr aDoc = aResult->partDoc(); + return document() == aDoc; + } + return false; +} + +void PartSetPlugin_Part::removeFeature(std::shared_ptr theFeature) +{ + ResultPartPtr aResult = std::dynamic_pointer_cast(firstResult()); + if (aResult.get()) { + DocumentPtr aDoc = aResult->partDoc(); + if (aDoc.get()) + aDoc->removeFeature(theFeature); + } +} diff --git a/src/PartSetPlugin/PartSetPlugin_Part.h b/src/PartSetPlugin/PartSetPlugin_Part.h index d679d9ccf..a07be67e1 100644 --- a/src/PartSetPlugin/PartSetPlugin_Part.h +++ b/src/PartSetPlugin/PartSetPlugin_Part.h @@ -8,13 +8,14 @@ #define PartSetPlugin_Part_H_ #include "PartSetPlugin.h" -#include +#include /**\class PartSetPlugin_Part * \ingroup Plugins * \brief Feature for creation of the new part in PartSet. + * All sub-features are sub-elements of composite feature. */ -class PartSetPlugin_Part : public ModelAPI_Feature +class PartSetPlugin_Part : public ModelAPI_CompositeFeature { public: /// Part kind @@ -46,6 +47,27 @@ class PartSetPlugin_Part : public ModelAPI_Feature /// Part must be added only to PartSet PARTSETPLUGIN_EXPORT virtual const std::string& documentToAdd(); + // composite feature methods + + /// Adds feature to its document + virtual std::shared_ptr addFeature(std::string theID); + + /// Returns the number of sub-features of the document + virtual int numberOfSubs() const; + + /// Returns the sub-feature by zero-base index + virtual std::shared_ptr subFeature(const int theIndex) const; + + /// Returns the sub-feature unique identifier in this composite feature by zero-base index + virtual int subFeatureId(const int theIndex) const; + + /// Returns true if feature or reuslt belong to this composite feature as subs + virtual bool isSub(ObjectPtr theObject) const; + + /// This method to inform that sub-feature is removed and must be removed from the internal data + /// structures of the owner (the remove from the document will be done outside just after) + virtual void removeFeature(std::shared_ptr theFeature); + /// Use plugin manager for features creation PartSetPlugin_Part(); }; -- 2.39.2