Salome HOME
Fix for the issue #2517 . Stabilization of the order of results of partition based...
[modules/shaper.git] / src / Model / Model_Objects.cpp
index 1da563d21b5f65b8e6390e88addef88770156ef9..b4e516cd64e75305d523ad0c750635d14376c1f0 100644 (file)
@@ -60,6 +60,22 @@ static const std::string& groupNameFoldering(const std::string& theGroupID,
   return theGroupID;
 }
 
+// Check theFeature is a first or last feature in folder and return this folder
+static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr)
+{
+  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+  for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+    if ((*anIt)->id() != theFolderAttr)
+      continue;
+
+    ObjectPtr anOwner = (*anIt)->owner();
+    FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(anOwner);
+    if (aFolder.get())
+      return aFolder;
+  }
+  return FolderPtr();
+}
+
 
 static const int TAG_OBJECTS = 2;  // tag of the objects sub-tree (features, results)
 
@@ -160,12 +176,24 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
     // store feature in the features array: before "initData" because in macro features
     // in initData it creates new features, appeared later than this
     TDF_Label aPrevFeateureLab;
+    FolderPtr aParentFolder;
     if (theAfterThis.get()) { // searching for the previous feature label
       std::shared_ptr<Model_Data> aPrevData =
         std::dynamic_pointer_cast<Model_Data>(theAfterThis->data());
       if (aPrevData.get()) {
         aPrevFeateureLab = aPrevData->label().Father();
       }
+      // Check if the previous feature is the last feature in a folder,
+      // then the folder should be updated to contain additional feature.
+      // Macro features are not stored in folder.
+      if (!theFeature->isMacro()) {
+        // If the last feature is a sub-feature of composite, use parent feature
+        // to check belonging to a folder.
+        FeaturePtr afterThis = ModelAPI_Tools::compositeOwner(theAfterThis);
+        if (!afterThis)
+          afterThis = theAfterThis;
+        aParentFolder = inFolder(afterThis, ModelAPI_Folder::LAST_FEATURE_ID());
+      }
     }
     AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab);
 
@@ -183,6 +211,12 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
     // must be after binding to the map because of "Box" macro feature that
     // creates other features in "initData"
     initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
+    // put feature to the end of folder if it is added while
+    // the history line is set to the last feature from the folder
+    if (aParentFolder) {
+      aParentFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(theFeature);
+      updateHistory(ModelAPI_Folder::group());
+    }
     // event: feature is added, mist be before "initData" to update OB correctly on Duplicate:
     // first new part, then the content
     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
@@ -281,6 +315,8 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
         aComposite->removeFeature(theFeature);
       }
     }
+    // remove feature from folder
+    removeFromFolder(std::list<FeaturePtr>(1, theFeature));
     // this must be before erase since theFeature erasing removes all information about
     // the feature results and groups of results
     // To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated
@@ -451,7 +487,7 @@ void Model_Objects::createHistory(const std::string& theGroupID)
 
         } else {
           // it may be a folder
-          ObjectPtr aFolder = folder(aRefs->Value(a));
+          const ObjectPtr& aFolder = folder(aRefs->Value(a));
           if (aFolder.get()) {
             // store folder information for the Features group only
             if (isFeature || isFolder) {
@@ -499,11 +535,12 @@ void Model_Objects::updateHistory(const std::string theGroup)
   }
 }
 
-ObjectPtr Model_Objects::folder(TDF_Label theLabel) const
+const ObjectPtr& Model_Objects::folder(TDF_Label theLabel) const
 {
   if (myFolders.IsBound(theLabel))
     return myFolders.Find(theLabel);
-  return ObjectPtr();
+  static ObjectPtr anEmptyResult;
+  return anEmptyResult;
 }
 
 FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
@@ -564,6 +601,9 @@ ObjectPtr Model_Objects::object(const std::string& theGroupID,
     return ObjectPtr();
   createHistory(theGroupID);
   const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
+  const std::vector<ObjectPtr>& aVec = myHistory[theGroupID];
+  //if (aVec.size() <= theIndex)
+  //  return aVec[aVec.size() - 1]; // too high index requested (to avoid crash in #2360)
   return aGroupID.empty() ? myHistory[theGroupID][theIndex] : myHistory[aGroupID][theIndex];
 }
 
@@ -784,7 +824,7 @@ void Model_Objects::synchronizeFeatures(
     TDF_Label& aFeatureLab = anUpdatedIter.Value();
     while(aFeatureLab.Depth() > 3)
       aFeatureLab = aFeatureLab.Father();
-    if (myFeatures.IsBound(aFeatureLab))
+    if (myFeatures.IsBound(aFeatureLab) || myFolders.IsBound(aFeatureLab))
       anUpdatedMap.Add(aFeatureLab);
   }
 
@@ -998,6 +1038,35 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& t
       } else aCurrentIter++;
     }
   }
+  // for the last feature in the folder, check if it is a sub-feature,
+  // then refer the folder to a top-level parent composite feature
+  const std::set<AttributePtr>& aRefs = aData->refsToMe();
+  std::set<AttributePtr>::iterator anIt = aRefs.begin();
+  for (; anIt != aRefs.end(); ++anIt)
+    if ((*anIt)->id() == ModelAPI_Folder::LAST_FEATURE_ID())
+      break;
+  if (anIt != aRefs.end()) {
+    FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+    if (aFeature) {
+      CompositeFeaturePtr aParent;
+      CompositeFeaturePtr aGrandParent = ModelAPI_Tools::compositeOwner(aFeature);
+      do {
+        aParent = aGrandParent;
+        if (aGrandParent)
+          aGrandParent = ModelAPI_Tools::compositeOwner(aParent);
+      } while (aGrandParent.get());
+      if (aParent) {
+        ObjectPtr aFolder = (*anIt)->owner();
+        // remove reference from the current feature
+        aData->removeBackReference(aFolder, ModelAPI_Folder::LAST_FEATURE_ID());
+        // set reference to a top-level parent
+        aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(aParent);
+        std::shared_ptr<Model_Data> aParentData =
+            std::dynamic_pointer_cast<Model_Data>(aParent->data());
+        aParentData->addBackReference(aFolder, ModelAPI_Folder::LAST_FEATURE_ID());
+      }
+    }
+  }
   aData->updateConcealmentFlag();
 }
 
@@ -1415,8 +1484,9 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
       continue;
     }
 
-    aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
-    if (aFoundFolder) {
+    const ObjectPtr& aFolderObj = folder(aCurLabel);
+    if (aFolderObj.get()) {
+      aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aFolderObj);
       AttributeReferencePtr aLastFeatAttr =
           aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
       if (aLastFeatAttr) {
@@ -1544,21 +1614,6 @@ bool Model_Objects::moveToFolder(
   return true;
 }
 
-static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr)
-{
-  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
-  for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
-    if ((*anIt)->id() != theFolderAttr)
-      continue;
-
-    ObjectPtr anOwner = (*anIt)->owner();
-    FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(anOwner);
-    if (aFolder.get())
-      return aFolder;
-  }
-  return FolderPtr();
-}
-
 static FolderPtr isExtractionCorrect(const FolderPtr& theFirstFeatureFolder,
                                      const FolderPtr& theLastFeatureFolder,
                                      bool& isExtractBefore)
@@ -1679,19 +1734,31 @@ FolderPtr Model_Objects::findContainingFolder(const FeaturePtr& theFeature, int&
 
   for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex) {
     TDF_Label aCurLabel = aRefs->Value(aRefIndex);
-    if (isSkippedFeature(feature(aCurLabel)))
-      continue;
 
     if (aFoundFolder)
       ++theIndexInFolder;
 
-    if (aCurLabel == aLabelToFind) // the feature is reached
+    if (aCurLabel == aLabelToFind) { // the feature is reached
+      if (aFoundFolder) {
+        if (isSkippedFeature(theFeature)) {
+          theIndexInFolder = -1;
+          return FolderPtr();
+        }
+        // decrease the index of the feature in the folder by the number of skipped features
+        for (int anIndex = theIndexInFolder - 1; anIndex > 0; anIndex--) {
+          aCurLabel = aRefs->Value(aRefIndex - anIndex);
+          if (isSkippedFeature(feature(aCurLabel)))
+            theIndexInFolder--;
+        }
+      }
       return aFoundFolder;
+    }
 
     if (!aFoundFolder) {
       // if the current label refers to a folder, feel all necessary data
-      aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
-      if (aFoundFolder) {
+      const ObjectPtr& aFolderObj = folder(aCurLabel);
+      if (aFolderObj.get()) {
+        aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aFolderObj);
         theIndexInFolder = -1;
 
         AttributeReferencePtr aLastRef =
@@ -1874,9 +1941,16 @@ FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theRever
   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
   if (aData.get() && aData->isValid()) {
     TDF_Label aFeatureLabel = aData->label().Father();
-    TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse);
-    if (!aNextLabel.IsNull())
-      return feature(aNextLabel);
+    do {
+      TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse);
+      if (aNextLabel.IsNull())
+        break; // last or something is wrong
+      FeaturePtr aFound = feature(aNextLabel);
+      if (aFound)
+        return aFound; // the feature is found
+      // if the next label is a folder, skip it
+      aFeatureLabel = folder(aNextLabel).get() ? aNextLabel : TDF_Label();
+    } while (!aFeatureLabel.IsNull());
   }
   return FeaturePtr(); // not found, last, or something is wrong
 }
@@ -1894,6 +1968,11 @@ FeaturePtr Model_Objects::lastFeature()
 {
   Handle(TDataStd_ReferenceArray) aRefs;
   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+    FeaturePtr aLast = feature(aRefs->Value(aRefs->Upper()));
+    if (!aLast.get() && aRefs->Length() != 0) { // erase the invalid feature from the array
+      RemoveFromRefArray(featuresLabel(), aRefs->Value(aRefs->Upper()));
+      return lastFeature(); // try once again, after the last was removed
+    }
     return feature(aRefs->Value(aRefs->Upper()));
   }
   return FeaturePtr(); // no features at all