Salome HOME
Ability to get index of the objects according to foldering (Task 2.3. Ability to...
[modules/shaper.git] / src / Model / Model_Objects.cpp
index 1bb70767645a98bcddd7974d21ef481d55343b43..4163c0b513234474e021f9e4a89b34082f397c45 100644 (file)
@@ -1,8 +1,22 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:        Model_Objects.cxx
-// Created:     15 May 2015
-// Author:      Mikhail PONIKAROV
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
 
 #include <Model_Objects.h>
 #include <Model_Data.h>
@@ -14,6 +28,7 @@
 #include <Model_ResultBody.h>
 #include <Model_ResultCompSolid.h>
 #include <Model_ResultGroup.h>
+#include <Model_ResultField.h>
 #include <Model_ResultParameter.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <TDF_LabelMap.hxx>
 #include <TDF_ListIteratorOfLabelList.hxx>
 
+static const std::string& groupNameFoldering(const std::string& theGroupID,
+                                             const bool theAllowFolder)
+{
+  if (theAllowFolder) {
+    static const std::string anOutOfFolderName = std::string("__") + ModelAPI_Feature::group();
+    static const std::string aDummyName;
+    return theGroupID == ModelAPI_Feature::group() ? anOutOfFolderName : aDummyName;
+  }
+  return theGroupID;
+}
+
+
 static const int TAG_OBJECTS = 2;  // tag of the objects sub-tree (features, results)
 
 // feature sub-labels
@@ -54,7 +81,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);
+  synchronizeFeatures(aNoUpdated, true, true, true, true);
   myHistory.clear();
 }
 
@@ -74,10 +101,18 @@ Model_Objects::~Model_Objects()
     ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group());
     ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
     aFeature->removeResults(0, false);
-    //aFeature->eraseResults();
     aFeature->erase();
     myFeatures.UnBind(aFeaturesIter.Key());
   }
+  while (!myFolders.IsEmpty()) {
+    NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator aFoldersIter(myFolders);
+    ObjectPtr aFolder = aFoldersIter.Value();
+    static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+    ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Folder::group());
+    ModelAPI_EventCreator::get()->sendUpdated(aFolder, EVENT_DISP);
+    aFolder->erase();
+    myFolders.UnBind(aFoldersIter.Key());
+  }
   myHistory.clear();
   aLoop->activateFlushes(isActive);
   // erase update, because features are destroyed and update should not performed for them anywhere
@@ -126,7 +161,7 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
     // in initData it creates new features, appeared later than this
     TDF_Label aPrevFeateureLab;
     if (theAfterThis.get()) { // searching for the previous feature label
-      std::shared_ptr<Model_Data> aPrevData = 
+      std::shared_ptr<Model_Data> aPrevData =
         std::dynamic_pointer_cast<Model_Data>(theAfterThis->data());
       if (aPrevData.get()) {
         aPrevFeateureLab = aPrevData->label().Father();
@@ -161,7 +196,7 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
 /// Appends to the array of references a new referenced label.
 /// If theIndex is not -1, removes element at this index, not theReferenced.
 /// \returns the index of removed element
-static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, 
+static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced,
   const int theIndex = -1)
 {
   int aResult = -1;  // no returned
@@ -200,7 +235,7 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature,
   std::list<ResultPtr>::const_iterator aResIter = aResults.cbegin();
   for (; aResIter != aResults.cend(); aResIter++) {
     ResultPtr aResult = (*aResIter);
-    std::shared_ptr<Model_Data> aData = 
+    std::shared_ptr<Model_Data> aData =
         std::dynamic_pointer_cast<Model_Data>(aResult->data());
     if (aData.get() != NULL) {
       const std::set<AttributePtr>& aRefs = aData->refsToMe();
@@ -213,7 +248,7 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature,
     }
   }
   // the dependencies can be in the feature itself
-  std::shared_ptr<Model_Data> aData = 
+  std::shared_ptr<Model_Data> aData =
       std::dynamic_pointer_cast<Model_Data>(theFeature->data());
   if (aData.get() && !aData->refsToMe().empty()) {
     const std::set<AttributePtr>& aRefs = aData->refsToMe();
@@ -226,7 +261,7 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature,
   }
 
   if (!theRefs.empty() && isSendError) {
-    Events_InfoMessage("Model_Objects", 
+    Events_InfoMessage("Model_Objects",
       "Feature '%1' is used and can not be deleted").arg(theFeature->data()->name()).send();
   }
 }
@@ -240,7 +275,7 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
     refsToFeature(theFeature, aRefs, false);
     std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aRefIter = aRefs.begin();
     for(; aRefIter != aRefs.end(); aRefIter++) {
-      std::shared_ptr<ModelAPI_CompositeFeature> aComposite = 
+      std::shared_ptr<ModelAPI_CompositeFeature> aComposite =
         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
       if (aComposite.get() && aComposite->isSub(theFeature)) {
         aComposite->removeFeature(theFeature);
@@ -269,18 +304,46 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
   }
 }
 
+void Model_Objects::eraseAllFeatures()
+{
+  static Events_ID kDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  static const ModelAPI_EventCreator* kCreator = ModelAPI_EventCreator::get();
+  // make all features invalid (like deleted)
+  NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
+  for(; aFIter.More(); aFIter.Next()) {
+    FeaturePtr aFeature = aFIter.Value();
+    std::list<ResultPtr> aResList;
+    ModelAPI_Tools::allResults(aFeature, aResList);
+    std::list<ResultPtr>::iterator aRIter = aResList.begin();
+    for(; aRIter != aResList.end(); aRIter++) {
+      ResultPtr aRes = *aRIter;
+      if (aRes && aRes->data()->isValid()) {
+        kCreator->sendDeleted(myDoc, aRes->groupName());
+        kCreator->sendUpdated(aRes, kDispEvent);
+        aRes->setData(aRes->data()->invalidPtr());
+
+      }
+    }
+    kCreator->sendUpdated(aFeature, kDispEvent);
+    aFeature->setData(aFeature->data()->invalidPtr());
+  }
+  kCreator->sendDeleted(myDoc, ModelAPI_Feature::group());
+  myFeatures.Clear(); // just remove features without modification of DS
+  updateHistory(ModelAPI_Feature::group());
+}
+
 void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
 {
   TDF_Label aFeaturesLab = featuresLabel();
   Handle(TDataStd_ReferenceArray) aRefs;
   if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
     return;
-  TDF_Label anAfterLab, aMovedLab = 
+  TDF_Label anAfterLab, aMovedLab =
     std::dynamic_pointer_cast<Model_Data>(theMoved->data())->label().Father();
   if (theAfterThis.get())
     anAfterLab = std::dynamic_pointer_cast<Model_Data>(theAfterThis->data())->label().Father();
 
-  Handle(TDataStd_HLabelArray1) aNewArray = 
+  Handle(TDataStd_HLabelArray1) aNewArray =
     new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper());
   int aPassedMovedFrom = 0; // the prev feature location is found and passed
   int aPassedMovedTo = 0; // the feature is added and this location is passed
@@ -316,8 +379,8 @@ void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
   // update the feature and the history
   clearHistory(theMoved);
   // make sure all (selection) attributes of moved feature will be updated
-  static Events_ID EVENT_UPD = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED);
-  ModelAPI_EventCreator::get()->sendUpdated(theMoved, EVENT_UPD);
+  static Events_ID kUpdateSelection = Events_Loop::loop()->eventByName(EVENT_UPDATE_SELECTION);
+  ModelAPI_EventCreator::get()->sendUpdated(theMoved, kUpdateSelection, false);
   ModelAPI_EventCreator::get()->sendReordered(theMoved);
 }
 
@@ -325,14 +388,13 @@ 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);
       if (!aResultGroup.empty()) {
-        std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = 
+        std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter =
           myHistory.find(aResultGroup);
         if (aHIter != myHistory.end())
           myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
@@ -345,24 +407,34 @@ void Model_Objects::createHistory(const std::string& theGroupID)
 {
   std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroupID);
   if (aHIter == myHistory.end()) {
-    std::vector<ObjectPtr> aResult = std::vector<ObjectPtr>();
+    std::vector<ObjectPtr> aResult;
+    std::vector<ObjectPtr> aResultOutOfFolder;
+    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++) {
         FeaturePtr aFeature = feature(aRefs->Value(a));
         if (aFeature.get()) {
-          // if feature is in sub-component, remove it from history: it is in sub-tree of sub-component
-          if (!ModelAPI_Tools::compositeOwner(aFeature).get()) {
-            if (isFeature) { // here may be also disabled features
-              if (aFeature->isInHistory()) {
-                aResult.push_back(aFeature);
-              }
-            } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
+          // if feature is in sub-component, remove it from history:
+          // it is in sub-tree of sub-component
+          bool isSub = ModelAPI_Tools::compositeOwner(aFeature).get() != NULL;
+          if (isFeature) { // here may be also disabled features
+            if (!isSub && aFeature->isInHistory()) {
+              aResult.push_back(aFeature);
+              // the feature is out of the folders
+              if (aLastFeatureInFolder.get() == NULL)
+                aResultOutOfFolder.push_back(aFeature);
+            }
+          } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
+            // construction results of sub-features should not be in the tree
+            if (!isSub || theGroupID != ModelAPI_ResultConstruction::group()) {
               // do not use reference to the list here since results can be changed by "isConcealed"
               const std::list<std::shared_ptr<ModelAPI_Result> > aResults = aFeature->results();
-              std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
+              std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator
+                aRIter = aResults.begin();
               for (; aRIter != aResults.cend(); aRIter++) {
                 ResultPtr aRes = *aRIter;
                 if (aRes->groupName() != theGroupID) break; // feature have only same group results
@@ -372,12 +444,40 @@ void Model_Objects::createHistory(const std::string& theGroupID)
               }
             }
           }
+
+          // the feature closes the folder, so the next features will be treated as out-of-folder
+          if (aLastFeatureInFolder.get() && aLastFeatureInFolder == aFeature)
+            aLastFeatureInFolder = FeaturePtr();
+
+        } else {
+          // it may be a folder
+          ObjectPtr aFolder = folder(aRefs->Value(a));
+          if (aFolder.get()) {
+            // 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 =
+                aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+            if (aLastFeatAttr)
+              aLastFeatureInFolder = ModelAPI_Feature::feature(aLastFeatAttr->value());
+          }
         }
       }
     }
     // to be sure that isConcealed did not update the history (issue 1089) during the iteration
-    if (myHistory.find(theGroupID) == myHistory.end())
+    if (myHistory.find(theGroupID) == myHistory.end()) {
       myHistory[theGroupID] = aResult;
+
+      // store the features placed out of any folder
+      const std::string& anOutOfFolderGroupID = groupNameFoldering(theGroupID, true);
+      if (!anOutOfFolderGroupID.empty())
+        myHistory[anOutOfFolderGroupID] = aResultOutOfFolder;
+    }
   }
 }
 
@@ -389,8 +489,21 @@ 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
+{
+  if (myFolders.IsBound(theLabel))
+    return myFolders.Find(theLabel);
+  return ObjectPtr();
 }
 
 FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
@@ -443,12 +556,15 @@ ObjectPtr Model_Objects::object(TDF_Label theLabel)
   return FeaturePtr();  // not found
 }
 
-ObjectPtr Model_Objects::object(const std::string& theGroupID, const int theIndex)
+ObjectPtr Model_Objects::object(const std::string& theGroupID,
+                                const int theIndex,
+                                const bool theAllowFolder)
 {
   if (theIndex == -1)
     return ObjectPtr();
   createHistory(theGroupID);
-  return myHistory[theGroupID][theIndex];
+  const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
+  return aGroupID.empty() ? myHistory[theGroupID][theIndex] : myHistory[aGroupID][theIndex];
 }
 
 std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
@@ -472,7 +588,8 @@ std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
         if (aRIter->get() && (*aRIter)->groupName() == theGroupID) {
           if ((*aRIter)->data()->name() == theName)
             return *aRIter;
-          ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
+          ResultCompSolidPtr aCompRes =
+            std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
           if (aCompRes.get()) {
             int aNumSubs = aCompRes->numberOfSubs();
             for(int a = 0; a < aNumSubs; a++) {
@@ -491,10 +608,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++) {
@@ -505,10 +631,11 @@ const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
   return -1;
 }
 
-int Model_Objects::size(const std::string& theGroupID)
+int Model_Objects::size(const std::string& theGroupID, const bool theAllowFolder)
 {
   createHistory(theGroupID);
-  return int(myHistory[theGroupID].size());
+  const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
+  return aGroupID.empty() ? int(myHistory[theGroupID].size()) : int(myHistory[aGroupID].size());
 }
 
 void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
@@ -540,6 +667,13 @@ TDF_Label Model_Objects::featuresLabel() const
   return myMain.FindChild(TAG_OBJECTS);
 }
 
+static std::string composeName(const std::string& theFeatureKind, const int theIndex)
+{
+  std::stringstream aNameStream;
+  aNameStream << theFeatureKind << "_" << theIndex;
+  return aNameStream.str();
+}
+
 void Model_Objects::setUniqueName(FeaturePtr theFeature)
 {
   if (!theFeature->data()->name().empty())
@@ -553,9 +687,7 @@ void Model_Objects::setUniqueName(FeaturePtr theFeature)
       aNumObjects++;
   }
   // generate candidate name
-  std::stringstream aNameStream;
-  aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
-  aName = aNameStream.str();
+  aName = composeName(theFeature->getKind(), aNumObjects + 1);
   // check this is unique, if not, increase index by 1
   for (aFIter.Initialize(myFeatures); aFIter.More();) {
     FeaturePtr aFeature = aFIter.Value();
@@ -570,9 +702,7 @@ void Model_Objects::setUniqueName(FeaturePtr theFeature)
 
     if (isSameName) {
       aNumObjects++;
-      std::stringstream aNameStream;
-      aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
-      aName = aNameStream.str();
+      aName = composeName(theFeature->getKind(), aNumObjects + 1);
       // reinitialize iterator to make sure a new name is unique
       aFIter.Initialize(myFeatures);
     } else
@@ -581,6 +711,28 @@ void Model_Objects::setUniqueName(FeaturePtr theFeature)
   theFeature->data()->setName(aName);
 }
 
+void Model_Objects::setUniqueName(FolderPtr theFolder)
+{
+  if (!theFolder->name().empty())
+    return; // name is already defined
+
+  int aNbFolders = myFolders.Size();
+  std::string aName = composeName(ModelAPI_Folder::ID(), aNbFolders);
+
+  // check the uniqueness of the name
+  NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator anIt(myFolders);
+  while (anIt.More()) {
+    if (anIt.Value()->data()->name() == aName) {
+      aName = composeName(ModelAPI_Folder::ID(), aNbFolders);
+      // reinitialize iterator to make sure a new name is unique
+      anIt.Initialize(myFolders);
+    } else
+      anIt.Next();
+  }
+
+  theFolder->data()->setName(aName);
+}
+
 void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag)
 {
   std::shared_ptr<Model_Data> aData(new Model_Data);
@@ -591,6 +743,10 @@ void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTa
   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
   if (aFeature.get()) {
     setUniqueName(aFeature);  // must be before "initAttributes" because duplicate part uses name
+  } else { // is it a folder?
+    FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(theObj);
+    if (aFolder)
+      setUniqueName(aFolder);
   }
   theObj->initAttributes();
 }
@@ -605,8 +761,8 @@ std::shared_ptr<ModelAPI_Feature> Model_Objects::featureById(const int theId)
 }
 
 void Model_Objects::synchronizeFeatures(
-  const TDF_LabelList& theUpdated, const bool theUpdateReferences, 
-  const bool theOpen, const bool theFlush)
+  const TDF_LabelList& theUpdated, const bool theUpdateReferences,
+  const bool theExecuteFeatures, const bool theOpen, const bool theFlush)
 {
   Model_Document* anOwner = std::dynamic_pointer_cast<Model_Document>(myDoc).get();
   if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize
@@ -643,7 +799,8 @@ void Model_Objects::synchronizeFeatures(
       aFeature = std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get())->createFeature(
         TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
         .ToCString(), anOwner);
-      if (!aFeature.get()) {  // somethig is wrong, most probably, the opened document has invalid structure
+      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();
         aLabIter.Value()->Label().ForgetAllAttributes();
         continue;
@@ -661,8 +818,16 @@ void Model_Objects::synchronizeFeatures(
       aFeature = myFeatures.Find(aFeatureLabel);
       aKeptFeatures.insert(aFeature);
       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("");
+          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") { // if parameters are changed, update the results (issue 937)
+        if (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();
           for (; aRIter != aResults.cend(); aRIter++) {
@@ -692,7 +857,8 @@ void Model_Objects::synchronizeFeatures(
         updateHistory(aFeature);
         aFeature->erase();
 
-        // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
+        // unbind after the "erase" call: on abort sketch
+        // is removes sub-objects that corrupts aFIter
         myFeatures.UnBind(aFIter.Key());
         // reinitialize iterator because unbind may corrupt the previous order in the map
         aFIter.Initialize(myFeatures);
@@ -703,52 +869,50 @@ void Model_Objects::synchronizeFeatures(
   if (theUpdateReferences) {
     synchronizeBackRefs();
   }
-  // update results of the features (after features created because they may be connected, like sketch and sub elements)
-  // After synchronisation of back references because sketch must be set in sub-elements before "execute" by updateResults
-  std::list<FeaturePtr> aComposites; // composites must be updated after their subs (issue 360)
+  // update results of the features (after features created because
+  // they may be connected, like sketch and sub elements)
+  // After synchronisation of back references because sketch
+  // must be set in sub-elements before "execute" by updateResults
+  std::set<FeaturePtr> aProcessed; // composites must be updated after their subs (issue 360)
   TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
   for (; aLabIter2.More(); aLabIter2.Next()) {
     TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
     if (myFeatures.IsBound(aFeatureLabel)) {  // a new feature is inserted
       FeaturePtr aFeature = myFeatures.Find(aFeatureLabel);
-      if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature).get())
-        aComposites.push_back(aFeature);
-      updateResults(aFeature);
+      updateResults(aFeature, aProcessed);
     }
   }
-  std::list<FeaturePtr>::iterator aComposite = aComposites.begin();
-  for(; aComposite != aComposites.end(); aComposite++) {
-    updateResults(*aComposite);
-  }
-
-  // the synchronize should be done after updateResults in order to correct back references of updated results
+  // the synchronize should be done after updateResults
+  // in order to correct back references of updated results
   if (theUpdateReferences) {
     synchronizeBackRefs();
   }
-  if (!theUpdated.IsEmpty()) { // this means there is no control what was modified => remove history cash
+  if (!theUpdated.IsEmpty()) {
+    // this means there is no control what was modified => remove history cash
     myHistory.clear();
   }
 
-  if (theOpen)
+  if (theExecuteFeatures)
     anOwner->executeFeatures() = false;
   aLoop->activateFlushes(isActive);
 
   if (theFlush) {
     aLoop->flush(aDeleteEvent);
-    aLoop->flush(aCreateEvent); // delete should be emitted before create to reacts to aborted feature
+    // delete should be emitted before create to reacts to aborted feature
+    aLoop->flush(aCreateEvent);
     aLoop->flush(anUpdateEvent);
     aLoop->flush(aCreateEvent); // after update of features, there could be results created
     aLoop->flush(aDeleteEvent); // or deleted
     aLoop->flush(aRedispEvent);
     aLoop->flush(aToHideEvent);
   }
-  if (theOpen)
+  if (theExecuteFeatures)
     anOwner->executeFeatures() = true;
 }
 
 /// synchronises back references for the given object basing on the collected data
 void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& theNewRefs,
-  ObjectPtr theObject) 
+  ObjectPtr theObject)
 {
   if (!theObject.get() || !theObject->data()->isValid())
     return; // invalid
@@ -765,14 +929,16 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& t
     std::set<AttributePtr>::iterator aCurrentIter = aData->refsToMe().begin();
     while(aCurrentIter != aData->refsToMe().end()) {
       if (theNewRefs.find(*aCurrentIter) == theNewRefs.end()) {
-        // for external references from other documents this system is not working: refs are collected from
-        // different Model_Objects, so before remove check this external object exists and still referenced
+        // for external references from other documents this system
+        // is not working: refs are collected from
+        // different Model_Objects, so before remove check this
+        // external object exists and still referenced
         bool aLeaveIt = false;
         if ((*aCurrentIter)->owner().get() && (*aCurrentIter)->owner()->document() != myDoc &&
             (*aCurrentIter)->owner()->data().get() && (*aCurrentIter)->owner()->data()->isValid()) {
           std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aRefs;
           (*aCurrentIter)->owner()->data()->referencesToObjects(aRefs);
-          std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >::iterator
+          std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> >>>::iterator
             aRefIter = aRefs.begin();
           for(; aRefIter != aRefs.end(); aRefIter++) {
             if ((*aCurrentIter)->id() == aRefIter->first) {
@@ -860,7 +1026,8 @@ void Model_Objects::synchronizeBackRefs()
       (*aRIter)->isConcealed();
     }
   }
-  // the rest all refs means that feature references to the external document feature: process also them
+  // the rest all refs means that feature references to the external document feature:
+  // process also them
   std::map<ObjectPtr, std::set<AttributePtr> >::iterator anExtIter = allRefs.begin();
   for(; anExtIter != allRefs.end(); anExtIter++) {
     synchronizeBackRefsForObject(anExtIter->second, anExtIter->first);
@@ -868,27 +1035,64 @@ void Model_Objects::synchronizeBackRefs()
 }
 
 TDF_Label Model_Objects::resultLabel(
-  const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theResultIndex) 
+  const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theResultIndex)
 {
-  const std::shared_ptr<Model_Data>& aData = 
+  const std::shared_ptr<Model_Data>& aData =
     std::dynamic_pointer_cast<Model_Data>(theFeatureData);
   return aData->label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1);
 }
 
+bool Model_Objects::hasCustomName(DataPtr theFeatureData,
+                                  ResultPtr theResult,
+                                  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());
+
+    // 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();
+    return false;
+  }
+
+  theParentName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex);
+  return true;
+}
+
 void Model_Objects::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
-                                 std::shared_ptr<ModelAPI_Result> theResult,
-                                 const int theResultIndex)
+                                std::shared_ptr<ModelAPI_Result> theResult,
+                                const int theResultIndex)
 {
   theResult->init();
   theResult->setDoc(myDoc);
   initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS);
-  if (theResult->data()->name().empty()) {  // if was not initialized, generate event and set a name
-    std::stringstream aNewName;
-    aNewName<<theFeatureData->name();
-    // if there are several results (issue #899: any number of result), add unique prefix starting from second
-    if (theResultIndex > 0 || theResult->groupName() == ModelAPI_ResultBody::group())
-      aNewName<<"_"<<theResultIndex + 1;
-    theResult->data()->setName(aNewName.str());
+  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)) {
+      std::stringstream aName;
+      aName << aNewName;
+      // if there are several results (issue #899: any number of result),
+      // add unique prefix starting from second
+      if (theResultIndex > 0 || theResult->groupName() == ModelAPI_ResultBody::group())
+        aName << "_" << theResultIndex + 1;
+      aNewName = aName.str();
+    }
+    theResult->data()->setName(aNewName);
   }
 }
 
@@ -913,7 +1117,7 @@ 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: 
+  // 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;
@@ -982,6 +1186,23 @@ std::shared_ptr<ModelAPI_ResultGroup> Model_Objects::createGroup(
   return aResult;
 }
 
+std::shared_ptr<ModelAPI_ResultField> Model_Objects::createField(
+    const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
+{
+  TDF_Label aLab = resultLabel(theFeatureData, theIndex);
+  TDataStd_Comment::Set(aLab, ModelAPI_ResultField::group().c_str());
+  ObjectPtr anOldObject = object(aLab);
+  std::shared_ptr<ModelAPI_ResultField> aResult;
+  if (anOldObject.get()) {
+    aResult = std::dynamic_pointer_cast<ModelAPI_ResultField>(anOldObject);
+  }
+  if (!aResult.get()) {
+    aResult = std::shared_ptr<ModelAPI_ResultField>(new Model_ResultField(theFeatureData));
+    storeResult(theFeatureData, aResult, theIndex);
+  }
+  return aResult;
+}
+
 std::shared_ptr<ModelAPI_ResultParameter> Model_Objects::createParameter(
       const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
@@ -999,6 +1220,229 @@ std::shared_ptr<ModelAPI_ResultParameter> Model_Objects::createParameter(
   return aResult;
 }
 
+std::shared_ptr<ModelAPI_Folder> Model_Objects::createFolder(
+    const std::shared_ptr<ModelAPI_Feature>& theBeforeThis)
+{
+  FolderPtr aFolder(new ModelAPI_Folder);
+  if (!aFolder)
+    return aFolder;
+
+  TDF_Label aFeaturesLab = featuresLabel();
+  TDF_Label aFolderLab = aFeaturesLab.NewChild();
+  // store feature in the features array: before "initData" because in macro features
+  // in initData it creates new features, appeared later than this
+  TDF_Label aPrevFeatureLab;
+  if (theBeforeThis.get()) { // searching for the previous feature label
+    std::shared_ptr<Model_Data> aPrevData =
+        std::dynamic_pointer_cast<Model_Data>(theBeforeThis->data());
+    if (aPrevData.get()) {
+      aPrevFeatureLab = nextLabel(aPrevData->label().Father(), true);
+    }
+  } else { // find the label of the last feature
+    Handle(TDataStd_ReferenceArray) aRefs;
+    if (aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+      aPrevFeatureLab = aRefs->Value(aRefs->Upper());
+  }
+  AddToRefArray(aFeaturesLab, aFolderLab, aPrevFeatureLab);
+
+  // keep the feature ID to restore document later correctly
+  TDataStd_Comment::Set(aFolderLab, ModelAPI_Folder::ID().c_str());
+  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"
+  initData(aFolder, aFolderLab, TAG_FEATURE_ARGUMENTS);
+  // event: folder is added, must 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);
+  ModelAPI_EventCreator::get()->sendUpdated(aFolder, anEvent);
+
+  return aFolder;
+}
+
+void Model_Objects::removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder)
+{
+  /// \todo
+}
+
+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;
+}
+
+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 (!aLastFeatureInFolder.IsNull()) {
+      if (IsEqual(aCurLabel, aLastFeatureInFolder))
+        aLastFeatureInFolder.Nullify(); // the last feature in the folder is achived
+      continue;
+    }
+
+    aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
+    if (aFoundFolder) {
+      AttributeReferencePtr aLastFeatAttr =
+          aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+      if (aLastFeatAttr && aLastFeatAttr->isInitialized()) {
+        // 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()) {
+    // check the next object is a folder
+    TDF_Label aLabel = aRefs->Value(aRefIndex + 1);
+    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);
+    TDF_Label aFeatureLabel;
+
+    aLimitingFeature = limitingFeature(aFeatures, theBelow);
+    aData = std::static_pointer_cast<Model_Data>(aLimitingFeature->data());
+    if (aData && aData->isValid())
+      aFeatureLabel = aData->label().Father();
+
+    if (!IsEqual(aCurLabel, aFeatureLabel))
+      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;
+
+  // 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);
+  } else {
+    // update last feature of the folder
+    AttributeReferencePtr aLastFeatAttr =
+        theFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+    aLastFeatAttr->setValue(theFeatures.back());
+  }
+
+  updateHistory(ModelAPI_Feature::group());
+  return true;
+}
+
+bool Model_Objects::removeFromFolder(
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures)
+{
+  /// \todo
+  return false;
+}
+
+
 std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
     const std::shared_ptr<ModelAPI_Result>& theResult)
 {
@@ -1031,8 +1475,22 @@ std::string Model_Objects::featureResultGroup(FeaturePtr theFeature)
   return anEmpty; // not found
 }
 
-void Model_Objects::updateResults(FeaturePtr theFeature)
+void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& theProcessed)
 {
+  if (theProcessed.find(theFeature) != theProcessed.end())
+    return;
+  theProcessed.insert(theFeature);
+  // for composites update subs recursively (sketch elements results are needed for the sketch)
+  CompositeFeaturePtr aComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+  if (aComp.get() && aComp->getKind() != "Part") { // don't go inside of parts sub-features
+    // update subs of composites first
+    int aSubNum = aComp->numberOfSubs();
+    for(int a = 0; a < aSubNum; a++) {
+      FeaturePtr aSub = aComp->subFeature(a);
+      updateResults(aComp->subFeature(a), theProcessed);
+    }
+  }
+
   // 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
@@ -1041,7 +1499,7 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(*aResIter);
     if (aBody.get()) {
       std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(aBody->data());
-      if (!aData.get() || !aData->isValid() || (!aBody->isDisabled() && aData->isDeleted())) { 
+      if (!aData.get() || !aData->isValid() || (!aBody->isDisabled() && aData->isDeleted())) {
         // found a disappeared result => remove it
         theFeature->eraseResultFromList(aBody);
         // start iterate from beginning because iterator is corrupted by removing
@@ -1065,23 +1523,23 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
       TDF_Label anArgLab = aLabIter.Value();
       Handle(TDataStd_Comment) aGroup;
       if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
-        if (aGroup->Get() == ModelAPI_ResultBody::group().c_str() || 
+        if (aGroup->Get() == ModelAPI_ResultBody::group().c_str() ||
             aGroup->Get() == ModelAPI_ResultCompSolid::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); 
+          std::shared_ptr<ModelAPI_ResultPart> aNewP = createPart(theFeature->data(), aResIndex);
           theFeature->setResult(aNewP, aResIndex);
           if (!aNewP->partDoc().get())
-            theFeature->execute(); // create the part result: it is better to restore the previous result if it is possible
-          break;
+            // 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
-          break;
         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
           aNewBody = createGroup(theFeature->data(), aResIndex);
+        } else if (aGroup->Get() == ModelAPI_ResultField::group().c_str()) {
+          aNewBody = createField(theFeature->data(), aResIndex);
         } else if (aGroup->Get() == ModelAPI_ResultParameter::group().c_str()) {
           theFeature->attributeChanged("expression"); // just produce a value
-          break;
         } else {
           Events_InfoMessage("Model_Objects", "Unknown type of result is found in the document:")
             .arg(TCollection_AsciiString(aGroup->Get()).ToCString()).send();
@@ -1096,23 +1554,46 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
 
 ResultPtr Model_Objects::findByName(const std::string theName)
 {
+  ResultPtr aResult;
+  FeaturePtr aResFeature; // keep feature to return the latest one
   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator anObjIter(myFeatures);
   for(; anObjIter.More(); anObjIter.Next()) {
     FeaturePtr& aFeature = anObjIter.ChangeValue();
     if (!aFeature.get() || aFeature->isDisabled()) // may be on close
       continue;
-    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::list<ResultPtr> allResults;
+    ModelAPI_Tools::allResults(aFeature, allResults);
+    std::list<ResultPtr>::iterator aRIter = allResults.begin();
+    for (; aRIter != allResults.cend(); aRIter++) {
       ResultPtr aRes = *aRIter;
       if (aRes.get() && aRes->data() && aRes->data()->isValid() && !aRes->isDisabled() &&
-          aRes->data()->name() == theName) {
-        return aRes;
+          aRes->data()->name() == theName)
+      {
+        if (!aResult.get() || isLater(aFeature, aResFeature)) { // select the latest
+          aResult = aRes;
+          aResFeature = aFeature;
+        }
       }
     }
   }
-  // not found
-  return ResultPtr();
+  return aResult;
+}
+
+TDF_Label Model_Objects::nextLabel(TDF_Label theCurrent, const bool theReverse)
+{
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+    for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
+      TDF_Label aCurLab = aRefs->Value(a);
+      if (aCurLab.IsEqual(theCurrent)) {
+        a += theReverse ? -1 : 1;
+        if (a >= aRefs->Lower() && a <= aRefs->Upper())
+          return aRefs->Value(a);
+        break; // finish iiteration: it's last feature
+      }
+    }
+  }
+  return TDF_Label();
 }
 
 FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theReverse)
@@ -1120,18 +1601,9 @@ 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();
-    Handle(TDataStd_ReferenceArray) aRefs;
-    if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
-      for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
-        TDF_Label aCurLab = aRefs->Value(a);
-        if (aCurLab.IsEqual(aFeatureLabel)) {
-          a += theReverse ? -1 : 1;
-          if (a >= aRefs->Lower() && a <= aRefs->Upper())
-            return feature(aRefs->Value(a));
-          break; // finish iiteration: it's last feature
-        }
-      }
-    }
+    TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse);
+    if (!aNextLabel.IsNull())
+      return feature(aNextLabel);
   }
   return FeaturePtr(); // not found, last, or something is wrong
 }
@@ -1179,6 +1651,22 @@ bool Model_Objects::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const
   return false; // not found, or something is wrong
 }
 
+std::list<std::shared_ptr<ModelAPI_Object> > Model_Objects::allObjects()
+{
+  std::list<std::shared_ptr<ModelAPI_Object> > aResult;
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+    for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
+      ObjectPtr anObject = object(aRefs->Value(a));
+      if (!anObject.get()) // is it a folder?
+        anObject = folder(aRefs->Value(a));
+      if (anObject.get())
+        aResult.push_back(anObject);
+    }
+  }
+  return aResult;
+}
+
 std::list<std::shared_ptr<ModelAPI_Feature> > Model_Objects::allFeatures()
 {
   std::list<std::shared_ptr<ModelAPI_Feature> > aResult;