Salome HOME
Make tests working on new results structure and selection of feature as argument
[modules/shaper.git] / src / PartSet / PartSet_TreeNodes.cpp
index 6c1c9dd89267c5444c17225efdbaacfc47ad1fdc..5e642c691aba56927ddd26dbe083d0db2579e517 100644 (file)
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_ResultBody.h>
-#include <ModelAPI_Feature.h>
 #include <ModelAPI_Tools.h>
-#include <ModelAPI_ResultCompSolid.h>
+#include <ModelAPI_ResultBody.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_AttributeDouble.h>
-
+#include <ModelAPI_Folder.h>
+#include <ModelAPI_AttributeReference.h>
 
 #include <QBrush>
+#include <QMap>
 
 
 #define ACTIVE_COLOR QColor(Qt::black)
@@ -109,7 +110,7 @@ QVariant PartSet_ObjectNode::data(int theColumn, int theRole) const
   case Qt::DecorationRole:
     switch (theColumn) {
     case 0:
-      switch (getVisibilityState()) {
+      switch (visibilityState()) {
       case NoneState:
         return QIcon();
       case Visible:
@@ -120,7 +121,10 @@ QVariant PartSet_ObjectNode::data(int theColumn, int theRole) const
         return QIcon(":pictures/eyeclosed.png");
       }
     case 1:
-      return ModuleBase_IconFactory::get()->getIcon(myObject);
+      if (myObject->groupName() == ModelAPI_Folder::group())
+        return QIcon(":pictures/features_folder.png");
+      else
+        return ModuleBase_IconFactory::get()->getIcon(myObject);
     case 2:
       if (isCurrentFeature(myObject))
         return QIcon(":pictures/arrow.png");
@@ -131,7 +135,9 @@ QVariant PartSet_ObjectNode::data(int theColumn, int theRole) const
 
 Qt::ItemFlags PartSet_ObjectNode::flags(int theColumn) const
 {
-  if (!myObject->isDisabled()) {
+  if (myObject->isDisabled()) {
+    return (theColumn == 2) ? Qt::ItemIsSelectable : aNullFlag;
+  } else {
     DocumentPtr aDoc = myObject->document();
     SessionPtr aSession = ModelAPI_Session::get();
     if (aSession->activeDocument() == aDoc)
@@ -140,7 +146,7 @@ Qt::ItemFlags PartSet_ObjectNode::flags(int theColumn) const
   return aDefaultFlag;
 }
 
-PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::getVisibilityState() const
+PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::visibilityState() const
 {
   Qt::ItemFlags aFlags = flags(1);
   if (aFlags == Qt::ItemFlags())
@@ -151,12 +157,17 @@ PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::getVisibilityState() con
   ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
   if (aResObj.get()) {
     ModuleBase_IWorkshop* aWork = workshop();
-    ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResObj);
+    ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResObj);
     if (aCompRes.get()) {
       VisibilityState aState = aCompRes->numberOfSubs(true) == 0 ?
         (aWork->isVisible(aCompRes) ? Visible : Hidden) : NoneState;
-      for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
-        ResultPtr aSubRes = aCompRes->subResult(i, true);
+      std::list<ResultPtr> aResultsList;
+      ModelAPI_Tools::allSubs(aCompRes, aResultsList);
+
+      std::list<ResultPtr>::const_iterator aIt;
+      //for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
+      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;
@@ -176,21 +187,98 @@ PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::getVisibilityState() con
   return NoneState;
 }
 
+void PartSet_ObjectNode::update()
+{
+  ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
+  if (aCompRes.get()) {
+    int aNb = aCompRes->numberOfSubs(true);
+    ModuleBase_ITreeNode* aNode;
+    ResultBodyPtr aBody;
+    int i;
+    for (i = 0; i < aNb; i++) {
+      aBody = aCompRes->subResult(i, true);
+      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);
+      }
+    }
+    // Delete extra objects
+    while (myChildren.size() > aNb) {
+      aNode = myChildren.takeLast();
+      delete aNode;
+    }
+    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+      aNode->update();
+    }
+  }
+}
 
-//////////////////////////////////////////////////////////////////////////////////
-PartSet_FolderNode::PartSet_FolderNode(ModuleBase_ITreeNode* theParent,
-  FolderType theType)
-  : PartSet_TreeNode(theParent), myType(theType)
+QTreeNodesList PartSet_ObjectNode::objectCreated(const QObjectPtrList& theObjects)
 {
+  QTreeNodesList aResult;
+
+  ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
+  if (aCompRes.get()) {
+    int aNb = aCompRes->numberOfSubs(true);
+    ModuleBase_ITreeNode* aNode;
+    ResultBodyPtr aBody;
+    int i;
+    for (i = 0; i < aNb; i++) {
+      aBody = aCompRes->subResult(i, true);
+      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);
+      }
+    }
+    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+      aResult.append(aNode->objectCreated(theObjects));
+    }
+  }
+  return aResult;
 }
 
-PartSet_FolderNode::~PartSet_FolderNode()
+QTreeNodesList PartSet_ObjectNode::objectsDeleted(const DocumentPtr& theDoc, const QString& theGroup)
 {
-  while (myChildren.length() > 0) {
-    ModuleBase_ITreeNode* aNode = myChildren.last();
-    myChildren.removeAll(aNode);
-    delete aNode;
+  QTreeNodesList aResult;
+  ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
+  if (aCompRes.get()) {
+    int aNb = aCompRes->numberOfSubs(true);
+    ModuleBase_ITreeNode* aNode;
+    // Delete extra objects
+    bool isDeleted = false;
+    while (myChildren.size() > aNb) {
+      aNode = myChildren.takeLast();
+      delete aNode;
+      isDeleted = true;
+    }
+    if (isDeleted)
+      aResult.append(this);
+    int i = 0;
+    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+      ((PartSet_ObjectNode*)aNode)->setObject(aCompRes->subResult(i, true));
+      aResult.append(aNode->objectsDeleted(theDoc, theGroup));
+      i++;
+    }
   }
+  return aResult;
+}
+//////////////////////////////////////////////////////////////////////////////////
+PartSet_FolderNode::PartSet_FolderNode(ModuleBase_ITreeNode* theParent,
+  FolderType theType)
+  : PartSet_TreeNode(theParent), myType(theType)
+{
 }
 
 QString PartSet_FolderNode::name() const
@@ -253,6 +341,14 @@ Qt::ItemFlags PartSet_FolderNode::flags(int theColumn) const
   return aDefaultFlag;
 }
 
+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);
+}
+
 void PartSet_FolderNode::update()
 {
   DocumentPtr aDoc = document();
@@ -260,31 +356,37 @@ void PartSet_FolderNode::update()
     return;
 
   // Remove extra sub-nodes
-  QTreeNodesList aDelList;
-  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
-    if (aDoc->index(aNode->object()) == -1)
-      aDelList.append(aNode);
-  }
-  foreach(ModuleBase_ITreeNode* aNode, aDelList) {
-    myChildren.removeAll(aNode);
-    delete aNode;
+  int aIndex;
+  int aId = 0;
+  while (aId < myChildren.size()) {
+    ModuleBase_ITreeNode* aNode = myChildren.at(aId);
+    aIndex = aDoc->index(aNode->object(), true);
+    if ((aIndex == -1) || (aId != aIndex)) {
+      myChildren.removeAll(aNode);
+      delete aNode;
+    } else
+      aId++;
   }
 
   // Add new nodes
   std::string aGroup = groupName();
-  int aSize = aDoc->size(aGroup);
+  int aSize = aDoc->size(aGroup, true);
   for (int i = 0; i < aSize; i++) {
-    ObjectPtr aObj = aDoc->object(aGroup, i);
+    ObjectPtr aObj = aDoc->object(aGroup, i, true);
     if (i < myChildren.size()) {
       if (myChildren.at(i)->object() != aObj) {
-        PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
+        ModuleBase_ITreeNode* aNode = createNode(aObj);
         myChildren.insert(i, aNode);
       }
     } else {
-      PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
+      ModuleBase_ITreeNode* aNode = createNode(aObj);
       myChildren.append(aNode);
     }
   }
+
+  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+    aNode->update();
+  }
 }
 
 std::string PartSet_FolderNode::groupName() const
@@ -312,22 +414,36 @@ QTreeNodesList PartSet_FolderNode::objectCreated(const QObjectPtrList& theObject
   std::string aName = groupName();
   DocumentPtr aDoc = document();
   int aIdx = -1;
+  QMap<int, ModuleBase_ITreeNode*> aNewNodes;
   foreach(ObjectPtr aObj, theObjects) {
     if ((aObj->document() == aDoc) && (aObj->groupName() == aName)) {
-      aIdx = aDoc->index(aObj);
+      aIdx = aDoc->index(aObj, true);
       if (aIdx != -1) {
         bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
         if (!aHasObject) {
-          PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
+          ModuleBase_ITreeNode* aNode = createNode(aObj);
+          aNewNodes[aIdx] = aNode;
           aResult.append(aNode);
-          if (aIdx < myChildren.size())
-            myChildren.insert(aIdx, aNode);
-          else
-            myChildren.append(aNode);
         }
       }
     }
   }
+  // Add nodes in correct order
+  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);
+  }
+  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+    aResult.append(aNode->objectCreated(theObjects));
+  }
   return aResult;
 }
 
@@ -338,16 +454,24 @@ QTreeNodesList PartSet_FolderNode::objectsDeleted(const DocumentPtr& theDoc,
   QTreeNodesList aResult;
   if ((theGroup.toStdString() == groupName()) && (theDoc == aDoc)) {
     QTreeNodesList aDelList;
-    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
-      if (aDoc->index(aNode->object()) == -1)
-        aDelList.append(aNode);
-    }
-    if (aDelList.size() > 0) {
-      foreach(ModuleBase_ITreeNode* aNode, aDelList) {
+    int aIndex;
+    int aId = 0;
+    bool aRemoved = false;
+    while (aId < myChildren.size()) {
+      ModuleBase_ITreeNode* aNode = myChildren.at(aId);
+      aIndex = aDoc->index(aNode->object(), true);
+      if ((aIndex == -1) || (aId != aIndex)) {
         myChildren.removeAll(aNode);
         delete aNode;
-      }
+        aRemoved = true;
+      }  else
+        aId++;
+    }
+    if (aRemoved)
       aResult.append(this);
+
+    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+      aResult.append(aNode->objectsDeleted(theDoc, theGroup));
     }
   }
   return aResult;
@@ -358,38 +482,53 @@ QTreeNodesList PartSet_FeatureFolderNode::objectCreated(const QObjectPtrList& th
 {
   QTreeNodesList aResult;
   // Process all folders
-  ModuleBase_ITreeNode* aFoder = 0;
   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
-    aFoder = dynamic_cast<PartSet_FolderNode*>(aNode);
-    if (!aFoder)
-      aFoder = dynamic_cast<PartSet_FeatureFolderNode*>(aNode);
-
-    if (aFoder) { // aFolder node
-      QTreeNodesList aList = aNode->objectCreated(theObjects);
-      if (aList.size() > 0)
-        aResult.append(aList);
+    if (aNode->type() == PartSet_FolderNode::typeId()) { // aFolder node
+      aResult.append(aNode->objectCreated(theObjects));
     }
   }
   // Process the root sub-objects
   DocumentPtr aDoc = document();
   int aIdx = -1;
   int aNb = numberOfFolders();
+  QMap<int, ModuleBase_ITreeNode*> aNewNodes;
   foreach(ObjectPtr aObj, theObjects) {
     if (aDoc == aObj->document()) {
-      if (aObj->groupName() == ModelAPI_Feature::group()) {
+      if ((aObj->groupName() == ModelAPI_Feature::group()) ||
+        (aObj->groupName() == ModelAPI_Folder::group())){
         ModuleBase_ITreeNode* aNode = createNode(aObj);
-        aIdx = aDoc->index(aObj) + aNb;
-        bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
-        if (!aHasObject) {
-          if (aIdx < myChildren.size())
-            myChildren.insert(aIdx, aNode);
-          else
-            myChildren.append(aNode);
-          aResult.append(aNode);
+        aIdx = aDoc->index(aObj, true);
+        if (aIdx != -1) {
+          aIdx += aNb;
+          bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
+          if (!aHasObject) {
+            aNewNodes[aIdx] = aNode;
+            aResult.append(aNode);
+          }
         }
       }
     }
   }
+  // 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);
+    }
+  }
+  while (aNewNodes.size()) {
+    i = myChildren.size();
+    myChildren.append(aNewNodes[i]);
+    aNewNodes.remove(i);
+  }
+
+  // Update sub-folders
+  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+    if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
+      (aNode->type() == PartSet_PartRootNode::typeId()))
+      aResult.append(aNode->objectCreated(theObjects));
+  }
   return aResult;
 }
 
@@ -397,6 +536,8 @@ QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theD
   const QString& theGroup)
 {
   QTreeNodesList aResult;
+
+  // Process sub-folders
   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
     if (aNode->childrenCount() > 0) { // aFolder node
       QTreeNodesList aList = aNode->objectsDeleted(theDoc, theGroup);
@@ -404,22 +545,31 @@ QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theD
         aResult.append(aList);
     }
   }
+
+  // Process root
   DocumentPtr aDoc = document();
-  if ((theDoc == aDoc) && (theGroup.toStdString() == ModelAPI_Feature::group())) {
-    QTreeNodesList aDelList;
-    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+  int aNb = numberOfFolders();
+  bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
+    (theGroup.toStdString() == ModelAPI_Folder::group()));
+  if ((theDoc == aDoc) && isGroup) {
+    int aIndex;
+    int aId = 0;
+    bool aRemoved = false;
+    while (aId < myChildren.size()) {
+      ModuleBase_ITreeNode* aNode = myChildren.at(aId);
       if (aNode->object().get()) {
-        if (aDoc->index(aNode->object()) == -1)
-          aDelList.append(aNode);
+        aIndex = aDoc->index(aNode->object(), true);
+        if ((aIndex == -1) || (aId != (aIndex + aNb))) {
+          myChildren.removeAll(aNode);
+          delete aNode;
+          aRemoved = true;
+          continue;
+        }
       }
+      aId++;
     }
-    if (aDelList.size() > 0) {
-      foreach(ModuleBase_ITreeNode* aNode, aDelList) {
-        myChildren.removeAll(aNode);
-        delete aNode;
-      }
+    if (aRemoved)
       aResult.append(this);
-    }
   }
   return aResult;
 }
@@ -434,7 +584,9 @@ ModuleBase_ITreeNode* PartSet_FeatureFolderNode::findParent(const DocumentPtr& t
       return aResult;
     }
   }
-  if ((theDoc == document()) && (theGroup.toStdString() == ModelAPI_Feature::group()))
+  bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
+    (theGroup.toStdString() == ModelAPI_Folder::group()));
+  if ((theDoc == document()) && isGroup)
     return this;
   return 0;
 }
@@ -457,13 +609,6 @@ PartSet_RootNode::PartSet_RootNode() : PartSet_FeatureFolderNode(0), myWorkshop(
   update();
 }
 
-PartSet_RootNode::~PartSet_RootNode()
-{
-  delete myParamsFolder;
-  delete myConstrFolder;
-  delete myPartsFolder;
-}
-
 
 void PartSet_RootNode::update()
 {
@@ -473,55 +618,46 @@ void PartSet_RootNode::update()
 
   // Update features content
   DocumentPtr aDoc = document();
+  int aNb = numberOfFolders();
 
   // Remove extra sub-nodes
-  QTreeNodesList aDelList;
-  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+  int aIndex;
+  int aId = 0;
+  while (aId < myChildren.size()) {
+    ModuleBase_ITreeNode* aNode = myChildren.at(aId);
     if (aNode->object().get()) {
-      if (aDoc->index(aNode->object()) == -1)
-        aDelList.append(aNode);
+      aIndex = aDoc->index(aNode->object(), true);
+      if ((aIndex == -1) || (aId != (aIndex + aNb))) {
+        myChildren.removeAll(aNode);
+        delete aNode;
+        continue;
+      }
     }
-  }
-  foreach(ModuleBase_ITreeNode* aNode, aDelList) {
-    myChildren.removeAll(aNode);
-    delete aNode;
+    aId++;
   }
 
   // Add new nodes
   std::string aGroup = ModelAPI_Feature::group();
-  int aSize = aDoc->size(aGroup);
-  int aId;
+  int aSize = aDoc->size(aGroup, true);
   FeaturePtr aFeature;
-  int aNb = numberOfFolders();
   for (int i = 0; i < aSize; i++) {
-    ObjectPtr aObj = aDoc->object(aGroup, i);
+    ObjectPtr aObj = aDoc->object(aGroup, i, true);
     aId = i + aNb; // Take into account existing folders
     if (aId < myChildren.size()) {
       if (myChildren.at(aId)->object() != aObj) {
-        aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
-        ModuleBase_ITreeNode* aNode;
-        if (aFeature->getKind() == PartSetPlugin_Part::ID())
-          aNode = new PartSet_PartRootNode(aObj, this);
-        else
-          aNode = new PartSet_ObjectNode(aObj, this);
+        ModuleBase_ITreeNode* aNode = createNode(aObj);
         myChildren.insert(aId, aNode);
       }
     } else {
-      aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
-      ModuleBase_ITreeNode* aNode;
-      if (aFeature->getKind() == PartSetPlugin_Part::ID())
-        aNode = new PartSet_PartRootNode(aObj, this);
-      else
-        aNode = new PartSet_ObjectNode(aObj, this);
+      ModuleBase_ITreeNode* aNode = createNode(aObj);
       myChildren.append(aNode);
     }
   }
   // Update sub-folders
-  ModuleBase_ITreeNode* aSubFolder = 0;
   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
-    aSubFolder = dynamic_cast<PartSet_PartRootNode*>(aNode);
-    if (aSubFolder)
-      aSubFolder->update();
+    if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
+      (aNode->type() == PartSet_PartRootNode::typeId()))
+      aNode->update();
   }
 }
 
@@ -532,11 +668,14 @@ DocumentPtr PartSet_RootNode::document() const
 
 ModuleBase_ITreeNode* PartSet_RootNode::createNode(const ObjectPtr& theObj)
 {
+  if (theObj->groupName() == ModelAPI_Folder::group())
+    return new PartSet_ObjectFolderNode(theObj, this);
+
   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
   if (aFeature->getKind() == PartSetPlugin_Part::ID())
     return new PartSet_PartRootNode(theObj, this);
-  else
-    return new PartSet_ObjectNode(theObj, this);
+
+  return new PartSet_ObjectNode(theObj, this);
 }
 
 //////////////////////////////////////////////////////////////////////////////////
@@ -556,13 +695,15 @@ PartSet_PartRootNode::PartSet_PartRootNode(const ObjectPtr& theObj, ModuleBase_I
   update();
 }
 
-PartSet_PartRootNode::~PartSet_PartRootNode()
+void PartSet_PartRootNode::deleteChildren()
 {
-  delete myParamsFolder;
-  delete myConstrFolder;
-  delete myResultsFolder;
-  delete myFieldsFolder;
-  delete myGroupsFolder;
+  if (!myFieldsFolder->childrenCount()) {
+    delete myFieldsFolder;
+  }
+  if (!myGroupsFolder->childrenCount()) {
+    delete myGroupsFolder;
+  }
+  PartSet_FeatureFolderNode::deleteChildren();
 }
 
 
@@ -591,38 +732,42 @@ void PartSet_PartRootNode::update()
   int aRows = numberOfFolders();
 
   // Remove extra sub-nodes
-  QTreeNodesList aDelList;
   int aIndex = -1;
-  int aId = -1;
-  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
-    aId++;
+  int aId = 0;
+  while (aId < myChildren.size()) {
+    ModuleBase_ITreeNode* aNode = myChildren.at(aId);
     if (aNode->object().get()) {
-      aIndex = aDoc->index(aNode->object());
-      if ((aIndex == -1) || (aId != (aIndex + aRows)))
-        aDelList.append(aNode);
+      aIndex = aDoc->index(aNode->object(), true);
+      if ((aIndex == -1) || (aId != (aIndex + aRows))) {
+        myChildren.removeAll(aNode);
+        delete aNode;
+        continue;
+      }
     }
-  }
-  foreach(ModuleBase_ITreeNode* aNode, aDelList) {
-    myChildren.removeAll(aNode);
-    delete aNode;
+    aId++;
   }
 
   std::string aGroup = ModelAPI_Feature::group();
-  int aSize = aDoc->size(aGroup);
+  int aSize = aDoc->size(aGroup, true);
   FeaturePtr aFeature;
   for (int i = 0; i < aSize; i++) {
-    ObjectPtr aObj = aDoc->object(aGroup, i);
+    ObjectPtr aObj = aDoc->object(aGroup, i, true);
     aId = i + aRows; // Take into account existing folders
     if (aId < myChildren.size()) {
       if (myChildren.at(aId)->object() != aObj) {
-        ModuleBase_ITreeNode* aNode = new PartSet_ObjectNode(aObj, this);
+        ModuleBase_ITreeNode* aNode = createNode(aObj);
         myChildren.insert(aId, aNode);
       }
     } else {
-      ModuleBase_ITreeNode* aNode = new PartSet_ObjectNode(aObj, this);
+      ModuleBase_ITreeNode* aNode = createNode(aObj);
       myChildren.append(aNode);
     }
   }
+  // Update sub-folders
+  foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+    if (aNode->type() == PartSet_ObjectFolderNode::typeId())
+      aNode->update();
+  }
 }
 
 DocumentPtr PartSet_PartRootNode::document() const
@@ -662,6 +807,8 @@ Qt::ItemFlags PartSet_PartRootNode::flags(int theColumn) const
 
 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);
 }
 
@@ -720,3 +867,224 @@ QTreeNodesList PartSet_PartRootNode::objectsDeleted(const DocumentPtr& theDoc,
   aResult.append(PartSet_FeatureFolderNode::objectsDeleted(theDoc, theGroup));
   return aResult;
 }
+
+//////////////////////////////////////////////////////////////////////////////////
+void PartSet_ObjectFolderNode::update()
+{
+  int aFirst, aLast;
+  getFirstAndLastIndex(aFirst, aLast);
+  if ((aFirst == -1) || (aLast == -1)) {
+    deleteChildren();
+    return;
+  }
+
+  int aNbItems = aLast - aFirst + 1;
+  if (!aNbItems) {
+    deleteChildren();
+    return;
+  }
+
+  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)) {
+        myChildren.removeAll(aNode);
+        delete aNode;
+        continue;
+      }
+    }
+    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()) {
+        aNode = new PartSet_ObjectNode(aObj, this);
+        myChildren.insert(i, aNode);
+      }
+    } else {
+      aNode = new PartSet_ObjectNode(aObj, this);
+      myChildren.append(aNode);
+    }
+  }
+}
+
+QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& theObjects)
+{
+  QTreeNodesList aResult;
+  int aFirst, aLast;
+  getFirstAndLastIndex(aFirst, aLast);
+  if ((aFirst == -1) || (aLast == -1)) {
+    return aResult;
+  }
+  int aNbItems = aLast - aFirst + 1;
+  if (!aNbItems) {
+    return aResult;
+  }
+  DocumentPtr aDoc = myObject->document();
+  // 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);
+        aResult.append(aNode);
+      }
+    } else {
+      aNode = new PartSet_ObjectNode(aObj, this);
+      myChildren.append(aNode);
+      aResult.append(aNode);
+    }
+  }
+  return aResult;
+}
+
+QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDoc,
+  const QString& theGroup)
+{
+  QTreeNodesList aResult;
+  int aFirst, aLast;
+  getFirstAndLastIndex(aFirst, aLast);
+  if ((aFirst == -1) || (aLast == -1)) {
+    return aResult;
+  }
+  int aNbItems = aLast - aFirst + 1;
+  if (!aNbItems) {
+    return aResult;
+  }
+  DocumentPtr aDoc = myObject->document();
+  // Delete obsolete nodes
+  bool aRemoved = false;
+  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)) {
+        myChildren.removeAll(aNode);
+        delete aNode;
+        aRemoved = true;
+        continue;
+      }
+    }
+    aId++;
+  }
+  if (aRemoved) {
+    aResult.append(this);
+  }
+  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
+{
+  DocumentPtr aDoc = myObject->document();
+  FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
+
+  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;
+  }
+
+  theFirst = aDoc->index(aFirstFeatureInFolder);
+  theLast = aDoc->index(aLastFeatureInFolder);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//PartSet_CompsolidNode::PartSet_CompsolidNode(const ObjectPtr& theObj,
+//  ModuleBase_ITreeNode* theParent) : PartSet_ObjectNode(theObj, theParent)
+//{
+//  update();
+//}
+
+//void PartSet_CompsolidNode::update()
+//{
+//  ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(myObject);
+//  int aNb = aCompRes->numberOfSubs(true);
+//  ModuleBase_ITreeNode* aNode;
+//  ResultBodyPtr aBody;
+//  int i;
+//  for (i = 0; i < aNb; i++) {
+//    aBody = aCompRes->subResult(i, true);
+//    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);
+//    }
+//  }
+//  // Delete extra objects
+//  while (myChildren.size() > aNb) {
+//    aNode = myChildren.takeLast();
+//    delete aNode;
+//  }
+//}
+//
+//QTreeNodesList PartSet_CompsolidNode::objectCreated(const QObjectPtrList& theObjects)
+//{
+//  QTreeNodesList aResult;
+//
+//  ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(myObject);
+//  int aNb = aCompRes->numberOfSubs(true);
+//  ModuleBase_ITreeNode* aNode;
+//  ResultBodyPtr aBody;
+//  int i;
+//  for (i = 0; i < aNb; i++) {
+//    aBody = aCompRes->subResult(i, true);
+//    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);
+//    }
+//  }
+//  return aResult;
+//}
+//
+//QTreeNodesList PartSet_CompsolidNode::objectsDeleted(const DocumentPtr& theDoc, const QString& theGroup)
+//{
+//  QTreeNodesList aResult;
+//  ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(myObject);
+//  int aNb = aCompRes->numberOfSubs(true);
+//  ModuleBase_ITreeNode* aNode;
+//  // Delete extra objects
+//  bool isDeleted = false;
+//  while (myChildren.size() > aNb) {
+//    aNode = myChildren.takeLast();
+//    delete aNode;
+//    isDeleted = true;
+//  }
+//  if (isDeleted)
+//    aResult.append(this);
+//  return aResult;
+//}
\ No newline at end of file