Salome HOME
Fix for issue #2718: Fatal error when open study with box rotated, translated and...
[modules/shaper.git] / src / Model / Model_Objects.cpp
index 1eb9349d564c4485455c2a1a2c81b5ba30a458ce..100ec495fe17690c3aabbd1a8277053680e4861a 100644 (file)
@@ -26,7 +26,6 @@
 #include <Model_ResultPart.h>
 #include <Model_ResultConstruction.h>
 #include <Model_ResultBody.h>
-#include <Model_ResultCompSolid.h>
 #include <Model_ResultGroup.h>
 #include <Model_ResultField.h>
 #include <Model_ResultParameter.h>
@@ -42,7 +41,6 @@
 #include <TDF_ChildIDIterator.hxx>
 #include <TDataStd_ReferenceArray.hxx>
 #include <TDataStd_HLabelArray1.hxx>
-#include <TDataStd_Name.hxx>
 #include <TDF_Reference.hxx>
 #include <TDF_ChildIDIterator.hxx>
 #include <TDF_LabelMapHasher.hxx>
@@ -53,17 +51,29 @@ static const std::string& groupNameFoldering(const std::string& theGroupID,
                                              const bool theAllowFolder)
 {
   if (theAllowFolder) {
-    static std::map<std::string, std::string> aNames;
-    std::map<std::string, std::string>::const_iterator aFound = aNames.find(theGroupID);
-    if (aFound == aNames.end()) {
-      aNames[theGroupID] = std::string("__") + theGroupID;
-      aFound = aNames.find(theGroupID);
-    }
-    return aFound->second;
+    static const std::string anOutOfFolderName = std::string("__") + ModelAPI_Feature::group();
+    static const std::string aDummyName;
+    return theGroupID == ModelAPI_Feature::group() ? anOutOfFolderName : aDummyName;
   }
   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)
 
@@ -85,7 +95,7 @@ void Model_Objects::setOwner(DocumentPtr theDoc)
   myDoc = theDoc;
   // update all fields and recreate features and result objects if needed
   TDF_LabelList aNoUpdated;
-  synchronizeFeatures(aNoUpdated, true, true, true, true);
+  synchronizeFeatures(aNoUpdated, true, false, true, true);
   myHistory.clear();
 }
 
@@ -164,12 +174,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);
 
@@ -187,6 +209,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,10 +309,12 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
     for(; aRefIter != aRefs.end(); aRefIter++) {
       std::shared_ptr<ModelAPI_CompositeFeature> aComposite =
         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
-      if (aComposite.get() && aComposite->isSub(theFeature)) {
+      if (aComposite.get() && aComposite->data()->isValid() && aComposite->isSub(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
@@ -333,7 +363,7 @@ void Model_Objects::eraseAllFeatures()
   }
   kCreator->sendDeleted(myDoc, ModelAPI_Feature::group());
   myFeatures.Clear(); // just remove features without modification of DS
-  updateHistory(ModelAPI_Feature::group());
+  myHistory.clear();
 }
 
 void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
@@ -347,6 +377,9 @@ void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
   if (theAfterThis.get())
     anAfterLab = std::dynamic_pointer_cast<Model_Data>(theAfterThis->data())->label().Father();
 
+  // check whether some folder refers to the moved feature by start or end: if yes, remove from it
+  removeFromFolder(std::list<FeaturePtr>(1, theMoved));
+
   Handle(TDataStd_HLabelArray1) aNewArray =
     new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper());
   int aPassedMovedFrom = 0; // the prev feature location is found and passed
@@ -392,9 +425,8 @@ void Model_Objects::clearHistory(ObjectPtr theObj)
 {
   if (theObj.get()) {
     const std::string aGroup = theObj->groupName();
-    std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(aGroup);
-    if (aHIter != myHistory.end())
-      myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
+    updateHistory(aGroup);
+
     if (theObj->groupName() == ModelAPI_Feature::group()) { // clear results group of the feature
       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
       std::string aResultGroup = featureResultGroup(aFeature);
@@ -417,6 +449,7 @@ void Model_Objects::createHistory(const std::string& theGroupID)
     FeaturePtr aLastFeatureInFolder;
     // iterate the array of references and get feature by feature from the array
     bool isFeature = theGroupID == ModelAPI_Feature::group();
+    bool isFolder = theGroupID == ModelAPI_Folder::group();
     Handle(TDataStd_ReferenceArray) aRefs;
     if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
       for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
@@ -455,9 +488,14 @@ 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()) {
-            aResult.push_back(aFolder);
+            // store folder information for the Features group only
+            if (isFeature || isFolder) {
+              aResult.push_back(aFolder);
+              if (!isFolder)
+                aResultOutOfFolder.push_back(aFolder);
+            }
 
             // get the last feature in the folder
             AttributeReferencePtr aLastFeatAttr =
@@ -474,7 +512,8 @@ void Model_Objects::createHistory(const std::string& theGroupID)
 
       // store the features placed out of any folder
       const std::string& anOutOfFolderGroupID = groupNameFoldering(theGroupID, true);
-      myHistory[anOutOfFolderGroupID] = aResultOutOfFolder;
+      if (!anOutOfFolderGroupID.empty())
+        myHistory[anOutOfFolderGroupID] = aResultOutOfFolder;
     }
   }
 }
@@ -487,15 +526,22 @@ void Model_Objects::updateHistory(const std::shared_ptr<ModelAPI_Object> theObje
 void Model_Objects::updateHistory(const std::string theGroup)
 {
   std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroup);
-  if (aHIter != myHistory.end())
+  if (aHIter != myHistory.end()) {
     myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
+
+    // erase history for the group of objects placed out of any folder
+    const std::string& anOutOfFolderGroupID = groupNameFoldering(theGroup, true);
+    if (!anOutOfFolderGroupID.empty())
+      myHistory.erase(anOutOfFolderGroupID);
+  }
 }
 
-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
@@ -511,41 +557,54 @@ ObjectPtr Model_Objects::object(TDF_Label theLabel)
   FeaturePtr aFeature = feature(theLabel);
   if (aFeature.get())
     return feature(theLabel);
-  TDF_Label aFeatureLabel = theLabel.Father().Father();  // let's suppose it is result
-  aFeature = feature(aFeatureLabel);
-  bool isSubResult = false;
-  if (!aFeature.get() && aFeatureLabel.Depth() > 1) { // let's suppose this is sub-result of result
+  TDF_Label aFeatureLabel = theLabel;  // let's suppose it is result of this feature
+  TDF_LabelList aSubLabs; // sub - labels from higher level to lower level of result
+  while(!aFeature.get() && aFeatureLabel.Depth() > 1) {
+    aSubLabs.Prepend(aFeatureLabel);
     aFeatureLabel = aFeatureLabel.Father().Father();
     aFeature = feature(aFeatureLabel);
-    isSubResult = true;
   }
   if (aFeature.get()) {
-    const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
-    std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
-    for (; aRIter != aResults.cend(); aRIter++) {
-      if (isSubResult) {
-        ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
-        if (aCompRes.get()) {
-          int aNumSubs = aCompRes->numberOfSubs();
-          for(int a = 0; a < aNumSubs; a++) {
-            ResultPtr aSub = aCompRes->subResult(a);
-            if (aSub.get()) {
-              std::shared_ptr<Model_Data> aSubData = std::dynamic_pointer_cast<Model_Data>(
-                  aSub->data());
-              if (aSubData->label().Father().IsEqual(theLabel))
-                return aSub;
+    ResultPtr aCurrentResult;
+    // searching for results then sub-results label by label
+    for(TDF_ListIteratorOfLabelList aSubLab(aSubLabs); aSubLab.More(); aSubLab.Next()) {
+      if (aCurrentResult.get()) { // iterate sub-results of result
+        ResultBodyPtr anOwner = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aCurrentResult);
+        if (!anOwner)
+          return ObjectPtr(); // only Body can have sub-results
+        int a, aNumSubs = anOwner->numberOfSubs();
+        for(a = 0; a < aNumSubs; a++) {
+          ResultPtr aSub = anOwner->subResult(a);
+          if (aSub.get()) {
+            std::shared_ptr<Model_Data> aSubData = std::dynamic_pointer_cast<Model_Data>(
+              aSub->data());
+            const TDF_Label& aSubLabVal = aSubLab.ChangeValue();
+            if (aSubData->label().Father().IsEqual(aSubLabVal)) {
+              aCurrentResult = aSub;
+              break;
             }
           }
         }
-      } else {
-        std::shared_ptr<Model_Data> aResData = std::dynamic_pointer_cast<Model_Data>(
-            (*aRIter)->data());
-        if (aResData->label().Father().IsEqual(theLabel))
-          return *aRIter;
+        if (a == aNumSubs) // not found an appropriate sub-result of result
+          return ObjectPtr();
+      } else { // iterate results of feature
+        const std::list<ResultPtr>& aResults = aFeature->results();
+        std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
+        for(; aRIter != aResults.cend(); aRIter++) {
+          std::shared_ptr<Model_Data> aResData =
+            std::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
+          if (aResData->label().Father().IsEqual(aSubLab.ChangeValue())) {
+            aCurrentResult = *aRIter;
+            break;
+          }
+        }
+        if (aRIter == aResults.cend()) // not found an appropriate result of feature
+          return ObjectPtr();
       }
     }
+    return aCurrentResult;
   }
-  return FeaturePtr();  // not found
+  return ObjectPtr();  // not found
 }
 
 ObjectPtr Model_Objects::object(const std::string& theGroupID,
@@ -554,9 +613,12 @@ ObjectPtr Model_Objects::object(const std::string& theGroupID,
 {
   if (theIndex == -1)
     return ObjectPtr();
+  createHistory(theGroupID);
   const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
-  createHistory(aGroupID);
-  return myHistory[aGroupID][theIndex];
+  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];
 }
 
 std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
@@ -574,24 +636,12 @@ std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
     std::list<std::shared_ptr<ModelAPI_Feature> > allObjs = allFeatures();
     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator anObjIter = allObjs.begin();
     for(; anObjIter != allObjs.end(); anObjIter++) {
-      const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = (*anObjIter)->results();
-      std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
-      for (; aRIter != aResults.cend(); aRIter++) {
-        if (aRIter->get() && (*aRIter)->groupName() == theGroupID) {
-          if ((*aRIter)->data()->name() == theName)
-            return *aRIter;
-          ResultCompSolidPtr aCompRes =
-            std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
-          if (aCompRes.get()) {
-            int aNumSubs = aCompRes->numberOfSubs();
-            for(int a = 0; a < aNumSubs; a++) {
-              ResultPtr aSub = aCompRes->subResult(a);
-              if (aSub.get() && aSub->groupName() == theGroupID) {
-                if (aSub->data()->name() == theName)
-                  return aSub;
-              }
-            }
-          }
+      std::list<ResultPtr> allRes;
+      ModelAPI_Tools::allResults(*anObjIter, allRes);
+      for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
+        if (aRes->get() && (*aRes)->groupName() == theGroupID) {
+          if ((*aRes)->data()->name() == theName)
+            return *aRes;
         }
       }
     }
@@ -600,10 +650,19 @@ std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
   return ObjectPtr();
 }
 
-const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
+const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject,
+                               const bool theAllowFolder)
 {
   std::string aGroup = theObject->groupName();
+  // treat folder as feature
+  if (aGroup == ModelAPI_Folder::group())
+    aGroup = ModelAPI_Feature::group();
   createHistory(aGroup);
+
+  // get the group of features out of folder (if enabled)
+  if (theAllowFolder && !groupNameFoldering(aGroup, theAllowFolder).empty())
+    aGroup = groupNameFoldering(aGroup, theAllowFolder);
+
   std::vector<ObjectPtr>& allObjs = myHistory[aGroup];
   std::vector<ObjectPtr>::iterator anObjIter = allObjs.begin(); // iterate to search object
   for(int anIndex = 0; anObjIter != allObjs.end(); anObjIter++, anIndex++) {
@@ -616,11 +675,26 @@ const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
 
 int Model_Objects::size(const std::string& theGroupID, const bool theAllowFolder)
 {
+  createHistory(theGroupID);
   const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
-  createHistory(aGroupID);
-  return int(myHistory[aGroupID].size());
+  return aGroupID.empty() ? int(myHistory[theGroupID].size()) : int(myHistory[aGroupID].size());
+}
+
+std::shared_ptr<ModelAPI_Object> Model_Objects::parent(
+  const std::shared_ptr<ModelAPI_Object> theChild)
+{
+  if (theChild.get()) {
+    std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theChild->data());
+    TDF_Label aLab = aData->label();
+    if (!aLab.IsNull() && aLab.Depth() > 2) {
+      ObjectPtr anObj = object(aLab.Father().Father().Father());
+      return anObj;
+    }
+  }
+  return ObjectPtr();
 }
 
+
 void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
 {
   // iterate the array of references and get feature by feature from the array
@@ -767,21 +841,28 @@ 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);
   }
 
   // update all objects by checking are they on labels or not
-  std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
+  std::set<ObjectPtr> aNewFeatures, aKeptFeatures;
   TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
   for (; aLabIter.More(); aLabIter.Next()) {
     TDF_Label aFeatureLabel = aLabIter.Value()->Label();
-    FeaturePtr aFeature;
-    if (!myFeatures.IsBound(aFeatureLabel)) {  // a new feature is inserted
+    if (!myFeatures.IsBound(aFeatureLabel) && !myFolders.IsBound(aFeatureLabel)) {
+      // a new feature or folder is inserted
+
+      std::string aFeatureID = TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(
+                               aLabIter.Value())->Get()).ToCString();
+      bool isFolder = aFeatureID == ModelAPI_Folder::ID();
+
+      std::shared_ptr<Model_Session> aSession =
+          std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get());
+
       // create a feature
-      aFeature = std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get())->createFeature(
-        TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
-        .ToCString(), anOwner);
+      ObjectPtr aFeature = isFolder ? ObjectPtr(new ModelAPI_Folder)
+                                    : ObjectPtr(aSession->createFeature(aFeatureID, anOwner));
       if (!aFeature.get()) {
         // somethig is wrong, most probably, the opened document has invalid structure
         Events_InfoMessage("Model_Objects", "Invalid type of object in the document").send();
@@ -790,7 +871,10 @@ void Model_Objects::synchronizeFeatures(
       }
       aFeature->init();
       // this must be before "setData" to redo the sketch line correctly
-      myFeatures.Bind(aFeatureLabel, aFeature);
+      if (isFolder)
+        myFolders.Bind(aFeatureLabel, aFeature);
+      else
+        myFeatures.Bind(aFeatureLabel, std::dynamic_pointer_cast<ModelAPI_Feature>(aFeature));
       aNewFeatures.insert(aFeature);
       initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
       updateHistory(aFeature);
@@ -798,18 +882,25 @@ void Model_Objects::synchronizeFeatures(
       // event: model is updated
       ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
     } else {  // nothing is changed, both iterators are incremented
-      aFeature = myFeatures.Find(aFeatureLabel);
-      aKeptFeatures.insert(aFeature);
+      ObjectPtr anObject;
+      FeaturePtr aFeature;
+      if (myFeatures.Find(aFeatureLabel, aFeature)) {
+        aKeptFeatures.insert(aFeature);
+        anObject = aFeature;
+      } else
+        if (myFolders.Find(aFeatureLabel, anObject))
+          aKeptFeatures.insert(anObject);
+
       if (anUpdatedMap.Contains(aFeatureLabel)) {
         if (!theOpen) { // on abort/undo/redo reinitialize attributes if something is changed
           std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs =
-            aFeature->data()->attributes("");
+            anObject->data()->attributes("");
           std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
           for(; anAttr != anAttrs.end(); anAttr++)
             (*anAttr)->reinit();
         }
-        ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
-        if (aFeature->getKind() == "Parameter") {
+        ModelAPI_EventCreator::get()->sendUpdated(anObject, anUpdateEvent);
+        if (aFeature && aFeature->getKind() == "Parameter") {
           // if parameters are changed, update the results (issue 937)
           const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
           std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
@@ -848,6 +939,26 @@ void Model_Objects::synchronizeFeatures(
     } else
       aFIter.Next();
   }
+  // verify folders are checked: if not => is was removed
+  for (NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator aFldIt(myFolders);
+       aFldIt.More(); aFldIt.Next()) {
+    ObjectPtr aCurObj = aFldIt.Value();
+    if (aKeptFeatures.find(aCurObj) == aKeptFeatures.end() &&
+        aNewFeatures.find(aCurObj) == aNewFeatures.end()) {
+      ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Folder::group());
+      // results of this feature must be redisplayed (hided)
+      // redisplay also removed feature (used for sketch and AISObject)
+      ModelAPI_EventCreator::get()->sendUpdated(aCurObj, aRedispEvent);
+      updateHistory(aCurObj);
+      aCurObj->erase();
+
+      // unbind after the "erase" call: on abort sketch
+      // is removes sub-objects that corrupts aFIter
+      myFolders.UnBind(aFldIt.Key());
+      // reinitialize iterator because unbind may corrupt the previous order in the map
+      aFldIt.Initialize(myFolders);
+    }
+  }
 
   if (theUpdateReferences) {
     synchronizeBackRefs();
@@ -875,8 +986,8 @@ void Model_Objects::synchronizeFeatures(
     myHistory.clear();
   }
 
-  if (theExecuteFeatures)
-    anOwner->executeFeatures() = false;
+  if (!theExecuteFeatures)
+    anOwner->setExecuteFeatures(false);
   aLoop->activateFlushes(isActive);
 
   if (theFlush) {
@@ -889,8 +1000,8 @@ void Model_Objects::synchronizeFeatures(
     aLoop->flush(aRedispEvent);
     aLoop->flush(aToHideEvent);
   }
-  if (theExecuteFeatures)
-    anOwner->executeFeatures() = true;
+  if (!theExecuteFeatures)
+    anOwner->setExecuteFeatures(true);
 }
 
 /// synchronises back references for the given object basing on the collected data
@@ -905,7 +1016,10 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& t
   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());
+      if (aRefFeat)
+        aData->addBackReference(aRefFeat, (*aNewIter)->id());
+      else // add back reference to a folder
+        aData->addBackReference((*aNewIter)->owner(), (*aNewIter)->id());
     }
   }
   if (theNewRefs.size() != aData->refsToMe().size()) { // some back ref must be removed
@@ -941,9 +1055,61 @@ 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();
 }
 
+static void collectReferences(std::shared_ptr<ModelAPI_Data> theData,
+                              std::map<ObjectPtr, std::set<AttributePtr> >& theRefs)
+{
+  if (theData.get()) {
+    std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+    theData->referencesToObjects(aRefs);
+    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::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = theRefs.find(*aRefTo);
+          if (aFound == theRefs.end()) {
+            theRefs[*aRefTo] = std::set<AttributePtr>();
+            aFound = theRefs.find(*aRefTo);
+          }
+          aFound->second.insert(theData->attribute(aRefsIt->first));
+        }
+      }
+    }
+  }
+}
+
 void Model_Objects::synchronizeBackRefs()
 {
   // collect all back references in the separated container: to update everything at once,
@@ -954,25 +1120,12 @@ void Model_Objects::synchronizeBackRefs()
   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()) {
-      std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
-      aFData->referencesToObjects(aRefs);
-      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::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));
-          }
-        }
-      }
-    }
+    collectReferences(aFeature->data(), allRefs);
+  }
+  NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator aFolders(myFolders);
+  for(; aFolders.More(); aFolders.Next()) {
+    ObjectPtr aFolder = aFolders.Value();
+    collectReferences(aFolder->data(), allRefs);
   }
   // second iteration: just compare back-references with existing in features and results
   for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
@@ -1030,30 +1183,36 @@ bool Model_Objects::hasCustomName(DataPtr theFeatureData,
                                   int theResultIndex,
                                   std::string& theParentName) const
 {
-  ResultCompSolidPtr aCompSolidRes =
-      std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theFeatureData->owner());
-  if (aCompSolidRes) {
-    FeaturePtr anOwner = ModelAPI_Feature::feature(theResult->data()->owner());
+  ResultBodyPtr aBodyRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theFeatureData->owner());
+  if (aBodyRes) {
+    // only for top-results (works for the cases when results are not yet added to the feature)
+    FeaturePtr anOwner = ModelAPI_Feature::feature(theResult);
 
     // names of sub-solids in CompSolid should be default (for example,
     // result of boolean operation 'Boolean_1' is a CompSolid which is renamed to 'MyBOOL',
     // however, sub-elements of 'MyBOOL' should be named 'Boolean_1_1', 'Boolean_1_2' etc.)
-    std::ostringstream aDefaultName;
-    aDefaultName << anOwner->name();
-    // compute default name of CompSolid (name of feature + index of CompSolid's result)
-    int aCompSolidResultIndex = 0;
-    const std::list<ResultPtr>& aResults = anOwner->results();
-    for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
-         anIt != aResults.end(); ++anIt, ++aCompSolidResultIndex)
-      if (aCompSolidRes == *anIt)
-        break;
-    aDefaultName << "_" << (aCompSolidResultIndex + 1);
-    theParentName = aDefaultName.str();
+    if (std::dynamic_pointer_cast<Model_Data>(aBodyRes->data())->label().Depth() == 6) {
+      std::ostringstream aDefaultName;
+      // compute default name of CompSolid (name of feature + index of CompSolid's result)
+      int aBodyResultIndex = 0;
+      const std::list<ResultPtr>& aResults = anOwner->results();
+      std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+      for (; anIt != aResults.end(); ++anIt, ++aBodyResultIndex)
+        if (aBodyRes == *anIt)
+          break;
+      aDefaultName << anOwner->name();
+      aDefaultName << "_" << (aBodyResultIndex + 1);
+      theParentName = aDefaultName.str();
+    } else { // just name of the parent result if it is deeper than just a sub-result
+      theParentName = aBodyRes->data()->name();
+    }
     return false;
   }
 
-  theParentName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex);
-  return true;
+  std::pair<std::string, bool> aName = ModelAPI_Tools::getDefaultName(theResult);
+  if (aName.second)
+    theParentName = aName.first;
+  return aName.second;
 }
 
 void Model_Objects::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
@@ -1066,7 +1225,11 @@ void Model_Objects::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
   if (theResult->data()->name().empty()) {
     // if was not initialized, generate event and set a name
     std::string aNewName = theFeatureData->name();
-    if (!hasCustomName(theFeatureData, theResult, theResultIndex, aNewName)) {
+    if (hasCustomName(theFeatureData, theResult, theResultIndex, aNewName)) {
+      // if the name of result is user-defined, then, at first time, assign name of the result
+      // by empty string to be sure that corresponding flag in the data model is set
+      theResult->data()->setName("");
+    } else {
       std::stringstream aName;
       aName << aNewName;
       // if there are several results (issue #899: any number of result),
@@ -1100,27 +1263,14 @@ std::shared_ptr<ModelAPI_ResultBody> Model_Objects::createBody(
     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
-  // for feature create compsolid, but for result sub create body:
-  // only one level of recursion is supported now
-  ResultPtr aResultOwner = std::dynamic_pointer_cast<ModelAPI_Result>(theFeatureData->owner());
-  ObjectPtr anOldObject;
-  if (aResultOwner.get()) {
-    TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
-  } else { // in compsolid (higher level result) old object probably may be found
-    TDataStd_Comment::Set(aLab, ModelAPI_ResultCompSolid::group().c_str());
-    anOldObject = object(aLab);
-  }
+  TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
+  ObjectPtr anOldObject = object(aLab);
   std::shared_ptr<ModelAPI_ResultBody> aResult;
   if (anOldObject.get()) {
     aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
   }
   if (!aResult.get()) {
-    // create compsolid anyway; if it is compsolid, it will create sub-bodies internally
-    if (aResultOwner.get()) {
-      aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
-    } else {
-      aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultCompSolid);
-    }
+    aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
     storeResult(theFeatureData, aResult, theIndex);
   }
   return aResult;
@@ -1233,6 +1383,7 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::createFolder(
   myFolders.Bind(aFolderLab, aFolder);
   // must be before the event sending: for OB the feature is already added
   updateHistory(ModelAPI_Folder::group());
+  updateHistory(ModelAPI_Feature::group());
 
   // must be after binding to the map because of "Box" macro feature that
   // creates other features in "initData"
@@ -1245,6 +1396,401 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::createFolder(
   return aFolder;
 }
 
+void Model_Objects::removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder)
+{
+  std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFolder->data());
+  if (!aData.get() || !aData->isValid())
+    return;
+
+  // this must be before erase since theFolder erasing removes all information about it
+  clearHistory(theFolder);
+  // erase fields
+  theFolder->erase();
+
+  TDF_Label aFolderLabel = aData->label().Father();
+  if (myFolders.IsBound(aFolderLabel))
+    myFolders.UnBind(aFolderLabel);
+
+  static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  ModelAPI_EventCreator::get()->sendUpdated(theFolder, EVENT_DISP);
+  // erase all attributes under the label of feature
+  aFolderLabel.ForgetAllAttributes();
+  // remove it from the references array
+  RemoveFromRefArray(featuresLabel(), aFolderLabel);
+  // event: feature is deleted
+  ModelAPI_EventCreator::get()->sendDeleted(theFolder->document(), ModelAPI_Folder::group());
+  updateHistory(ModelAPI_Folder::group());
+  updateHistory(ModelAPI_Feature::group());
+}
+
+// Returns one of the limiting features of the list
+static FeaturePtr limitingFeature(std::list<FeaturePtr>& theFeatures, const bool isLast)
+{
+  FeaturePtr aFeature;
+  if (isLast) {
+    aFeature = theFeatures.back();
+    theFeatures.pop_back();
+  } else {
+    aFeature = theFeatures.front();
+    theFeatures.pop_front();
+  }
+  return aFeature;
+}
+
+// Verify the feature is sub-element in composite feature or it is not used in the history
+static bool isSkippedFeature(FeaturePtr theFeature)
+{
+  bool isSub = ModelAPI_Tools::compositeOwner(theFeature).get() != NULL;
+  return isSub || (theFeature && !theFeature->isInHistory());
+}
+
+std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const bool theBelow)
+{
+  if (theFeatures.empty())
+    return FolderPtr(); // nothing to move
+
+  TDF_Label aFeaturesLab = featuresLabel();
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+    return FolderPtr(); // no reference array (something is wrong)
+
+  std::list<std::shared_ptr<ModelAPI_Feature> > aFeatures = theFeatures;
+  std::shared_ptr<ModelAPI_Feature> aLimitingFeature = limitingFeature(aFeatures, theBelow);
+
+  std::shared_ptr<Model_Data> aData =
+      std::static_pointer_cast<Model_Data>(aLimitingFeature->data());
+  if (!aData || !aData->isValid())
+    return FolderPtr(); // invalid feature
+
+  // label of the first feature in the list for fast searching
+  TDF_Label aFirstFeatureLabel = aData->label().Father();
+
+  // find a folder above the features and
+  // check the given features represent a sequential list of objects following the folder
+  FolderPtr aFoundFolder;
+  TDF_Label aLastFeatureInFolder;
+  int aRefIndex = aRefs->Lower();
+  for(; aRefIndex <= aRefs->Upper(); ++aRefIndex) { // iterate all existing features
+    TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+    if (IsEqual(aCurLabel, aFirstFeatureLabel))
+      break; // no need to continue searching
+
+    // searching the folder below, just continue to search last feature from the list
+    if (theBelow)
+      continue;
+
+    // if feature is in sub-component, skip it
+    FeaturePtr aCurFeature = feature(aCurLabel);
+    if (isSkippedFeature(aCurFeature))
+      continue;
+
+    if (!aLastFeatureInFolder.IsNull()) {
+      if (IsEqual(aCurLabel, aLastFeatureInFolder))
+        aLastFeatureInFolder.Nullify(); // the last feature in the folder is achived
+      continue;
+    }
+
+    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) {
+        // setup iterating inside a folder to find last feature
+        ObjectPtr aLastFeature = aLastFeatAttr->value();
+        if (aLastFeature) {
+          aData = std::static_pointer_cast<Model_Data>(aLastFeature->data());
+          if (aData && aData->isValid())
+            aLastFeatureInFolder = aData->label().Father();
+        }
+      }
+    }
+  }
+
+  if (theBelow && aRefIndex < aRefs->Upper()) {
+    TDF_Label aLabel;
+    // skip following features which are sub-components or not in history
+    for (int anIndex = aRefIndex + 1; anIndex <= aRefs->Upper(); ++anIndex) {
+      aLabel = aRefs->Value(anIndex);
+      FeaturePtr aCurFeature = feature(aLabel);
+      if (!isSkippedFeature(aCurFeature))
+        break;
+    }
+    // check the next object is a folder
+    aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aLabel));
+  }
+
+  if (!aLastFeatureInFolder.IsNull() || // the last feature of the folder above is not found
+      !aFoundFolder)
+    return FolderPtr();
+
+  // check the given features are sequential list
+  int aStep = theBelow ? -1 : 1;
+  for (aRefIndex += aStep;
+       !aFeatures.empty() && aRefIndex >= aRefs->Lower() && aRefIndex <= aRefs->Upper();
+       aRefIndex += aStep) {
+    TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+    // if feature is in sub-component, skip it
+    FeaturePtr aCurFeature = feature(aCurLabel);
+    if (isSkippedFeature(aCurFeature))
+      continue;
+
+    aLimitingFeature = limitingFeature(aFeatures, theBelow);
+    if (!aCurFeature->data()->isEqual(aLimitingFeature->data()))
+      return FolderPtr(); // not a sequential list
+  }
+
+  return aFoundFolder;
+}
+
+bool Model_Objects::moveToFolder(
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const std::shared_ptr<ModelAPI_Folder>& theFolder)
+{
+  if (theFeatures.empty() || !theFolder)
+    return false;
+
+  // labels for the folder and last feature in the list
+  TDF_Label aFolderLabel, aLastFeatureLabel;
+  std::shared_ptr<Model_Data> aData =
+      std::static_pointer_cast<Model_Data>(theFolder->data());
+  if (aData && aData->isValid())
+    aFolderLabel = aData->label().Father();
+  aData = std::static_pointer_cast<Model_Data>(theFeatures.back()->data());
+  if (aData && aData->isValid())
+    aLastFeatureLabel = aData->label().Father();
+
+  if (aFolderLabel.IsNull() || aLastFeatureLabel.IsNull())
+    return false;
+
+  AttributeReferencePtr aFirstFeatAttr =
+      theFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+  AttributeReferencePtr aLastFeatAttr =
+      theFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+  bool initFirstAttr = !aFirstFeatAttr->value().get();
+  bool initLastAttr  = !aLastFeatAttr->value().get();
+
+  // check the folder is below the list of features
+  bool isFolderBelow = false;
+  TDF_Label aFeaturesLab = featuresLabel();
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+    return false; // no reference array (something is wrong)
+  for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex) {
+    TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+    if (aCurLabel == aFolderLabel)
+      break; // folder is above the features
+    else if (aCurLabel == aLastFeatureLabel) {
+      isFolderBelow = true;
+      break;
+    }
+  }
+
+  if (isFolderBelow) {
+    aData = std::static_pointer_cast<Model_Data>(theFeatures.front()->data());
+    if (!aData || !aData->isValid())
+      return false;
+    TDF_Label aPrevFeatureLabel = aData->label().Father();
+    // label of the feature before the first feature in the list
+    for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex)
+      if (aPrevFeatureLabel == aRefs->Value(aRefIndex)) {
+        if (aRefIndex == aRefs->Lower())
+          aPrevFeatureLabel.Nullify();
+        else
+          aPrevFeatureLabel = aRefs->Value(aRefIndex - 1);
+        break;
+      }
+
+    // move the folder in the list of references before the first feature
+    RemoveFromRefArray(aFeaturesLab, aFolderLabel);
+    AddToRefArray(aFeaturesLab, aFolderLabel, aPrevFeatureLabel);
+    // update first feature of the folder
+    initFirstAttr = true;
+  } else {
+    // update last feature of the folder
+    initLastAttr = true;
+  }
+
+  if (initFirstAttr)
+    aFirstFeatAttr->setValue(theFeatures.front());
+  if (initLastAttr)
+    aLastFeatAttr->setValue(theFeatures.back());
+
+  updateHistory(ModelAPI_Feature::group());
+  return true;
+}
+
+static FolderPtr isExtractionCorrect(const FolderPtr& theFirstFeatureFolder,
+                                     const FolderPtr& theLastFeatureFolder,
+                                     bool& isExtractBefore)
+{
+  if (theFirstFeatureFolder.get()) {
+    if (theLastFeatureFolder.get())
+      return theFirstFeatureFolder == theLastFeatureFolder ? theFirstFeatureFolder : FolderPtr();
+    else
+      isExtractBefore = true;
+    return theFirstFeatureFolder;
+  } else if (theLastFeatureFolder.get()) {
+    isExtractBefore = false;
+    return theLastFeatureFolder;
+  }
+  // no folder found
+  return FolderPtr();
+}
+
+bool Model_Objects::removeFromFolder(
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const bool theBefore)
+{
+  if (theFeatures.empty())
+    return false;
+
+  FolderPtr aFirstFeatureFolder =
+      inFolder(theFeatures.front(), ModelAPI_Folder::FIRST_FEATURE_ID());
+  FolderPtr aLastFeatureFolder =
+      inFolder(theFeatures.back(),  ModelAPI_Folder::LAST_FEATURE_ID());
+
+  bool isExtractBeforeFolder = theBefore;
+  FolderPtr aFoundFolder =
+      isExtractionCorrect(aFirstFeatureFolder, aLastFeatureFolder, isExtractBeforeFolder);
+  if (!aFoundFolder)
+    return false; // list of features cannot be extracted
+
+  // references of the current folder
+  ObjectPtr aFolderStartFeature;
+  ObjectPtr aFolderEndFeature;
+  if (aFirstFeatureFolder != aLastFeatureFolder) {
+    aFolderStartFeature = aFoundFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID())->value();
+    aFolderEndFeature   = aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->value();
+  }
+
+  FeaturePtr aFeatureToFind = isExtractBeforeFolder ? theFeatures.back() : theFeatures.front();
+  std::shared_ptr<Model_Data> aData =
+      std::static_pointer_cast<Model_Data>(aFeatureToFind->data());
+  if (!aData || !aData->isValid())
+    return false;
+  TDF_Label aLabelToFind = aData->label().Father();
+
+  // search the label in the list of references
+  TDF_Label aFeaturesLab = featuresLabel();
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+    return false; // no reference array (something is wrong)
+  int aRefIndex = aRefs->Lower();
+  for (; aRefIndex <= aRefs->Upper(); ++aRefIndex)
+    if (aRefs->Value(aRefIndex) == aLabelToFind)
+      break;
+
+  // update folder position
+  if (isExtractBeforeFolder) {
+    aData = std::dynamic_pointer_cast<Model_Data>(aFoundFolder->data());
+    TDF_Label aFolderLabel = aData->label().Father();
+    TDF_Label aPrevFeatureLabel = aRefs->Value(aRefIndex);
+    // update start reference of the folder
+    if (aFolderStartFeature.get()) {
+      FeaturePtr aNewStartFeature;
+      do { // skip all features placed in the composite features
+        aPrevFeatureLabel = aRefs->Value(aRefIndex++);
+        aNewStartFeature =
+            aRefIndex <= aRefs->Upper() ? feature(aRefs->Value(aRefIndex)) : FeaturePtr();
+      } while (aNewStartFeature && isSkippedFeature(aNewStartFeature));
+      aFolderStartFeature = aNewStartFeature;
+    }
+    // move the folder in the list of references after the last feature from the list
+    RemoveFromRefArray(aFeaturesLab, aFolderLabel);
+    AddToRefArray(aFeaturesLab, aFolderLabel, aPrevFeatureLabel);
+  } else {
+    // update end reference of the folder
+    if (aFolderEndFeature.get()) {
+      FeaturePtr aNewEndFeature;
+      do { // skip all features placed in the composite features
+        --aRefIndex;
+        aNewEndFeature =
+            aRefIndex >= aRefs->Lower() ? feature(aRefs->Value(aRefIndex)) : FeaturePtr();
+      } while (aNewEndFeature && isSkippedFeature(aNewEndFeature));
+      aFolderEndFeature = aNewEndFeature;
+    }
+  }
+
+  // update folder references
+  aFoundFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID())->setValue(aFolderStartFeature);
+  aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(aFolderEndFeature);
+
+  updateHistory(ModelAPI_Feature::group());
+  return true;
+}
+
+FolderPtr Model_Objects::findContainingFolder(const FeaturePtr& theFeature, int& theIndexInFolder)
+{
+  // search the label in the list of references
+  TDF_Label aFeaturesLab = featuresLabel();
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+    return FolderPtr(); // no reference array (something is wrong)
+
+  std::shared_ptr<Model_Data> aData =
+      std::static_pointer_cast<Model_Data>(theFeature->data());
+  if (!aData || !aData->isValid())
+    return FolderPtr();
+  TDF_Label aLabelToFind = aData->label().Father();
+
+  theIndexInFolder = -1;
+  FolderPtr aFoundFolder;
+  TDF_Label aLastFeatureLabel;
+
+  for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex) {
+    TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+
+    if (aFoundFolder)
+      ++theIndexInFolder;
+
+    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
+      const ObjectPtr& aFolderObj = folder(aCurLabel);
+      if (aFolderObj.get()) {
+        aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aFolderObj);
+        theIndexInFolder = -1;
+
+        AttributeReferencePtr aLastRef =
+            aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+        if (aLastRef->value()) {
+          aData = std::static_pointer_cast<Model_Data>(aLastRef->value()->data());
+          if (aData && aData->isValid())
+            aLastFeatureLabel = aData->label().Father();
+        } else // folder is empty
+          aFoundFolder = FolderPtr();
+      }
+    } else if (aLastFeatureLabel == aCurLabel) {
+      // folder is finished, clear all stored data
+      theIndexInFolder = -1;
+      aFoundFolder = FolderPtr();
+    }
+  }
+
+  // folder is not found
+  theIndexInFolder = -1;
+  return FolderPtr();
+}
+
+
 std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
     const std::shared_ptr<ModelAPI_Result>& theResult)
 {
@@ -1252,7 +1798,7 @@ std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
   if (aData.get()) {
     TDF_Label aFeatureLab = aData->label().Father().Father().Father();
     FeaturePtr aFeature = feature(aFeatureLab);
-    if (!aFeature.get() && aFeatureLab.Depth() > 1) { // this may be sub-result of result
+    while(!aFeature.get() && aFeatureLab.Depth() > 1) { // this may be sub-result of result
       aFeatureLab = aFeatureLab.Father().Father();
       aFeature = feature(aFeatureLab);
     }
@@ -1293,8 +1839,6 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& t
     }
   }
 
-  // for not persistent is will be done by parametric updater automatically
-  //if (!theFeature->isPersistentResult()) return;
   // check the existing results and remove them if there is nothing on the label
   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
   while(aResIter != theFeature->results().cend()) {
@@ -1325,17 +1869,23 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& t
       TDF_Label anArgLab = aLabIter.Value();
       Handle(TDataStd_Comment) aGroup;
       if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
-        if (aGroup->Get() == ModelAPI_ResultBody::group().c_str() ||
-            aGroup->Get() == ModelAPI_ResultCompSolid::group().c_str()) {
+        if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) {
           aNewBody = createBody(theFeature->data(), aResIndex);
         } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
-          std::shared_ptr<ModelAPI_ResultPart> aNewP = createPart(theFeature->data(), aResIndex);
-          theFeature->setResult(aNewP, aResIndex);
-          if (!aNewP->partDoc().get())
-            // create the part result: it is better to restore the previous result if it is possible
-            theFeature->execute();
+          if (aResIndex <= theFeature->results().size()) { // to avoid crash if previous execute
+            // for index = 0 erases result
+            std::shared_ptr<ModelAPI_ResultPart> aNewP = createPart(theFeature->data(), aResIndex);
+            theFeature->setResult(aNewP, aResIndex);
+            if (!aNewP->partDoc().get())
+              // create the part result: it is better to restore the previous result if it is possible
+              theFeature->execute();
+          }
         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
-          theFeature->execute(); // construction shapes are needed for sketch solver
+          ResultConstructionPtr aConstr = createConstruction(theFeature->data(), aResIndex);
+          if (!aConstr->updateShape())
+            theFeature->execute(); // not stored shape in the data structure, execute to have it
+          else
+            theFeature->setResult(aConstr, aResIndex); // result is ready without execution
         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
           aNewBody = createGroup(theFeature->data(), aResIndex);
         } else if (aGroup->Get() == ModelAPI_ResultField::group().c_str()) {
@@ -1352,6 +1902,22 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& t
       }
     }
   }
+  if (aResSize > 0) { // check there exist a body that must be updated
+    std::list<ResultPtr>::const_iterator aRes = theFeature->results().cbegin();
+    for (; aResSize && aRes != theFeature->results().cend(); aRes++, aResSize++) {
+      if ((*aRes)->data()->isValid()) {
+        if ((*aRes)->groupName() == ModelAPI_ResultBody::group()) {
+          ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRes);
+          aBody->updateSubs(aBody->shape(), false);
+        } else if ((*aRes)->groupName() == ModelAPI_ResultConstruction::group()) {
+          // update the cashed myShape presented in construction
+          ResultConstructionPtr aConstr =
+            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
+          aConstr->updateShape();
+        }
+      }
+    }
+  }
 }
 
 ResultPtr Model_Objects::findByName(const std::string theName)
@@ -1403,9 +1969,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
 }
@@ -1423,6 +1996,12 @@ FeaturePtr Model_Objects::lastFeature()
 {
   Handle(TDataStd_ReferenceArray) aRefs;
   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+    // comment this because of #2674 - features are removed from array on deactivation of Part
+    /*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