+ static Events_Loop* aLoop = Events_Loop::loop();
+ static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+ static const Events_ID kCreatedEvent = aLoop->eventByName(EVENT_OBJECT_CREATED);
+ static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED);
+ static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation");
+ static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation");
+ static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation");
+ static const Events_ID kStabilityEvent = aLoop->eventByName(EVENT_STABILITY_CHANGED);
+ static const Events_ID kPreviewBlockedEvent = aLoop->eventByName(EVENT_PREVIEW_BLOCKED);
+ static const Events_ID kPreviewRequestedEvent = aLoop->eventByName(EVENT_PREVIEW_REQUESTED);
+ static const Events_ID kReorderEvent = aLoop->eventByName(EVENT_ORDER_UPDATED);
+ static const Events_ID kRedisplayEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ static const Events_ID kUpdatedSel = aLoop->eventByName(EVENT_UPDATE_SELECTION);
+
+#ifdef DEB_UPDATE
+ std::cout<<"****** Event "<<theMessage->eventID().eventText()<<std::endl;
+#endif
+ // check the automatic update flag on any event
+ bool aNewAutomaticState = ModelAPI_Session::get()->isAutoUpdateBlocked();
+ if (myUpdateBlocked != aNewAutomaticState) {
+ myUpdateBlocked = aNewAutomaticState;
+ if (!myUpdateBlocked) { // process all modified features, even if preview is blocked
+ bool aPreviewBlockedState = myIsPreviewBlocked; // to update the selected arguments
+ myIsPreviewBlocked = false;
+ // iterate everything and add features in state "MustBeUpdated" into modified
+ std::list<std::shared_ptr<ModelAPI_Document> > allDocs =
+ ModelAPI_Session::get()->allOpenedDocuments();
+ std::list<std::shared_ptr<ModelAPI_Document> >::iterator aDoc = allDocs.begin();
+ for(; aDoc != allDocs.end(); aDoc++) {
+ std::list<std::shared_ptr<ModelAPI_Feature> > allFeats = (*aDoc)->allFeatures();
+ std::list<std::shared_ptr<ModelAPI_Feature> >::iterator aFeat = allFeats.begin();
+ for(; aFeat != allFeats.end(); aFeat++) {
+ if ((*aFeat)->data()->isValid() &&
+ (*aFeat)->data()->execState() == ModelAPI_StateMustBeUpdated) {
+ addModified(*aFeat, FeaturePtr());
+ }
+ }
+ }
+ processFeatures();
+ myIsPreviewBlocked = myIsPreviewBlocked;
+ }
+ }
+
+ if (theMessage->eventID() == kStabilityEvent) {
+ updateStability(theMessage->sender());
+ return;
+ }
+ if (theMessage->eventID() == kPreviewBlockedEvent) {
+ myIsPreviewBlocked = true;
+ return;
+ }
+ if (theMessage->eventID() == kPreviewRequestedEvent) {
+ if (myIsPreviewBlocked) {
+ bool anUpdateState = myUpdateBlocked;
+ myUpdateBlocked = false;
+ myIsPreviewBlocked = false;
+ processFeatures();
+ myIsPreviewBlocked = true;
+ myUpdateBlocked = anUpdateState;
+ }
+ return;
+ }
+ if (theMessage->eventID() == kUpdatedSel) {
+ std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
+ std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+ updateSelection(aMsg->objects());
+ }
+ // creation is added to "update" to avoid recomputation twice:
+ // on create and immediately after on update
+ if (theMessage->eventID() == kCreatedEvent) {
+ std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
+ std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+ const std::set<ObjectPtr>& anObjs = aMsg->objects();
+ std::set<ObjectPtr>::const_iterator anObjIter = anObjs.cbegin();
+ std::list<ObjectPtr> aFeatures, aResults;
+ for(; anObjIter != anObjs.cend(); anObjIter++) {
+ if (std::dynamic_pointer_cast<Model_Document>((*anObjIter)->document())->executeFeatures()) {
+ if ((*anObjIter)->groupName() == ModelAPI_Feature::group()) {
+ // results creation means enabling, not update
+ aFeatures.push_back(*anObjIter);
+ } else {
+ aResults.push_back(*anObjIter);
+ }
+ }
+ }
+ ModelAPI_EventCreator::get()->sendUpdated(aFeatures, kUpdatedEvent);
+ ModelAPI_EventCreator::get()->sendUpdated(aResults, kRedisplayEvent);
+ return;
+ }
+ if (theMessage->eventID() == kUpdatedEvent) {
+ std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aMsg =
+ std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+ const std::set<ObjectPtr>& anObjs = aMsg->objects();
+ std::set<ObjectPtr>::const_iterator anObjIter = anObjs.cbegin();
+ bool aSomeModified = false; // check that features not changed: only redisplay is needed
+ for(; anObjIter != anObjs.cend(); anObjIter++) {
+ if (!(*anObjIter)->data()->isValid())
+ continue;
+#ifdef DEB_UPDATE
+ std::cout<<">>> in event updated "<<(*anObjIter)->groupName()<<
+ " "<<(*anObjIter)->data()->name()<<std::endl;
+#endif
+ if ((*anObjIter)->groupName() == ModelAPI_ResultParameter::group()) {
+ myIsParamUpdated = true;
+ }
+ // on undo/redo, abort do not update persistent features
+ FeaturePtr anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
+ if (anUpdated.get()) {
+ if (addModified(anUpdated, FeaturePtr()))
+ aSomeModified = true;
+ if (myUpdateBlocked) { // execute this feature anyway to show the current result
+ /*if (!anUpdated->isStable() && anUpdated->results().size() && (
+ anUpdated->firstResult()->groupName() == ModelAPI_ResultBody::group() ||
+ anUpdated->firstResult()->groupName() == ModelAPI_ResultPart::group())) {
+ if (aFactory->validate(anUpdated)) {
+ executeFeature(anUpdated);
+ redisplayWithResults(anUpdated, ModelAPI_StateNothing, false);
+ static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ aLoop->flush(EVENT_DISP);
+ }
+ }*/
+ }
+ } else {
+ // process the updated result as update of features that refers to this result
+ const std::set<std::shared_ptr<ModelAPI_Attribute> >&
+ aRefs = (*anObjIter)->data()->refsToMe();
+ std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aRefIter = aRefs.cbegin();
+ FeaturePtr aReason;
+ ResultPtr aReasonResult = std::dynamic_pointer_cast<ModelAPI_Result>(*anObjIter);
+ if (aReasonResult.get())
+ aReason = (*anObjIter)->document()->feature(aReasonResult);
+ for(; aRefIter != aRefs.cend(); aRefIter++) {
+ if (!(*aRefIter)->owner()->data()->isValid())
+ continue;
+ FeaturePtr anUpdated = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIter)->owner());
+ if (anUpdated.get()) {
+ if (addModified(anUpdated, aReason))
+ aSomeModified = true;
+ }
+ }
+ }
+ }
+ // this event is for solver update, not here, do not react immediately
+ if (aSomeModified) {
+ processFeatures();
+ }
+ } else if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent ||
+ theMessage->eventID() == kOpStartEvent) {
+ myIsPreviewBlocked = false;
+
+ if (theMessage->eventID() == kOpFinishEvent) {// if update is blocked, skip
+ myIsFinish = true;
+ // add features that wait for finish as modified
+ std::map<std::shared_ptr<ModelAPI_Feature>, std::set<std::shared_ptr<ModelAPI_Feature> > >::
+ iterator aFeature = myProcessOnFinish.begin();
+ for(; aFeature != myProcessOnFinish.end(); aFeature++) {
+ if (aFeature->first->data()->isValid()) {// there may be already removed while wait
+ if (aFeature->second.empty()) {
+ addModified(aFeature->first, FeaturePtr());
+ continue;
+ }
+ std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aReasons;
+ for(aReasons = aFeature->second.begin(); aReasons != aFeature->second.end(); aReasons++){
+ addModified(aFeature->first, *aReasons);
+ }
+ }
+ }
+ myIsFinish = false;
+ }
+ // processed features must be only on finish, so clear anyway (to avoid re-import on load)
+ myProcessOnFinish.clear();
+
+ // #2156: current must be sketch, left after the macro execution
+ DocumentPtr anActiveDoc = ModelAPI_Session::get()->activeDocument();
+ FeaturePtr aCurrent;
+ if (anActiveDoc.get())
+ aCurrent = anActiveDoc->currentFeature(false);
+
+ if (!(theMessage->eventID() == kOpStartEvent)) {
+ processFeatures(false);
+ }
+
+ if (anActiveDoc.get() && aCurrent.get() && aCurrent->data()->isValid()) {
+ if (anActiveDoc->currentFeature(false) != aCurrent &&
+ ModelAPI_Tools::compositeOwner(anActiveDoc->currentFeature(false)) == aCurrent)
+ anActiveDoc->setCurrentFeature(aCurrent, false); // #2156 make the current feature back
+ }
+
+ // remove all macros before clearing all created
+ std::set<FeaturePtr>::iterator anUpdatedIter = myWaitForFinish.begin();
+ while(anUpdatedIter != myWaitForFinish.end()) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anUpdatedIter);
+ if (aFeature.get()) {
+ // remove macro on finish
+ if (aFeature->isMacro()) {
+ aFeature->document()->removeFeature(aFeature);
+ myWaitForFinish.erase(aFeature);
+ }
+ // to avoid the map update problems on "remove"
+ if (myWaitForFinish.find(aFeature) == myWaitForFinish.end()) {
+ anUpdatedIter = myWaitForFinish.begin();
+ } else {
+ anUpdatedIter++;
+ }
+ } else {
+ anUpdatedIter++;
+ }
+ }
+ // the redisplay signal should be flushed in order
+ // to erase the feature presentation in the viewer
+ // if should be done after removeFeature() of document,
+ // by this reason, upper processFeatures() do not perform this flush
+ Events_Loop::loop()->flush(kRedisplayEvent);
+
+ // in the end of transaction everything is updated, so clear the old objects
+ //myIsParamUpdated = false; // to avoid problems in sprocket.py parameter update
+ myWaitForFinish.clear();
+ } else if (theMessage->eventID() == kReorderEvent) {
+ std::shared_ptr<ModelAPI_OrderUpdatedMessage> aMsg =
+ std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
+ if (aMsg->reordered().get())
+ addModified(aMsg->reordered(), aMsg->reordered()); // to update all attributes
+ }