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(ObjectPtr(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(ObjectPtr(anAttributeOwnerFolder), id()); \
} \
}
int aSubs = aComp->numberOfSubs(false);
for(int a = 0; a < aSubs; a++) {
FeaturePtr aSub = aComp->subFeature(a, false);
- if (myObjs->isLater(aSub, aCurrent)) {
+ if (aSub && myObjs->isLater(aSub, aCurrent)) {
isModified = true;
aCurrent = aSub;
}
Model_Application::getApplication()->document(theDocID));
}
-ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex)
+ObjectPtr Model_Document::object(const std::string& theGroupID,
+ const int theIndex,
+ const bool theAllowFolder)
{
- return myObjs->object(theGroupID, theIndex);
+ return myObjs->object(theGroupID, theIndex, theAllowFolder);
}
std::shared_ptr<ModelAPI_Object> Model_Document::objectByName(
return myObjs->objectByName(theGroupID, theName);
}
-const int Model_Document::index(std::shared_ptr<ModelAPI_Object> theObject)
+const int Model_Document::index(std::shared_ptr<ModelAPI_Object> theObject,
+ const bool theAllowFolder)
{
- return myObjs->index(theObject);
+ return myObjs->index(theObject, theAllowFolder);
}
-int Model_Document::size(const std::string& theGroupID)
+int Model_Document::size(const std::string& theGroupID, const bool theAllowFolder)
{
if (myObjs == 0) // may be on close
return 0;
- return myObjs->size(theGroupID);
+ return myObjs->size(theGroupID, theAllowFolder);
}
std::shared_ptr<ModelAPI_Feature> Model_Document::currentFeature(const bool theVisible)
return myObjs->createParameter(theFeatureData, theIndex);
}
+std::shared_ptr<ModelAPI_Folder> Model_Document::addFolder(
+ std::shared_ptr<ModelAPI_Feature> theAddBefore)
+{
+ return myObjs->createFolder(theAddBefore);
+}
+
+void Model_Document::removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder)
+{
+ if (theFolder)
+ myObjs->removeFolder(theFolder);
+}
+
+std::shared_ptr<ModelAPI_Folder> Model_Document::findFolderAbove(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures)
+{
+ return myObjs->findFolder(theFeatures, false);
+}
+
+std::shared_ptr<ModelAPI_Folder> Model_Document::findFolderBelow(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures)
+{
+ return myObjs->findFolder(theFeatures, true);
+}
+
+std::shared_ptr<ModelAPI_Folder> Model_Document::findContainingFolder(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ int& theIndexInFolder)
+{
+ return myObjs->findContainingFolder(theFeature, theIndexInFolder);
+}
+
+bool Model_Document::moveToFolder(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+ const std::shared_ptr<ModelAPI_Folder>& theFolder)
+{
+ return myObjs->moveToFolder(theFeatures, theFolder);
+}
+
+bool Model_Document::removeFromFolder(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+ const bool theBefore)
+{
+ return myObjs->removeFromFolder(theFeatures, theBefore);
+}
+
std::shared_ptr<ModelAPI_Feature> Model_Document::feature(
const std::shared_ptr<ModelAPI_Result>& theResult)
{
return myObjs->allFeatures();
}
+std::list<std::shared_ptr<ModelAPI_Object> > Model_Document::allObjects()
+{
+ return myObjs->allObjects();
+}
+
void Model_Document::setActive(const bool theFlag)
{
if (theFlag != myIsActive) {
//! Returns the object index in the group. Object must be visible. Otherwise returns -1.
//! \param theObject object of this document
+ //! \param theAllowFolder take into account grouping feature by folders
//! \returns index started from zero, or -1 if object is invisible or belongs to another document
- MODEL_EXPORT virtual const int index(std::shared_ptr<ModelAPI_Object> theObject);
+ MODEL_EXPORT virtual const int index(std::shared_ptr<ModelAPI_Object> theObject,
+ const bool theAllowFolder = false);
//! Internal sub-document by ID
MODEL_EXPORT virtual std::shared_ptr<Model_Document> subDoc(int theDocID);
//! Returns the feature in the group by the index (started from zero)
//! \param theGroupID group that contains a feature
//! \param theIndex zero-based index of feature in the group
- MODEL_EXPORT virtual ObjectPtr object(const std::string& theGroupID, const int theIndex);
+ //! \param theAllowFolder take into account grouping feature by folders
+ MODEL_EXPORT virtual ObjectPtr object(const std::string& theGroupID,
+ const int theIndex,
+ const bool theAllowFolder = false);
//! Returns the number of features in the group
- MODEL_EXPORT virtual int size(const std::string& theGroupID);
+ //! \param theGroupID group of objects
+ //! \param theAllowFolder take into account grouping feature by folders
+ MODEL_EXPORT virtual int size(const std::string& theGroupID, const bool theAllowFolder = false);
//! Returns the feature that is currently edited in this document, normally
//! this is the latest created feature
MODEL_EXPORT virtual std::shared_ptr<ModelAPI_Feature>
feature(const std::shared_ptr<ModelAPI_Result>& theResult);
+ //! Creates a folder (group of the features in the object browser)
+ //! \param theAddBefore a feature, the folder is added before
+ //! (if empty, the folder is added after the last feature)
+ MODEL_EXPORT virtual std::shared_ptr<ModelAPI_Folder> addFolder(
+ std::shared_ptr<ModelAPI_Feature> theAddBefore = std::shared_ptr<ModelAPI_Feature>());
+ //! Removes the folder from the document (all features in the folder will be kept).
+ MODEL_EXPORT virtual void removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder);
+ //! Search a folder above the list of features applicable to store them
+ //! (it means the list of features stored in the folder should be consequential)
+ //! \return Empty pointer if there is no applicable folder
+ MODEL_EXPORT virtual std::shared_ptr<ModelAPI_Folder> findFolderAbove(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures);
+ //! Search a folder below the list of features applicable to store them
+ //! (it means the list of features stored in the folder should be consequential)
+ //! \return Empty pointer if there is no applicable folder
+ MODEL_EXPORT virtual std::shared_ptr<ModelAPI_Folder> findFolderBelow(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures);
+ //! Search a folder containing the given feature.
+ //! Addtionally calculates a zero-based index of the feature in this folder.
+ //! \param theFeature feature to search
+ //! \param theIndexInFolder zero-based index in the folder or -1 if the feature is top-level.
+ //! \return the folder containing the feature or empty pointer if the feature is top-level.
+ MODEL_EXPORT virtual std::shared_ptr<ModelAPI_Folder> findContainingFolder(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ int& theIndexInFolder);
+ //! Add a list of features to the folder. The correctness of the adding is not performed
+ //! (such checks have been done in corresponding find.. method).
+ //! \return \c true if the movement is successfull
+ MODEL_EXPORT virtual 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
+ MODEL_EXPORT virtual bool removeFromFolder(
+ 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
bool executeFeatures() {return myExecuteFeatures;}
///! history. Not very fast method, for calling once, not in big cycles.
MODEL_EXPORT virtual std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures();
+ //! Returns all objects of the document including the hidden features which are not in
+ //! history. Not very fast method, for calling once, not in big cycles.
+ MODEL_EXPORT virtual std::list<std::shared_ptr<ModelAPI_Object> > allObjects();
+
/// Returns the global identifier of the current transaction (needed for the update algo)
MODEL_EXPORT virtual int transactionID();
/// Increases the transaction ID
#include <TDF_LabelMap.hxx>
#include <TDF_ListIteratorOfLabelList.hxx>
+static const std::string& groupNameFoldering(const std::string& theGroupID,
+ const bool theAllowFolder)
+{
+ if (theAllowFolder) {
+ static const std::string anOutOfFolderName = std::string("__") + ModelAPI_Feature::group();
+ static const std::string aDummyName;
+ return theGroupID == ModelAPI_Feature::group() ? anOutOfFolderName : aDummyName;
+ }
+ return theGroupID;
+}
+
+
static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
// feature sub-labels
aFeature->erase();
myFeatures.UnBind(aFeaturesIter.Key());
}
+ while (!myFolders.IsEmpty()) {
+ NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator aFoldersIter(myFolders);
+ ObjectPtr aFolder = aFoldersIter.Value();
+ static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Folder::group());
+ ModelAPI_EventCreator::get()->sendUpdated(aFolder, EVENT_DISP);
+ aFolder->erase();
+ myFolders.UnBind(aFoldersIter.Key());
+ }
myHistory.clear();
aLoop->activateFlushes(isActive);
// erase update, because features are destroyed and update should not performed for them anywhere
{
if (theObj.get()) {
const std::string aGroup = theObj->groupName();
- std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(aGroup);
- if (aHIter != myHistory.end())
- myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
+ updateHistory(aGroup);
+
if (theObj->groupName() == ModelAPI_Feature::group()) { // clear results group of the feature
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
std::string aResultGroup = featureResultGroup(aFeature);
{
std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroupID);
if (aHIter == myHistory.end()) {
- std::vector<ObjectPtr> aResult = std::vector<ObjectPtr>();
+ std::vector<ObjectPtr> aResult;
+ std::vector<ObjectPtr> aResultOutOfFolder;
+ FeaturePtr aLastFeatureInFolder;
// iterate the array of references and get feature by feature from the array
bool isFeature = theGroupID == ModelAPI_Feature::group();
+ bool isFolder = theGroupID == ModelAPI_Folder::group();
Handle(TDataStd_ReferenceArray) aRefs;
if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
if (isFeature) { // here may be also disabled features
if (!isSub && aFeature->isInHistory()) {
aResult.push_back(aFeature);
+ // the feature is out of the folders
+ if (aLastFeatureInFolder.get() == NULL)
+ aResultOutOfFolder.push_back(aFeature);
}
} else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
// construction results of sub-features should not be in the tree
}
}
}
+
+ // the feature closes the folder, so the next features will be treated as out-of-folder
+ if (aLastFeatureInFolder.get() && aLastFeatureInFolder == aFeature)
+ aLastFeatureInFolder = FeaturePtr();
+
+ } else {
+ // it may be a folder
+ ObjectPtr aFolder = folder(aRefs->Value(a));
+ if (aFolder.get()) {
+ // store folder information for the Features group only
+ if (isFeature || isFolder) {
+ aResult.push_back(aFolder);
+ if (!isFolder)
+ aResultOutOfFolder.push_back(aFolder);
+ }
+
+ // get the last feature in the folder
+ AttributeReferencePtr aLastFeatAttr =
+ aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ if (aLastFeatAttr)
+ aLastFeatureInFolder = ModelAPI_Feature::feature(aLastFeatAttr->value());
+ }
}
}
}
// to be sure that isConcealed did not update the history (issue 1089) during the iteration
- if (myHistory.find(theGroupID) == myHistory.end())
+ if (myHistory.find(theGroupID) == myHistory.end()) {
myHistory[theGroupID] = aResult;
+
+ // store the features placed out of any folder
+ const std::string& anOutOfFolderGroupID = groupNameFoldering(theGroupID, true);
+ if (!anOutOfFolderGroupID.empty())
+ myHistory[anOutOfFolderGroupID] = aResultOutOfFolder;
+ }
}
}
void Model_Objects::updateHistory(const std::string theGroup)
{
std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroup);
- if (aHIter != myHistory.end())
+ if (aHIter != myHistory.end()) {
myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
+
+ // erase history for the group of objects placed out of any folder
+ const std::string& anOutOfFolderGroupID = groupNameFoldering(theGroup, true);
+ if (!anOutOfFolderGroupID.empty())
+ myHistory.erase(anOutOfFolderGroupID);
+ }
+}
+
+ObjectPtr Model_Objects::folder(TDF_Label theLabel) const
+{
+ if (myFolders.IsBound(theLabel))
+ return myFolders.Find(theLabel);
+ return ObjectPtr();
}
FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
return FeaturePtr(); // not found
}
-ObjectPtr Model_Objects::object(const std::string& theGroupID, const int theIndex)
+ObjectPtr Model_Objects::object(const std::string& theGroupID,
+ const int theIndex,
+ const bool theAllowFolder)
{
if (theIndex == -1)
return ObjectPtr();
createHistory(theGroupID);
- return myHistory[theGroupID][theIndex];
+ const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
+ return aGroupID.empty() ? myHistory[theGroupID][theIndex] : myHistory[aGroupID][theIndex];
}
std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
return ObjectPtr();
}
-const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
+const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject,
+ const bool theAllowFolder)
{
std::string aGroup = theObject->groupName();
+ // treat folder as feature
+ if (aGroup == ModelAPI_Folder::group())
+ aGroup = ModelAPI_Feature::group();
createHistory(aGroup);
+
+ // get the group of features out of folder (if enabled)
+ if (theAllowFolder && !groupNameFoldering(aGroup, theAllowFolder).empty())
+ aGroup = groupNameFoldering(aGroup, theAllowFolder);
+
std::vector<ObjectPtr>& allObjs = myHistory[aGroup];
std::vector<ObjectPtr>::iterator anObjIter = allObjs.begin(); // iterate to search object
for(int anIndex = 0; anObjIter != allObjs.end(); anObjIter++, anIndex++) {
return -1;
}
-int Model_Objects::size(const std::string& theGroupID)
+int Model_Objects::size(const std::string& theGroupID, const bool theAllowFolder)
{
createHistory(theGroupID);
- return int(myHistory[theGroupID].size());
+ const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
+ return aGroupID.empty() ? int(myHistory[theGroupID].size()) : int(myHistory[aGroupID].size());
}
void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
return myMain.FindChild(TAG_OBJECTS);
}
+static std::string composeName(const std::string& theFeatureKind, const int theIndex)
+{
+ std::stringstream aNameStream;
+ aNameStream << theFeatureKind << "_" << theIndex;
+ return aNameStream.str();
+}
+
void Model_Objects::setUniqueName(FeaturePtr theFeature)
{
if (!theFeature->data()->name().empty())
aNumObjects++;
}
// generate candidate name
- std::stringstream aNameStream;
- aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
- aName = aNameStream.str();
+ aName = composeName(theFeature->getKind(), aNumObjects + 1);
// check this is unique, if not, increase index by 1
for (aFIter.Initialize(myFeatures); aFIter.More();) {
FeaturePtr aFeature = aFIter.Value();
if (isSameName) {
aNumObjects++;
- std::stringstream aNameStream;
- aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
- aName = aNameStream.str();
+ aName = composeName(theFeature->getKind(), aNumObjects + 1);
// reinitialize iterator to make sure a new name is unique
aFIter.Initialize(myFeatures);
} else
theFeature->data()->setName(aName);
}
+void Model_Objects::setUniqueName(FolderPtr theFolder)
+{
+ if (!theFolder->name().empty())
+ return; // name is already defined
+
+ int aNbFolders = myFolders.Size();
+ std::string aName = composeName(ModelAPI_Folder::ID(), aNbFolders);
+
+ // check the uniqueness of the name
+ NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator anIt(myFolders);
+ while (anIt.More()) {
+ if (anIt.Value()->data()->name() == aName) {
+ aName = composeName(ModelAPI_Folder::ID(), aNbFolders);
+ // reinitialize iterator to make sure a new name is unique
+ anIt.Initialize(myFolders);
+ } else
+ anIt.Next();
+ }
+
+ theFolder->data()->setName(aName);
+}
+
void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag)
{
std::shared_ptr<Model_Data> aData(new Model_Data);
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
if (aFeature.get()) {
setUniqueName(aFeature); // must be before "initAttributes" because duplicate part uses name
+ } else { // is it a folder?
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(theObj);
+ if (aFolder)
+ setUniqueName(aFolder);
}
theObj->initAttributes();
}
}
// update all objects by checking are they on labels or not
- std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
+ std::set<ObjectPtr> aNewFeatures, aKeptFeatures;
TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
for (; aLabIter.More(); aLabIter.Next()) {
TDF_Label aFeatureLabel = aLabIter.Value()->Label();
- FeaturePtr aFeature;
- if (!myFeatures.IsBound(aFeatureLabel)) { // a new feature is inserted
+ if (!myFeatures.IsBound(aFeatureLabel) && !myFolders.IsBound(aFeatureLabel)) {
+ // a new feature or folder is inserted
+
+ std::string aFeatureID = TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(
+ aLabIter.Value())->Get()).ToCString();
+ bool isFolder = aFeatureID == ModelAPI_Folder::ID();
+
+ std::shared_ptr<Model_Session> aSession =
+ std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get());
+
// create a feature
- aFeature = std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get())->createFeature(
- TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
- .ToCString(), anOwner);
+ ObjectPtr aFeature = isFolder ? ObjectPtr(new ModelAPI_Folder)
+ : ObjectPtr(aSession->createFeature(aFeatureID, anOwner));
if (!aFeature.get()) {
// somethig is wrong, most probably, the opened document has invalid structure
Events_InfoMessage("Model_Objects", "Invalid type of object in the document").send();
}
aFeature->init();
// this must be before "setData" to redo the sketch line correctly
- myFeatures.Bind(aFeatureLabel, aFeature);
+ if (isFolder)
+ myFolders.Bind(aFeatureLabel, aFeature);
+ else
+ myFeatures.Bind(aFeatureLabel, std::dynamic_pointer_cast<ModelAPI_Feature>(aFeature));
aNewFeatures.insert(aFeature);
initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
updateHistory(aFeature);
// event: model is updated
ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
} else { // nothing is changed, both iterators are incremented
- aFeature = myFeatures.Find(aFeatureLabel);
- aKeptFeatures.insert(aFeature);
+ ObjectPtr anObject;
+ FeaturePtr aFeature;
+ if (myFeatures.Find(aFeatureLabel, aFeature)) {
+ aKeptFeatures.insert(aFeature);
+ anObject = aFeature;
+ } else
+ if (myFolders.Find(aFeatureLabel, anObject))
+ aKeptFeatures.insert(anObject);
+
if (anUpdatedMap.Contains(aFeatureLabel)) {
if (!theOpen) { // on abort/undo/redo reinitialize attributes if something is changed
std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs =
- aFeature->data()->attributes("");
+ anObject->data()->attributes("");
std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
for(; anAttr != anAttrs.end(); anAttr++)
(*anAttr)->reinit();
}
- ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
- if (aFeature->getKind() == "Parameter") {
+ ModelAPI_EventCreator::get()->sendUpdated(anObject, anUpdateEvent);
+ if (aFeature && aFeature->getKind() == "Parameter") {
// if parameters are changed, update the results (issue 937)
const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
} else
aFIter.Next();
}
+ // verify folders are checked: if not => is was removed
+ for (NCollection_DataMap<TDF_Label, ObjectPtr>::Iterator aFldIt(myFolders);
+ aFldIt.More(); aFldIt.Next()) {
+ ObjectPtr aCurObj = aFldIt.Value();
+ if (aKeptFeatures.find(aCurObj) == aKeptFeatures.end() &&
+ aNewFeatures.find(aCurObj) == aNewFeatures.end()) {
+ ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Folder::group());
+ // results of this feature must be redisplayed (hided)
+ // redisplay also removed feature (used for sketch and AISObject)
+ ModelAPI_EventCreator::get()->sendUpdated(aCurObj, aRedispEvent);
+ updateHistory(aCurObj);
+ aCurObj->erase();
+
+ // unbind after the "erase" call: on abort sketch
+ // is removes sub-objects that corrupts aFIter
+ myFolders.UnBind(aFldIt.Key());
+ }
+ }
if (theUpdateReferences) {
synchronizeBackRefs();
for(; aNewIter != theNewRefs.end(); aNewIter++) {
if (aData->refsToMe().find(*aNewIter) == aData->refsToMe().end()) {
FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aNewIter)->owner());
- aData->addBackReference(aRefFeat, (*aNewIter)->id());
+ if (aRefFeat)
+ aData->addBackReference(aRefFeat, (*aNewIter)->id());
+ else // add back reference to a folder
+ aData->addBackReference((*aNewIter)->owner(), (*aNewIter)->id());
}
}
if (theNewRefs.size() != aData->refsToMe().size()) { // some back ref must be removed
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()) {
return aResult;
}
+std::shared_ptr<ModelAPI_Folder> Model_Objects::createFolder(
+ const std::shared_ptr<ModelAPI_Feature>& theBeforeThis)
+{
+ FolderPtr aFolder(new ModelAPI_Folder);
+ if (!aFolder)
+ return aFolder;
+
+ TDF_Label aFeaturesLab = featuresLabel();
+ TDF_Label aFolderLab = aFeaturesLab.NewChild();
+ // store feature in the features array: before "initData" because in macro features
+ // in initData it creates new features, appeared later than this
+ TDF_Label aPrevFeatureLab;
+ if (theBeforeThis.get()) { // searching for the previous feature label
+ std::shared_ptr<Model_Data> aPrevData =
+ std::dynamic_pointer_cast<Model_Data>(theBeforeThis->data());
+ if (aPrevData.get()) {
+ aPrevFeatureLab = nextLabel(aPrevData->label().Father(), true);
+ }
+ } else { // find the label of the last feature
+ Handle(TDataStd_ReferenceArray) aRefs;
+ if (aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+ aPrevFeatureLab = aRefs->Value(aRefs->Upper());
+ }
+ AddToRefArray(aFeaturesLab, aFolderLab, aPrevFeatureLab);
+
+ // keep the feature ID to restore document later correctly
+ TDataStd_Comment::Set(aFolderLab, ModelAPI_Folder::ID().c_str());
+ myFolders.Bind(aFolderLab, aFolder);
+ // must be before the event sending: for OB the feature is already added
+ updateHistory(ModelAPI_Folder::group());
+ updateHistory(ModelAPI_Feature::group());
+
+ // must be after binding to the map because of "Box" macro feature that
+ // creates other features in "initData"
+ initData(aFolder, aFolderLab, TAG_FEATURE_ARGUMENTS);
+ // event: folder is added, must be before "initData" to update OB correctly on Duplicate:
+ // first new part, then the content
+ static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
+ ModelAPI_EventCreator::get()->sendUpdated(aFolder, anEvent);
+
+ return aFolder;
+}
+
+void Model_Objects::removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder)
+{
+ std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFolder->data());
+ if (!aData.get() || !aData->isValid())
+ return;
+
+ // this must be before erase since theFolder erasing removes all information about it
+ clearHistory(theFolder);
+ // erase fields
+ theFolder->erase();
+
+ TDF_Label aFolderLabel = aData->label().Father();
+ if (myFolders.IsBound(aFolderLabel))
+ myFolders.UnBind(aFolderLabel);
+
+ static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ ModelAPI_EventCreator::get()->sendUpdated(theFolder, EVENT_DISP);
+ // erase all attributes under the label of feature
+ aFolderLabel.ForgetAllAttributes();
+ // remove it from the references array
+ RemoveFromRefArray(featuresLabel(), aFolderLabel);
+ // event: feature is deleted
+ ModelAPI_EventCreator::get()->sendDeleted(theFolder->document(), ModelAPI_Folder::group());
+ updateHistory(ModelAPI_Folder::group());
+ updateHistory(ModelAPI_Feature::group());
+}
+
+// Returns one of the limiting features of the list
+static FeaturePtr limitingFeature(std::list<FeaturePtr>& theFeatures, const bool isLast)
+{
+ FeaturePtr aFeature;
+ if (isLast) {
+ aFeature = theFeatures.back();
+ theFeatures.pop_back();
+ } else {
+ aFeature = theFeatures.front();
+ theFeatures.pop_front();
+ }
+ return aFeature;
+}
+
+// Verify the feature is sub-element in composite feature or it is not used in the history
+static bool isSkippedFeature(FeaturePtr theFeature)
+{
+ bool isSub = ModelAPI_Tools::compositeOwner(theFeature).get() != NULL;
+ return isSub || (theFeature && !theFeature->isInHistory());
+}
+
+std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+ const bool theBelow)
+{
+ if (theFeatures.empty())
+ return FolderPtr(); // nothing to move
+
+ TDF_Label aFeaturesLab = featuresLabel();
+ Handle(TDataStd_ReferenceArray) aRefs;
+ if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+ return FolderPtr(); // no reference array (something is wrong)
+
+ std::list<std::shared_ptr<ModelAPI_Feature> > aFeatures = theFeatures;
+ std::shared_ptr<ModelAPI_Feature> aLimitingFeature = limitingFeature(aFeatures, theBelow);
+
+ std::shared_ptr<Model_Data> aData =
+ std::static_pointer_cast<Model_Data>(aLimitingFeature->data());
+ if (!aData || !aData->isValid())
+ return FolderPtr(); // invalid feature
+
+ // label of the first feature in the list for fast searching
+ TDF_Label aFirstFeatureLabel = aData->label().Father();
+
+ // find a folder above the features and
+ // check the given features represent a sequential list of objects following the folder
+ FolderPtr aFoundFolder;
+ TDF_Label aLastFeatureInFolder;
+ int aRefIndex = aRefs->Lower();
+ for(; aRefIndex <= aRefs->Upper(); ++aRefIndex) { // iterate all existing features
+ TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+ if (IsEqual(aCurLabel, aFirstFeatureLabel))
+ break; // no need to continue searching
+
+ // searching the folder below, just continue to search last feature from the list
+ if (theBelow)
+ continue;
+
+ // if feature is in sub-component, skip it
+ FeaturePtr aCurFeature = feature(aCurLabel);
+ if (isSkippedFeature(aCurFeature))
+ continue;
+
+ if (!aLastFeatureInFolder.IsNull()) {
+ if (IsEqual(aCurLabel, aLastFeatureInFolder))
+ aLastFeatureInFolder.Nullify(); // the last feature in the folder is achived
+ continue;
+ }
+
+ aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
+ if (aFoundFolder) {
+ AttributeReferencePtr aLastFeatAttr =
+ aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ if (aLastFeatAttr) {
+ // setup iterating inside a folder to find last feature
+ ObjectPtr aLastFeature = aLastFeatAttr->value();
+ if (aLastFeature) {
+ aData = std::static_pointer_cast<Model_Data>(aLastFeature->data());
+ if (aData && aData->isValid())
+ aLastFeatureInFolder = aData->label().Father();
+ }
+ }
+ }
+ }
+
+ if (theBelow && aRefIndex < aRefs->Upper()) {
+ TDF_Label aLabel;
+ // skip following features which are sub-components or not in history
+ for (int anIndex = aRefIndex + 1; anIndex <= aRefs->Upper(); ++anIndex) {
+ aLabel = aRefs->Value(anIndex);
+ FeaturePtr aCurFeature = feature(aLabel);
+ if (!isSkippedFeature(aCurFeature))
+ break;
+ }
+ // check the next object is a folder
+ aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aLabel));
+ }
+
+ if (!aLastFeatureInFolder.IsNull() || // the last feature of the folder above is not found
+ !aFoundFolder)
+ return FolderPtr();
+
+ // check the given features are sequential list
+ int aStep = theBelow ? -1 : 1;
+ for (aRefIndex += aStep;
+ !aFeatures.empty() && aRefIndex >= aRefs->Lower() && aRefIndex <= aRefs->Upper();
+ aRefIndex += aStep) {
+ TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+ // if feature is in sub-component, skip it
+ FeaturePtr aCurFeature = feature(aCurLabel);
+ if (isSkippedFeature(aCurFeature))
+ continue;
+
+ aLimitingFeature = limitingFeature(aFeatures, theBelow);
+ if (!aCurFeature->data()->isEqual(aLimitingFeature->data()))
+ return FolderPtr(); // not a sequential list
+ }
+
+ return aFoundFolder;
+}
+
+bool Model_Objects::moveToFolder(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+ const std::shared_ptr<ModelAPI_Folder>& theFolder)
+{
+ if (theFeatures.empty() || !theFolder)
+ return false;
+
+ // labels for the folder and last feature in the list
+ TDF_Label aFolderLabel, aLastFeatureLabel;
+ std::shared_ptr<Model_Data> aData =
+ std::static_pointer_cast<Model_Data>(theFolder->data());
+ if (aData && aData->isValid())
+ aFolderLabel = aData->label().Father();
+ aData = std::static_pointer_cast<Model_Data>(theFeatures.back()->data());
+ if (aData && aData->isValid())
+ aLastFeatureLabel = aData->label().Father();
+
+ if (aFolderLabel.IsNull() || aLastFeatureLabel.IsNull())
+ return false;
+
+ 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();
+ Handle(TDataStd_ReferenceArray) aRefs;
+ if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+ return false; // no reference array (something is wrong)
+ for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex) {
+ TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+ if (aCurLabel == aFolderLabel)
+ break; // folder is above the features
+ else if (aCurLabel == aLastFeatureLabel) {
+ isFolderBelow = true;
+ break;
+ }
+ }
+
+ if (isFolderBelow) {
+ aData = std::static_pointer_cast<Model_Data>(theFeatures.front()->data());
+ if (!aData || !aData->isValid())
+ return false;
+ TDF_Label aPrevFeatureLabel = aData->label().Father();
+ // label of the feature before the first feature in the list
+ for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex)
+ if (aPrevFeatureLabel == aRefs->Value(aRefIndex)) {
+ if (aRefIndex == aRefs->Lower())
+ aPrevFeatureLabel.Nullify();
+ else
+ aPrevFeatureLabel = aRefs->Value(aRefIndex - 1);
+ break;
+ }
+
+ // move the folder in the list of references before the first feature
+ RemoveFromRefArray(aFeaturesLab, aFolderLabel);
+ AddToRefArray(aFeaturesLab, aFolderLabel, aPrevFeatureLabel);
+ // update first feature of the folder
+ initFirstAttr = true;
+ } else {
+ // update last feature of the folder
+ 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 bool theBefore)
+{
+ 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;
+ if (isExtractBeforeFolder) {
+ aFeatureToFind = theFeatures.back();
+ // if the last feature is composite, obtain its last sub-feature for correct positioning of
+ // the folder in the reference array when theFeatures will be extracted before folder
+ CompositeFeaturePtr aComposite =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureToFind);
+ if (aComposite)
+ aFeatureToFind = aComposite->subFeature(aComposite->numberOfSubs() - 1);
+ } else
+ aFeatureToFind = 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;
+}
+
+FolderPtr Model_Objects::findContainingFolder(const FeaturePtr& theFeature, int& theIndexInFolder)
+{
+ // search the label in the list of references
+ TDF_Label aFeaturesLab = featuresLabel();
+ Handle(TDataStd_ReferenceArray) aRefs;
+ if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
+ return FolderPtr(); // no reference array (something is wrong)
+
+ std::shared_ptr<Model_Data> aData =
+ std::static_pointer_cast<Model_Data>(theFeature->data());
+ if (!aData || !aData->isValid())
+ return FolderPtr();
+ TDF_Label aLabelToFind = aData->label().Father();
+
+ theIndexInFolder = -1;
+ FolderPtr aFoundFolder;
+ TDF_Label aLastFeatureLabel;
+
+ for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex) {
+ TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+ if (isSkippedFeature(feature(aCurLabel)))
+ continue;
+
+ if (aFoundFolder)
+ ++theIndexInFolder;
+
+ if (aCurLabel == aLabelToFind) // the feature is reached
+ return aFoundFolder;
+
+ if (!aFoundFolder) {
+ // if the current label refers to a folder, feel all necessary data
+ aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
+ if (aFoundFolder) {
+ theIndexInFolder = -1;
+
+ AttributeReferencePtr aLastRef =
+ aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ if (aLastRef->value()) {
+ aData = std::static_pointer_cast<Model_Data>(aLastRef->value()->data());
+ if (aData && aData->isValid())
+ aLastFeatureLabel = aData->label().Father();
+ } else // folder is empty
+ aFoundFolder = FolderPtr();
+ }
+ } else if (aLastFeatureLabel == aCurLabel) {
+ // folder is finished, clear all stored data
+ theIndexInFolder = -1;
+ aFoundFolder = FolderPtr();
+ }
+ }
+
+ // folder is not found
+ theIndexInFolder = -1;
+ return FolderPtr();
+}
+
+
std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
const std::shared_ptr<ModelAPI_Result>& theResult)
{
return aResult;
}
+TDF_Label Model_Objects::nextLabel(TDF_Label theCurrent, const bool theReverse)
+{
+ Handle(TDataStd_ReferenceArray) aRefs;
+ if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+ for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
+ TDF_Label aCurLab = aRefs->Value(a);
+ if (aCurLab.IsEqual(theCurrent)) {
+ a += theReverse ? -1 : 1;
+ if (a >= aRefs->Lower() && a <= aRefs->Upper())
+ return aRefs->Value(a);
+ break; // finish iiteration: it's last feature
+ }
+ }
+ }
+ return TDF_Label();
+}
+
FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theReverse)
{
std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
if (aData.get() && aData->isValid()) {
TDF_Label aFeatureLabel = aData->label().Father();
- Handle(TDataStd_ReferenceArray) aRefs;
- if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
- for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
- TDF_Label aCurLab = aRefs->Value(a);
- if (aCurLab.IsEqual(aFeatureLabel)) {
- a += theReverse ? -1 : 1;
- if (a >= aRefs->Lower() && a <= aRefs->Upper())
- return feature(aRefs->Value(a));
- break; // finish iiteration: it's last feature
- }
- }
- }
+ TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse);
+ if (!aNextLabel.IsNull())
+ return feature(aNextLabel);
}
return FeaturePtr(); // not found, last, or something is wrong
}
return false; // not found, or something is wrong
}
+std::list<std::shared_ptr<ModelAPI_Object> > Model_Objects::allObjects()
+{
+ std::list<std::shared_ptr<ModelAPI_Object> > aResult;
+ Handle(TDataStd_ReferenceArray) aRefs;
+ if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+ for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
+ ObjectPtr anObject = object(aRefs->Value(a));
+ if (!anObject.get()) // is it a folder?
+ anObject = folder(aRefs->Value(a));
+ if (anObject.get())
+ aResult.push_back(anObject);
+ }
+ }
+ return aResult;
+}
+
std::list<std::shared_ptr<ModelAPI_Feature> > Model_Objects::allFeatures()
{
std::list<std::shared_ptr<ModelAPI_Feature> > aResult;
#include <Model.h>
#include <ModelAPI_Document.h>
#include <ModelAPI_Feature.h>
+#include <ModelAPI_Folder.h>
#include <ModelAPI_Result.h>
#include <ModelAPI_ResultParameter.h>
//! Returns the object index in the group. Object must be visible. Otherwise returns -1.
//! \param theObject object of this document
+ //! \param theAllowFolder take into account grouping feature by folders
//! \returns index started from zero, or -1 if object is invisible or belongs to another document
- const int index(std::shared_ptr<ModelAPI_Object> theObject);
+ const int index(std::shared_ptr<ModelAPI_Object> theObject,
+ const bool theAllowFolder = false);
//! Returns the feature in the group by the index (started from zero)
//! \param theGroupID group that contains a feature
//! \param theIndex zero-based index of feature in the group
- ObjectPtr object(const std::string& theGroupID, const int theIndex);
+ //! \param theAllowFolder take into account grouping feature by folders
+ ObjectPtr object(const std::string& theGroupID,
+ const int theIndex,
+ const bool theAllowFolder = false);
//! Returns the number of features in the group
- int size(const std::string& theGroupID);
+ //! \param theGroupID group of objects
+ //! \param theAllowFolder take into account grouping feature by folders
+ int size(const std::string& theGroupID, const bool theAllowFolder = false);
//! Returns all (and disabled) results of the given type.
//! Not fast method (iterates all features).
std::shared_ptr<ModelAPI_Feature>
feature(const std::shared_ptr<ModelAPI_Result>& theResult);
+ /// Creates a folder (group of the features in the object browser)
+ std::shared_ptr<ModelAPI_Folder> createFolder(
+ const std::shared_ptr<ModelAPI_Feature>& theBeforeThis);
+ //! Removes the folder from the document (all features in the folder will be kept).
+ void removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder);
+ //! Search a folder applicable for the list of features
+ //! (it means the list of features stored in the folder should be consequential)
+ //! \param theFeatures list of features to be added to folder
+ //! \param theBelow search the folder below the features (if \c false, search above)
+ //! \return Empty pointer if there is no applicable folder
+ std::shared_ptr<ModelAPI_Folder> findFolder(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
+ const bool theBelow);
+ //! Search a folder containing the given feature.
+ //! Addtionally calculates a zero-based index of the feature in this folder.
+ //! \param theFeature feature to search
+ //! \param theIndexInFolder zero-based index in the folder or -1 if the feature is top-level.
+ //! \return the folder containing the feature or empty pointer if the feature is top-level.
+ std::shared_ptr<ModelAPI_Folder> findContainingFolder(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ int& theIndexInFolder);
+ //! Add a list of features to the folder. The correctness of the adding is not performed
+ //! (such checks have been done in corresponding find.. method).
+ //! \return \c true if the movement is successfull
+ 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,
+ const bool theBefore = true);
+
//! Sets the owner of this manager
void setOwner(DocumentPtr theDoc);
//! feature type + "_" + index
void setUniqueName(FeaturePtr theFeature);
+ //! Initializes the foldet with an unique name ("Folder_" + index)
+ void setUniqueName(FolderPtr theFolder);
+
//! Synchronizes myFeatures list with the updated document
//! \param theUpdated list of labels that are marked as modified, so featrues must be also
//! \param theUpdateReferences causes the update of back-references
/// Returns true if theLater is in history of features creation later than theCurrent
bool isLater(FeaturePtr theLater, FeaturePtr theCurrent) const;
+ /// Returns the next or previous label
+ /// \param theCurrent given label
+ /// \param theReverse if it is true, iterates in reverced order (next becomes previous)
+ TDF_Label nextLabel(TDF_Label theCurrent, const bool theReverse = false);
+
/// Returns the result group identifier of the given feature (for this at least one result must
/// be created before)
std::string featureResultGroup(FeaturePtr theFeature);
//! history. Not very fast method, for calling once, not in big cycles.
std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures();
+ //! Returns all objects of the document including the hidden features which are not in
+ //! history. Not very fast method, for calling once, not in big cycles.
+ std::list<std::shared_ptr<ModelAPI_Object> > allObjects();
+
//! synchronises back references for the given object basing on the collected data
void synchronizeBackRefsForObject(
const std::set<std::shared_ptr<ModelAPI_Attribute>>& theNewRefs, ObjectPtr theObject);
int theResultIndex,
std::string& theParentName) const;
+ /// Return object representing a folder or empty pointer
+ ObjectPtr folder(TDF_Label theLabel) const;
+
private:
TDF_Label myMain; ///< main label of the data storage
/// For optimization mapped by labels
NCollection_DataMap<TDF_Label, FeaturePtr> myFeatures;
+ /// Managed folders
+ NCollection_DataMap<TDF_Label, ObjectPtr> myFolders;
+
/// Map from group id to the array that contains all objects located in history.
/// Each array is updated by demand from scratch, by browing all the features in the history.
std::map<std::string, std::vector<ObjectPtr> > myHistory;
ModelAPI_Expression.h
ModelAPI_Feature.h
ModelAPI_FeatureValidator.h
+ ModelAPI_Folder.h
ModelAPI_IReentrant.h
ModelAPI_Object.h
ModelAPI_Plugin.h
ModelAPI_Expression.cpp
ModelAPI_Feature.cpp
ModelAPI_FeatureValidator.cpp
+ ModelAPI_Folder.cpp
ModelAPI_IReentrant.cpp
ModelAPI_Object.cpp
ModelAPI_Plugin.cpp
TestCustomName_Rename.py
TestCustomName_RotateGroup.py
TestCustomName_Translation.py
+ TestFolder_Create.py
+ TestFolder_Update.py
+ TestFolder_Remove.py
+ TestFolder_Stability.py
)
%feature("director") ModelAPI_Feature;
%feature("director") ModelAPI_CompositeFeature;
%feature("director") ModelAPI_Data;
+%feature("director") ModelAPI_Folder;
// shared pointers
// For ModelAPI_ResultConstruction.shape()
%shared_ptr(ModelAPI_Feature)
%shared_ptr(ModelAPI_CompositeFeature)
%shared_ptr(ModelAPI_Data)
+%shared_ptr(ModelAPI_Folder)
%shared_ptr(ModelAPI_Attribute)
%shared_ptr(ModelAPI_AttributeDocRef)
%shared_ptr(ModelAPI_AttributeDouble)
}
}
+%apply int& OUTPUT {int& theIndexInFolder};
+
// all supported interfaces
%include "ModelAPI_Entity.h"
%include "ModelAPI_Document.h"
%include "ModelAPI_ResultParameter.h"
%include "ModelAPI_Tools.h"
%include "ModelAPI_ResultCompSolid.h"
+%include "ModelAPI_Folder.h"
// std::list -> []
%template(StringList) std::list<std::string>;
%template(featureToCompositeFeature) shared_ptr_cast<ModelAPI_CompositeFeature, ModelAPI_Feature>;
%template(objectToFeature) shared_ptr_cast<ModelAPI_Feature, ModelAPI_Object>;
%template(objectToResult) shared_ptr_cast<ModelAPI_Result, ModelAPI_Object>;
+%template(objectToFolder) shared_ptr_cast<ModelAPI_Folder, ModelAPI_Object>;
%template(compositeFeatureToFeature) shared_ptr_cast<ModelAPI_Feature, ModelAPI_CompositeFeature>;
%template(modelAPI_Result) shared_ptr_cast<ModelAPI_Result, ModelAPI_Object>;
#include <set>
class ModelAPI_Feature;
+class ModelAPI_Folder;
class ModelAPI_Object;
class ModelAPI_Result;
class ModelAPI_ResultConstruction;
//! Returns the object in the group by the index (started from zero)
//! \param theGroupID group that contains an object
//! \param theIndex zero-based index of feature in the group
+ //! \param theAllowFolder take into account grouping feature by folders
virtual std::shared_ptr<ModelAPI_Object> object(const std::string& theGroupID,
- const int theIndex) = 0;
+ const int theIndex,
+ const bool theAllowFolder = false) = 0;
//! Returns the first found object in the group by the object name
//! \param theGroupID group that contains an object
//! Returns the object index in the group. Object must be visible. Otherwise returns -1.
//! \param theObject object of this document
+ //! \param theAllowFolder take into account grouping feature by folders
//! \returns index started from zero, or -1 if object is invisible or belongs to another document
- virtual const int index(std::shared_ptr<ModelAPI_Object> theObject) = 0;
+ virtual const int index(std::shared_ptr<ModelAPI_Object> theObject,
+ const bool theAllowFolder = false) = 0;
//! Returns the number of objects in the group of objects
- virtual int size(const std::string& theGroupID) = 0;
+ //! \param theGroupID group of objects
+ //! \param theAllowFolder take into account grouping feature by folders
+ virtual int size(const std::string& theGroupID, const bool theAllowFolder = false) = 0;
//! Returns the feature that is currently edited in this document, normally
//! this is the latest created feature
//! history. Not very fast method, for calling once, not in big cycles.
virtual std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures() = 0;
+ //! Returns all objects of the document including the hidden features which are not in
+ //! history. Not very fast method, for calling once, not in big cycles.
+ virtual std::list<std::shared_ptr<ModelAPI_Object> > allObjects() = 0;
+
+ //! Creates a folder (group of the features in the object browser)
+ //! \param theAddBefore a feature, the folder is added before
+ //! (if empty, the folder is added after the last feature)
+ virtual std::shared_ptr<ModelAPI_Folder> addFolder(
+ std::shared_ptr<ModelAPI_Feature> theAddBefore = std::shared_ptr<ModelAPI_Feature>()) = 0;
+ //! Removes the folder from the document (all features in the folder will be kept).
+ virtual void removeFolder(std::shared_ptr<ModelAPI_Folder> theFolder) = 0;
+ //! Search a folder above the list of features applicable to store them
+ //! (it means the list of features stored in the folder should be consequential)
+ //! \return Empty pointer if there is no applicable folder
+ virtual std::shared_ptr<ModelAPI_Folder> findFolderAbove(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures) = 0;
+ //! Search a folder below the list of features applicable to store them
+ //! (it means the list of features stored in the folder should be consequential)
+ //! \return Empty pointer if there is no applicable folder
+ virtual std::shared_ptr<ModelAPI_Folder> findFolderBelow(
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures) = 0;
+ //! Search a folder containing the given feature.
+ //! Addtionally calculates a zero-based index of the feature in this folder.
+ //! \param theFeature feature to search
+ //! \param theIndexInFolder zero-based index in the folder or -1 if the feature is top-level.
+ //! \return the folder containing the feature or empty pointer if the feature is top-level.
+ virtual std::shared_ptr<ModelAPI_Folder> findContainingFolder(
+ const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ int& theIndexInFolder) = 0;
+ //! Add a list of features to the folder. The correctness of the adding is not performed
+ //! (such checks have been done in corresponding find.. method).
+ //! \return \c true if the movement is successfull
+ 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,
+ 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;
//! Returns true if this document is currently active
--- /dev/null
+// Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "ModelAPI_Folder.h"
+
+#include <ModelAPI_AttributeReference.h>
+
+ModelAPI_Folder::ModelAPI_Folder()
+{
+}
+
+ModelAPI_Folder::~ModelAPI_Folder()
+{
+}
+
+void ModelAPI_Folder::init()
+{
+}
+
+void ModelAPI_Folder::initAttributes()
+{
+ data()->addAttribute(FIRST_FEATURE_ID(), ModelAPI_AttributeReference::typeId());
+ data()->addAttribute(LAST_FEATURE_ID(), ModelAPI_AttributeReference::typeId());
+}
+
+void ModelAPI_Folder::execute()
+{
+}
--- /dev/null
+// Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef ModelAPI_Folder_H_
+#define ModelAPI_Folder_H_
+
+#include <ModelAPI.h>
+#include <ModelAPI_Object.h>
+
+/**\class ModelAPI_Folder
+ * \ingroup DataModel
+ * \brief Folder feature (groups the features).
+ */
+class ModelAPI_Folder : public ModelAPI_Object
+{
+public:
+ MODELAPI_EXPORT ModelAPI_Folder();
+ /// To virtually destroy the fields of successors
+ MODELAPI_EXPORT virtual ~ModelAPI_Folder();
+
+ /// Folder feature ID
+ static const std::string& ID()
+ {
+ static const std::string MY_FOLDER_ID("Folder");
+ return MY_FOLDER_ID;
+ }
+
+ /// Returns the group identifier of all features
+ inline static std::string group()
+ {
+ static std::string MY_GROUP = "Folders";
+ return MY_GROUP;
+ }
+
+ /// Returns the group identifier of this result
+ virtual std::string groupName()
+ {
+ return group();
+ }
+
+ /// Attribute referring first feature in the folder
+ static const std::string& FIRST_FEATURE_ID()
+ {
+ static const std::string MY_FIRST_FEATURE_ID("first_feature");
+ return MY_FIRST_FEATURE_ID;
+ }
+
+ /// Attribute referring last feature in the folder
+ static const std::string& LAST_FEATURE_ID()
+ {
+ static const std::string MY_LAST_FEATURE_ID("last_feature");
+ return MY_LAST_FEATURE_ID;
+ }
+
+ /// Request for initialization of data model of the object: adding all attributes
+ MODELAPI_EXPORT virtual void initAttributes();
+
+ /// Computes or recomputes the results
+ MODELAPI_EXPORT virtual void execute();
+
+ /// Returns the feature is disabled or not.
+ virtual bool isDisabled()
+ { return false; }
+
+ //
+ // Helper methods, aliases for data()->method()
+ // -----------------------------------------------------------------------------------------------
+ /// Returns the name stored in the attribute
+ inline std::string name()
+ {
+ return data()->name();
+ }
+ /// Returns the reference attribute by the identifier
+ inline std::shared_ptr<ModelAPI_AttributeReference> reference(const std::string& theID)
+ {
+ return data()->reference(theID);
+ }
+
+protected:
+ /// This method is called just after creation of the object: it must initialize
+ /// all fields, normally initialized in the constructor
+ MODELAPI_EXPORT virtual void init();
+};
+
+//! Pointer on a folder object
+typedef std::shared_ptr<ModelAPI_Folder> FolderPtr;
+
+#endif
return ModelAPI_Tools::removeFeatures(aFeatures, false);
}
+//***********************************************************************
bool removeFeatures(const std::set<FeaturePtr>& theFeatures,
const bool theFlushRedisplay)
{
return true;
}
+//***********************************************************************
// Fills the references list by all references of the feature from the references map.
// This is a recusive method to find references by next found feature in the map of references.
// \param theFeature a feature to find references
#include "ModelAPI_ResultField.h"
#include "ModelAPI_Tools.h"
#include "ModelAPI_ResultCompSolid.h"
+ #include "ModelAPI_Folder.h"
#include <memory>
#include <string>
--- /dev/null
+## Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from ModelAPI import *
+
+__updated__ = "2017-11-22"
+
+#=========================================================================
+# Test 1. Check the Folder is created in PartSet
+#=========================================================================
+aSession = ModelAPI_Session.get()
+aPartSetDoc = aSession.activeDocument()
+
+aSession.startOperation()
+aPoint0 = aPartSetDoc.addFeature("Point")
+aPoint0Data = aPoint0.data()
+assert(aPoint0Data is not None)
+aPoint0Data.real("x").setValue(0.)
+aPoint0Data.real("y").setValue(0.)
+aPoint0Data.real("z").setValue(0.)
+aPoint0Data.string("creation_method").setValue("by_xyz")
+aSession.finishOperation()
+
+aSession.startOperation()
+aPoint1 = aPartSetDoc.addFeature("Point")
+aPoint1Data = aPoint1.data()
+assert(aPoint1Data is not None)
+aPoint1Data.real("x").setValue(0.)
+aPoint1Data.real("y").setValue(0.)
+aPoint1Data.real("z").setValue(0.)
+aPoint1Data.string("creation_method").setValue("by_xyz")
+aSession.finishOperation()
+
+assert(aPartSetDoc.size("Features") == 2), "Wrong number of features: {}".format(aPartSetDoc.size("Features"))
+
+# Folder before the feature
+aSession.startOperation()
+aFolder1 = aPartSetDoc.addFolder(aPoint1)
+aSession.finishOperation()
+
+assert(aPartSetDoc.size("Folders") == 1), "Wrong number of folders: {}".format(aPartSetDoc.size("Folders"))
+assert(aPartSetDoc.size("Features") == 3), "Wrong number of features: {}".format(aPartSetDoc.size("Features"))
+FOLDER_NAME_EXPECTED = "Folder_1"
+assert(aFolder1.name() == FOLDER_NAME_EXPECTED), "Actual name '{}', expected '{}'".format(aFolder1.name(), FOLDER_NAME_EXPECTED)
+
+## Folder at the end of features list
+#aSession.startOperation()
+#aPartSetDoc.addFolder()
+#aSession.finishOperation()
+#assert(aPartSetDoc.size("Folders") == 2)
+
+#=========================================================================
+# Test 2. Check the Folder is created in a Part
+#=========================================================================
+aSession.startOperation()
+aPart = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+
+# check part is a last feature
+aFeaturesList = aSession.moduleDocument().allObjects()
+aLast = aFeaturesList[len(aFeaturesList)-1]
+assert(aLast.data().isEqual(aPart.data())), "Part is not a last object in the list"
+
+# add point and a folder before it
+aPartDoc = aSession.activeDocument()
+aSession.startOperation()
+aPoint2 = aPartDoc.addFeature("Point")
+aPoint2Data = aPoint2.data()
+assert(aPoint2Data is not None)
+aPoint2Data.real("x").setValue(0.)
+aPoint2Data.real("y").setValue(0.)
+aPoint2Data.real("z").setValue(0.)
+aPoint2Data.string("creation_method").setValue("by_xyz")
+aSession.finishOperation()
+
+assert(aPartDoc.size("Features") == 1), "Wrong number of features: {}".format(aPartDoc.size("Features"))
+
+aSession.startOperation()
+aFolder2 = aPartDoc.addFolder(aPoint2)
+aSession.finishOperation()
+
+assert(aPartDoc.size("Folders") == 1), "Wrong number of folders: {}".format(aPartDoc.size("Folders"))
+assert(aPartDoc.size("Features") == 2), "Wrong number of features: {}".format(aPartDoc.size("Features"))
+FOLDER_NAME_EXPECTED = "Folder_1"
+assert(aFolder2.name() == FOLDER_NAME_EXPECTED), "Actual name '{}', expected '{}'".format(aFolder2.name(), FOLDER_NAME_EXPECTED)
+
+from salome.shaper import model
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from ModelAPI import *
+
+__updated__ = "2017-11-24"
+
+aSession = ModelAPI_Session.get()
+
+
+def newPoint(theDocument, theX, theY, theZ):
+ aSession.startOperation()
+ aPoint = theDocument.addFeature("Point")
+ aPointData = aPoint.data()
+ assert(aPointData is not None)
+ aPointData.real("x").setValue(theX)
+ aPointData.real("y").setValue(theY)
+ aPointData.real("z").setValue(theZ)
+ aPointData.string("creation_method").setValue("by_xyz")
+ aSession.finishOperation()
+ return aPoint
+
+
+#=========================================================================
+# Prepare some features and folders
+#=========================================================================
+aSession.startOperation()
+aPart = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+
+# add points
+aPartDoc = aSession.activeDocument()
+aPoint1 = newPoint(aPartDoc, 0., 0., 0.)
+aPoint2 = newPoint(aPartDoc, 10., 0., 0.)
+aPoint3 = newPoint(aPartDoc, 10., 10., 0.)
+aPoint4 = newPoint(aPartDoc, 0., 10., 0.)
+
+# add folders
+aSession.startOperation()
+aFolder1 = aPartDoc.addFolder(aPoint2)
+aSession.finishOperation()
+aSession.startOperation()
+aFolder2 = aPartDoc.addFolder(aPoint2)
+aSession.finishOperation()
+aSession.startOperation()
+aFolder3 = aPartDoc.addFolder(aPoint3)
+aSession.finishOperation()
+
+# place points into folders
+toFolder = FeatureList()
+toFolder.append(aPoint1)
+
+aSession.startOperation()
+aFolder = aPartDoc.findFolderBelow(toFolder)
+assert(aFolder is not None)
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+
+toFolder = FeatureList()
+toFolder.append(aPoint3)
+toFolder.append(aPoint4)
+
+aSession.startOperation()
+aFolder = aPartDoc.findFolderAbove(toFolder)
+assert(aFolder is not None)
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+
+NB_FEATURES_FULL = 7
+NB_FEATURES_OUT = 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(aFolder1, True) == 0), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder1, True))
+assert(aPartDoc.index(aFolder2, True) == 1), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder2, True))
+assert(aPartDoc.index(aFolder3, True) == 3), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+
+assert(aPartDoc.index(aPoint1, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint1, True))
+assert(aPartDoc.index(aPoint2, True) == 2), "Wrong index of the point: {}".format(aPartDoc.index(aPoint2, 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))
+
+
+#=========================================================================
+# Test 1. Remove empty folder
+#=========================================================================
+aSession.startOperation()
+aPartDoc.removeFolder(aFolder2)
+aSession.finishOperation()
+
+NB_FEATURES_FULL -= 1
+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(aFolder1, True) == 0), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder1, True))
+assert(aPartDoc.index(aFolder2, True) == -1), "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(aPoint1, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint1, True))
+assert(aPartDoc.index(aPoint2, True) == 1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint2, 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))
+
+
+#=========================================================================
+# Test 2. Remove non-empty folder
+#=========================================================================
+aSession.startOperation()
+aPartDoc.removeFolder(aFolder3)
+aSession.finishOperation()
+
+NB_FEATURES_FULL -= 1
+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(aFolder1, True) == 0), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder1, True))
+assert(aPartDoc.index(aFolder2, True) == -1), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder2, True))
+assert(aPartDoc.index(aFolder3, True) == -1), "Wrong index of the folder: {}".format(aPartDoc.index(aFolder3, True))
+
+assert(aPartDoc.index(aPoint1, True) == -1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint1, True))
+assert(aPartDoc.index(aPoint2, True) == 1), "Wrong index of the point: {}".format(aPartDoc.index(aPoint2, True))
+assert(aPartDoc.index(aPoint3, True) == 2), "Wrong index of the point: {}".format(aPartDoc.index(aPoint3, True))
+assert(aPartDoc.index(aPoint4, True) == 3), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4, True))
+
+
+from salome.shaper import model
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+ Test checks adding sketch into a folder
+"""
+
+from ModelAPI import *
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+Sketch_0 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_0.addLine(10, -10, 10, 10)
+model.do()
+
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 25)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_1_2f")], model.selection(), 50, 0)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchCircle_2 = Sketch_2.addCircle(100, -100, 50)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_3")], model.selection(), 10, 0)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("SOLID", "Extrusion_2_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_2_1/To_Face_1"))
+SketchProjection_1 = Sketch_3.addProjection(model.selection("VERTEX", "Extrusion_2_1/Generated_Face_1&Extrusion_2_1/To_Face_1__cc"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_3 = Sketch_3.addCircle(100, -100, 25)
+SketchConstraintCoincidence_1 = Sketch_3.setCoincident(SketchPoint_1.result(), SketchCircle_3.center())
+ExtrusionCut_1.setNestedSketch(Sketch_3)
+model.do()
+model.end()
+
+
+aSession = ModelAPI_Session.get()
+aPartDoc = aSession.activeDocument()
+
+#=========================================================================
+# Test 1. Sketch and extrusion could be added to the folder above
+#=========================================================================
+aSession.startOperation()
+Folder_1 = aPartDoc.addFolder(Sketch_1.feature())
+aSession.finishOperation()
+
+NB_FEATURES_FULL = 7
+NB_FEATURES_OUT = 7
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+toFolder = FeatureList()
+toFolder.append(Sketch_1.feature())
+toFolder.append(Extrusion_1.feature())
+
+# move features to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderAbove(toFolder)
+assert(aFolder is not None and aFolder.data().isEqual(Folder_1.data()))
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+NB_FEATURES_OUT -= 2
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the sketch in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_1.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 0)
+# check the index of the extrusion in the folder
+aFound = aPartDoc.findContainingFolder(Extrusion_1.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 1)
+
+
+#=========================================================================
+# Test 2. Sketch could be added to the folder below
+#=========================================================================
+aSession.startOperation()
+Folder_2 = aPartDoc.addFolder(Extrusion_2.feature())
+aSession.finishOperation()
+
+NB_FEATURES_FULL += 1
+NB_FEATURES_OUT += 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+toFolder = FeatureList()
+toFolder.append(Sketch_2.feature())
+
+# move feature to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderBelow(toFolder)
+assert(aFolder is not None and aFolder.data().isEqual(Folder_2.data()))
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+NB_FEATURES_OUT -= 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the sketch in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_2.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 0)
+
+
+#=========================================================================
+# Test 3. Sketch could be removed from the folder
+#=========================================================================
+fromFolder = FeatureList()
+fromFolder.append(Sketch_1.feature())
+
+aSession.startOperation()
+isMovedOut = aPartDoc.removeFromFolder(fromFolder)
+aSession.finishOperation()
+assert(isMovedOut)
+assert(aPartDoc.index(Sketch_1.feature(), True) == 1), "Wrong index of the {}: {}".format(Sketch_1.feature().name(), aPartDoc.index(Sketch_1.feature(), True))
+NB_FEATURES_OUT += 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+
+#=========================================================================
+# Test 4. Add 2 sketches to the folder below
+#=========================================================================
+
+toFolder = FeatureList()
+toFolder.append(Sketch_0.feature())
+toFolder.append(Sketch_1.feature())
+
+# move features to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderBelow(toFolder)
+assert(aFolder is not None and aFolder.data().isEqual(Folder_1.data()))
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+NB_FEATURES_OUT -= 2
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the sketch in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_0.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 0)
+# check the index of the extrusion in the folder
+aFound = aPartDoc.findContainingFolder(Sketch_1.feature())
+assert(aFound[0].data().isEqual(aFolder.data()))
+assert(aFound[1] == 1)
+
+
+from salome.shaper import model
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+#=========================================================================
+# Test checks stability of the foldering mechanism due to incorrect input parameters
+#=========================================================================
+from ModelAPI import *
+
+__updated__ = "2017-11-23"
+
+aSession = ModelAPI_Session.get()
+
+
+def newPoint(theDocument, theX, theY, theZ):
+ aSession.startOperation()
+ aPoint = theDocument.addFeature("Point")
+ aPointData = aPoint.data()
+ assert(aPointData is not None)
+ aPointData.real("x").setValue(theX)
+ aPointData.real("y").setValue(theY)
+ aPointData.real("z").setValue(theZ)
+ aPointData.string("creation_method").setValue("by_xyz")
+ aSession.finishOperation()
+ return aPoint
+
+
+#=========================================================================
+# Initialization of the model
+#=========================================================================
+aSession.startOperation()
+aPart = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+
+# add point and a folder before it
+aPartDoc = aSession.activeDocument()
+aPoint1 = newPoint(aPartDoc, 0., 0., 0.)
+
+aSession.startOperation()
+aFolder1 = aPartDoc.addFolder(aPoint1)
+aSession.finishOperation()
+
+NB_FEATURES_FULL = 2
+NB_FEATURES_OUT = 2
+
+assert(aPartDoc.size("Folders") == 1), "Wrong number of folders: {}".format(aPartDoc.size("Folders"))
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}".format(aPartDoc.size("Features"))
+
+#=========================================================================
+# Test 1. Check number of features out of folder
+# and absense of the crash while getting size of incorrect group
+#=========================================================================
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+assert(aPartDoc.size("Construction", True) == 1), "Wrong size: {}".format(aPartDoc.size("Construction", True))
+
+#=========================================================================
+# Test 2. Add a feature to the folder and check number of features once again
+#=========================================================================
+toFolder = FeatureList()
+toFolder.append(aPoint1)
+
+aSession.startOperation()
+aFolder2 = aPartDoc.addFolder(aPoint1)
+aSession.finishOperation()
+
+NB_FEATURES_FULL += 1
+NB_FEATURES_OUT += 1
+
+aSession.startOperation()
+aFolder = aPartDoc.findFolderAbove(toFolder)
+assert(aFolder is not None)
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+
+NB_FEATURES_OUT -= 1
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+assert(aPartDoc.size("Construction", True) == 1), "Wrong size: {}".format(aPartDoc.size("Construction", True))
+
+
+from salome.shaper import model
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from ModelAPI import *
+
+__updated__ = "2017-11-23"
+
+aSession = ModelAPI_Session.get()
+
+
+def newPoint(theDocument, theX, theY, theZ):
+ aSession.startOperation()
+ aPoint = theDocument.addFeature("Point")
+ aPointData = aPoint.data()
+ assert(aPointData is not None)
+ aPointData.real("x").setValue(theX)
+ aPointData.real("y").setValue(theY)
+ aPointData.real("z").setValue(theZ)
+ aPointData.string("creation_method").setValue("by_xyz")
+ aSession.finishOperation()
+ return aPoint
+
+
+#=========================================================================
+# Test 1. Add a point into a folder above
+#=========================================================================
+aSession.startOperation()
+aPart = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+
+# add point and a folder before it
+aPartDoc = aSession.activeDocument()
+aPoint1 = newPoint(aPartDoc, 0., 0., 0.)
+
+aSession.startOperation()
+aFolder1 = aPartDoc.addFolder(aPoint1)
+aSession.finishOperation()
+
+NB_FEATURES_FULL = 2
+NB_FEATURES_OUT = 2
+
+assert(aPartDoc.size("Folders") == 1), "Wrong number of folders: {}".format(aPartDoc.size("Folders"))
+assert(aPartDoc.size("Features") == 2), "Wrong number of features: {}".format(aPartDoc.size("Features"))
+FOLDER_NAME_EXPECTED = "Folder_1"
+assert(aFolder1.name() == FOLDER_NAME_EXPECTED), "Actual name '{}', expected '{}'".format(aFolder1.name(), FOLDER_NAME_EXPECTED)
+
+toFolder = FeatureList()
+toFolder.append(aPoint1)
+
+# 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_OUT -= 1
+# full number of features
+assert(aPartDoc.size("Features") == NB_FEATURES_FULL), "Wrong number of features: {}, expected: {}".format(aPartDoc.size("Features"), NB_FEATURES_FULL)
+# number of features outside the folder
+assert(aPartDoc.size("Features", True) == NB_FEATURES_OUT), "Wrong number of features outside a folder: {}, expected: {}".format(aPartDoc.size("Features", True), NB_FEATURES_OUT)
+
+# check the index of the point in the folder
+aFound = aPartDoc.findContainingFolder(aPoint1)
+assert(aFound[0].data().isEqual(aFolder1.data()))
+assert(aFound[1] == 0)
+
+#=========================================================================
+# Test 2. Add a point into a folder below
+#=========================================================================
+aPoint2 = newPoint(aPartDoc, 10., 0., 0.)
+aPoint3 = newPoint(aPartDoc, 10., 10., 0.)
+
+NB_FEATURES_FULL += 2
+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)
+
+# add a folder
+aSession.startOperation()
+aFolder2 = aPartDoc.addFolder(aPoint3)
+aSession.finishOperation()
+
+NB_FEATURES_FULL += 1
+NB_FEATURES_OUT += 1
+
+assert(aPartDoc.size("Folders") == 2), "Wrong number of folders: {}".format(aPartDoc.size("Folders"))
+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)
+
+toFolder = FeatureList()
+toFolder.append(aPoint2)
+
+# move point to the folder
+aSession.startOperation()
+aFolder = aPartDoc.findFolderBelow(toFolder)
+assert(aFolder is not None)
+isAdded = aPartDoc.moveToFolder(toFolder, aFolder)
+aSession.finishOperation()
+assert(isAdded)
+
+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)
+
+# check the index of the point in the folder
+aFound = aPartDoc.findContainingFolder(aPoint2)
+assert(aFound[0].data().isEqual(aFolder2.data()))
+assert(aFound[1] == 0)
+aFound = aPartDoc.findContainingFolder(aPoint3)
+assert(aFound == -1)
+
+#=========================================================================
+# Test 3. Add several points into a folder
+#=========================================================================
+aPoint4 = newPoint(aPartDoc, 0., 10., 0.)
+
+NB_FEATURES_FULL += 1
+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)
+
+# index without respect to foldering
+assert(aPartDoc.index(aPoint4) == 5), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4))
+# index according to folders
+assert(aPartDoc.index(aPoint4, True) == 3), "Wrong index of the point: {}".format(aPartDoc.index(aPoint4, True))
+
+# add a folder
+aSession.startOperation()
+aFolder3 = aPartDoc.addFolder(aPoint3)
+aSession.finishOperation()
+
+NB_FEATURES_FULL += 1
+NB_FEATURES_OUT += 1
+
+assert(aPartDoc.size("Folders") == 3), "Wrong number of folders: {}".format(aPartDoc.size("Folders"))
+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)
+
+# index without respect to foldering
+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(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()
+toFolder.append(aPoint3)
+toFolder.append(aPoint4)
+
+# 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_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)
+
+# index without respect to foldering
+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(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))
+
+# check the index of the point in the folder
+aFound = aPartDoc.findContainingFolder(aPoint3)
+assert(aFound[0].data().isEqual(aFolder3.data()))
+assert(aFound[1] == 0)
+aFound = aPartDoc.findContainingFolder(aPoint4)
+assert(aFound[0].data().isEqual(aFolder3.data()))
+assert(aFound[1] == 1)
+
+
+# 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())
ModelHighAPI_Services.h
ModelHighAPI_Tools.h
ModelHighAPI_FeatureStore.h
+ ModelHighAPI_Folder.h
)
SET(PROJECT_SOURCES
ModelHighAPI_Services.cpp
ModelHighAPI_Tools.cpp
ModelHighAPI_FeatureStore.cpp
+ ModelHighAPI_Folder.cpp
)
SET(PROJECT_LIBRARIES
// shared pointers
%shared_ptr(ModelHighAPI_Interface)
+%shared_ptr(ModelHighAPI_Folder)
// typemaps
%include "ModelHighAPI_Dumper.h"
%include "ModelHighAPI_Integer.h"
%include "ModelHighAPI_Interface.h"
+%include "ModelHighAPI_Folder.h"
%include "ModelHighAPI_RefAttr.h"
%include "ModelHighAPI_Reference.h"
%include "ModelHighAPI_Selection.h"
#include <ModelAPI_Document.h>
#include <ModelAPI_Entity.h>
#include <ModelAPI_Feature.h>
+#include <ModelAPI_Folder.h>
#include <ModelAPI_Result.h>
#include <ModelAPI_ResultBody.h>
#include <ModelAPI_ResultCompSolid.h>
return aFound->second.myCurrentName;
// entity is not found, store it
- std::string aName;
+ std::string aName, aKind;
bool isDefaultName = false;
+ bool isSaveNotDumped = theSaveNotDumped;
std::ostringstream aDefaultName;
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
if (aFeature) {
aName = aFeature->name();
- const std::string& aKind = aFeature->getKind();
- DocumentPtr aDoc = aFeature->document();
+ aKind = aFeature->getKind();
+ } else {
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(theEntity);
+ if (aFolder) {
+ aName = aFolder->data()->name();
+ aKind = ModelAPI_Folder::ID();
+ isSaveNotDumped = false;
+ myNotDumpedFolders.insert(aFolder);
+ }
+ }
+
+ ObjectPtr anObject = std::dynamic_pointer_cast<ModelAPI_Object>(theEntity);
+ if (anObject) {
+ DocumentPtr aDoc = anObject->document();
int& aNbFeatures = myFeatureCount[aDoc][aKind];
aNbFeatures += 1;
}
myNames[theEntity] = EntityName(aDefaultName.str(), aName, isDefaultName);
- if (theSaveNotDumped)
+ if (isSaveNotDumped)
myNotDumpedEntities.insert(theEntity);
// store names of results
bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc)
{
bool isOk = true;
- std::list<FeaturePtr> aFeatures = theDoc->allFeatures();
- std::list<FeaturePtr>::const_iterator aFeatIt = aFeatures.begin();
+ std::list<ObjectPtr> anObjects = theDoc->allObjects();
+ std::list<ObjectPtr>::const_iterator anObjIt = anObjects.begin();
// firstly, dump all parameters
- for (; aFeatIt != aFeatures.end(); ++ aFeatIt)
- dumpParameter(*aFeatIt);
+ for (; anObjIt != anObjects.end(); ++ anObjIt) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIt);
+ if (aFeature)
+ dumpParameter(aFeature);
+ }
// dump all other features
- for (aFeatIt = aFeatures.begin(); aFeatIt != aFeatures.end(); ++aFeatIt) {
- CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIt);
+ for (anObjIt = anObjects.begin(); anObjIt != anObjects.end(); ++anObjIt) {
+ CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*anObjIt);
if (aCompFeat) // iteratively process composite features
isOk = process(aCompFeat) && isOk;
- else if (!isDumped(*aFeatIt)) // dump common feature
- dumpFeature(*aFeatIt);
+ else if (!isDumped(*anObjIt)) {
+ // dump folder
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(*anObjIt);
+ if (aFolder)
+ dumpFolder(aFolder);
+ else {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIt);
+ if (aFeature) // dump common feature
+ dumpFeature(aFeature);
+ }
+ }
}
return isOk;
}
// dump "setName" for composite feature
if (isDumpSetName)
dumpEntitySetName();
+ // dump folders if any
+ dumpFolders();
return isOk;
}
+void ModelHighAPI_Dumper::dumpFolders()
+{
+ std::set<FolderPtr>::const_iterator aFolderIt = myNotDumpedFolders.begin();
+ while (aFolderIt != myNotDumpedFolders.end()) {
+ FolderPtr aFolder = *aFolderIt++;
+ dumpFolder(aFolder);
+ }
+}
+
void ModelHighAPI_Dumper::dumpSubFeatureNameAndColor(const std::string theSubFeatureGet,
const FeaturePtr& theSubFeature)
{
{
EntityNameMap::const_iterator aFound = myNames.find(theEntity);
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
- return aFound != myNames.end() || myFeaturesToSkip.find(aFeature) != myFeaturesToSkip.end();
+ return (aFound != myNames.end() && aFound->second.myIsDumped) ||
+ myFeaturesToSkip.find(aFeature) != myFeaturesToSkip.end();
}
bool ModelHighAPI_Dumper::isDefaultColor(const ResultPtr& theResult) const
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FolderPtr& theFolder)
+{
+ myDumpBuffer << name(theFolder);
+ myNotDumpedFolders.erase(theFolder);
+ return *this;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& theEntity)
{
myDumpBuffer << name(theEntity);
// then store currently dumped string
theDumper.myFullDump << aBufCopy;
+ // now, store all not dumped folders
+ theDumper.dumpFolders();
+
return theDumper;
}
class ModelAPI_Document;
class ModelAPI_Entity;
class ModelAPI_Feature;
+class ModelAPI_Folder;
class ModelAPI_Object;
class ModelAPI_Result;
typedef std::shared_ptr<ModelAPI_Document> DocumentPtr;
typedef std::shared_ptr<ModelAPI_Entity> EntityPtr;
typedef std::shared_ptr<ModelAPI_Feature> FeaturePtr;
+typedef std::shared_ptr<ModelAPI_Folder> FolderPtr;
typedef std::shared_ptr<ModelAPI_Result> ResultPtr;
/**\class ModelHighAPI_Dumper
virtual void dumpParameter(const FeaturePtr& theFeature) = 0;
/// Dump given feature
virtual void dumpFeature(const FeaturePtr& theFeature, const bool theForce = false) = 0;
+ /// Dump folder
+ virtual void dumpFolder(const FolderPtr& theFolder) = 0;
/// Set a feature that should not be dumped anyway
MODELHIGHAPI_EXPORT
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const FeaturePtr& theEntity);
+ /// Dump folder
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const FolderPtr& theFolder);
+
/// Dump result
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const ResultPtr& theResult);
/// Check the result feature has default transparency
bool isDefaultTransparency(const ResultPtr& theResult) const;
+ /// Dump stored folders if possible
+ void dumpFolders();
+
private:
struct EntityName {
std::string myCurrentName; ///< default name of current feature
std::set<FeaturePtr> myFeaturesToSkip;
protected:
- /// list of entities, used by other features but not dumped yet
+ /// list of entities, used by other features but not dumped yet
std::set<EntityPtr> myNotDumpedEntities;
+ /// list of folders which do not dumped yet
+ std::set<FolderPtr> myNotDumpedFolders;
friend class SketchAPI_Sketch;
+ friend class ModelHighAPI_Folder;
};
#endif
#define PRECISION 6
#define TOLERANCE (1.e-7)
-ModelHighAPI_FeatureStore::ModelHighAPI_FeatureStore(FeaturePtr theFeature) {
- storeData(theFeature->data(), myAttrs);
- // iterate results to store
- std::list<ResultPtr> allResults;
- ModelAPI_Tools::allResults(theFeature, allResults);
- std::list<ResultPtr>::iterator aRes = allResults.begin();
- for(; aRes != allResults.end(); aRes++) {
- std::map<std::string, std::string> aResDump;
- storeData((*aRes)->data(), aResDump);
- myRes.push_back(aResDump);
+ModelHighAPI_FeatureStore::ModelHighAPI_FeatureStore(ObjectPtr theObject) {
+ storeData(theObject->data(), myAttrs);
+
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
+ if (aFeature) {
+ // iterate results to store
+ std::list<ResultPtr> allResults;
+ ModelAPI_Tools::allResults(aFeature, allResults);
+ std::list<ResultPtr>::iterator aRes = allResults.begin();
+ for(; aRes != allResults.end(); aRes++) {
+ std::map<std::string, std::string> aResDump;
+ storeData((*aRes)->data(), aResDump);
+ myRes.push_back(aResDump);
+ }
}
}
-std::string ModelHighAPI_FeatureStore::compare(FeaturePtr theFeature) {
- std::string anError = compareData(theFeature->data(), myAttrs);
+std::string ModelHighAPI_FeatureStore::compare(ObjectPtr theObject) {
+ std::string anError = compareData(theObject->data(), myAttrs);
if (!anError.empty()) {
- return "Features '" + theFeature->name() + "' differ:" + anError;
- }
- std::list<ResultPtr> allResults;
- ModelAPI_Tools::allResults(theFeature, allResults);
- std::list<ResultPtr>::iterator aRes = allResults.begin();
- std::list<std::map<std::string, std::string> >::iterator aResIter = myRes.begin();
- for(; aRes != allResults.end() && aResIter != myRes.end(); aRes++, aResIter++) {
- anError = compareData((*aRes)->data(), *aResIter);
- if (!anError.empty())
- return "Results of feature '" + theFeature->name() + "' '" + (*aRes)->data()->name() +
- "' differ:" + anError;
- }
- if (aRes != allResults.end()) {
- return "Current model has more results '" + (*aRes)->data()->name() + "'";
+ return "Features '" + theObject->data()->name() + "' differ:" + anError;
}
- if (aResIter != myRes.end()) {
- return "Original model had more results '" + (*aResIter)["__name__"] + "'";
+
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
+ if (aFeature) {
+ std::list<ResultPtr> allResults;
+ ModelAPI_Tools::allResults(aFeature, allResults);
+ std::list<ResultPtr>::iterator aRes = allResults.begin();
+ std::list<std::map<std::string, std::string> >::iterator aResIter = myRes.begin();
+ for(; aRes != allResults.end() && aResIter != myRes.end(); aRes++, aResIter++) {
+ anError = compareData((*aRes)->data(), *aResIter);
+ if (!anError.empty())
+ return "Results of feature '" + aFeature->name() + "' '" + (*aRes)->data()->name() +
+ "' differ:" + anError;
+ }
+ if (aRes != allResults.end()) {
+ return "Current model has more results '" + (*aRes)->data()->name() + "'";
+ }
+ if (aResIter != myRes.end()) {
+ return "Original model had more results '" + (*aResIter)["__name__"] + "'";
+ }
}
return ""; // ok
}
#include <string>
#include <memory>
-class ModelAPI_Feature;
+class ModelAPI_Object;
class ModelAPI_Data;
class GeomAPI_Shape;
class ModelAPI_Attribute;
-typedef std::shared_ptr<ModelAPI_Feature> FeaturePtr;
-typedef std::shared_ptr<ModelAPI_Attribute> AttributePtr;
+typedef std::shared_ptr<ModelAPI_Object> ObjectPtr;
+typedef std::shared_ptr<ModelAPI_Attribute> AttributePtr;
/**\class ModelHighAPI_FeatureStore
* \ingroup CPPHighAPI
// unused constructor for the map container needs
ModelHighAPI_FeatureStore() {}
// constructor that initializes this object by feature to store
- ModelHighAPI_FeatureStore(FeaturePtr theFeature);
+ ModelHighAPI_FeatureStore(ObjectPtr theObject);
// compares the stored feature information with the given feature
- std::string compare(FeaturePtr theFeature);
+ std::string compare(ObjectPtr theObject);
private:
/// stores the information about all attributes of data in map
--- /dev/null
+// Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "ModelHighAPI_Folder.h"
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Reference.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <ModelAPI_AttributeReference.h>
+#include <ModelAPI_Document.h>
+
+//--------------------------------------------------------------------------------------
+
+ModelHighAPI_Folder::ModelHighAPI_Folder(const std::shared_ptr<ModelAPI_Folder> & theFolder)
+ : ModelHighAPI_Interface(FeaturePtr()),
+ myFolder(theFolder)
+{
+ initialize();
+}
+
+ModelHighAPI_Folder::~ModelHighAPI_Folder()
+{
+}
+
+bool ModelHighAPI_Folder::initialize()
+{
+ if (!myFolder) {
+ throwException(ID() + " exception: The folder is NULL.");
+ return false;
+ }
+
+ myFirstFeature = myFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+ if (!myFirstFeature)
+ return false;
+ myAttrGetter[ModelAPI_Folder::FIRST_FEATURE_ID()] = "firstFeature";
+
+ myLastFeature = myFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ if (!myLastFeature)
+ return false;
+ myAttrGetter[ModelAPI_Folder::LAST_FEATURE_ID()] = "lastFeature";
+
+ return true;
+}
+
+void ModelHighAPI_Folder::dump(ModelHighAPI_Dumper& theDumper) const
+{
+ const std::string& aDocName = theDumper.name(myFolder->document());
+
+ AttributeReferencePtr aStartRef = myFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+ AttributeReferencePtr aEndRef = myFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+
+ // Dump folder if it is empty or when its features have been already dumped.
+ // Otherwise, just store the name of the folder.
+ if (!aEndRef->value())
+ theDumper << myFolder << " = model.addFolder(" << aDocName << ")" << std::endl;
+ else if (theDumper.isDumped(aEndRef->value()))
+ theDumper << myFolder << " = model.addFolder(" << aDocName << ", "
+ << aStartRef << ", " << aEndRef << ")" << std::endl;
+ else
+ theDumper.name(myFolder);
+}
+
+//--------------------------------------------------------------------------------------
+
+std::shared_ptr<ModelHighAPI_Folder> addFolder(const std::shared_ptr<ModelAPI_Document>& theDoc)
+{
+ std::shared_ptr<ModelAPI_Folder> aFolder = theDoc->addFolder();
+ return std::shared_ptr<ModelHighAPI_Folder>(new ModelHighAPI_Folder(aFolder));
+}
+
+std::shared_ptr<ModelHighAPI_Folder> addFolder(const std::shared_ptr<ModelAPI_Document>& theDoc,
+ const ModelHighAPI_Reference& theFirstFeature,
+ const ModelHighAPI_Reference& theLastFeature)
+{
+ std::shared_ptr<ModelAPI_Folder> aFolder = theDoc->addFolder(theFirstFeature.feature());
+
+ AttributeReferencePtr aFirstFeatAttr = aFolder->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+ fillAttribute(theFirstFeature.feature(), aFirstFeatAttr);
+
+ AttributeReferencePtr aLastFeatAttr = aFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ fillAttribute(theLastFeature.feature(), aLastFeatAttr);
+
+ return std::shared_ptr<ModelHighAPI_Folder>(new ModelHighAPI_Folder(aFolder));
+}
--- /dev/null
+// Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef SRC_MODELHIGHAPI_MODELHIGHAPI_FOLDER_H_
+#define SRC_MODELHIGHAPI_MODELHIGHAPI_FOLDER_H_
+
+//--------------------------------------------------------------------------------------
+#include <ModelHighAPI_Interface.h>
+
+#include <ModelAPI_Folder.h>
+
+#include <memory>
+//--------------------------------------------------------------------------------------
+class ModelAPI_AttributeReference;
+class ModelAPI_Document;
+class ModelHighAPI_Reference;
+//--------------------------------------------------------------------------------------
+/**\class ModelHighAPI_Folder
+ * \ingroup CPPHighAPI
+ * \brief Class for filling ModelAPI_Folder
+ */
+class ModelHighAPI_Folder : public ModelHighAPI_Interface
+{
+public:
+ /// Constructor for a folder
+ MODELHIGHAPI_EXPORT
+ explicit ModelHighAPI_Folder(const std::shared_ptr<ModelAPI_Folder>& theFolder);
+ /// Destructor
+ MODELHIGHAPI_EXPORT virtual ~ModelHighAPI_Folder();
+
+ static std::string ID() { return ModelAPI_Folder::ID(); }
+ virtual std::string getID() { return ID(); }
+
+ /// First feature reference
+ std::shared_ptr<ModelAPI_AttributeReference> firstFeature() const
+ { return myFirstFeature; }
+
+ /// Last feature reference
+ std::shared_ptr<ModelAPI_AttributeReference> lastFeature() const
+ { return myLastFeature; }
+
+ /// Dump wrapped feature
+ MODELHIGHAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+protected:
+ bool initialize();
+
+private:
+ std::shared_ptr<ModelAPI_Folder> myFolder;
+
+ std::shared_ptr<ModelAPI_AttributeReference> myFirstFeature;
+ std::shared_ptr<ModelAPI_AttributeReference> myLastFeature;
+};
+
+//--------------------------------------------------------------------------------------
+/**\ingroup CPPHighAPI
+ * \brief Create empty Folder feature
+ */
+MODELHIGHAPI_EXPORT
+std::shared_ptr<ModelHighAPI_Folder> addFolder(const std::shared_ptr<ModelAPI_Document>& theDoc);
+
+/**\ingroup CPPHighAPI
+ * \brief Create Folder feature
+ */
+MODELHIGHAPI_EXPORT
+std::shared_ptr<ModelHighAPI_Folder> addFolder(const std::shared_ptr<ModelAPI_Document>& theDoc,
+ const ModelHighAPI_Reference& theFirstFeature,
+ const ModelHighAPI_Reference& theLastFeature);
+//--------------------------------------------------------------------------------------
+#endif /* SRC_MODELHIGHAPI_MODELHIGHAPI_FOLDER_H_ */
}
}
// store the model features information: iterate all features
- int aFeaturesCount = 0; // stores the number of compared features for this document to compate
+ int anObjectsCount = 0; // stores the number of compared features for this document to compate
std::set<std::string> aProcessed; // processed features names (that are in the current document)
- std::list<FeaturePtr> allFeatures = theDoc->allFeatures();
- std::list<FeaturePtr>::iterator allIter = allFeatures.begin();
- for(; allIter != allFeatures.end(); allIter++) {
- FeaturePtr aFeat = *allIter;
+
+ // process all objects (features and folders)
+ std::list<ObjectPtr> allObjects = theDoc->allObjects();
+ std::list<ObjectPtr>::iterator allIter = allObjects.begin();
+ for(; allIter != allObjects.end(); allIter++) {
+ ObjectPtr anObject = *allIter;
if (theCompare) {
std::map<std::string, ModelHighAPI_FeatureStore>::iterator
- aFeatFind = aDocFind->second.find(aFeat->name());
- if (aFeatFind == aDocFind->second.end()) {
- return "Document '" + theDocName + "' feature '" + aFeat->name() + "' not found";
+ anObjFind = aDocFind->second.find(anObject->data()->name());
+ if (anObjFind == aDocFind->second.end()) {
+ return "Document '" + theDocName + "' feature '" + anObject->data()->name() + "' not found";
}
- std::string anError = aFeatFind->second.compare(aFeat);
+ std::string anError = anObjFind->second.compare(anObject);
if (!anError.empty()) {
anError = "Document " + theDocName + " " + anError;
return anError;
}
- aFeaturesCount++;
- aProcessed.insert(aFeat->name());
+ anObjectsCount++;
+ aProcessed.insert(anObject->data()->name());
} else {
- theStore[theDocName][aFeat->name()] = ModelHighAPI_FeatureStore(aFeat);
+ theStore[theDocName][anObject->data()->name()] = ModelHighAPI_FeatureStore(anObject);
}
- // iterate all results of this feature
- std::list<ResultPtr> allResults;
- ModelAPI_Tools::allResults(aFeat, allResults);
- std::list<ResultPtr>::iterator aRes = allResults.begin();
- for(; aRes != allResults.end(); aRes++) {
- // recoursively store features of sub-documents
- if ((*aRes)->groupName() == ModelAPI_ResultPart::group()) {
- DocumentPtr aDoc = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRes)->partDoc();
- if (aDoc.get()) {
- std::string anError = storeFeatures((*aRes)->data()->name(), aDoc, theStore, theCompare);
- if (!anError.empty())
- return anError;
+
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
+ if (aFeature) {
+ // iterate all results of this feature
+ std::list<ResultPtr> allResults;
+ ModelAPI_Tools::allResults(aFeature, allResults);
+ std::list<ResultPtr>::iterator aRes = allResults.begin();
+ for(; aRes != allResults.end(); aRes++) {
+ // recoursively store features of sub-documents
+ if ((*aRes)->groupName() == ModelAPI_ResultPart::group()) {
+ DocumentPtr aDoc = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRes)->partDoc();
+ if (aDoc.get()) {
+ std::string anError =
+ storeFeatures((*aRes)->data()->name(), aDoc, theStore, theCompare);
+ if (!anError.empty())
+ return anError;
+ }
}
}
}
}
// checks the number of compared features
if (theCompare) {
- if (aDocFind->second.size() != aFeaturesCount) {
+ if (aDocFind->second.size() != anObjectsCount) {
// search for disappeared feature
std::string aLostName;
std::map<std::string, ModelHighAPI_FeatureStore>::iterator aLostIter;
#include "ModelHighAPI.h"
#include "ModelHighAPI_Double.h"
#include "ModelHighAPI_Dumper.h"
+ #include "ModelHighAPI_Folder.h"
#include "ModelHighAPI_Integer.h"
#include "ModelHighAPI_Interface.h"
#include "ModelHighAPI_Macro.h"
#include <ModelAPI_Tools.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Events.h>
+#include <ModelAPI_Folder.h>
#include <ModelGeomAlgo_Point2D.h>
}
void checkObjects(const QObjectPtrList& theObjects, bool& hasResult, bool& hasFeature,
- bool& hasParameter, bool& hasCompositeOwner, bool& hasResultInHistory)
+ bool& hasParameter, bool& hasCompositeOwner, bool& hasResultInHistory,
+ bool& hasFolder)
{
hasResult = false;
hasFeature = false;
hasParameter = false;
hasCompositeOwner = false;
hasResultInHistory = false;
+ hasFolder = false;
foreach(ObjectPtr aObj, theObjects) {
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aObj);
ResultParameterPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aResult);
hasResult |= (aResult.get() != NULL);
hasFeature |= (aFeature.get() != NULL);
+ hasFolder |= (aFolder.get() != NULL);
hasParameter |= (aConstruction.get() != NULL);
if (hasFeature)
hasCompositeOwner |= (ModelAPI_Tools::compositeOwner(aFeature) != NULL);
hasResultInHistory = aFeature.get() && aFeature->isInHistory();
}
- if (hasFeature && hasResult && hasParameter && hasCompositeOwner)
+ if (hasFeature && hasResult && hasParameter && hasCompositeOwner && hasFeature)
break;
}
}
if (!aFeature.get() && anObject->groupName() == ModelAPI_ResultParameter::group()) {
aFeature = ModelAPI_Feature::feature(anObject);
}
- theFeatures.insert(aFeature);
+ if (aFeature.get())
+ theFeatures.insert(aFeature);
+ }
+}
+
+//**************************************************************
+void convertToFolders(const QObjectPtrList& theObjects,
+ std::set<FolderPtr>& theFolders)
+{
+ QObjectPtrList::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();
+ for(; anIt != aLast; anIt++) {
+ ObjectPtr anObject = *anIt;
+ FolderPtr aFeature = std::dynamic_pointer_cast<ModelAPI_Folder>(anObject);
+ if (aFeature.get())
+ theFolders.insert(aFeature);
}
}
+
+//**************************************************************
QString translate(const Events_InfoMessage& theMessage)
{
QString aMessage;
#include <ModelAPI_Attribute.h>
#include <ModelAPI_Feature.h>
+#include <ModelAPI_Folder.h>
#include <TopAbs_ShapeEnum.hxx>
#include <TopoDS_Shape.hxx>
/// \param hasParameter will be set to true if list contains Parameter objects
/// \param hasCompositeOwner will be set to true if list contains Sub-Feature objects
/// \param hasResultInHistory will be set to true if one of result is in history
+/// \param hasFolder will be set to true if one of folder is in the list
MODULEBASE_EXPORT void checkObjects(const QObjectPtrList& theObjects, bool& hasResult,
bool& hasFeature, bool& hasParameter, bool& hasCompositeOwner,
- bool& hasResultInHistory);
+ bool& hasResultInHistory, bool& hasFolder);
/// Sets the default coeffient into the driver calculated accordingly the shape type.
/// It provides 1.e-4 for results of construction type
std::set<FeaturePtr>& theFeatures);
+/// Converts a list of objects to set of folders.
+/// \param theObjects a list of objects
+/// \param theFeatures an out conteiner of features
+void MODULEBASE_EXPORT convertToFolders(const QObjectPtrList& theObjects,
+ std::set<FolderPtr>& theFolders);
+
+
/// Returns translation from the given data.
/// If translation is not exists then it returns a string
/// from the info data without translation
bool hasParameter = false;
bool hasCompositeOwner = false;
bool hasResultInHistory = false;
+ bool hasFolder = false;
ModuleBase_Tools::checkObjects(aObjects, hasResult, hasFeature, hasParameter,
- hasCompositeOwner, hasResultInHistory);
+ hasCompositeOwner, hasResultInHistory, hasFolder);
ModuleBase_Operation* aCurrentOp = myWorkshop->currentOperation();
if (aSelected == 1) {
std::set<AttributePtr>::const_iterator anIt;
for (anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*anIt)->owner());
- if (aRefFeature->getKind() == theFeatureId)
+ if (aRefFeature && aRefFeature->getKind() == theFeatureId)
return aRefFeature;
}
return FeaturePtr();
# In case of theFeature is not a constraint, it will not be dumped.
self.myFeatures[SketchAPI.SketchAPI_Constraint.ID()](theFeature).dump(self)
+ ## Create wrapper for a folder and dump it
+ def dumpFolder(self, theFolder):
+ if theFolder.ID() in self.myFeatures:
+ self.myFeatures[theFolder.ID()](theFolder).dump(self)
+
## Dump all parameters
def dumpParameter(self, theFeature):
aFeatureKind = theFeature.getKind()
from ModelHighAPI import updateFeatures
from ModelHighAPI import undo, redo
from ModelHighAPI import reset
+from ModelHighAPI import addFolder
from ModelHighAPI import ModelHighAPI_Selection as selection
from ModelHighAPI import checkPythonDump as checkPythonDump
#include <ModelAPI_ResultBody.h>
#include <ModelAPI_Tools.h>
#include <ModelAPI_ResultField.h>
+#include <ModelAPI_Folder.h>
+#include <ModelAPI_AttributeReference.h>
#include <Config_DataModelReader.h>
XGUI_ContextMenuMgr::XGUI_ContextMenuMgr(XGUI_Workshop* theParent)
: QObject(theParent),
myWorkshop(theParent),
- mySeparator(0)
+ mySeparator1(0), mySeparator2(0), mySeparator3(0)
{
}
aDesktop);
addAction("WIREFRAME_CMD", aAction);
- mySeparator = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
- mySeparator->setSeparator(true);
+ mySeparator1 = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
+ mySeparator1->setSeparator(true);
+
+ mySeparator2 = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
+ mySeparator2->setSeparator(true);
+
+ mySeparator3 = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
+ mySeparator3->setSeparator(true);
//mySelectActions = new QActionGroup(this);
//mySelectActions->setExclusive(true);
addAction("TINSPECTOR_VIEW", aAction);
#endif
+ // Features folders actions
+ aAction = ModuleBase_Tools::createAction(QIcon(":pictures/create_folder.png"),
+ tr("Insert a folder before"), aDesktop);
+ addAction("INSERT_FOLDER_CMD", aAction);
+
+ aAction = ModuleBase_Tools::createAction(QIcon(":pictures/insert_folder_before.png"),
+ tr("Move into the previous folder"), aDesktop);
+ addAction("ADD_TO_FOLDER_BEFORE_CMD", aAction);
+
+ aAction = ModuleBase_Tools::createAction(QIcon(":pictures/insert_folder_after.png"),
+ tr("Move into the next folder"), aDesktop);
+ addAction("ADD_TO_FOLDER_AFTER_CMD", aAction);
+
+ aAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_out_before.png"),
+ tr("Move out before the folder"), aDesktop);
+ addAction("ADD_OUT_FOLDER_BEFORE_CMD", aAction);
+
+ aAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_out_after.png"),
+ tr("Move out after the folder"), aDesktop);
+ addAction("ADD_OUT_FOLDER_AFTER_CMD", aAction);
+
buildObjBrowserMenu();
buildViewerMenu();
}
bool hasParameter = false;
bool hasCompositeOwner = false;
bool hasResultInHistory = false;
+ bool hasFolder = false;
ModuleBase_Tools::checkObjects(aObjects, hasResult, hasFeature, hasParameter,
- hasCompositeOwner, hasResultInHistory);
+ hasCompositeOwner, hasResultInHistory, hasFolder);
//Process Feature
- if (aSelected == 1) {
+ if (aSelected == 1) { // single selection
ObjectPtr aObject = aObjects.first();
if (aObject) {
if (hasResult && myWorkshop->canBeShaded(aObject)) {
(hasFeature || hasParameter));
}
}
- } else {
+ // end single selection
+ } else { // multiselection
// parameter is commented because the actions are not in the list of result parameter actions
if (hasResult /*&& (!hasParameter)*/) {
action("SHOW_CMD")->setEnabled(true);
action("SHADING_CMD")->setEnabled(true);
action("WIREFRAME_CMD")->setEnabled(true);
}
- }
+ } // end multiselection
+
+ // Check folder management commands state if only features are selected
+ if ((!hasResult) && hasFeature && (!hasParameter) && (!hasCompositeOwner) &&
+ (!hasResultInHistory) && (!hasFolder)) {
+ std::list<FeaturePtr> aFeatures = aSelMgr->getSelectedFeatures();
+ if (aFeatures.size() > 0) { // Check that features do not include Parts
+ QModelIndexList aIndexes = aSelMgr->selection()->selectedIndexes();
+ QModelIndex aFirstIdx = aIndexes.first();
+ QModelIndex aLastIdx = aIndexes.last();
+ QModelIndex aParentIdx = aFirstIdx.parent();
+
+ // if all selected are from the same level
+ bool isSameParent = true;
+ foreach(QModelIndex aIdx, aIndexes) {
+ if (aIdx.parent() != aParentIdx) {
+ isSameParent = false;
+ break;
+ }
+ }
+ if (isSameParent) {
+ // Check is selection continuous
+ XGUI_DataModel* aModel = myWorkshop->objectBrowser()->dataModel();
+ DocumentPtr aDoc = aMgr->activeDocument();
+ std::list<FeaturePtr> aFeatures = aSelMgr->getSelectedFeatures();
+
+ bool isContinuos = true;
+ if (aSelected > 1) {
+ int aId = -1;
+ foreach(FeaturePtr aF, aFeatures) {
+ if (aId == -1)
+ aId = aDoc->index(aF);
+ else {
+ aId++;
+ if (aId != aDoc->index(aF)) {
+ isContinuos = false;
+ break;
+ }
+ }
+ }
+ }
+ if (isContinuos) {
+ ObjectPtr aDataObj = aModel->object(aParentIdx);
+
+ ObjectPtr aPrevObj;
+ if (aFirstIdx.row() > 0) {
+ QModelIndex aPrevIdx = aFirstIdx.sibling(aFirstIdx.row() - 1, 0);
+ aPrevObj = aModel->object(aPrevIdx);
+ }
+
+ ObjectPtr aNextObj;
+ if (aLastIdx.row() < (aModel->rowCount(aParentIdx) - 1)) {
+ QModelIndex aNextIdx = aFirstIdx.sibling(aLastIdx.row() + 1, 0);
+ aNextObj = aModel->object(aNextIdx);
+ }
+
+ bool isPrevFolder = (aPrevObj.get() &&
+ (aPrevObj->groupName() == ModelAPI_Folder::group()));
+ bool isNextFolder = (aNextObj.get() &&
+ (aNextObj->groupName() == ModelAPI_Folder::group()));
+ bool isInFolder = (aDataObj.get() &&
+ (aDataObj->groupName() == ModelAPI_Folder::group()));
+ bool isOutsideFolder = !isInFolder;
+
+ bool hasFirst = false;
+ bool hasLast = false;
+ if (isInFolder) {
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aDataObj);
+ FeaturePtr aFirstFeatureInFolder;
+ AttributeReferencePtr aFirstFeatAttr =
+ aFolder->data()->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+ if (aFirstFeatAttr)
+ aFirstFeatureInFolder = ModelAPI_Feature::feature(aFirstFeatAttr->value());
+ hasFirst = (aFirstFeatureInFolder == aFeatures.front());
+
+ FeaturePtr aLastFeatureInFolder;
+ AttributeReferencePtr aLastFeatAttr =
+ aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ if (aLastFeatAttr)
+ aLastFeatureInFolder = ModelAPI_Feature::feature(aLastFeatAttr->value());
+ hasLast = (aLastFeatureInFolder == aFeatures.back());
+ }
+ action("INSERT_FOLDER_CMD")->setEnabled(isOutsideFolder);
+ action("ADD_TO_FOLDER_BEFORE_CMD")->setEnabled(isOutsideFolder && isPrevFolder);
+ action("ADD_TO_FOLDER_AFTER_CMD")->setEnabled(isOutsideFolder && isNextFolder);
+ action("ADD_OUT_FOLDER_BEFORE_CMD")->setEnabled(isInFolder && hasFirst);
+ action("ADD_OUT_FOLDER_AFTER_CMD")->setEnabled(isInFolder && hasLast);
+ }
+ }
+ }
+ } // end folder management commands
+
bool allActive = true;
foreach( ObjectPtr aObject, aObjects )
if( aMgr->activeDocument() != aObject->document() ) {
action("SHOW_RESULTS_CMD")->setEnabled(hasFeature);
action("SHOW_FEATURE_CMD")->setEnabled(hasResult && hasResultInHistory);
- }
+ } // end selection processing
// Show/Hide command has to be disabled for objects from non active document
bool aDeactivate = false;
aList.append(action("SHOW_CMD"));
aList.append(action("HIDE_CMD"));
aList.append(action("SHOW_ONLY_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator1);
aList.append(action("RENAME_CMD"));
aList.append(action("COLOR_CMD"));
aList.append(action("DEFLECTION_CMD"));
aList.clear();
aList.append(action("WIREFRAME_CMD"));
aList.append(action("SHADING_CMD"));
- aList.append(mySeparator); // this separator is not shown as this action is added after show only
+ aList.append(mySeparator1); // this separator is not shown as this action is added after show only
// qt list container contains only one instance of the same action
aList.append(action("SHOW_CMD"));
aList.append(action("HIDE_CMD"));
aList.append(action("SHOW_ONLY_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator2);
aList.append(action("RENAME_CMD"));
aList.append(action("COLOR_CMD"));
aList.append(action("DEFLECTION_CMD"));
aList.append(action("RENAME_CMD"));
aList.append(action("SHOW_RESULTS_CMD"));
aList.append(action("MOVE_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator1);
+ aList.append(action("INSERT_FOLDER_CMD"));
+ aList.append(action("ADD_TO_FOLDER_BEFORE_CMD"));
+ aList.append(action("ADD_TO_FOLDER_AFTER_CMD"));
+ aList.append(mySeparator2);
+ aList.append(action("ADD_OUT_FOLDER_BEFORE_CMD"));
+ aList.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
+ aList.append(mySeparator3);
aList.append(action("CLEAN_HISTORY_CMD"));
aList.append(action("DELETE_CMD"));
myObjBrowserMenus[ModelAPI_Feature::group()] = aList;
aList.clear();
aList.append(action("RENAME_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator1);
aList.append(action("CLEAN_HISTORY_CMD"));
aList.append(action("DELETE_CMD"));
myObjBrowserMenus[ModelAPI_ResultParameter::group()] = aList;
//-------------------------------------
+
+ aList.clear();
+ aList.append(action("DELETE_CMD"));
+ myObjBrowserMenus[ModelAPI_Folder::group()] = aList;
+
}
void XGUI_ContextMenuMgr::buildViewerMenu()
// Result construction menu
aList.append(action("HIDE_CMD"));
aList.append(action("SHOW_ONLY_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator1);
aList.append(action("COLOR_CMD"));
aList.append(action("DEFLECTION_CMD"));
#ifdef USE_TRANSPARENCY
aList.clear();
aList.append(action("WIREFRAME_CMD"));
aList.append(action("SHADING_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator1);
aList.append(action("HIDE_CMD"));
aList.append(action("SHOW_ONLY_CMD"));
- aList.append(mySeparator);
+ aList.append(mySeparator2);
aList.append(action("COLOR_CMD"));
aList.append(action("DEFLECTION_CMD"));
#ifdef USE_TRANSPARENCY
} else if (aSelected > 1) {
aActions.append(action("WIREFRAME_CMD"));
aActions.append(action("SHADING_CMD"));
- aActions.append(mySeparator);
+ aActions.append(mySeparator1);
aActions.append(action("SHOW_CMD"));
aActions.append(action("HIDE_CMD"));
aActions.append(action("SHOW_ONLY_CMD"));
- aActions.append(mySeparator);
+ aActions.append(mySeparator2);
+ aActions.append(action("ADD_TO_FOLDER_BEFORE_CMD"));
+ aActions.append(action("ADD_TO_FOLDER_AFTER_CMD"));
+ aActions.append(action("ADD_OUT_FOLDER_BEFORE_CMD"));
+ aActions.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
+ aActions.append(mySeparator3);
//aActions.append(action("MOVE_CMD"));
aActions.append(action("COLOR_CMD"));
aActions.append(action("DEFLECTION_CMD"));
//QActionGroup* mySelectActions;
- QAction* mySeparator;
+ QAction* mySeparator1;
+ QAction* mySeparator2;
+ QAction* mySeparator3;
};
#endif
#include <ModelAPI_ResultCompSolid.h>
#include <ModelAPI_ResultField.h>
#include <ModelAPI_Tools.h>
+#include <ModelAPI_Folder.h>
+#include <ModelAPI_AttributeReference.h>
#include <Config_FeatureMessage.h>
#include <Config_DataModelReader.h>
/// Returns pointer on document if the given object is document object
ModelAPI_Document* getSubDocument(void* theObj)
{
- ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
+ ModelAPI_Document* aDoc = 0;
+ try {
+ aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
+ } catch(...) {}
return aDoc;
}
// Insert new object
int aRow = aRootDoc->size(aObjType) - 1;
if (aRow != -1) {
- if (aObjType == aRootType) {
+ if ((aObjType == aRootType) || (aObjType == ModelAPI_Folder::group())) {
insertRow(aRow + aNbFolders + 1);
} else {
int aFolderId = myXMLReader->rootFolderId(aObjType);
}
}
}
- int aRow = aDoc->index(aObject);
+ int aRow = aDoc->index(aObject, true);
if (aRow != -1) {
int aNbSubFolders = foldersCount(aDoc.get());
- if (aObjType == aSubType) {
+ if ((aObjType == aSubType) || (aObjType == ModelAPI_Folder::group())) {
// List of objects under document root
insertRow(aRow + aNbSubFolders, aDocRoot);
} else {
for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
std::string aGroup = (*aIt);
if (aDoc == aRootDoc) { // If root objects
- int aRow = aRootDoc->size(aGroup);
- if (aGroup == aRootType) {
+ int aRow = aRootDoc->size(aGroup, true);
+ if ((aGroup == aRootType) || (aGroup == ModelAPI_Folder::group())) {
// Process root folder
removeRow(aRow + aNbFolders);
rebuildBranch(aNbFolders, aRow);
// Check that some folders could erased
QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
- if ((aNotEmptyFolder.toStdString() == aGroup) && (aRootDoc->size(aGroup) == 0)) {
+ if ((aNotEmptyFolder.toStdString() == aGroup) && (aRootDoc->size(aGroup, true) == 0)) {
// Appears first object in folder which can not be shown empty
removeRow(myXMLReader->rootFolderId(aGroup));
removeShownFolder(aRootDoc, aNotEmptyFolder);
// Remove row for sub-document
QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get(), 0);
if (aDocRoot.isValid()) {
- int aRow = aDoc->size(aGroup);
+ int aRow = aDoc->size(aGroup, true);
int aNbSubFolders = foldersCount(aDoc.get());
- if (aGroup == aSubType) {
+ if ((aGroup == aSubType) || (aGroup == ModelAPI_Folder::group())) {
// List of objects under document root
removeRow(aRow + aNbSubFolders, aDocRoot);
rebuildBranch(aNbSubFolders, aRow, aDocRoot);
}
// Check that some folders could disappear
QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
- int aSize = aDoc->size(aGroup);
+ int aSize = aDoc->size(aGroup, true);
foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
if ((aNotEmptyFolder.toStdString() == aGroup) && (aSize == 0)) {
// Appears first object in folder which can not be shown empty
std::set<ObjectPtr> aObjects = aUpdMsg->objects();
std::set<ObjectPtr>::const_iterator aIt;
- std::string aObjType;
for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
ObjectPtr aObject = (*aIt);
if (aObject->data()->isValid()) {
QModelIndex aIndex = objectIndex(aResult, 0);
removeRows(0, aResult->stepsSize(), aIndex);
} else {
- QModelIndex aIndex = objectIndex(aObject, 0);
- if (aIndex.isValid()) {
- emit dataChanged(aIndex, aIndex);
+ if (aObject->groupName() == ModelAPI_Folder::group()) {
+ rebuildDataTree();
+ } else {
+ QModelIndex aIndex = objectIndex(aObject, 0);
+ if (aIndex.isValid()) {
+ emit dataChanged(aIndex, aIndex);
+ }
}
}
} else {
{
std::string aType = theObject->groupName();
DocumentPtr aDoc = theObject->document();
- int aRow = aDoc->index(theObject);
+ int aRow = aDoc->index(theObject, true);
if (aRow == -1) {
// it could be a part of complex object
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
}
}
}
+ int aFRow = -1;
+ FolderPtr aFolder = aDoc->findContainingFolder(aFeature, aFRow);
+ if (aFolder.get())
+ aRow = aFRow;
} else {
ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
if (aResult.get()) {
}
SessionPtr aSession = ModelAPI_Session::get();
DocumentPtr aRootDoc = aSession->moduleDocument();
- if (aDoc == aRootDoc && myXMLReader->rootType() == aType) {
+ if (aDoc == aRootDoc &&
+ ((myXMLReader->rootType() == aType) || (aType == ModelAPI_Folder::group()))) {
// The object from root document
aRow += foldersCount();
- } else if (myXMLReader->subType() == aType) {
+ } else if ((myXMLReader->subType() == aType) || (aType == ModelAPI_Folder::group())) {
// The object from sub document
aRow += foldersCount(aDoc.get());
}
}
}
} else {
- ModelAPI_Object* aObj =
- dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
+ ObjectPtr aObj = object(theIndex);
if (aObj) {
switch (theRole) {
case Qt::DisplayRole:
{
if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
- ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
+ ResultParameterPtr aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObj);
AttributeDoublePtr aValueAttribute =
aParam->data()->real(ModelAPI_ResultParameter::VALUE());
QString aVal = QString::number(aValueAttribute->value());
}
QString aSuffix;
if (aObj->groupName() == myXMLReader->subType()) {
- ResultPartPtr aPartRes = getPartResult(aObj);
+ ResultPartPtr aPartRes = getPartResult(aObj.get());
if (aPartRes.get()) {
if (aPartRes->partDoc().get() == NULL)
aSuffix = " (Not loaded)";
return aObj->data()->name().c_str() + aSuffix;
}
case Qt::DecorationRole:
- return ModuleBase_IconFactory::get()->getIcon(object(theIndex));
+ {
+ if (aObj->groupName() == ModelAPI_Folder::group())
+ return QIcon(":pictures/features_folder.png");
+ else
+ return ModuleBase_IconFactory::get()->getIcon(aObj);
+ }
}
} else {
switch (theRole) {
int aNbItems = 0;
std::string aType = myXMLReader->rootType();
if (!aType.empty())
- aNbItems = aRootDoc->size(aType);
+ aNbItems = aRootDoc->size(aType, true);
return aNbFolders + aNbItems;
}
int aNbSubItems = 0;
std::string aSubType = myXMLReader->subType();
if (!aSubType.empty())
- aNbSubItems = aSubDoc->size(aSubType);
+ aNbSubItems = aSubDoc->size(aSubType, true);
return aNbSubItems + aNbSubFolders;
} else {
// Check for composite object
ModelAPI_ResultField* aFieldRes = dynamic_cast<ModelAPI_ResultField*>(aObj);
if (aFieldRes)
return aFieldRes->stepsSize();
+ ModelAPI_Folder* aFolder = dynamic_cast<ModelAPI_Folder*>(aObj);
+ if (aFolder)
+ return getNumberOfFolderItems(aFolder);
}
}
}
else { // return object under root index
std::string aType = myXMLReader->rootType();
int aObjId = theRow - aNbFolders;
- if (aObjId < aRootDoc->size(aType)) {
- ObjectPtr aObj = aRootDoc->object(aType, aObjId);
+ if (aObjId < aRootDoc->size(aType, true)) {
+ ObjectPtr aObj = aRootDoc->object(aType, aObjId, true);
aIndex = objectIndex(aObj, theColumn);
}
}
if (aId == 0) { // return object index inside of first level of folders
std::string aType = myXMLReader->rootFolderType(aParentPos);
if (theRow < aRootDoc->size(aType)) {
- ObjectPtr aObj = aRootDoc->object(aType, theRow);
+ ObjectPtr aObj = aRootDoc->object(aType, theRow, true);
aIndex = objectIndex(aObj, theColumn);
}
} else {
} else {
// this is an object under sub document root
std::string aType = myXMLReader->subType();
- ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
+ ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders, true);
aIndex = objectIndex(aObj, theColumn);
}
} else {
dynamic_cast<ModelAPI_ResultField*>(aParentObj);
if (aFieldRes) {
aIndex = createIndex(theRow, theColumn, aFieldRes->step(theRow));
+ } else {
+ ModelAPI_Folder* aFolder = dynamic_cast<ModelAPI_Folder*>(aParentObj);
+ ObjectPtr aObj = getObjectInFolder(aFolder, theRow);
+ if (aObj.get())
+ aIndex = objectIndex(aObj, theColumn);
}
}
}
}
ObjectPtr aObj = object(theIndex);
if (!aObj.get()) {
- // It can b e a step of a field
+ // It can be a step of a field
ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>
((ModelAPI_Entity*)theIndex.internalPointer());
if (aCompFea.get()) {
return objectIndex(aCompFea);
}
+ DocumentPtr aDoc = aFeature->document();
+ int aRow;
+ FolderPtr aFolder = aDoc->findContainingFolder(aFeature, aRow);
+ if (aFolder.get())
+ return objectIndex(aFolder);
}
ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
if (aResult.get()) {
DocumentPtr aRootDoc = aSession->moduleDocument();
DocumentPtr aSubDoc = aObj->document();
if (aSubDoc == aRootDoc) {
- if (aType == myXMLReader->rootType())
+ if ((aType == myXMLReader->rootType()) || (aType == ModelAPI_Folder::group()))
return QModelIndex();
else {
// return first level of folder index
return createIndex(aFolderId, 1, (void*)Q_NULLPTR);
}
} else {
- if (aType == myXMLReader->subType())
+ if ((aType == myXMLReader->subType()) || (aType == ModelAPI_Folder::group()))
return findDocumentRootIndex(aSubDoc.get());
else {
// return first level of folder index
}
}
} else { // If document is attached to feature
- int aNb = aRootDoc->size(ModelAPI_Feature::group());
+ int aNb = aRootDoc->size(ModelAPI_Feature::group(), true);
ObjectPtr aObj;
ResultPartPtr aPartRes;
for (int i = 0; i < aNb; i++) {
- aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
+ aObj = aRootDoc->object(ModelAPI_Feature::group(), i, true);
aPartRes = getPartResult(aObj.get());
if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
int aRow = i;
}
return NoneState;
}
+
+
+int XGUI_DataModel::getNumberOfFolderItems(const ModelAPI_Folder* theFolder) const
+{
+ DocumentPtr aDoc = theFolder->document();
+
+ FeaturePtr aFirstFeatureInFolder;
+ AttributeReferencePtr aFirstFeatAttr =
+ theFolder->data()->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+ if (aFirstFeatAttr)
+ aFirstFeatureInFolder = ModelAPI_Feature::feature(aFirstFeatAttr->value());
+ if (!aFirstFeatureInFolder.get())
+ return 0;
+
+ FeaturePtr aLastFeatureInFolder;
+ AttributeReferencePtr aLastFeatAttr =
+ theFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID());
+ if (aLastFeatAttr)
+ aLastFeatureInFolder = ModelAPI_Feature::feature(aLastFeatAttr->value());
+ if (!aLastFeatureInFolder.get())
+ return 0;
+
+ int aFirst = aDoc->index(aFirstFeatureInFolder);
+ int aLast = aDoc->index(aLastFeatureInFolder);
+ return aLast - aFirst + 1;
+}
+
+ObjectPtr XGUI_DataModel::getObjectInFolder(const ModelAPI_Folder* theFolder, int theId) const
+{
+ DocumentPtr aDoc = theFolder->document();
+
+ FeaturePtr aFirstFeatureInFolder;
+ AttributeReferencePtr aFirstFeatAttr =
+ theFolder->data()->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+ if (aFirstFeatAttr)
+ aFirstFeatureInFolder = ModelAPI_Feature::feature(aFirstFeatAttr->value());
+ if (!aFirstFeatureInFolder.get())
+ return ObjectPtr();
+
+ int aFirst = aDoc->index(aFirstFeatureInFolder);
+ return aDoc->object(ModelAPI_Feature::group(), aFirst + theId);
+}
/// \param fromRoot - root document flag
QStringList listOfShowNotEmptyFolders(bool fromRoot = true) const;
+ int getNumberOfFolderItems(const ModelAPI_Folder* theFolder) const;
+ ObjectPtr getObjectInFolder(const ModelAPI_Folder* theFolder, int theId) const;
+
VisibilityState getVisibilityState(const QModelIndex& theIndex) const;
void addShownFolder(DocumentPtr theDoc, QString theFolder)
}
}
}
+
+std::list<FeaturePtr> XGUI_SelectionMgr::getSelectedFeatures()
+{
+ std::list<FeaturePtr> aFeatures;
+ QObjectPtrList aObjects = selection()->selectedObjects();
+ if (aObjects.isEmpty())
+ return aFeatures;
+
+ bool isPart = false;
+ foreach(ObjectPtr aObj, aObjects) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
+ if (aFeature.get()) {
+ ResultPtr aRes = aFeature->firstResult();
+ isPart = (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group()));
+ if (!isPart)
+ aFeatures.push_back(aFeature);
+ }
+ }
+ return aFeatures;
+}
\ No newline at end of file
#include "XGUI.h"
#include <ModuleBase_Definitions.h>
#include <ModuleBase_ISelection.h>
+#include <ModelAPI_Feature.h>
#include <QObject>
#include <QModelIndexList>
/// \param thePlace a widget where selection has happened.
void updateSelectionBy(const ModuleBase_ISelection::SelectionPlace& thePlace);
+ /// Returns list of selected features (ignores other selected objects and parts)
+ std::list<FeaturePtr> getSelectedFeatures();
+
signals:
//! Emited when selection in a one of viewers was changed
void selectionChanged();
setViewerSelectionMode(TopAbs_EDGE);
} else if (theId == "SELECT_FACE_CMD") {
setViewerSelectionMode(TopAbs_FACE);
+ } else if (theId == "INSERT_FOLDER_CMD") {
+ insertFeatureFolder();
+ } else if (theId == "ADD_TO_FOLDER_BEFORE_CMD") {
+ insertToFolder(true);
+ } else if (theId == "ADD_TO_FOLDER_AFTER_CMD") {
+ insertToFolder(false);
+ } else if (theId == "ADD_OUT_FOLDER_BEFORE_CMD") {
+ moveOutFolder(true);
+ } else if (theId == "ADD_OUT_FOLDER_AFTER_CMD") {
+ moveOutFolder(false);
} else if (theId == "SELECT_RESULT_CMD") {
//setViewerSelectionMode(-1);
//IMP: an attempt to use result selection with other selection modes
bool hasParameter = false;
bool hasCompositeOwner = false;
bool hasResultInHistory = false;
+ bool hasFolder = false;
ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasCompositeOwner,
- hasResultInHistory);
- if (!(hasFeature || hasParameter))
+ hasResultInHistory, hasFolder);
+ if (!(hasFeature || hasParameter || hasFolder))
return;
// delete objects
ModuleBase_Tools::convertToFeatures(anObjects, aFeatures);
ModelAPI_Tools::findAllReferences(aFeatures, aReferences);
+ std::set<FolderPtr> aFolders;
+ ModuleBase_Tools::convertToFolders(anObjects, aFolders);
+
bool aDone = false;
QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1";
aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
aFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());
aDone = ModelAPI_Tools::removeFeatures(aFeatures, false);
}
+ if (aFolders.size() > 0) {
+ std::set<FolderPtr>::const_iterator anIt = aFolders.begin(),
+ aLast = aFolders.end();
+ for (; anIt != aLast; anIt++) {
+ FolderPtr aFolder = *anIt;
+ if (aFolder.get()) {
+ DocumentPtr aDoc = aFolder->document();
+ aDoc->removeFolder(aFolder);
+ }
+ }
+ }
+
if (aDone)
operationMgr()->commitOperation();
else
objectBrowser()->blockSignals(aBlocked);
}
}
+
+void XGUI_Workshop::insertFeatureFolder()
+{
+ QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
+ if (aObjects.isEmpty())
+ return;
+ ObjectPtr aObj = aObjects.first();
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
+ if (aFeature.get() == NULL)
+ return;
+ SessionPtr aMgr = ModelAPI_Session::get();
+ DocumentPtr aDoc = aMgr->activeDocument();
+
+ aMgr->startOperation();
+ aDoc->addFolder(aFeature);
+ aMgr->finishOperation();
+}
+
+
+void XGUI_Workshop::insertToFolder(bool isBefore)
+{
+ std::list<FeaturePtr> aFeatures = mySelector->getSelectedFeatures();
+ if (aFeatures.empty())
+ return;
+
+ SessionPtr aMgr = ModelAPI_Session::get();
+ DocumentPtr aDoc = aMgr->activeDocument();
+
+ FolderPtr aFolder = isBefore? aDoc->findFolderAbove(aFeatures):
+ aDoc->findFolderBelow(aFeatures);
+ if (!aFolder.get())
+ return;
+
+ aMgr->startOperation();
+ aDoc->moveToFolder(aFeatures, aFolder);
+ aMgr->finishOperation();
+}
+
+void XGUI_Workshop::moveOutFolder(bool isBefore)
+{
+ std::list<FeaturePtr> aFeatures = mySelector->getSelectedFeatures();
+ if (aFeatures.empty())
+ return;
+
+ SessionPtr aMgr = ModelAPI_Session::get();
+ DocumentPtr aDoc = aMgr->activeDocument();
+
+ aMgr->startOperation();
+ aDoc->removeFromFolder(aFeatures, isBefore);
+ aMgr->finishOperation();
+}
\ No newline at end of file
/// Display results from a group
void displayGroupResults(DocumentPtr theDoc, std::string theGroup);
+ /// Insert folder object before currently selected feature
+ void insertFeatureFolder();
+
+ /// Insert an object to a folder above or below
+ void insertToFolder(bool isBefore);
+
+ /// Insert an object to a folder above or below
+ void moveOutFolder(bool isBefore);
+
private slots:
/// SLOT, that is called after the operation is started. Update workshop state according to
/// the started operation, e.g. visualizes the property panel and connect to it.
<file>pictures/eyeopen.png</file>
<file>pictures/transparency.png</file>
+ <file>pictures/features_folder.png</file>
+ <file>pictures/create_folder.png</file>
+ <file>pictures/insert_folder_after.png</file>
+ <file>pictures/insert_folder_before.png</file>
+ <file>pictures/move_out_after.png</file>
+ <file>pictures/move_out_before.png</file>
</qresource>
</RCC>