]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'Dev_FolderFeature' of salome:modules/shaper into Dev_FolderFeature
authorvsv <vsv@opencascade.com>
Fri, 24 Nov 2017 11:34:33 +0000 (14:34 +0300)
committervsv <vsv@opencascade.com>
Fri, 24 Nov 2017 11:34:33 +0000 (14:34 +0300)
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/Model/Model_Document.cpp
src/Model/Model_Document.h
src/Model/Model_Objects.cpp
src/Model/Model_Objects.h
src/ModelAPI/ModelAPI_Document.h
src/ModelAPI/ModelAPI_Folder.cpp
src/ModelAPI/Test/TestFolder_Update.py

index 9911a796463fe41ec18cfc94fa6e9e22b048003b..49bca1d2752823a715467acb473d742a254b4a2b 100644 (file)
@@ -468,9 +468,9 @@ void Model_Data::eraseBackReferences()
     aRes->setIsConcealed(false);
 }
 
-void Model_Data::removeBackReference(FeaturePtr theFeature, std::string theAttrID)
+void Model_Data::removeBackReference(ObjectPtr theObject, std::string theAttrID)
 {
-  AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
+  AttributePtr anAttribute = theObject->data()->attribute(theAttrID);
   removeBackReference(anAttribute);
 }
 
@@ -492,10 +492,7 @@ void Model_Data::removeBackReference(AttributePtr theAttr)
 void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID,
    const bool theApplyConcealment)
 {
-  // it is possible to add the same attribute twice: may be last time the owner was not Stable...
-  AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
-  if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
-    myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
+  addBackReference(ObjectPtr(theFeature), theAttrID);
 
   if (theApplyConcealment &&  theFeature->isStable() &&
       ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
@@ -510,6 +507,14 @@ void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID,
   }
 }
 
+void Model_Data::addBackReference(ObjectPtr theObject, std::string theAttrID)
+{
+  // it is possible to add the same attribute twice: may be last time the owner was not Stable...
+  AttributePtr anAttribute = theObject->data()->attribute(theAttrID);
+  if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
+    myRefsToMe.insert(anAttribute);
+}
+
 void Model_Data::updateConcealmentFlag()
 {
   std::set<AttributePtr>::iterator aRefsIter = myRefsToMe.begin();
index 186cfefc2a353a030c9df47d881a6b8140a4d3c2..72875fc5a6ef170756c549039bd3b5625b3db6c3 100644 (file)
@@ -36,6 +36,7 @@
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Feature.h>
+#include <ModelAPI_Folder.h>
 #include <ModelAPI_Object.h>
 
 #include <TDF_Label.hxx>
@@ -271,7 +272,7 @@ private:
   /// Removes a back reference (with identifier which attribute references to this object)
   /// \param theFeature feature referenced to this
   /// \param theAttrID identifier of the attribute that is references from theFeature to this
-  void removeBackReference(FeaturePtr theFeature, std::string theAttrID);
+  void removeBackReference(ObjectPtr theObject, std::string theAttrID);
   /// Removes a back reference (by the attribute)
   /// \param theAttr the referenced attribute
   void removeBackReference(AttributePtr theAttr);
@@ -281,6 +282,10 @@ private:
   /// \param theApplyConcealment applies consealment flag changes
   void addBackReference(FeaturePtr theFeature, std::string theAttrID,
     const bool theApplyConcealment = true);
+  /// Adds a back reference to an object
+  /// \param theObject object referenced to this
+  /// \param theAttrID identifier of the attribute that is references from theFolder to this
+  void addBackReference(ObjectPtr theObject, std::string theAttrID);
 
   /// Makes the concealment flag up to date for this object-owner.
   MODEL_EXPORT virtual void updateConcealmentFlag();
@@ -303,11 +308,15 @@ private:
 /// Without concealment change, it will be done later, on synchronization.
 #define ADD_BACK_REF(TARGET) \
   if (TARGET.get() != NULL) { \
+    std::shared_ptr<Model_Data> aTargetData = \
+        std::dynamic_pointer_cast<Model_Data>((TARGET)->data()); \
     FeaturePtr anAttributeOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner()); \
-    if (anAttributeOwnerFeature.get()) { \
-      std::shared_ptr<Model_Data> aTargetData = std::dynamic_pointer_cast<Model_Data>( \
-        (TARGET)->data()); \
+    if (anAttributeOwnerFeature.get()) \
       aTargetData->addBackReference(anAttributeOwnerFeature, id(), false); \
+    else { \
+      FolderPtr anAttributeOwnerFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(owner()); \
+      if (anAttributeOwnerFolder.get()) \
+        aTargetData->addBackReference(anAttributeOwnerFolder, id()); \
     } \
   }
 
@@ -315,11 +324,15 @@ private:
 /// Without concealment change, it will be done later, on synchronization.
 #define REMOVE_BACK_REF(TARGET) \
   if (TARGET.get() != NULL) { \
+    std::shared_ptr<Model_Data> aTargetData = \
+        std::dynamic_pointer_cast<Model_Data>((TARGET)->data()); \
     FeaturePtr anAttOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner()); \
-    if (anAttOwnerFeature.get()) { \
-      std::shared_ptr<Model_Data> aTargetData = std::dynamic_pointer_cast<Model_Data>( \
-        (TARGET)->data()); \
+    if (anAttOwnerFeature.get()) \
       aTargetData->removeBackReference(anAttOwnerFeature, id()); \
+    else { \
+      FolderPtr anAttributeOwnerFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(owner()); \
+      if (anAttributeOwnerFolder.get()) \
+        aTargetData->removeBackReference(anAttributeOwnerFolder, id()); \
     } \
   }
 
index 58a8b6b42e3e9a3e00b2465ce6ce1ed74e0579c0..669c6ac1fce327703ed3c4fc1ba5f0bd951c6a30 100755 (executable)
@@ -1289,9 +1289,10 @@ bool Model_Document::moveToFolder(
 }
 
 bool Model_Document::removeFromFolder(
-      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures)
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const bool theBefore)
 {
-  return myObjs->removeFromFolder(theFeatures);
+  return myObjs->removeFromFolder(theFeatures, theBefore);
 }
 
 std::shared_ptr<ModelAPI_Feature> Model_Document::feature(
index 300c07d61859ecba0f64ca74565c24a6422f1d51..946025f73fe34fa23d6644943b226afbc3be1083 100644 (file)
@@ -228,9 +228,14 @@ class Model_Document : public ModelAPI_Document
       const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
       const std::shared_ptr<ModelAPI_Folder>& theFolder);
   //! Remove features from the folder
+  //! \param theFeatures list of features to be removed
+  //! \param theBefore   extract features before the folder (this parameter is applicable only
+  //!                    when all features in the folder are taking out,
+  //!                    in other cases the direction is taken automatically)
   //! \return \c true if the features have been moved out
   MODEL_EXPORT virtual bool removeFromFolder(
-      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures);
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const bool theBefore = true);
 
   ///! Returns true if parametric updater need to execute feature on recomputartion
   ///! On abort, undo or redo it is not necessary: results in document are updated automatically
index 4163c0b513234474e021f9e4a89b34082f397c45..4522d14d8acfb7c2307804854cc654be07406999 100644 (file)
@@ -961,6 +961,29 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& t
   aData->updateConcealmentFlag();
 }
 
+static void collectReferences(std::shared_ptr<ModelAPI_Data> theData,
+                              std::map<ObjectPtr, std::set<AttributePtr> >& theRefs)
+{
+  if (theData.get()) {
+    std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+    theData->referencesToObjects(aRefs);
+    std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefsIt = aRefs.begin();
+    for(; aRefsIt != aRefs.end(); aRefsIt++) {
+      std::list<ObjectPtr>::iterator aRefTo = aRefsIt->second.begin();
+      for(; aRefTo != aRefsIt->second.end(); aRefTo++) {
+        if (*aRefTo) {
+          std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = theRefs.find(*aRefTo);
+          if (aFound == theRefs.end()) {
+            theRefs[*aRefTo] = std::set<AttributePtr>();
+            aFound = theRefs.find(*aRefTo);
+          }
+          aFound->second.insert(theData->attribute(aRefsIt->first));
+        }
+      }
+    }
+  }
+}
+
 void Model_Objects::synchronizeBackRefs()
 {
   // collect all back references in the separated container: to update everything at once,
@@ -971,25 +994,12 @@ void Model_Objects::synchronizeBackRefs()
   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
   for(; aFeatures.More(); aFeatures.Next()) {
     FeaturePtr aFeature = aFeatures.Value();
-    std::shared_ptr<Model_Data> aFData = std::dynamic_pointer_cast<Model_Data>(aFeature->data());
-    if (aFData.get()) {
-      std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
-      aFData->referencesToObjects(aRefs);
-      std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefsIt = aRefs.begin();
-      for(; aRefsIt != aRefs.end(); aRefsIt++) {
-        std::list<ObjectPtr>::iterator aRefTo = aRefsIt->second.begin();
-        for(; aRefTo != aRefsIt->second.end(); aRefTo++) {
-          if (*aRefTo) {
-            std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(*aRefTo);
-            if (aFound == allRefs.end()) {
-              allRefs[*aRefTo] = std::set<AttributePtr>();
-              aFound = allRefs.find(*aRefTo);
-            }
-            aFound->second.insert(aFeature->data()->attribute(aRefsIt->first));
-          }
-        }
-      }
-    }
+    collectReferences(aFeature->data(), allRefs);
+  }
+  NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator aFolders(myFolders);
+  for(; aFolders.More(); aFolders.Next()) {
+    ObjectPtr aFolder = aFolders.Value();
+    collectReferences(aFolder->data(), allRefs);
   }
   // second iteration: just compare back-references with existing in features and results
   for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
@@ -1328,7 +1338,7 @@ std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
     if (aFoundFolder) {
       AttributeReferencePtr aLastFeatAttr =
           aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
-      if (aLastFeatAttr && aLastFeatAttr->isInitialized()) {
+      if (aLastFeatAttr) {
         // setup iterating inside a folder to find last feature
         ObjectPtr aLastFeature = aLastFeatAttr->value();
         if (aLastFeature) {
@@ -1390,6 +1400,13 @@ bool Model_Objects::moveToFolder(
   if (aFolderLabel.IsNull() || aLastFeatureLabel.IsNull())
     return false;
 
+  AttributeReferencePtr aFirstFeatAttr =
+      theFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+  AttributeReferencePtr aLastFeatAttr =
+      theFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+  bool initFirstAttr = !aFirstFeatAttr->value().get();
+  bool initLastAttr  = !aLastFeatAttr->value().get();
+
   // check the folder is below the list of features
   bool isFolderBelow = false;
   TDF_Label aFeaturesLab = featuresLabel();
@@ -1424,22 +1441,119 @@ bool Model_Objects::moveToFolder(
     // move the folder in the list of references before the first feature
     RemoveFromRefArray(aFeaturesLab, aFolderLabel);
     AddToRefArray(aFeaturesLab, aFolderLabel, aPrevFeatureLabel);
+    // update first feature of the folder
+    initFirstAttr = true;
   } else {
     // update last feature of the folder
-    AttributeReferencePtr aLastFeatAttr =
-        theFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
-    aLastFeatAttr->setValue(theFeatures.back());
+    initLastAttr = true;
   }
 
+  if (initFirstAttr)
+    aFirstFeatAttr->setValue(theFeatures.front());
+  if (initLastAttr)
+    aLastFeatAttr->setValue(theFeatures.back());
+
   updateHistory(ModelAPI_Feature::group());
   return true;
 }
 
+static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr)
+{
+  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+  for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+    if ((*anIt)->id() != theFolderAttr)
+      continue;
+
+    ObjectPtr anOwner = (*anIt)->owner();
+    FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(anOwner);
+    if (aFolder.get())
+      return aFolder;
+  }
+  return FolderPtr();
+}
+
+static FolderPtr isExtractionCorrect(const FolderPtr& theFirstFeatureFolder,
+                                     const FolderPtr& theLastFeatureFolder,
+                                     bool& isExtractBefore)
+{
+  if (theFirstFeatureFolder.get()) {
+    if (theLastFeatureFolder.get())
+      return theFirstFeatureFolder == theLastFeatureFolder ? theFirstFeatureFolder : FolderPtr();
+    else
+      isExtractBefore = true;
+    return theFirstFeatureFolder;
+  } else if (theLastFeatureFolder.get()) {
+    isExtractBefore = false;
+    return theLastFeatureFolder;
+  }
+  // no folder found
+  return FolderPtr();
+}
+
 bool Model_Objects::removeFromFolder(
-      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures)
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const bool theBefore)
 {
-  /// \todo
-  return false;
+  if (theFeatures.empty())
+    return false;
+
+  FolderPtr aFirstFeatureFolder = inFolder(theFeatures.front(), ModelAPI_Folder::FIRST_FEATURE_ID());
+  FolderPtr aLastFeatureFolder  = inFolder(theFeatures.back(),  ModelAPI_Folder::LAST_FEATURE_ID());
+
+  bool isExtractBeforeFolder = theBefore;
+  FolderPtr aFoundFolder =
+      isExtractionCorrect(aFirstFeatureFolder, aLastFeatureFolder, isExtractBeforeFolder);
+  if (!aFoundFolder)
+    return false; // list of features cannot be extracted
+
+  // references of the current folder
+  ObjectPtr aFolderStartFeature;
+  ObjectPtr aFolderEndFeature;
+  if (aFirstFeatureFolder != aLastFeatureFolder) {
+    aFolderStartFeature = aFoundFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID())->value();
+    aFolderEndFeature   = aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->value();
+  }
+
+  FeaturePtr aFeatureToFind = isExtractBeforeFolder ? theFeatures.back() : theFeatures.front();
+  std::shared_ptr<Model_Data> aData =
+      std::static_pointer_cast<Model_Data>(aFeatureToFind->data());
+  if (!aData || !aData->isValid())
+    return false;
+  TDF_Label aLabelToFind = aData->label().Father();
+
+  // search the label in the list of references
+  TDF_Label aFeaturesLab = featuresLabel();
+  Handle(TDataStd_ReferenceArray) aRefs;
+  if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+    return false; // no reference array (something is wrong)
+  int aRefIndex = aRefs->Lower();
+  for (; aRefIndex <= aRefs->Upper(); ++aRefIndex)
+    if (aRefs->Value(aRefIndex) == aLabelToFind)
+      break;
+
+  // update folder position
+  if (isExtractBeforeFolder) {
+    aData = std::dynamic_pointer_cast<Model_Data>(aFoundFolder->data());
+    TDF_Label aFolderLabel = aData->label().Father();
+    TDF_Label aPrevFeatureLabel = aRefs->Value(aRefIndex);
+    // update start reference of the folder
+    if (aFolderStartFeature.get())
+      aFolderStartFeature = feature(aRefs->Value(aRefIndex + 1));
+    // move the folder in the list of references after the last feature from the list
+    RemoveFromRefArray(aFeaturesLab, aFolderLabel);
+    AddToRefArray(aFeaturesLab, aFolderLabel, aPrevFeatureLabel);
+  } else {
+    // update end reference of the folder
+    if (aFolderEndFeature.get())
+      aFolderEndFeature = feature(aRefs->Value(aRefIndex - 1));
+  }
+
+  // update folder references
+  aFoundFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID())->setValue(aFolderStartFeature);
+  aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(aFolderEndFeature);
+
+  updateHistory(ModelAPI_Feature::group());
+  return true;
 }
 
 
index 5e1f0b350b438a3fa786f82c1dcd8e8f3d32d01e..19572e143001cce978f159a0c629c30f5d6bfb88 100644 (file)
@@ -168,8 +168,13 @@ class Model_Objects
   bool moveToFolder(const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
                     const std::shared_ptr<ModelAPI_Folder>& theFolder);
   //! Remove features from the folder
+  //! \param theFeatures list of features to be removed
+  //! \param theBefore   extract features before the folder (this parameter is applicable only
+  //!                    when all features in the folder are taking out,
+  //!                    in other cases the direction is taken automatically)
   //! \return \c true if the features have been moved out
-  bool removeFromFolder(const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures);
+  bool removeFromFolder(const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+                        const bool theBefore = true);
 
   //! Sets the owner of this manager
   void setOwner(DocumentPtr theDoc);
index 7ad72541614f68d5b3527ea6a87df4c7352b900d..525805b1d575251736573fcc9d3f27cb7da11eb9 100644 (file)
@@ -202,9 +202,14 @@ public:
   virtual bool moveToFolder(const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
                             const std::shared_ptr<ModelAPI_Folder>& theFolder) = 0;
   //! Remove features from the folder
+  //! \param theFeatures list of features to be removed
+  //! \param theBefore   extract features before the folder (this parameter is applicable only
+  //!                    when all features in the folder are taking out,
+  //!                    in other cases the direction is taken automatically)
   //! \return \c true if the features have been moved out
   virtual bool removeFromFolder(
-      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures) = 0;
+      const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+      const bool theBefore = true) = 0;
 
   //! Informs the document that it becomes active and some actions must be performed
   virtual void setActive(const bool theFlag) = 0;
index 1cc97cb366036f7aa5648ec91b0fdd6b14e34594..9655293740f67bc3fba3485c963b8d2ad6bde62b 100644 (file)
@@ -38,6 +38,9 @@ void ModelAPI_Folder::initAttributes()
 {
   data()->addAttribute(FIRST_FEATURE_ID(), ModelAPI_AttributeReference::typeId());
   data()->addAttribute(LAST_FEATURE_ID(),  ModelAPI_AttributeReference::typeId());
+  // nullify references for sure
+  reference(FIRST_FEATURE_ID())->setValue(ObjectPtr());
+  reference(LAST_FEATURE_ID())->setValue(ObjectPtr());
 }
 
 void ModelAPI_Folder::execute()
index 1ef1a8c6afa4ee2117e6703f91dd8231353ad295..a118cbacfe4fc87d3df5332ffd1b4f094899589c 100644 (file)
@@ -109,7 +109,7 @@ toFolder.append(aPoint2)
 
 # move point to the folder
 aSession.startOperation()
-aFolder = aPartDoc.findFolderAbove(toFolder)
+aFolder = aPartDoc.findFolderBelow(toFolder)
 assert(aFolder is not None)
 isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
 aSession.finishOperation()
@@ -138,7 +138,7 @@ assert(aPartDoc.index(aPoint4, True) == 3), "Wrong index of the point: {}".forma
 
 # add a folder
 aSession.startOperation()
-aFolder2 = aPartDoc.addFolder(aPoint3)
+aFolder3 = aPartDoc.addFolder(aPoint3)
 aSession.finishOperation()
 
 NB_FEATURES_FULL += 1
@@ -149,10 +149,10 @@ assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features
 assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
 
 # index without respect to foldering
-assert(aPartDoc.index(aFolder2) == 4), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder2))
+assert(aPartDoc.index(aFolder3) == 4), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3))
 assert(aPartDoc.index(aPoint4) == 6), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4))
 # index according to folders
-assert(aPartDoc.index(aFolder2, True) == 2), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder2, True))
+assert(aPartDoc.index(aFolder3, True) == 2), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
 assert(aPartDoc.index(aPoint4, True) == 4), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4, True))
 
 toFolder = FeatureList()
@@ -173,14 +173,163 @@ assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features
 assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
 
 # index without respect to foldering
-assert(aPartDoc.index(aFolder2) == 4), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder2))
+assert(aPartDoc.index(aFolder3) == 4), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3))
 assert(aPartDoc.index(aPoint3) == 5), "Wrong index of the point: {}".format(aPartDoc.index(aPoint3))
 assert(aPartDoc.index(aPoint4) == 6), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4))
 # index according to folders
-assert(aPartDoc.index(aFolder2, True) == 2), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder2, True))
+assert(aPartDoc.index(aFolder3, True) == 2), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
 assert(aPartDoc.index(aPoint3, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint3, True))
 assert(aPartDoc.index(aPoint4, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4, True))
 
 
+# add more points to the folder to move them out
+aPoint5 = newPoint(aPartDoc, 0., 0., 10.)
+aPoint6 = newPoint(aPartDoc, 10., 0., 10.)
+aPoint7 = newPoint(aPartDoc, 10., 10., 10.)
+aPoint8 = newPoint(aPartDoc, 0., 10., 10.)
+
+toFolder = FeatureList()
+toFolder.append(aPoint5)
+toFolder.append(aPoint6)
+toFolder.append(aPoint7)
+toFolder.append(aPoint8)
+
+# move point to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderAbove(toFolder)
+assert(aFolder is not None)
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+
+NB_FEATURES_FULL += 4
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+assert(aPartDoc.index(aPoint5, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint5, True))
+assert(aPartDoc.index(aPoint6, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint6, True))
+assert(aPartDoc.index(aPoint7, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint7, True))
+assert(aPartDoc.index(aPoint8, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint8, True))
+
+assert(aFolder3.reference("first_feature").value() is not None)
+assert(aFolder3.reference("last_feature").value() is not None)
+
+#=========================================================================
+# Test 4. Remove a point from a folder before it
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(aPoint3)
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder)
+aSession.finishOperation()
+assert(isMovedOut)
+
+NB_FEATURES_OUT += 1
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+assert(aPartDoc.index(aPoint3, True) == 2), "Wrong index of the point: {}".format(aPartDoc.index(aPoint3, True))
+assert(aPartDoc.index(aFolder3, True) == 3), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+
+assert(aFolder3.reference("first_feature").value() is not None)
+assert(aFolder3.reference("last_feature").value() is not None)
+
+#=========================================================================
+# Test 5. Remove a point from a folder after it
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(aPoint8)
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder)
+aSession.finishOperation()
+assert(isMovedOut)
+
+NB_FEATURES_OUT += 1
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+assert(aPartDoc.index(aPoint8, True) == 4), "Wrong index of the point: {}".format(aPartDoc.index(aPoint8, True))
+assert(aPartDoc.index(aFolder3, True) == 3), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+
+assert(aFolder3.reference("first_feature").value() is not None)
+assert(aFolder3.reference("last_feature").value() is not None)
+
+#=========================================================================
+# Test 6. Try to remove several points which are not start nor end in a folder
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(aPoint5)
+fromFolder.append(aPoint6)
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder)
+aSession.finishOperation()
+assert(isMovedOut is False)
+
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+assert(aPartDoc.index(aFolder3, True) == 3), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+assert(aPartDoc.index(aPoint5, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint5, True))
+assert(aPartDoc.index(aPoint6, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint6, True))
+assert(aPartDoc.index(aPoint8, True) == 4), "Wrong index of the point: {}".format(aPartDoc.index(aPoint8, True))
+
+assert(aFolder3.reference("first_feature").value() is not None)
+assert(aFolder3.reference("last_feature").value() is not None)
+
+#=========================================================================
+# Test 7. Remove several points from a folder after it
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(aPoint6)
+fromFolder.append(aPoint7)
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder)
+aSession.finishOperation()
+assert(isMovedOut)
+
+NB_FEATURES_OUT += 2
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+assert(aPartDoc.index(aFolder3, True) == 3), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+assert(aPartDoc.index(aPoint6, True) == 4), "Wrong index of the point: {}".format(aPartDoc.index(aPoint6, True))
+assert(aPartDoc.index(aPoint7, True) == 5), "Wrong index of the point: {}".format(aPartDoc.index(aPoint7, True))
+assert(aPartDoc.index(aPoint8, True) == 6), "Wrong index of the point: {}".format(aPartDoc.index(aPoint8, True))
+
+assert(aFolder3.reference("first_feature").value() is not None)
+assert(aFolder3.reference("last_feature").value() is not None)
+
+#=========================================================================
+# Test 8. Remove all remaining points from a folder after it
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(aPoint4)
+fromFolder.append(aPoint5)
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder, False)
+aSession.finishOperation()
+assert(isMovedOut)
+
+NB_FEATURES_OUT += 2
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+assert(aPartDoc.index(aFolder3, True) == 3), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+assert(aPartDoc.index(aPoint4, True) == 4), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4, True))
+assert(aPartDoc.index(aPoint5, True) == 5), "Wrong index of the point: {}".format(aPartDoc.index(aPoint5, True))
+assert(aPartDoc.index(aPoint6, True) == 6), "Wrong index of the point: {}".format(aPartDoc.index(aPoint6, True))
+assert(aPartDoc.index(aPoint7, True) == 7), "Wrong index of the point: {}".format(aPartDoc.index(aPoint7, True))
+assert(aPartDoc.index(aPoint8, True) == 8), "Wrong index of the point: {}".format(aPartDoc.index(aPoint8, True))
+
+# folder is empty
+assert(aFolder3.reference("first_feature").value() is None)
+assert(aFolder3.reference("last_feature").value() is None)
+
+
 from salome.shaper import model
 assert(model.checkPythonDump())