From: mpv Date: Thu, 6 Nov 2014 07:25:00 +0000 (+0300) Subject: Debug of the parametric model updates X-Git-Tag: V_0.5~36 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=93152527420704cf35e22b11d1de198e1710bd90;p=modules%2Fshaper.git Debug of the parametric model updates --- diff --git a/src/Events/Events_Loop.cpp b/src/Events/Events_Loop.cpp index b13472aee..eadae7283 100644 --- a/src/Events/Events_Loop.cpp +++ b/src/Events/Events_Loop.cpp @@ -43,7 +43,7 @@ void Events_Loop::send(const boost::shared_ptr& theMessage, bool myImmediateListeners[theMessage->eventID().eventText()]->processEvent(theMessage); } // if it is grouped message, just accumulate it - if (isGroup) { + if (isGroup && myFlushed.find(theMessage->eventID().myID) == myFlushed.end()) { boost::shared_ptr aGroup = boost::dynamic_pointer_cast(theMessage); if (aGroup) { @@ -118,9 +118,11 @@ void Events_Loop::flush(const Events_ID& theID) std::map>::iterator aMyGroup = myGroups.find(theID.eventText()); if (aMyGroup != myGroups.end()) { // really sends + myFlushed.insert(theID.myID); boost::shared_ptr aGroup = aMyGroup->second; myGroups.erase(aMyGroup); send(aGroup, false); + myFlushed.erase(myFlushed.find(theID.myID)); } } @@ -128,3 +130,20 @@ void Events_Loop::activateFlushes(const bool theActivate) { myFlushActive = theActivate; } + +void Events_Loop::clear(const Events_ID& theID) +{ + std::map>::iterator aMyGroup = + myGroups.find(theID.eventText()); + if (aMyGroup != myGroups.end()) { // really sends + myGroups.erase(aMyGroup); + } +} + +void Events_Loop::autoFlush(const Events_ID& theID, const bool theAuto) +{ + if (theAuto) + myFlushed.insert(theID.myID); + else + myFlushed.erase(myFlushed.find(theID.myID)); +} diff --git a/src/Events/Events_Loop.h b/src/Events/Events_Loop.h index b02c978c8..b8a628ff7 100644 --- a/src/Events/Events_Loop.h +++ b/src/Events/Events_Loop.h @@ -9,6 +9,7 @@ #include #include +#include #include class Events_MessageGroup; @@ -34,6 +35,9 @@ class Events_Loop /// map from event ID to groupped messages (accumulated on flush) std::map > myGroups; + ///< set of messages that are flushed right now, so they are not grouped + std::set myFlushed; + /// to process flushes or not bool myFlushActive; @@ -62,6 +66,12 @@ class Events_Loop //! Allows to disable flushes: needed in synchronization of document mechanism //! (to synchronize all and only then flush create, update, etc in correct order) EVENTS_EXPORT void activateFlushes(const bool theActivate); + + //! Clears all collected messages + EVENTS_EXPORT void clear(const Events_ID& theID); + + //! Enables flush without grouping for the given message + EVENTS_EXPORT void autoFlush(const Events_ID& theID, const bool theAuto = true); }; #endif diff --git a/src/GeomData/GeomData_Dir.cpp b/src/GeomData/GeomData_Dir.cpp index b7c2b1c30..ddf20ebbd 100644 --- a/src/GeomData/GeomData_Dir.cpp +++ b/src/GeomData/GeomData_Dir.cpp @@ -24,7 +24,6 @@ void GeomData_Dir::setValue(const double theX, const double theY, const double t void GeomData_Dir::setValue(const boost::shared_ptr& theDir) { setValue(theDir->x(), theDir->y(), theDir->z()); - owner()->data()->sendAttributeUpdated(this); } double GeomData_Dir::x() const diff --git a/src/GeomData/GeomData_Point.cpp b/src/GeomData/GeomData_Point.cpp index 023b12d96..61c92e12b 100644 --- a/src/GeomData/GeomData_Point.cpp +++ b/src/GeomData/GeomData_Point.cpp @@ -23,7 +23,6 @@ void GeomData_Point::setValue(const double theX, const double theY, const double void GeomData_Point::setValue(const boost::shared_ptr& thePoint) { setValue(thePoint->x(), thePoint->y(), thePoint->z()); - owner()->data()->sendAttributeUpdated(this); } double GeomData_Point::x() const diff --git a/src/GeomData/GeomData_Point2D.cpp b/src/GeomData/GeomData_Point2D.cpp index 08913436c..924f80f8c 100644 --- a/src/GeomData/GeomData_Point2D.cpp +++ b/src/GeomData/GeomData_Point2D.cpp @@ -21,7 +21,6 @@ void GeomData_Point2D::setValue(const double theX, const double theY) void GeomData_Point2D::setValue(const boost::shared_ptr& thePoint) { setValue(thePoint->x(), thePoint->y()); - owner()->data()->sendAttributeUpdated(this); } double GeomData_Point2D::x() const diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 59cb68ddb..4ad70e847 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -257,11 +257,6 @@ bool Model_Document::compactNested() void Model_Document::finishOperation() { - // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside - std::set::iterator aSubIter = mySubs.begin(); - for (; aSubIter != mySubs.end(); aSubIter++) - subDoc(*aSubIter)->finishOperation(); - // just to be sure that everybody knows that changes were performed if (!myDoc->HasOpenCommand() && myNestedNum != -1) boost::static_pointer_cast(Model_Session::get()) @@ -273,10 +268,28 @@ void Model_Document::finishOperation() aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TOHIDE)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + // this must be here just after everything is finished but before real transaction stop + // to avoid messages about modifications outside of the transaction + // and to rebuild everything after all updates and creates + if (Model_Session::get()->moduleDocument().get() == this) { // once for root document + Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + static boost::shared_ptr aFinishMsg + (new Events_Message(Events_Loop::eventByName("FinishOperation"))); + Events_Loop::loop()->send(aFinishMsg); + Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), false); + } + // to avoid "updated" message appearance by updater + //aLoop->clear(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + if (!myDoc->HasOpenCommand() && myNestedNum != -1) boost::static_pointer_cast(Model_Session::get()) ->setCheckTransactions(true); // for nested transaction commit + // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->finishOperation(); + if (myNestedNum != -1) // this nested transaction is owervritten myNestedNum++; if (!myDoc->HasOpenCommand()) { diff --git a/src/Model/Model_Events.cpp b/src/Model/Model_Events.cpp index 421c493e2..850b68d5d 100644 --- a/src/Model/Model_Events.cpp +++ b/src/Model/Model_Events.cpp @@ -35,8 +35,9 @@ Model_ObjectUpdatedMessage::Model_ObjectUpdatedMessage(const ObjectPtr& theObjec const Events_ID& theEvent) : ModelAPI_ObjectUpdatedMessage(theEvent, 0) { - if (theObject) + if (theObject) { myObjects.insert(theObject); + } } const std::set& Model_ObjectUpdatedMessage::objects() const diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index 37b020eee..13b8a9a50 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -41,14 +41,14 @@ bool Model_Session::save(const char* theFileName, std::list& theRes void Model_Session::startOperation() { ROOT_DOC->startOperation(); + static boost::shared_ptr aStartedMsg + (new Events_Message(Events_Loop::eventByName("StartOperation"))); + Events_Loop::loop()->send(aStartedMsg); } void Model_Session::finishOperation() { ROOT_DOC->finishOperation(); - static boost::shared_ptr aFinishMsg - (new Events_Message(Events_Loop::eventByName("FinishOperation"))); - Events_Loop::loop()->send(aFinishMsg); } void Model_Session::abortOperation() diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index 80f44ccf4..7209c8aef 100644 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -42,6 +42,8 @@ Model_Update::Model_Update() 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 automatically", Config_Prop::Bool, "false"); @@ -57,6 +59,7 @@ void Model_Update::processEvent(const boost::shared_ptr& theMess 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"); bool isAutomaticChanged = false; if (theMessage->eventID() == kChangedEvent) { // automatic and manual rebuild flag is changed isAutomatic = @@ -69,16 +72,19 @@ void Model_Update::processEvent(const boost::shared_ptr& theMess } else if (theMessage->eventID() == kCreatedEvent || theMessage->eventID() == kUpdatedEvent) { boost::shared_ptr aMsg = boost::dynamic_pointer_cast(theMessage); - if (theMessage->eventID() == kCreatedEvent) { - myJustCreatedOrUpdated.clear(); - } const std::set& anObjs = aMsg->objects(); std::set::const_iterator anObjIter = anObjs.cbegin(); - for(; anObjIter != anObjs.cend(); anObjIter++) + for(; anObjIter != anObjs.cend(); anObjIter++) { myJustCreatedOrUpdated.insert(*anObjIter); - } else if (theMessage->eventID() == kOpFinishEvent || theMessage->eventID() == kOpAbortEvent) { + } + } else if (theMessage->eventID() == kOpStartEvent) { myJustCreatedOrUpdated.clear(); - return; + 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; + } } if (isExecuted) @@ -86,7 +92,7 @@ void Model_Update::processEvent(const boost::shared_ptr& theMess //Events_LongOp::start(this); isExecuted = true; - list > aDocs; + std::list > aDocs; boost::shared_ptr aMsg = boost::dynamic_pointer_cast(theMessage); if (aMsg) myInitial = aMsg->objects(); @@ -103,8 +109,12 @@ void Model_Update::processEvent(const boost::shared_ptr& theMess aDocs.push_back((*aFIter)->document()); } // iterate all features of features-documents to update them (including hidden) + std::set > alreadyUsed; list >::iterator aDIter = aDocs.begin(); for (; aDIter != aDocs.end(); aDIter++) { + if (alreadyUsed.find(*aDIter) != alreadyUsed.end()) + continue; + alreadyUsed.insert(*aDIter); int aNbFeatures = (*aDIter)->size(ModelAPI_Feature::group(), true); for (int aFIndex = 0; aFIndex < aNbFeatures; aFIndex++) { FeaturePtr aFeature = boost::dynamic_pointer_cast( @@ -114,18 +124,35 @@ void Model_Update::processEvent(const boost::shared_ptr& theMess } } myUpdated.clear(); - if (theMessage->eventID() == kUpdatedEvent) { - // flush updates without execution now (updates are caused by this process) - aLoop->flush(kUpdatedEvent); - } // 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::redisplayWithResults(FeaturePtr theFeature) { + // 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++) { + boost::shared_ptr aRes = *aRIter; + aRes->data()->mustBeUpdated(false); + 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); +} + bool Model_Update::updateFeature(FeaturePtr theFeature) { // check it is already processed @@ -163,7 +190,6 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) // execute feature if it must be updated if (aMustbeUpdated) { - if (boost::dynamic_pointer_cast(theFeature->document())->executeFeatures() || !theFeature->isPersistentResult()) { ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); @@ -185,7 +211,7 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) boost::shared_ptr aSel = boost::dynamic_pointer_cast(*aRefsIter); for(int a = aSel->size() - 1; a >= 0; a--) { - aSel->value(a)->update(); + aSel->value(a)->update(); } } // execute in try-catch to avoid internal problems of the feature @@ -196,14 +222,8 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) "Feature " + theFeature->getKind() + " has failed during the execution"); theFeature->eraseResults(); } - theFeature->data()->mustBeUpdated(false); - const std::list >& aResults = theFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - boost::shared_ptr aRes = *aRIter; - aRes->data()->mustBeUpdated(false); - } - } else { + redisplayWithResults(theFeature); + } else { // must be updatet, but not updated yet theFeature->data()->mustBeUpdated(true); const std::list >& aResults = theFeature->results(); std::list >::const_iterator aRIter = aResults.begin(); @@ -211,23 +231,14 @@ bool Model_Update::updateFeature(FeaturePtr theFeature) boost::shared_ptr aRes = *aRIter; aRes->data()->mustBeUpdated(true); } - aMustbeUpdated = false; } } else { theFeature->eraseResults(); + redisplayWithResults(theFeature); // result also must be updated } + } else { // for automatically updated features (on abort, etc) it is necessary to redisplay anyway + redisplayWithResults(theFeature); } - // 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); - } - // to redisplay "presentable" feature (for ex. distance constraint) - ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP); } 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(); diff --git a/src/Model/Model_Update.h b/src/Model/Model_Update.h index f73378580..a29d67d8d 100644 --- a/src/Model/Model_Update.h +++ b/src/Model/Model_Update.h @@ -47,6 +47,8 @@ class Model_Update : public Events_Listener /// Recoursively checks and updates the object (result or feature) if needed (calls updateFeature) /// Returns true if object was updated. bool updateObject(boost::shared_ptr theObject); + /// Sends the redisplay events for feature and results, updates the updated status + void redisplayWithResults(boost::shared_ptr theFeature); }; #endif diff --git a/src/PartSet/PartSet_Listener.cpp b/src/PartSet/PartSet_Listener.cpp index 24c78b60f..8d34fb041 100644 --- a/src/PartSet/PartSet_Listener.cpp +++ b/src/PartSet/PartSet_Listener.cpp @@ -77,7 +77,7 @@ void PartSet_Listener::processEvent(const boost::shared_ptr& the FeaturePtr aFeature = aCreationOp->feature(); const std::list& aResults = aFeature->results(); boost::shared_ptr aUpdMsg = - boost::dynamic_pointer_cast(theMessage); + boost::dynamic_pointer_cast(theMessage); std::set aFeatures = aUpdMsg->objects(); std::set::const_iterator aObjIt, aNoObj = aFeatures.cend(); diff --git a/src/SketchPlugin/SketchPlugin_Line.cpp b/src/SketchPlugin/SketchPlugin_Line.cpp index 2d85a43b3..95b6de896 100644 --- a/src/SketchPlugin/SketchPlugin_Line.cpp +++ b/src/SketchPlugin/SketchPlugin_Line.cpp @@ -100,7 +100,8 @@ bool SketchPlugin_Line::isFixed() { void SketchPlugin_Line::attributeChanged() { static bool myIsUpdated = false; // to avoid infinitive cycle on attrubtes change boost::shared_ptr aSelection = data()->selection(EXTERNAL_ID())->value(); - if (aSelection && !myIsUpdated) { // update arguments due to the selection value + // update arguments due to the selection value + if (aSelection && !aSelection->isNull() && !myIsUpdated) { myIsUpdated = true; boost::shared_ptr anEdge( new GeomAPI_Edge(aSelection)); boost::shared_ptr aStartAttr = diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index b5f101595..2b45cb65a 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -270,11 +270,12 @@ void SketchPlugin_Sketch::erase() } void SketchPlugin_Sketch::attributeChanged() { - static bool myIsUpdated = false; // to avoid infinitive cycle on attrubtes change + static bool kIsUpdated = false; // to avoid infinitive cycle on attrubtes change + static bool kIsAttrChanged = false; boost::shared_ptr aSelection = data()->selection(SketchPlugin_Feature::EXTERNAL_ID())->value(); - if (aSelection && !myIsUpdated) { // update arguments due to the selection value - myIsUpdated = true; + if (aSelection && !kIsUpdated) { // update arguments due to the selection value + kIsUpdated = true; // update the sketch plane boost::shared_ptr aPlane = GeomAlgoAPI_FaceBuilder::plane(aSelection); if (aPlane) { @@ -295,8 +296,9 @@ void SketchPlugin_Sketch::attributeChanged() { boost::shared_ptr aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir))); boost::shared_ptr aXDir(new GeomAPI_Dir(aYDir->cross(aNormDir))); - boost::shared_ptr anOrigin = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); + kIsAttrChanged = false; // track the attributes were really changed during the plane update + boost::shared_ptr anOrigin = boost::dynamic_pointer_cast + (data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); anOrigin->setValue(anOrigPnt); boost::shared_ptr aNormal = boost::dynamic_pointer_cast( data()->attribute(SketchPlugin_Sketch::NORM_ID())); @@ -308,7 +310,23 @@ void SketchPlugin_Sketch::attributeChanged() { data()->attribute(SketchPlugin_Sketch::DIRY_ID())); aDirY->setValue(aYDir); boost::shared_ptr aDir = aPlane->direction(); + + if (kIsAttrChanged) { + // the plane was changed, so reexecute sub-elements to update shapes (located in new plane) + ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators(); + list aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list(); + for(list::iterator aSubIt = aSubs.begin(); aSubIt != aSubs.end(); aSubIt++) { + boost::shared_ptr aFeature = + boost::dynamic_pointer_cast(*aSubIt); + if (aFeature && aFactory->validate(aFeature)) { + aFeature->execute(); + } + } + kIsAttrChanged = false; + } } - myIsUpdated = false; + kIsUpdated = false; + } else if (kIsUpdated) { // other attributes are updated during the selection comupation + kIsAttrChanged = true; } }