Salome HOME
Update copyrights
[modules/shaper.git] / src / PartSet / PartSet_TreeNodes.cpp
index fad5c0c9d45016990061e58778a2fbbc6e3b1e90..c08539925ec34de2a67ea6c9985c940525bc0739 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2019  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
 //
 // 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
+// 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>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include "PartSet_TreeNodes.h"
+#include "PartSet_Tools.h"
 
 #include <ModuleBase_IconFactory.h>
 #include <ModuleBase_IWorkshop.h>
+#include <ModuleBase_Tools.h>
 
 #include <PartSetPlugin_Part.h>
 
@@ -121,13 +122,12 @@ QVariant PartSet_ObjectNode::data(int theColumn, int theRole) const
         return QIcon(":pictures/eyeclosed.png");
       }
     case 1:
-      if (myObject->groupName() == ModelAPI_Folder::group())
-        return QIcon(":pictures/features_folder.png");
-      else
-        return ModuleBase_IconFactory::get()->getIcon(myObject);
+      return ModuleBase_IconFactory::get()->getIcon(myObject);
     case 2:
       if (isCurrentFeature(myObject))
         return QIcon(":pictures/arrow.png");
+      else
+        return QIcon();
     }
   }
   return PartSet_TreeNode::data(theColumn, theRole);
@@ -159,21 +159,24 @@ PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::visibilityState() const
     ModuleBase_IWorkshop* aWork = workshop();
     ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResObj);
     if (aCompRes.get()) {
-      VisibilityState aState = aCompRes->numberOfSubs(true) == 0 ?
-        (aWork->isVisible(aCompRes) ? Visible : Hidden) : NoneState;
       std::list<ResultPtr> aResultsList;
       ModelAPI_Tools::allSubs(aCompRes, aResultsList);
+      VisibilityState aState = aResultsList.size() == 0 ?
+        (aWork->isVisible(aCompRes) ? Visible : Hidden) : NoneState;
 
       std::list<ResultPtr>::const_iterator aIt;
-      //for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
+      ResultBodyPtr aCompSub;
       for (aIt = aResultsList.cbegin(); aIt != aResultsList.cend(); aIt++) {
-        ResultPtr aSubRes = (*aIt); // aCompRes->subResult(i, true);
-        VisibilityState aS = aWork->isVisible(aSubRes) ? Visible : Hidden;
-        if (aState == NoneState)
-          aState = aS;
-        else if (aState != aS) {
-          aState = SemiVisible;
-          break;
+        ResultPtr aSubRes = (*aIt);
+        aCompSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aSubRes);
+        if (!(aCompSub.get() && aCompSub->numberOfSubs() > 0)) {
+          VisibilityState aS = aWork->isVisible(aSubRes) ? Visible : Hidden;
+          if (aState == NoneState)
+            aState = aS;
+          else if (aState != aS) {
+            aState = SemiVisible;
+            break;
+          }
         }
       }
       return aState;
@@ -187,37 +190,100 @@ PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::visibilityState() const
   return NoneState;
 }
 
-void PartSet_ObjectNode::update()
+int PartSet_ObjectNode::numberOfSubs() const
+{
+  ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
+  if (aCompRes.get())
+   return aCompRes->numberOfSubs(true);
+  else {
+    CompositeFeaturePtr aCompFeature =
+      std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myObject);
+    if (aCompFeature.get() && aCompFeature->data()->isValid())
+      return aCompFeature->numberOfSubs(true);
+    else {
+      ResultFieldPtr aFieldRes = std::dynamic_pointer_cast<ModelAPI_ResultField>(myObject);
+      if (aFieldRes.get())
+        return aFieldRes->stepsSize();
+    }
+  }
+  return 0;
+}
+
+
+ObjectPtr PartSet_ObjectNode::subObject(int theId) const
 {
-  CompositeFeaturePtr aCompFeature;
   ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
-  int aNb = 0;
   if (aCompRes.get())
-    aNb = aCompRes->numberOfSubs(true);
+    return aCompRes->subResult(theId, true);
   else {
-    aCompFeature = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myObject);
+    CompositeFeaturePtr aCompFeature =
+      std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myObject);
     if (aCompFeature.get())
-      aNb = aCompFeature->numberOfSubs(true);
+      return aCompFeature->subFeature(theId, true);
   }
+  return ObjectPtr();
+}
 
+void PartSet_ObjectNode::update()
+{
+  int aNb = numberOfSubs();
   if (aNb > 0) {
+    ResultFieldPtr aFieldRes = std::dynamic_pointer_cast<ModelAPI_ResultField>(myObject);
+
+    // If the object is a field result then delete extra sub-objects
+    if (aFieldRes.get()) {
+      while (myChildren.size() > aNb) {
+        ModuleBase_ITreeNode* aNode = myChildren.last();
+        myChildren.removeAll(aNode);
+        delete aNode;
+      }
+    }
+    else {
+      ObjectPtr aObj;
+      ModuleBase_ITreeNode* aNode;
+      int aId = 0;
+      while (aId < myChildren.size()) {
+        aNode = myChildren.at(aId);
+        aObj = subObject(aId);
+        if (aNode->object() != aObj) {
+          myChildren.removeAll(aNode);
+          delete aNode;
+        }
+        else
+          aId++;
+      }
+    }
+
     ModuleBase_ITreeNode* aNode;
     ObjectPtr aBody;
     int i;
     for (i = 0; i < aNb; i++) {
-      if (aCompRes.get())
-        aBody = aCompRes->subResult(i, true);
-      else
-        aBody = aCompFeature->subFeature(i, true);
-
-      if (i < myChildren.size()) {
-        aNode = myChildren.at(i);
-        if (aNode->object() != aBody) {
-          ((PartSet_ObjectNode*)aNode)->setObject(aBody);
+      aBody = subObject(i);
+      if (aBody.get()) {
+        if (i < myChildren.size()) {
+          aNode = myChildren.at(i);
+          if (aNode->object() != aBody) {
+            ((PartSet_ObjectNode*)aNode)->setObject(aBody);
+          }
+        }
+        else {
+          aNode = new PartSet_ObjectNode(aBody, this);
+          myChildren.append(aNode);
+          aNode->update();
+        }
+      }
+      else if (aFieldRes.get()) {
+        ModelAPI_ResultField::ModelAPI_FieldStep* aStep = aFieldRes->step(i);
+        if (i < myChildren.size()) {
+          PartSet_StepNode* aStepNode = static_cast<PartSet_StepNode*>(myChildren.at(i));
+          if (aStepNode->entity() != aStep) {
+            aStepNode->setEntity(aStep);
+          }
+        }
+        else {
+          aNode = new PartSet_StepNode(aStep, this);
+          myChildren.append(aNode);
         }
-      } else {
-        aNode = new PartSet_ObjectNode(aBody, this);
-        myChildren.append(aNode);
       }
     }
     // Delete extra objects
@@ -237,39 +303,41 @@ void PartSet_ObjectNode::update()
 QTreeNodesList PartSet_ObjectNode::objectCreated(const QObjectPtrList& theObjects)
 {
   QTreeNodesList aResult;
-
-  CompositeFeaturePtr aCompFeature;
-  ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
-  int aNb = 0;
-  if (aCompRes.get())
-    aNb = aCompRes->numberOfSubs(true);
-  else {
-    aCompFeature = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myObject);
-    if (aCompFeature.get())
-      aNb = aCompFeature->numberOfSubs(true);
-  }
-
+  int aNb = numberOfSubs();
   if (aNb > 0) {
     ModuleBase_ITreeNode* aNode;
+    ResultFieldPtr aFieldRes = std::dynamic_pointer_cast<ModelAPI_ResultField>(myObject);
     ObjectPtr aBody;
     int i;
     for (i = 0; i < aNb; i++) {
-      if (aCompRes.get())
-        aBody = aCompRes->subResult(i, true);
-      else
-        aBody = aCompFeature->subFeature(i, true);
-
-      if (i < myChildren.size()) {
-        aNode = myChildren.at(i);
-        if (aNode->object() != aBody) {
-          ((PartSet_ObjectNode*)aNode)->setObject(aBody);
+      aBody = subObject(i);
+      if (aBody.get()) {
+        if (i < myChildren.size()) {
+          aNode = myChildren.at(i);
+          if (aNode->object() != aBody) {
+            ((PartSet_ObjectNode*)aNode)->setObject(aBody);
+            aResult.append(aNode);
+          }
+        }
+        else {
+          aNode = new PartSet_ObjectNode(aBody, this);
+          myChildren.append(aNode);
           aResult.append(aNode);
+          aNode->update();
+        }
+      }
+      else {
+        ModelAPI_ResultField::ModelAPI_FieldStep* aStep = aFieldRes->step(i);
+        if (i < myChildren.size()) {
+          PartSet_StepNode* aStepNode = static_cast<PartSet_StepNode*>(myChildren.at(i));
+          if (aStepNode->entity() != aStep) {
+            aStepNode->setEntity(aStep);
+          }
+        }
+        else {
+          aNode = new PartSet_StepNode(aStep, this);
+          myChildren.append(aNode);
         }
-      } else {
-        aNode = new PartSet_ObjectNode(aBody, this);
-        myChildren.append(aNode);
-        aResult.append(aNode);
-        aNode->update();
       }
     }
     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
@@ -283,39 +351,39 @@ QTreeNodesList PartSet_ObjectNode::objectsDeleted(
   const DocumentPtr& theDoc, const QString& theGroup)
 {
   QTreeNodesList aResult;
-  CompositeFeaturePtr aCompFeature;
-  ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
-  int aNb = 0;
-  if (aCompRes.get())
-    aNb = aCompRes->numberOfSubs(true);
-  else {
-    aCompFeature = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myObject);
-    if (aCompFeature.get())
-      aNb = aCompFeature->numberOfSubs(true);
-  }
-
-  if (aNb > 0) {
-    ModuleBase_ITreeNode* aNode;
-    // Delete extra objects
-    bool isDeleted = false;
-    while (myChildren.size() > aNb) {
-      aNode = myChildren.takeLast();
-      delete aNode;
-      isDeleted = true;
-    }
-    if (isDeleted)
+  int aNb = numberOfSubs();
+  if (aNb != myChildren.size()) {
+    if (aNb == 0) {
+      deleteChildren();
       aResult.append(this);
-    int i = 0;
-    ObjectPtr aBody;
-    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
-      if (aCompRes.get())
-        aBody = aCompRes->subResult(i, true);
-      else
-        aBody = aCompFeature->subFeature(i, true);
-
-      ((PartSet_ObjectNode*)aNode)->setObject(aBody);
-      aResult.append(aNode->objectsDeleted(theDoc, theGroup));
-      i++;
+    }
+    else {
+      // Delete extra objects
+      bool isDeleted = false;
+      ObjectPtr aObj;
+      ModuleBase_ITreeNode* aNode;
+      int aId = 0;
+      while (aId < myChildren.size()) {
+        aNode = myChildren.at(aId);
+        aObj = subObject(aId);
+        if (aNode->object() != aObj) {
+          myChildren.removeAll(aNode);
+          delete aNode;
+          isDeleted = true;
+        }
+        else
+          aId++;
+      }
+      if (isDeleted)
+        aResult.append(this);
+      int i = 0;
+      ObjectPtr aBody;
+      foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+        aBody = subObject(i);
+        ((PartSet_ObjectNode*)aNode)->setObject(aBody);
+        aResult.append(aNode->objectsDeleted(theDoc, theGroup));
+        i++;
+      }
     }
   }
   return aResult;
@@ -373,6 +441,28 @@ QVariant PartSet_FolderNode::data(int theColumn, int theRole) const
       }
     }
   }
+  if ((theColumn == 2) && (theRole == Qt::DecorationRole)) {
+    if (document().get()) {
+      SessionPtr aSession = ModelAPI_Session::get();
+      if (document() != aSession->activeDocument())
+          return QIcon();
+
+      FeaturePtr aFeature = document()->currentFeature(true);
+      if (!aFeature.get()) { // There is no current feature
+        ModuleBase_ITreeNode* aLastFolder = 0;
+        foreach(ModuleBase_ITreeNode* aNode, parent()->children()) {
+          if (aNode->type() == PartSet_FolderNode::typeId())
+            aLastFolder = aNode;
+          else
+            break;
+        }
+        if (aLastFolder == this)
+          return QIcon(":pictures/arrow.png");
+        else
+          return QIcon();
+      }
+    }
+  }
   return PartSet_TreeNode::data(theColumn, theRole);
 }
 
@@ -392,7 +482,9 @@ ModuleBase_ITreeNode* PartSet_FolderNode::createNode(const ObjectPtr& theObj)
   //ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObj);
   //if (aCompRes.get())
   //  return new PartSet_CompsolidNode(theObj, this);
-  return new PartSet_ObjectNode(theObj, this);
+  ModuleBase_ITreeNode* aNode = new PartSet_ObjectNode(theObj, this);
+  aNode->update();
+  return aNode;
 }
 
 void PartSet_FolderNode::update()
@@ -476,18 +568,20 @@ QTreeNodesList PartSet_FolderNode::objectCreated(const QObjectPtrList& theObject
     }
   }
   // Add nodes in correct order
-  int i;
-  for (i = 0; i < myChildren.size(); i++) {
-    if (aNewNodes.contains(i)) {
-      myChildren.insert(i, aNewNodes[i]);
+  if (aNewNodes.size() > 0) {
+    int i;
+    for (i = 0; i < myChildren.size(); i++) {
+      if (aNewNodes.contains(i)) {
+        myChildren.insert(i, aNewNodes[i]);
+        aNewNodes.remove(i);
+      }
+    }
+    while (aNewNodes.size()) {
+      i = myChildren.size();
+      myChildren.append(aNewNodes[i]);
       aNewNodes.remove(i);
     }
   }
-  while (aNewNodes.size()) {
-    i = myChildren.size();
-    myChildren.append(aNewNodes[i]);
-    aNewNodes.remove(i);
-  }
   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
     aResult.append(aNode->objectCreated(theObjects));
   }
@@ -504,19 +598,23 @@ QTreeNodesList PartSet_FolderNode::objectsDeleted(const DocumentPtr& theDoc,
     int aIndex;
     int aId = 0;
     bool aRemoved = false;
+    bool aToSort = false;
     while (aId < myChildren.size()) {
       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
       aIndex = aDoc->index(aNode->object(), true);
-      if ((aIndex == -1) || (aId != aIndex)) {
+      aToSort |= ((aIndex != -1) && (aId != aIndex));
+      if (aIndex == -1) {
         myChildren.removeAll(aNode);
         delete aNode;
         aRemoved = true;
-      }  else
+      }
+      else
         aId++;
     }
     if (aRemoved)
       aResult.append(this);
-
+    if (aToSort)
+      sortChildren();
     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
       aResult.append(aNode->objectsDeleted(theDoc, theGroup));
     }
@@ -552,19 +650,22 @@ QTreeNodesList PartSet_FeatureFolderNode::objectCreated(const QObjectPtrList& th
     }
   }
   // To add in correct order
-  int i;
-  for (i = 0; i < myChildren.size(); i++) {
-    if (aNewNodes.contains(i)) {
-      myChildren.insert(i, aNewNodes[i]);
-      aNewNodes.remove(i);
+  if (aNewNodes.size() > 0) {
+    int i;
+    for (i = 0; i < myChildren.size(); i++) {
+      if (aNewNodes.contains(i)) {
+        myChildren.insert(i, aNewNodes[i]);
+        aNewNodes.remove(i);
+      }
+    }
+    while (aNewNodes.size()) {
+      i = myChildren.size();
+      if (aNewNodes.contains(i)) {
+        myChildren.append(aNewNodes[i]);
+        aNewNodes.remove(i);
+      }
     }
   }
-  while (aNewNodes.size()) {
-    i = myChildren.size();
-    myChildren.append(aNewNodes[i]);
-    aNewNodes.remove(i);
-  }
-
   // Update sub-folders
   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
     aResult.append(aNode->objectCreated(theObjects));
@@ -595,11 +696,13 @@ QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theD
     int aIndex;
     int aId = 0;
     bool aRemoved = false;
+    bool aToSort = false;
     while (aId < myChildren.size()) {
       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
       if (aNode->object().get()) {
         aIndex = aDoc->index(aNode->object(), true);
-        if ((aIndex == -1) || (aId != (aIndex + aNb))) {
+        aToSort |= ((aIndex != -1) && (aId != (aIndex + aNb)));
+        if (aIndex == -1) {
           myChildren.removeAll(aNode);
           delete aNode;
           aRemoved = true;
@@ -610,6 +713,8 @@ QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theD
     }
     if (aRemoved)
       aResult.append(this);
+    if (aToSort)
+      sortChildren();
   }
   return aResult;
 }
@@ -715,7 +820,9 @@ ModuleBase_ITreeNode* PartSet_RootNode::createNode(const ObjectPtr& theObj)
   if (aFeature->getKind() == PartSetPlugin_Part::ID())
     return new PartSet_PartRootNode(theObj, this);
 
-  return new PartSet_ObjectNode(theObj, this);
+  PartSet_ObjectNode* aNode = new PartSet_ObjectNode(theObj, this);
+  aNode->update();
+  return aNode;
 }
 
 //////////////////////////////////////////////////////////////////////////////////
@@ -761,11 +868,19 @@ void PartSet_PartRootNode::update()
 
   bool aHasFields = myFieldsFolder->childrenCount() > 0;
   bool aHasGroups = myGroupsFolder->childrenCount() > 0;
-  if (aHasFields && (!myChildren.contains(myFieldsFolder))) {
-    myChildren.insert(3, myFieldsFolder);
+  if (aHasFields) {
+    if (!myChildren.contains(myFieldsFolder)) {
+      myChildren.insert(3, myFieldsFolder);
+    }
+  } else if (myChildren.contains(myFieldsFolder)) {
+    myChildren.removeAll(myFieldsFolder);
   }
-  if (aHasGroups && (!myChildren.contains(myGroupsFolder))) {
-    myChildren.insert(aHasFields ? 4 : 3, myGroupsFolder);
+  if (aHasGroups) {
+    if (!myChildren.contains(myGroupsFolder)) {
+      myChildren.insert(aHasFields ? 4 : 3, myGroupsFolder);
+    }
+  } else if (myChildren.contains(myGroupsFolder)) {
+    myChildren.removeAll(myGroupsFolder);
   }
 
   // Update features content
@@ -773,14 +888,18 @@ void PartSet_PartRootNode::update()
 
   // Remove extra sub-nodes
   int aIndex = -1;
-  int aId = 0;
+  int aId = aRows;
+  QMap<int, ModuleBase_ITreeNode*> aExistingNodes;
   while (aId < myChildren.size()) {
     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
     if (aNode->object().get()) {
       aIndex = aDoc->index(aNode->object(), true);
       if ((aIndex == -1) || (aId != (aIndex + aRows))) {
         myChildren.removeAll(aNode);
-        delete aNode;
+        if (aIndex == -1)
+          delete aNode;
+        else
+          aExistingNodes[aIndex + aRows] = aNode;
         continue;
       }
     }
@@ -795,12 +914,19 @@ void PartSet_PartRootNode::update()
     aId = i + aRows; // Take into account existing folders
     if (aId < myChildren.size()) {
       if (myChildren.at(aId)->object() != aObj) {
-        ModuleBase_ITreeNode* aNode = createNode(aObj);
-        myChildren.insert(aId, aNode);
+        if (aExistingNodes.contains(aId)) {
+          myChildren.insert(aId, aExistingNodes[aId]);
+          aExistingNodes.remove(aId);
+        }
+        else {
+          myChildren.insert(aId, createNode(aObj));
+        }
       }
     } else {
-      ModuleBase_ITreeNode* aNode = createNode(aObj);
-      myChildren.append(aNode);
+      if (aExistingNodes.contains(myChildren.size()))
+        myChildren.append(aExistingNodes[myChildren.size()]);
+      else
+        myChildren.append(createNode(aObj));
     }
   }
   // Update sub-folders
@@ -824,20 +950,33 @@ QVariant PartSet_PartRootNode::data(int theColumn, int theRole) const
   case 1:
     switch (theRole) {
     case Qt::DisplayRole:
+    {
+      ResultPartPtr aPartRes = getPartResult(myObject);
+      if (aPartRes.get()) {
+        if (aPartRes->partDoc().get() == NULL)
+          return QString(myObject->data()->name().c_str()) + " (Not loaded)";
+      }
       return QString(myObject->data()->name().c_str());
+    }
     case Qt::DecorationRole:
       return ModuleBase_IconFactory::get()->getIcon(myObject);
     }
   case 2:
-    if (theRole == Qt::DecorationRole)
+    if (theRole == Qt::DecorationRole) {
       if (isCurrentFeature(myObject))
         return QIcon(":pictures/arrow.png");
+      else
+        return QIcon();
+    }
   }
   return PartSet_TreeNode::data(theColumn, theRole);
 }
 
 Qt::ItemFlags PartSet_PartRootNode::flags(int theColumn) const
 {
+  if (myObject->isDisabled())
+    return (theColumn == 2) ? Qt::ItemIsSelectable : aNullFlag;
+
   SessionPtr aSession = ModelAPI_Session::get();
   DocumentPtr aActiveDoc = aSession->activeDocument();
   if ((aActiveDoc == document()) || (myObject->document() == aActiveDoc))
@@ -849,7 +988,9 @@ ModuleBase_ITreeNode* PartSet_PartRootNode::createNode(const ObjectPtr& theObj)
 {
   if (theObj->groupName() == ModelAPI_Folder::group())
     return new PartSet_ObjectFolderNode(theObj, this);
-  return new PartSet_ObjectNode(theObj, this);
+  PartSet_ObjectNode* aNode = new PartSet_ObjectNode(theObj, this);
+  aNode->update();
+  return aNode;
 }
 
 int PartSet_PartRootNode::numberOfFolders() const
@@ -911,8 +1052,8 @@ QTreeNodesList PartSet_PartRootNode::objectsDeleted(const DocumentPtr& theDoc,
 //////////////////////////////////////////////////////////////////////////////////
 void PartSet_ObjectFolderNode::update()
 {
-  int aFirst, aLast;
-  getFirstAndLastIndex(aFirst, aLast);
+  int aFirst = -1, aLast = -1;
+  PartSet_Tools::getFirstAndLastIndexInFolder(myObject, aFirst, aLast);
   if ((aFirst == -1) || (aLast == -1)) {
     deleteChildren();
     return;
@@ -925,32 +1066,44 @@ void PartSet_ObjectFolderNode::update()
   }
 
   DocumentPtr aDoc = myObject->document();
-  // Delete obsolete nodes
-  int aId = 0;
-  while (aId < myChildren.size()) {
-    ModuleBase_ITreeNode* aNode = myChildren.at(aId);
-    if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
-      if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
+  if (aNbItems < myChildren.size()) {
+    // Delete obsolete nodes
+    int aId = 0;
+    int aNbOfFeatures = aDoc->size(ModelAPI_Feature::group(), true);
+    while (aId < myChildren.size()) {
+      ModuleBase_ITreeNode* aNode = myChildren.at(aId);
+      if ((aFirst + aId) < aNbOfFeatures) {
+        if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
+          myChildren.removeAll(aNode);
+          delete aNode;
+          continue;
+        }
+      }
+      else {
         myChildren.removeAll(aNode);
         delete aNode;
         continue;
       }
+      aId++;
     }
-    aId++;
   }
-
-  // Add new nodes
-  ModuleBase_ITreeNode* aNode;
-  for (int i = 0; i < aNbItems; i++) {
-    ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
-    if (i < myChildren.size()) {
-      if (aObj != myChildren.at(i)->object()) {
+  if (aNbItems > myChildren.size()) {
+    // Add new nodes
+    ModuleBase_ITreeNode* aNode;
+    for (int i = 0; i < aNbItems; i++) {
+      ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
+      if (i < myChildren.size()) {
+        if (aObj != myChildren.at(i)->object()) {
+          aNode = new PartSet_ObjectNode(aObj, this);
+          myChildren.insert(i, aNode);
+          aNode->update();
+        }
+      }
+      else {
         aNode = new PartSet_ObjectNode(aObj, this);
-        myChildren.insert(i, aNode);
+        myChildren.append(aNode);
+        aNode->update();
       }
-    } else {
-      aNode = new PartSet_ObjectNode(aObj, this);
-      myChildren.append(aNode);
     }
   }
 }
@@ -958,8 +1111,8 @@ void PartSet_ObjectFolderNode::update()
 QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& theObjects)
 {
   QTreeNodesList aResult;
-  int aFirst, aLast;
-  getFirstAndLastIndex(aFirst, aLast);
+  int aFirst = -1, aLast = -1;
+  PartSet_Tools::getFirstAndLastIndexInFolder(myObject, aFirst, aLast);
   if ((aFirst == -1) || (aLast == -1)) {
     return aResult;
   }
@@ -977,11 +1130,13 @@ QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& the
         aNode = new PartSet_ObjectNode(aObj, this);
         myChildren.insert(i, aNode);
         aResult.append(aNode);
+        aNode->update();
       }
     } else {
       aNode = new PartSet_ObjectNode(aObj, this);
       myChildren.append(aNode);
       aResult.append(aNode);
+      aNode->update();
     }
   }
   return aResult;
@@ -991,8 +1146,8 @@ QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDo
   const QString& theGroup)
 {
   QTreeNodesList aResult;
-  int aFirst, aLast;
-  getFirstAndLastIndex(aFirst, aLast);
+  int aFirst = -1, aLast = -1;
+  PartSet_Tools::getFirstAndLastIndexInFolder(myObject, aFirst, aLast);
   if ((aFirst == -1) || (aLast == -1)) {
     return aResult;
   }
@@ -1000,13 +1155,17 @@ QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDo
   if (!aNbItems) {
     return aResult;
   }
+  if (aNbItems >= myChildren.size()) // Nothing was deleted here
+    return aResult;
+
   DocumentPtr aDoc = myObject->document();
   // Delete obsolete nodes
   bool aRemoved = false;
   int aId = 0;
+  int aNbOfFeatures = aDoc->size(ModelAPI_Feature::group(), true);
   while (aId < myChildren.size()) {
     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
-    if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
+    if ((aFirst + aId) < aNbOfFeatures) {
       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
         myChildren.removeAll(aNode);
         delete aNode;
@@ -1014,6 +1173,13 @@ QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDo
         continue;
       }
     }
+    else {
+      myChildren.removeAll(aNode);
+      aResult.removeAll(aNode);
+      delete aNode;
+      aRemoved = true;
+      continue;
+    }
     aId++;
   }
   if (aRemoved) {
@@ -1022,31 +1188,17 @@ QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDo
   return aResult;
 }
 
-FeaturePtr PartSet_ObjectFolderNode::getFeature(const std::string& theId) const
-{
-  FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
-  AttributeReferencePtr aFeatAttr = aFolder->data()->reference(theId);
-  if (aFeatAttr)
-    return ModelAPI_Feature::feature(aFeatAttr->value());
-  return FeaturePtr();
-}
 
-void PartSet_ObjectFolderNode::getFirstAndLastIndex(int& theFirst, int& theLast) const
+
+//////////////////////////////////////////////////////////////////////////////////
+QVariant PartSet_StepNode::data(int theColumn, int theRole) const
 {
-  DocumentPtr aDoc = myObject->document();
-  FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
+  if ((theColumn == 1) && (theRole == Qt::DisplayRole)) {
+    ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
+      dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>(myEntity);
 
-  FeaturePtr aFirstFeatureInFolder = getFeature(ModelAPI_Folder::FIRST_FEATURE_ID());
-  if (!aFirstFeatureInFolder.get()) {
-    theFirst = -1;
-    return;
-  }
-  FeaturePtr aLastFeatureInFolder = getFeature(ModelAPI_Folder::LAST_FEATURE_ID());
-  if (!aLastFeatureInFolder.get()) {
-    theLast = -1;
-    return;
+    return "Step " + QString::number(aStep->id() + 1) + " " +
+      aStep->field()->textLine(aStep->id()).c_str();
   }
-
-  theFirst = aDoc->index(aFirstFeatureInFolder);
-  theLast = aDoc->index(aLastFeatureInFolder);
+  return PartSet_TreeNode::data(theColumn, theRole);
 }