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);
}
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)) {
}
}
+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();
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_Data.h>
#include <ModelAPI_Feature.h>
+#include <ModelAPI_Folder.h>
#include <ModelAPI_Object.h>
#include <TDF_Label.hxx>
/// 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);
/// \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();
/// 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()); \
} \
}
/// 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()); \
} \
}
}
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(
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
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,
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()) {
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) {
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();
// 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;
}
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);
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;
{
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()
# 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()
# add a folder
aSession.startOperation()
-aFolder2 = aPartDoc.addFolder(aPoint3)
+aFolder3 = aPartDoc.addFolder(aPoint3)
aSession.finishOperation()
NB_FEATURES_FULL += 1
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()
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())