X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Update.cpp;h=91751aa772becc664787e5ce6007dfe6f0c17507;hb=7ba8e2b57ff8965ae644b538c167b7b301e6e41b;hp=af5407cafedba7467c26761d5fc88277ca062f14;hpb=a0247c36615e233b68bc5ed98c1b87a999a4a51e;p=modules%2Fshaper.git diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index af5407caf..91751aa77 100644 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -1,59 +1,199 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + // File: Model_Update.cxx // Created: 25 Jun 2014 // Author: Mikhail PONIKAROV #include +#include +#include #include #include #include #include #include #include +#include +#include +#include #include +#include +#include +#include #include #include +#include +#include using namespace std; -Model_Update MY_INSTANCE; /// the only one instance initialized on load of the library +Model_Update MY_UPDATER_INSTANCE; /// the only one instance initialized on load of the library Model_Update::Model_Update() { - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + Events_Loop* aLoop = Events_Loop::loop(); + static const Events_ID kChangedEvent = aLoop->eventByName("PreferenceChanged"); + aLoop->registerListener(this, kChangedEvent); + static const Events_ID kRebuildEvent = aLoop->eventByName("Rebuild"); + aLoop->registerListener(this, kRebuildEvent); + static const Events_ID kCreatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED); + aLoop->registerListener(this, kCreatedEvent); + static const Events_ID kUpdatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED); + aLoop->registerListener(this, kUpdatedEvent); + static const Events_ID kMovedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); + aLoop->registerListener(this, kMovedEvent); + static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation"); + aLoop->registerListener(this, kOpFinishEvent); + static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation"); + aLoop->registerListener(this, kOpAbortEvent); + static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation"); + aLoop->registerListener(this, kOpStartEvent); + + Config_PropManager::registerProp("Model update", "automatic_rebuild", "Rebuild immediately", + Config_Prop::Bool, "false"); + isAutomatic = Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true"; } -void Model_Update::processEvent(const Events_Message* theMessage) +void Model_Update::processEvent(const std::shared_ptr& theMessage) { - if (isExecuted) return; // nothing to do: it is executed now - Events_LongOp::start(this); + static Events_Loop* aLoop = Events_Loop::loop(); + static const Events_ID kChangedEvent = aLoop->eventByName("PreferenceChanged"); + static const Events_ID kRebuildEvent = aLoop->eventByName("Rebuild"); + static const Events_ID kCreatedEvent = aLoop->eventByName(EVENT_OBJECT_CREATED); + static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED); + static const Events_ID kMovedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); + static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation"); + static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation"); + static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation"); + bool isAutomaticChanged = false; + if (theMessage->eventID() == kChangedEvent) { // automatic and manual rebuild flag is changed + isAutomatic = + Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true"; + } else if (theMessage->eventID() == kRebuildEvent) { // the rebuild command + if (isAutomatic == false) { + isAutomaticChanged = true; + isAutomatic = true; + } + } else if (theMessage->eventID() == kCreatedEvent || theMessage->eventID() == kUpdatedEvent || + theMessage->eventID() == kMovedEvent) { + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + const std::set& anObjs = aMsg->objects(); + std::set::const_iterator anObjIter = anObjs.cbegin(); + for(; anObjIter != anObjs.cend(); anObjIter++) { + myJustCreatedOrUpdated.insert(*anObjIter); + // TODO(mpv): check the next line. Came into dev 0.6.1 from BR_PYTHON_PLUGIN + // (*anObjIter)->data()->mustBeUpdated(true); // object must be updated because it was changed + } + if (theMessage->eventID() == kMovedEvent) + return; // this event is for solver update, not here + } else if (theMessage->eventID() == kOpStartEvent) { + myJustCreatedOrUpdated.clear(); + return; // we don't need the update only on operation start (caused problems in PartSet_Listener::processEvent) + } else if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent) { + if (isAutomatic == false) { // Apply button now works as "Rebuild" + isAutomaticChanged = true; + isAutomatic = true; + } + // the hardcode (DBC asked): hide the sketch referenced by extrusion on apply + if (theMessage->eventID() == kOpFinishEvent) { + std::set >::iterator aFIter; + for(aFIter = myJustCreatedOrUpdated.begin(); aFIter != myJustCreatedOrUpdated.end(); aFIter++) + { + FeaturePtr aF = std::dynamic_pointer_cast(*aFIter); + if (aF && aF->getKind() == "Extrusion") { + if (aF->selection("extrusion_face")) { + ResultPtr aSketchRes = aF->selection("extrusion_face")->context(); + if (aSketchRes) { + static Events_ID HIDE_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TOHIDE); + ModelAPI_EventCreator::get()->sendUpdated(aSketchRes, HIDE_DISP); + } + } + } + } + } + } + + if (isExecuted) + return; // nothing to do: it is executed now + + //Events_LongOp::start(this); isExecuted = true; - const ModelAPI_ObjectUpdatedMessage* aMsg = - dynamic_cast(theMessage); - myInitial = aMsg->objects(); - // collect all documents involved into the update - set > aDocs; - set >::iterator aFIter = myInitial.begin(); - for(; aFIter != myInitial.end(); aFIter++) { - aDocs.insert((*aFIter)->document()); + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + if (aMsg) myInitial = aMsg->objects(); + else { + myInitial.clear(); + } + // iterate all documents: features in Root first, then - subs + updateInDoc(ModelAPI_Session::get()->moduleDocument()); + + myUpdated.clear(); + // flush to update display + static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); + aLoop->flush(EVENT_DISP); + //Events_LongOp::end(this); + if (isAutomaticChanged) isAutomatic = false; + + if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent) { + myJustCreatedOrUpdated.clear(); + } + + isExecuted = false; +} + +void Model_Update::updateInDoc(std::shared_ptr theDoc) +{ + // all features one by one + int aNbFeatures = theDoc->size(ModelAPI_Feature::group(), true); + for (int aFIndex = 0; aFIndex < aNbFeatures; aFIndex++) { + FeaturePtr aFeature = std::dynamic_pointer_cast( + theDoc->object(ModelAPI_Feature::group(), aFIndex, true)); + if (aFeature) + updateFeature(aFeature); } - // iterate all features of features-documents to update them (including hidden) - set >::iterator aDIter = aDocs.begin(); - for(; aDIter != aDocs.end(); aDIter++) { - int aNbFeatures = (*aDIter)->size(ModelAPI_Feature::group(), true); - for(int aFIndex = 0; aFIndex < aNbFeatures; aFIndex++) { - FeaturePtr aFeature = boost::dynamic_pointer_cast - ((*aDIter)->object(ModelAPI_Feature::group(), aFIndex, true)); - if (aFeature) - updateFeature(aFeature); + // all sub-documents one by one + std::shared_ptr aDoc = std::dynamic_pointer_cast(theDoc); + if (aDoc) { + const std::set& aSubs = aDoc->subDocuments(); + for(std::set::iterator aSub = aSubs.begin(); aSub != aSubs.end(); aSub++) { + DocumentPtr aSubDoc = theDoc->subDocument(*aSub); + if (aSubDoc) { + updateInDoc(aSubDoc); + } } } - myUpdated.clear(); - // flush +} + +void Model_Update::redisplayWithResults(FeaturePtr theFeature, const ModelAPI_ExecState theState) +{ + // make updated and redisplay all results static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); - Events_Loop::loop()->flush(EVENT_DISP); - Events_LongOp::end(this); - isExecuted = false; + 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(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()->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) @@ -62,48 +202,141 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) if (myUpdated.find(theFeature) != myUpdated.end()) return myUpdated[theFeature]; // check all features this feature depended on (recursive call of updateFeature) + ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); bool aMustbeUpdated = myInitial.find(theFeature) != myInitial.end(); - if (theFeature) { // only real feature contains references to other objects - // references - list > aRefs = - theFeature->data()->attributes(ModelAPI_AttributeReference::type()); - list >::iterator aRefsIter = aRefs.begin(); - for(; aRefsIter != aRefs.end(); aRefsIter++) { - boost::shared_ptr aSub = - boost::dynamic_pointer_cast(*aRefsIter)->value(); - if (updateObject(aSub)) { - aMustbeUpdated = true; + if (theFeature) { // only real feature contains references to other objects + if (theFeature->data()->execState() != ModelAPI_StateDone) + aMustbeUpdated = true; + + // composite feature must be executed after sub-features execution + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(theFeature); + if (aComposite) { + int aSubsNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubsNum; a++) { + if (updateFeature(aComposite->subFeature(a))) + aMustbeUpdated = true; } } - // lists of references - aRefs = theFeature->data()->attributes(ModelAPI_AttributeRefList::type()); - for(aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) { - list aListRef = - boost::dynamic_pointer_cast(*aRefsIter)->list(); - list::iterator aListIter = aListRef.begin(); - for(; aListIter != aListRef.end(); aListIter++) { - boost::shared_ptr aSub = *aListIter; - if (updateObject(aSub)) { + 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 (updateObject(*aRefObj)) { aMustbeUpdated = true; } + aState = stateByReference(*aRefObj, aState); } } + + //std::cout<<"Update feature "<getKind()<<" must be updated = "<execute(); - // 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++) { - boost::shared_ptr aRes = *aRIter; - myUpdated[aRes] = true; - ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP); + 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 (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; + } + } + 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; + } + } + } + } + // 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 + 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, aState); + } 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 { // 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(); - std::list >::const_iterator aRIter = aResults.begin(); - for(; aRIter != aResults.cend(); aRIter++) { + } 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(); + std::list >::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { if (myInitial.find(*aRIter) != myInitial.end()) { aMustbeUpdated = true; break; @@ -115,26 +348,31 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) return aMustbeUpdated; } -bool Model_Update::updateObject(boost::shared_ptr theObject) +bool Model_Update::updateObject(std::shared_ptr theObject, const bool theCyclic) { - if (!theObject) - return false; - FeaturePtr aFeature = boost::dynamic_pointer_cast(theObject); - if (aFeature) { // for feature just call update Feature - return updateFeature(aFeature); - } - // check general object, possible just a result if (myUpdated.find(theObject) != myUpdated.end()) - return myUpdated[theObject]; // already processed - // check the feature of this object must be executed - ResultPtr aResult = boost::dynamic_pointer_cast(theObject); - if (aResult) { - FeaturePtr aResFeature = aResult->document()->feature(aResult); - if (aResFeature) { - return updateFeature(aResFeature); + return myUpdated[theObject]; // already processed + + /* + if (theCyclic) { // algorithm for update of all features by dependencies tree + if (!theObject) + return false; + FeaturePtr aFeature = std::dynamic_pointer_cast(theObject); + if (aFeature) { // for feature just call update Feature + return updateFeature(aFeature); + } + // check general object, possible just a result + if (myUpdated.find(theObject) != myUpdated.end()) + return myUpdated[theObject]; // already processed + // check the feature of this object must be executed + ResultPtr aResult = std::dynamic_pointer_cast(theObject); + if (aResult) { + FeaturePtr aResFeature = aResult->document()->feature(aResult); + if (aResFeature) { + return updateFeature(aResFeature); + } } } - if (myInitial.find(theObject) != myInitial.end()) - return true; - return false; // nothing is known + */ + return myInitial.find(theObject) != myInitial.end(); }