]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'BR_ADVANCED_CURRENT_FEATURE_MANAGEMENT' into Dev_1.5.0
authormpv <mpv@opencascade.com>
Mon, 12 Oct 2015 08:58:19 +0000 (11:58 +0300)
committermpv <mpv@opencascade.com>
Mon, 12 Oct 2015 08:58:19 +0000 (11:58 +0300)
17 files changed:
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/Model/Model_Document.cpp
src/Model/Model_Objects.cpp
src/Model/Model_Objects.h
src/Model/Model_Session.cpp
src/Model/Model_Update.cpp
src/Model/Model_Update.h
src/ModelAPI/ModelAPI_Events.h
src/ModelAPI/ModelAPI_Feature.cpp
src/ModelAPI/ModelAPI_Feature.h
src/ModelAPI/ModelAPI_Result.cpp
src/ModuleBase/ModuleBase_Operation.h
src/ModuleBase/ModuleBase_OperationFeature.cpp
src/ModuleBase/ModuleBase_OperationFeature.h
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_OperationMgr.h

index 8d21b7a7834e5a8ed8d12fcf21fa41fb80dc7af1..75b38aeb01e0f85057c88e9bc7dfeef34acb9202 100644 (file)
@@ -368,13 +368,20 @@ void Model_Data::eraseBackReferences()
 void Model_Data::removeBackReference(FeaturePtr theFeature, std::string theAttrID)
 {
   AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
-  if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
+  removeBackReference(anAttribute);
+}
+
+void Model_Data::removeBackReference(AttributePtr theAttr)
+{
+  if (myRefsToMe.find(theAttr) == myRefsToMe.end())
     return;
 
-  myRefsToMe.erase(anAttribute);
+  myRefsToMe.erase(theAttr);
 
   // remove concealment immideately: on deselection it must be posible to reselect in GUI the same
-  if (ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
+  FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttr->owner());
+  if (aFeatureOwner.get() &&
+    ModelAPI_Session::get()->validators()->isConcealed(aFeatureOwner->getKind(), theAttr->id())) {
     updateConcealmentFlag();
   }
 }
@@ -382,13 +389,12 @@ void Model_Data::removeBackReference(FeaturePtr theFeature, std::string theAttrI
 void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID, 
    const bool theApplyConcealment)
 {
-  // do not add the same attribute twice
+  // it is possible to add the same attribute twice: may be last time the owner was not Stable...
   AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
-  if (myRefsToMe.find(anAttribute) != myRefsToMe.end())
-    return;
+  if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
+    myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
 
-  myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
-  if (theApplyConcealment && 
+  if (theApplyConcealment &&  theFeature->isStable() && 
       ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
     std::shared_ptr<ModelAPI_Result> aRes = 
       std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
@@ -407,10 +413,15 @@ void Model_Data::updateConcealmentFlag()
   for(; aRefsIter != myRefsToMe.end(); aRefsIter++) {
     if (aRefsIter->get()) {
       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefsIter)->owner());
-      if (aFeature.get() && !aFeature->isDisabled()) {
+      if (aFeature.get() && !aFeature->isDisabled() && aFeature->isStable()) {
         if (ModelAPI_Session::get()->validators()->isConcealed(
               aFeature->getKind(), (*aRefsIter)->id())) {
-          return; // it is still concealed, nothing to do
+          std::shared_ptr<ModelAPI_Result> aRes = 
+            std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
+          if (aRes.get()) {
+            aRes->setIsConcealed(true); // set concealed
+          }
+          return;
         }
       }
     }
@@ -418,11 +429,8 @@ void Model_Data::updateConcealmentFlag()
   // thus, no concealment references anymore => make not-concealed
   std::shared_ptr<ModelAPI_Result> aRes = 
     std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
-  if (aRes.get() && aRes->isConcealed()) {
+  if (aRes.get()) {
     aRes->setIsConcealed(false);
-    static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
-    ModelAPI_EventCreator::get()->sendUpdated(aRes, anEvent);
-    Events_Loop::loop()->flush(anEvent);
   }
 }
 
index 1e6c0d65082a4df12d4f9b7c7e61c9b78feed426..da40e7d4a8de9e5247bd08e92167765da748209c 100644 (file)
@@ -223,11 +223,13 @@ protected:
 private:
   /// Removes all information about back references
   void eraseBackReferences();
-  /// Adds a back reference (with identifier which attribute references to this object
-  /// It does not change the consealment flag of the data object result
+  /// Removes a back reference (with identifier which attribute references to this object)
   /// \param theFeature feature referenced to this
   /// \param theAttrID identifier of the attribute that is references from theFeature to this
   void removeBackReference(FeaturePtr theFeature, std::string theAttrID);
+  /// Removes a back reference (by the attribute)
+  /// \param theAttr the referenced attribute
+  void removeBackReference(AttributePtr theAttr);
   /// Adds a back reference (with identifier which attribute references to this object
   /// \param theFeature feature referenced to this
   /// \param theAttrID identifier of the attribute that is references from theFeature to this
index e0ae73e76109b438637f051a4f49870317863581..28fda6f314c0c20abf921d4d4e7619ca0afb94c1 100644 (file)
@@ -739,8 +739,7 @@ std::shared_ptr<ModelAPI_Feature> Model_Document::currentFeature(const bool theV
     TDF_Label aLab = aRef->Get();
     FeaturePtr aResult = myObjs->feature(aLab);
     if (theVisible) { // get nearest visible (in history) going up
-      while(aResult.get() &&  // sub-composites are never in history
-             (!aResult->isInHistory() || ModelAPI_Tools::compositeOwner(aResult).get())) {
+      while(aResult.get() &&  !aResult->isInHistory()) {
         aResult = myObjs->nextFeature(aResult, true);
       }
     }
@@ -759,20 +758,16 @@ void Model_Document::setCurrentFeature(
 
   TDF_Label aRefLab = generalLabel().FindChild(TAG_CURRENT_FEATURE);
   CompositeFeaturePtr aMain; // main feature that may nest the new current
+  std::set<FeaturePtr> anOwners; // composites that contain theCurrent (with any level of nesting)
   if (theCurrent.get()) {
     aMain = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theCurrent);
-    if (!aMain.get()) {
-      // if feature nests into compisite feature, make the composite feature as current
-      const std::set<AttributePtr>& aRefsToMe = theCurrent->data()->refsToMe();
-      std::set<AttributePtr>::const_iterator aRefToMe = aRefsToMe.begin();
-      for(; aRefToMe != aRefsToMe.end(); aRefToMe++) {
-        CompositeFeaturePtr aComposite = 
-          std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*aRefToMe)->owner());
-        if (aComposite.get() && aComposite->isSub(theCurrent)) {
-          aMain = aComposite;
-          break;
-        }
+    CompositeFeaturePtr anOwner = ModelAPI_Tools::compositeOwner(theCurrent);
+    while(anOwner.get()) {
+      if (!aMain.get()) {
+        aMain = anOwner;
       }
+      anOwners.insert(anOwner);
+      anOwner = ModelAPI_Tools::compositeOwner(anOwner);
     }
   }
 
@@ -817,8 +812,13 @@ void Model_Document::setCurrentFeature(
     if (anIter == theCurrent) aPassed = true;
 
     bool aDisabledFlag = !aPassed;
-    if (aMain.get() && aMain->isSub(anIter)) // sub-elements of not-disabled feature are not disabled
-      aDisabledFlag = false;
+    if (aMain.get()) {
+      if (aMain->isSub(anIter)) // sub-elements of not-disabled feature are not disabled
+        aDisabledFlag = false;
+      else if (anOwners.find(anIter) != anOwners.end()) // disable the higher-level feature is the nested is the current
+        aDisabledFlag = true;
+    }
+
     if (anIter->getKind() == "Parameter") {// parameters are always out of the history of features, but not parameters
       if (theCurrent.get() && theCurrent->getKind() != "Parameter")
         aDisabledFlag = false;
index 82831c710236276940b14fed8e748974bce803ab..53c9d554f3f56bb5307f22fd8455053308abcba9 100644 (file)
@@ -696,89 +696,82 @@ void Model_Objects::synchronizeFeatures(
   anOwner->executeFeatures() = true;
 }
 
-void Model_Objects::synchronizeBackRefs()
+/// synchronises back references for the given object basing on the collected data
+void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& theNewRefs,
+  ObjectPtr theObject) 
 {
-  // keeps the concealed flags of result to catch the change and create created/deleted events
-  std::list<std::pair<ResultPtr, bool> > aConcealed;
-  // first cycle: erase all data about back-references
-  NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
-  for(; aFeatures.More(); aFeatures.Next()) {
-    FeaturePtr aFeature = aFeatures.Value();
-    std::shared_ptr<Model_Data> aFData = 
-      std::dynamic_pointer_cast<Model_Data>(aFeature->data());
-    if (aFData.get()) {
-      aFData->eraseBackReferences();
+  if (!theObject.get() || !theObject->data()->isValid())
+    return; // invalid
+  std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
+  // iterate new list to compare with curent
+  std::set<AttributePtr>::iterator aNewIter = theNewRefs.begin();
+  for(; aNewIter != theNewRefs.end(); aNewIter++) {
+    if (aData->refsToMe().find(*aNewIter) == aData->refsToMe().end()) {
+      FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aNewIter)->owner());
+      aData->addBackReference(aRefFeat, (*aNewIter)->id());
     }
-    const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
-    std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
-    for (; aRIter != aResults.cend(); aRIter++) {
-      std::shared_ptr<Model_Data> aResData = 
-        std::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
-      if (aResData.get()) {
-        aConcealed.push_back(std::pair<ResultPtr, bool>(*aRIter, (*aRIter)->isConcealed()));
-        aResData->eraseBackReferences();
-      }
-      // iterate sub-bodies of compsolid
-      ResultCompSolidPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
-      if (aComp.get()) {
-        int aNumSub = aComp->numberOfSubs();
-        for(int a = 0; a < aNumSub; a++) {
-          ResultPtr aSub = aComp->subResult(a);
-          std::shared_ptr<Model_Data> aResData = 
-            std::dynamic_pointer_cast<Model_Data>(aSub->data());
-          if (aResData.get()) {
-            aConcealed.push_back(std::pair<ResultPtr, bool>(aSub, aSub->isConcealed()));
-            aResData->eraseBackReferences();
-          }
-        }
-      }
+  }
+  if (theNewRefs.size() != aData->refsToMe().size()) { // some back ref must be removed
+    std::set<AttributePtr>::iterator aCurrentIter = aData->refsToMe().begin();
+    while(aCurrentIter != aData->refsToMe().end()) {
+      if (theNewRefs.find(*aCurrentIter) == theNewRefs.end()) {
+        aData->removeBackReference(*aCurrentIter);
+        aCurrentIter = aData->refsToMe().begin(); // reinitialize iteration after delete
+      } else aCurrentIter++;
     }
   }
+  aData->updateConcealmentFlag();
+}
 
-  // second cycle: set new back-references: only features may have reference, iterate only them
-  ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
-  for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
+void Model_Objects::synchronizeBackRefs()
+{
+  // collect all back references in the separated container: to update everything at once,
+  // without additional Concealment switchin on and off: only the final modification
+
+  // referenced (slave) objects to referencing attirbutes
+  std::map<ObjectPtr, std::set<AttributePtr> > allRefs;
+  NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
+  for(; aFeatures.More(); aFeatures.Next()) {
     FeaturePtr aFeature = aFeatures.Value();
-    std::shared_ptr<Model_Data> aFData = 
-      std::dynamic_pointer_cast<Model_Data>(aFeature->data());
+    std::shared_ptr<Model_Data> aFData = std::dynamic_pointer_cast<Model_Data>(aFeature->data());
     if (aFData.get()) {
       std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
       aFData->referencesToObjects(aRefs);
-      std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator 
-        aRefsIter = aRefs.begin();
-      for(; aRefsIter != aRefs.end(); aRefsIter++) {
-        std::list<ObjectPtr>::iterator aRefTo = aRefsIter->second.begin();
-        for(; aRefTo != aRefsIter->second.end(); aRefTo++) {
+      std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefsIt = aRefs.begin();
+      for(; aRefsIt != aRefs.end(); aRefsIt++) {
+        std::list<ObjectPtr>::iterator aRefTo = aRefsIt->second.begin();
+        for(; aRefTo != aRefsIt->second.end(); aRefTo++) {
           if (*aRefTo) {
-            std::shared_ptr<Model_Data> aRefData = 
-              std::dynamic_pointer_cast<Model_Data>((*aRefTo)->data());
-            aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated
-            // update enable/disable status: the nested status must be equal to the composite
-            CompositeFeaturePtr aComp = 
-              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
-            if (aComp.get()) {
-              FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>(*aRefTo);
-              if (aReferenced.get()) {
-                aReferenced->setDisabled(aComp->isDisabled());
-              }
+            std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(*aRefTo);
+            if (aFound == allRefs.end()) {
+              allRefs[*aRefTo] = std::set<AttributePtr>();
+              aFound = allRefs.find(*aRefTo);
             }
+            aFound->second.insert(aFeature->data()->attribute(aRefsIt->first));
           }
         }
       }
     }
   }
-  std::list<std::pair<ResultPtr, bool> >::iterator aCIter = aConcealed.begin();
-  for(; aCIter != aConcealed.end(); aCIter++) {
-    if (aCIter->first->isConcealed() != aCIter->second) { // something is changed => produce event
-      if (aCIter->second) { // was concealed become not => creation event
-        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
-        ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, anEvent);
-      } else { // was not concealed become concealed => delete event
-        ModelAPI_EventCreator::get()->sendDeleted(myDoc, aCIter->first->groupName());
-        // redisplay for the viewer (it must be disappeared also)
-        static Events_ID EVENT_DISP = 
-          Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-        ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, EVENT_DISP);
+  // second iteration: just compare back-references with existing in features and results
+  for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
+    FeaturePtr aFeature = aFeatures.Value();
+    static std::set<AttributePtr> anEmpty;
+    std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(aFeature);
+    if (aFound == allRefs.end()) { // not found => erase all back references
+      synchronizeBackRefsForObject(anEmpty, aFeature);
+    } else {
+      synchronizeBackRefsForObject(aFound->second, aFeature);
+    }
+    // also for results
+    const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
+    std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
+    for(; aRes != aResults.cend(); aRes++) {
+      aFound = allRefs.find(*aRes);
+      if (aFound == allRefs.end()) { // not found => erase all back references
+        synchronizeBackRefsForObject(anEmpty, *aRes);
+      } else {
+        synchronizeBackRefsForObject(aFound->second, *aRes);
       }
     }
   }
index dc1fe7855a74cd19abd0879fcaa072365af8ca1d..9f947c776f62d0f392f076e63198c4d11736242b 100644 (file)
@@ -190,10 +190,13 @@ class Model_Objects
   /// be created before)
   std::string featureResultGroup(FeaturePtr theFeature);
 
-  ///! Returns all features of the document including the hidden features which are not in
-  ///! history. Not very fast method, for calling once, not in big cycles.
+  //! Returns all features of the document including the hidden features which are not in
+  //! history. Not very fast method, for calling once, not in big cycles.
   std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures();
 
+  //! synchronises back references for the given object basing on the collected data
+  void synchronizeBackRefsForObject(
+    const std::set<std::shared_ptr<ModelAPI_Attribute>>& theNewRefs, ObjectPtr theObject);
 
  private:
   TDF_Label myMain; ///< main label of the data storage
index ea5375afbb59077ec613106b6c5c32fa5eff1a5e..172b7d3ff220ffd0e685853b53ffc524b62cb89f 100644 (file)
@@ -219,6 +219,15 @@ std::shared_ptr<ModelAPI_Document> Model_Session::activeDocument()
 static void makeCurrentLast(std::shared_ptr<ModelAPI_Document> theDoc) {
   if (theDoc.get()) {
     FeaturePtr aLast = std::dynamic_pointer_cast<Model_Document>(theDoc)->lastFeature();
+    // if last is nested into something else, make this something else as last:
+    // otherwise it will look like edition of sub-element, so, the main will be disabled
+    if (aLast.get()) {
+      CompositeFeaturePtr aMain = ModelAPI_Tools::compositeOwner(aLast);
+      while(aMain.get()) {
+        aLast = aMain;
+        aMain = ModelAPI_Tools::compositeOwner(aLast);
+      }
+    }
     theDoc->setCurrentFeature(aLast, false);
   }
 }
index 69b34511427b86548183f9f238b290f550032646..49657767605ea735537cec2d23ce1cb13f6b1316 100644 (file)
@@ -54,6 +54,8 @@ Model_Update::Model_Update()
   aLoop->registerListener(this, kOpAbortEvent);
   static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation");
   aLoop->registerListener(this, kOpStartEvent);
+  static const Events_ID kStabilityEvent = aLoop->eventByName(EVENT_STABILITY_CHANGED);
+  aLoop->registerListener(this, kStabilityEvent);
 
   /* not needed now with history line
   Config_PropManager::registerProp("Model update", "automatic_rebuild", "Rebuild immediately",
@@ -76,9 +78,12 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
   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);
 #ifdef DEB_UPDATE
   std::cout<<"****** Event "<<theMessage->eventID().eventText()<<std::endl;
 #endif
+  if (theMessage->eventID() == kStabilityEvent)
+    updateStability(theMessage->sender());
   if (theMessage->eventID() == kChangedEvent) { // automatic and manual rebuild flag is changed
     /*bool aPropVal =
       Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
@@ -274,8 +279,13 @@ 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->isDisabled())
+  if (theFeature->isDisabled()) {
+    // possibly sub-elements are not disabled?
+    CompositeFeaturePtr aCompos = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+    if (aCompos)
+      iterateUpdate(aCompos);
     return;
+  }
 
   // do not execute the composite that contains the current
   bool isPostponedMain = false;
@@ -664,6 +674,53 @@ void Model_Update::executeFeature(FeaturePtr theFeature)
   redisplayWithResults(theFeature, aState);
 }
 
+void Model_Update::updateStability(void* theSender)
+{
+  if (theSender) {
+    bool added = false; // object may be was crated
+    ModelAPI_Object* aSender = static_cast<ModelAPI_Object*>(theSender);
+    if (aSender && aSender->document()) {
+      FeaturePtr aFeatureSender = 
+        std::dynamic_pointer_cast<ModelAPI_Feature>(aSender->data()->owner());
+      if (aFeatureSender.get()) {
+        Model_Objects* aDocObjects = 
+          std::dynamic_pointer_cast<Model_Document>(aSender->document())->objects();
+        if (aDocObjects) {
+          //aDocObjects->synchronizeBackRefs();
+          // remove or add all concealment refs from this feature
+          std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+          aSender->data()->referencesToObjects(aRefs);
+          std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefIt = aRefs.begin();
+          for(; aRefIt != aRefs.end(); aRefIt++) {
+            std::list<ObjectPtr>& aRefFeaturesList = aRefIt->second;
+            std::list<ObjectPtr>::iterator aReferenced = aRefFeaturesList.begin();
+            for(; aReferenced != aRefFeaturesList.end(); aReferenced++) {
+               // stability is only on results: feature to feature reference mean nested 
+              // features, that will remove nesting references
+              if (aReferenced->get() && (*aReferenced)->data()->isValid() && 
+                (*aReferenced)->groupName() != ModelAPI_Feature::group()) {
+                std::shared_ptr<Model_Data> aData = 
+                  std::dynamic_pointer_cast<Model_Data>((*aReferenced)->data());
+                if (aFeatureSender->isStable()) {
+                  aData->addBackReference(aFeatureSender, aRefIt->first);
+                } else {
+                  aData->removeBackReference(aFeatureSender, aRefIt->first);
+                  added = true; // remove of concealment may be caused creation of some result
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    if (added) {
+      static Events_Loop* aLoop = Events_Loop::loop();
+      static Events_ID kEventCreated = aLoop->eventByName(EVENT_OBJECT_CREATED);
+      aLoop->flush(kEventCreated);
+    }
+  }
+}
+
 ///////////////// Updated items iterator ////////////////////////
 Model_Update::IterationItem::IterationItem(std::shared_ptr<ModelAPI_CompositeFeature> theFeature)
 {
index 862a078cee86db631bcff1f09868a8beb4345618..3b543c1f540996c4fe157d991b193a3141a90dee 100644 (file)
@@ -125,6 +125,8 @@ protected:
   /// Returns true if the feature is older that the argument and it must be updated
   bool isOlder(std::shared_ptr<ModelAPI_Feature> theFeature, 
                std::shared_ptr<ModelAPI_Object> theArgument);
+  /// Updates the properties of object because of stability state changes
+  void updateStability(void* theSender);
 };
 
 #endif
index 45349a52c3c97fb6415be40b221a9d36e4d3aab6..f4fee024af80ffcb7445c878186228bbc48287d9 100644 (file)
@@ -56,6 +56,9 @@ static const char * EVENT_SOLVER_REPAIRED = "SolverRepaired";
 /// Event ID that order of objects in group is changed, so, tree must be fully rectreated (movement of feature)
 static const char * EVENT_ORDER_UPDATED = "OrderUpdated";
 
+/// Event ID that informs that some object has changed the stability
+static const char * EVENT_STABILITY_CHANGED = "StabilityChanged";
+
 /// Message that feature was changed (used for Object Browser update): moved, updated and deleted
 class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup
 {
index 9edfefa4c8f69ed57c5128ecadbc25342d675016..5b9d7e3d4e0f3da971bd37d24dd6347179928f9f 100644 (file)
@@ -199,6 +199,25 @@ bool ModelAPI_Feature::isDisabled()
   return myIsDisabled;
 }
 
+bool ModelAPI_Feature::setStable(const bool theFlag)
+{
+  if (myIsStable != theFlag) {
+    myIsStable = theFlag;
+    // send an event about the stability change (editing is started/finished)
+    static Events_Loop* aLoop = Events_Loop::loop();
+    static Events_ID EVENT_STAB = aLoop->eventByName(EVENT_STABILITY_CHANGED);
+    std::shared_ptr<Events_Message> aMessage(new Events_Message(EVENT_STAB, this));
+    aLoop->send(aMessage, false);
+    return true;
+  }
+  return false;
+}
+
+bool ModelAPI_Feature::isStable()
+{
+  return myIsStable;
+}
+
 bool ModelAPI_Feature::isPreviewNeeded() const
 {
   return true;
@@ -207,4 +226,5 @@ bool ModelAPI_Feature::isPreviewNeeded() const
 void ModelAPI_Feature::init()
 {
   myIsDisabled = false;
+  myIsStable = true;
 }
index 2508e6a2ea9f726e3d789a208c2d4e5b15c257e6..af55636cb58e7b573d2f5cf1235e16d5bff53f22 100644 (file)
@@ -28,6 +28,9 @@ class ModelAPI_Feature : public ModelAPI_Object
   std::list<std::shared_ptr<ModelAPI_Result> > myResults;
   ///< is feature disabled or not
   bool myIsDisabled;
+  ///< is feature is stable (not editing)
+  bool myIsStable;
+
  public:
   /// Returns the unique kind of a feature (like "Point")
   virtual const std::string& getKind() = 0;
@@ -132,6 +135,13 @@ class ModelAPI_Feature : public ModelAPI_Object
   /// Returns the feature by the object (result).
   MODELAPI_EXPORT static std::shared_ptr<ModelAPI_Feature> feature(ObjectPtr theObject);
 
+  /// Set the stable feature flag. If feature is currently editing then it is not stable.
+  /// \returns true if state is really changed
+  MODELAPI_EXPORT virtual bool setStable(const bool theFlag);
+
+  /// Returns the feature is stable or not.
+  MODELAPI_EXPORT virtual bool isStable();
+
  //
  // Helper methods, aliases for data()->method()
  // -----------------------------------------------------------------------------------------------
index 624566416846743e143ed66c62a2589e6356172a..cefbd7af8310d7d2119ced6737c347304fc2e5e3 100644 (file)
@@ -54,8 +54,17 @@ void ModelAPI_Result::setIsConcealed(const bool theValue)
 {
   if (myIsConcealed != theValue) {
     myIsConcealed = theValue;
-    if (document().get()) // can be on creation of result
+    if (document().get()) // can be on creation of result
       document()->updateHistory(groupName()); // to update the history cash data in the document
+      if (myIsConcealed) {
+        ModelAPI_EventCreator::get()->sendDeleted(document(), groupName());
+        static Events_ID kDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+        ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), kDispEvent);
+      } else {
+        static Events_ID kEventCreated = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
+        ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), kEventCreated);
+      }
+    }
   }
 }
 
index 9a34e6423d326db9d12ac3012448614579acda58..12e5ddb86a91ef2d4f581da500541337fb292c53 100644 (file)
@@ -91,12 +91,15 @@ Q_OBJECT
 
 signals:
   /// The operation is started
+  void beforeStarted();
   void started();
 
   /// The operation is aborted
+  void beforeAborted();
   void aborted();
 
   /// The operation is committed
+  void beforeCommitted();
   void committed();
 
   /// The operation is aborted or committed
index 7458ae9fd27d996e1a27f2579905555c36f18a2d..c6762043e1d8796f78cbf4725c80ee9200dc101f 100755 (executable)
@@ -26,6 +26,7 @@
 #include <ModelAPI_Object.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
 
 #include <GeomAPI_Pnt2d.h>
 
@@ -78,6 +79,9 @@ void ModuleBase_OperationFeature::startOperation()
   if (!aFeature.get() || !isEditOperation())
     return;
 
+  if (aFeature.get() && isEditOperation())
+    aFeature->setStable(false);
+
   myVisualizedObjects.clear();
   // store hidden result features
   std::list<ResultPtr> aResults = aFeature->results();
@@ -179,6 +183,7 @@ void ModuleBase_OperationFeature::start()
   }
   ModelAPI_Session::get()->startOperation(anId.toStdString());
 
+  emit beforeStarted();
   startOperation();
 
   if (!myIsEditing) {
@@ -192,29 +197,15 @@ void ModuleBase_OperationFeature::start()
       return;
     }
   }
-  /// Set current feature and remeber old current feature
-  if (myIsEditing) {
-    SessionPtr aMgr = ModelAPI_Session::get();
-    DocumentPtr aDoc = aMgr->activeDocument();
-    // the parameter of current feature should be false, we should use all feature, not only visible
-    // in order to correctly save the previous feature of the nested operation, where the
-    // features can be not visible in the tree. The problem case is Edit sketch entitity(line)
-    // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit.
-    // When sketch entity operation started, the sketch should be cashed here as the current.
-    // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch
-    // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
-    // As a result the sketch disappears from the viewer. However after commit it is displayed back.
-    myPreviousCurrentFeature = aDoc->currentFeature(false);
-    aDoc->setCurrentFeature(feature(), false);
-  }
-
-  startOperation();
+  //Already called startOperation();
   emit started();
 
 }
 
 void ModuleBase_OperationFeature::abort()
 {
+  emit beforeAborted();
+
   // the viewer update should be blocked in order to avoid the features blinking before they are
   // hidden
   std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
@@ -230,21 +221,12 @@ void ModuleBase_OperationFeature::abort()
   if (aPropertyPanel)
     aPropertyPanel->cleanContent();
 
-  SessionPtr aMgr = ModelAPI_Session::get();
-  if (myIsEditing) {
-    DocumentPtr aDoc = aMgr->activeDocument();
-    bool aIsOp = aMgr->isOperation();
-    if (!aIsOp)
-      aMgr->startOperation();
-    aDoc->setCurrentFeature(myPreviousCurrentFeature, true);
-    if (!aIsOp)
-      aMgr->finishOperation();
-    myPreviousCurrentFeature = FeaturePtr();
-  }
-  abortOperation();
+  myFeature->setStable(true);
 
+  abortOperation();
   stopOperation();
 
+  SessionPtr aMgr = ModelAPI_Session::get();
   aMgr->abortOperation();
   emit stopped();
   // the viewer update should be unblocked in order to avoid the features blinking before they are
@@ -268,19 +250,13 @@ bool ModuleBase_OperationFeature::commit()
     ModuleBase_IPropertyPanel* aPropertyPanel = propertyPanel();
     if (aPropertyPanel)
       aPropertyPanel->cleanContent();
+    
+    myFeature->setStable(true);
 
     SessionPtr aMgr = ModelAPI_Session::get();
     /// Set current feature and remeber old current feature
-    if (myIsEditing) {
-      DocumentPtr aDoc = aMgr->activeDocument();
-      bool aIsOp = aMgr->isOperation();
-      if (!aIsOp)
-        aMgr->startOperation();
-      aDoc->setCurrentFeature(myPreviousCurrentFeature, true);
-      if (!aIsOp)
-        aMgr->finishOperation();
-      myPreviousCurrentFeature = FeaturePtr();
-    }
+
+    emit beforeCommitted();
     commitOperation();
     aMgr->finishOperation();
 
@@ -352,6 +328,16 @@ CompositeFeaturePtr ModuleBase_OperationFeature::parentFeature() const
   return myParentFeature;
 }
 
+void ModuleBase_OperationFeature::setPreviousCurrentFeature(const FeaturePtr& theFeature)
+{
+  myPreviousCurrentFeature = theFeature;
+}
+
+FeaturePtr ModuleBase_OperationFeature::previousCurrentFeature()
+{
+  return myPreviousCurrentFeature;
+}
+
 void ModuleBase_OperationFeature::initSelection(ModuleBase_ISelection* theSelection,
                                          ModuleBase_IViewer* theViewer)
 {
index f9d850fb8ac4e351ad63dd316b8f09e6b24aa90b..48c8506e12e6647a41d08c9ac966778f2fdcb79e 100755 (executable)
@@ -107,6 +107,14 @@ Q_OBJECT
   /// \return Installed parent feature (can be NULL)
   CompositeFeaturePtr parentFeature() const;
 
+  /// Stores the previous to the operation current feature
+  /// \set theFeature a feature
+  void setPreviousCurrentFeature(const FeaturePtr& theFeature);
+
+  /// Returns the previous to the operation current feature
+  /// \return theFeature a feature
+  FeaturePtr previousCurrentFeature();
+
 signals:
   /// The operation is filled with existing preselection
   void activatedByPreselection(); 
index 361547bbfad2fbb9bb492dbd8c7c8903127729e2..8cf826404cc2daf701f87c03f6b84c349c7ed537 100644 (file)
@@ -116,9 +116,14 @@ bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
     currentOperation()->postpone();
   myOperations.append(theOperation);
 
+  connect(theOperation, SIGNAL(beforeStarted()), SLOT(onBeforeOperationStarted()));
+  connect(theOperation, SIGNAL(beforeAborted()), SLOT(onBeforeOperationAborted()));
+  connect(theOperation, SIGNAL(beforeCommitted()), SLOT(onBeforeOperationCommitted()));
+
   connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
   connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
   connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
+
   connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
   connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
@@ -309,6 +314,18 @@ bool XGUI_OperationMgr::isGrantedOperation(const QString& theId)
   return isGranted;
 }
 
+void XGUI_OperationMgr::setCurrentFeature(const FeaturePtr& theFeature)
+{
+  SessionPtr aMgr = ModelAPI_Session::get();
+  DocumentPtr aDoc = aMgr->activeDocument();
+  bool aIsOp = aMgr->isOperation();
+  if (!aIsOp)
+    aMgr->startOperation();
+  aDoc->setCurrentFeature(theFeature, false);
+  if (!aIsOp)
+    aMgr->finishOperation();
+}
+
 bool XGUI_OperationMgr::canStartOperation(const QString& theId, const bool isAdditionallyGranted)
 {
   bool aCanStart = true;
@@ -374,6 +391,32 @@ void XGUI_OperationMgr::onAbortOperation()
   }
 }
 
+void XGUI_OperationMgr::onBeforeOperationStarted()
+{
+  ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
+  if (!aCurrentOperation)
+    return;
+
+  /// Set current feature and remeber old current feature
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
+  if (aFOperation) {
+    SessionPtr aMgr = ModelAPI_Session::get();
+    DocumentPtr aDoc = aMgr->activeDocument();
+    // the parameter of current feature should be false, we should use all feature, not only visible
+    // in order to correctly save the previous feature of the nested operation, where the
+    // features can be not visible in the tree. The problem case is Edit sketch entitity(line)
+    // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit.
+    // When sketch entity operation started, the sketch should be cashed here as the current.
+    // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch
+    // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
+    // As a result the sketch disappears from the viewer. However after commit it is displayed back.
+    aFOperation->setPreviousCurrentFeature(aDoc->currentFeature(false));
+    if (aFOperation->isEditOperation()) // it should be performed by the feature edit only
+      // in create operation, the current feature is changed by addFeature()
+      aDoc->setCurrentFeature(aFOperation->feature(), false);
+  }
+}
+
 void XGUI_OperationMgr::onOperationStarted()
 {
   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
@@ -381,12 +424,40 @@ void XGUI_OperationMgr::onOperationStarted()
   emit operationStarted(aSenderOperation);
 }
 
+void XGUI_OperationMgr::onBeforeOperationAborted()
+{
+  onBeforeOperationCommitted();
+}
+
 void XGUI_OperationMgr::onOperationAborted()
 {
   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
   emit operationAborted(aSenderOperation);
 }
 
+void XGUI_OperationMgr::onBeforeOperationCommitted()
+{
+  ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
+  if (!aCurrentOperation)
+    return;
+
+  /// Restore the previous current feature
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
+  if (aFOperation) {
+    if (aFOperation->isEditOperation()) {
+      /// Restore the previous current feature
+      setCurrentFeature(aFOperation->previousCurrentFeature());
+    }
+    else { // create operation
+      // the Top created feature should stays the current. In nested operations, like Line in the Sketch or
+      // Sketch in ExtrusionCut, a previous feature should be restored on commit. It is performed here
+      // in order to perform it in the current transaction without opening a new one.
+      if (myOperations.front() != aFOperation)
+        setCurrentFeature(aFOperation->previousCurrentFeature());
+    }
+  }
+}
+
 void XGUI_OperationMgr::onOperationCommitted()
 {
   // apply state for all features from the stack of operations should be updated
index f6c25a87b439909f5e753dc154c41ac4d78ed4ab..052aa86b5c9cd20e968337d7094251f750cdf298 100644 (file)
@@ -10,6 +10,7 @@
 #include "XGUI.h"
 
 #include <ModuleBase_Operation.h>
+#include "ModelAPI_Feature.h"
 
 #include <QList>
 #include <QObject>
@@ -174,6 +175,10 @@ protected: // TEMPORARY
   /// \return boolean result
   bool isGrantedOperation(const QString& theId);
 
+  /// Sets the feature as a current in the document
+  /// \param theFeature a feature
+  void setCurrentFeature(const FeaturePtr& theFeature);
+
  public slots:
   /// SLOT, that is called by the key in the property panel is clicked.
   /// \param theEvent the mouse event
@@ -184,13 +189,24 @@ protected: // TEMPORARY
   /// If there is a suspended operation, restart it.
   void onOperationStopped();
 
-  /// Slot called on operation start
+  /// Slot called before operation started. Stores the previous current feature, set the feature
+  /// of the operation as a current in the document. The previous current feature should be restored
+  /// by the operation abort/commit
+  void onBeforeOperationStarted();
+
+  /// Slot called after operation started
   void onOperationStarted();
 
-  /// Slot called on operation abort
+  /// Slot called before operation aborted. Restore the previous current operation
+  void onBeforeOperationAborted();
+
+  /// Slot called after operation aborted
   void onOperationAborted();
 
-  /// Slot called on operation commit
+  /// Slot called before operation committed. Restore the previous current operation
+  void onBeforeOperationCommitted();
+
+  /// Slot called after operation committed
   void onOperationCommitted();
 
   /// Slot called on operation resume
@@ -207,7 +223,6 @@ private:
   /// Current workshop
   ModuleBase_IWorkshop* myWorkshop;
 
-
   /// Lock/Unlock access to Ok button in property panel
   bool myIsValidationLock;
   /// Lock/Unlock access to Ok button in property panel