X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Objects.cpp;h=b4e516cd64e75305d523ad0c750635d14376c1f0;hb=cb2bfff600626039e210f08de27b5229541d367a;hp=4522d14d8acfb7c2307804854cc654be07406999;hpb=8578511c4164ad4fd45ad1c6a92cc8aaacba5972;p=modules%2Fshaper.git diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 4522d14d8..b4e516cd6 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -60,6 +60,22 @@ static const std::string& groupNameFoldering(const std::string& theGroupID, return theGroupID; } +// Check theFeature is a first or last feature in folder and return this folder +static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr) +{ + const std::set& aRefs = theFeature->data()->refsToMe(); + for (std::set::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) { + if ((*anIt)->id() != theFolderAttr) + continue; + + ObjectPtr anOwner = (*anIt)->owner(); + FolderPtr aFolder = std::dynamic_pointer_cast(anOwner); + if (aFolder.get()) + return aFolder; + } + return FolderPtr(); +} + static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results) @@ -81,7 +97,7 @@ void Model_Objects::setOwner(DocumentPtr theDoc) myDoc = theDoc; // update all fields and recreate features and result objects if needed TDF_LabelList aNoUpdated; - synchronizeFeatures(aNoUpdated, true, true, true, true); + synchronizeFeatures(aNoUpdated, true, false, true, true); myHistory.clear(); } @@ -160,12 +176,24 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT // store feature in the features array: before "initData" because in macro features // in initData it creates new features, appeared later than this TDF_Label aPrevFeateureLab; + FolderPtr aParentFolder; if (theAfterThis.get()) { // searching for the previous feature label std::shared_ptr aPrevData = std::dynamic_pointer_cast(theAfterThis->data()); if (aPrevData.get()) { aPrevFeateureLab = aPrevData->label().Father(); } + // Check if the previous feature is the last feature in a folder, + // then the folder should be updated to contain additional feature. + // Macro features are not stored in folder. + if (!theFeature->isMacro()) { + // If the last feature is a sub-feature of composite, use parent feature + // to check belonging to a folder. + FeaturePtr afterThis = ModelAPI_Tools::compositeOwner(theAfterThis); + if (!afterThis) + afterThis = theAfterThis; + aParentFolder = inFolder(afterThis, ModelAPI_Folder::LAST_FEATURE_ID()); + } } AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab); @@ -183,6 +211,12 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT // must be after binding to the map because of "Box" macro feature that // creates other features in "initData" initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS); + // put feature to the end of folder if it is added while + // the history line is set to the last feature from the folder + if (aParentFolder) { + aParentFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(theFeature); + updateHistory(ModelAPI_Folder::group()); + } // event: feature is added, mist 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); @@ -281,6 +315,8 @@ void Model_Objects::removeFeature(FeaturePtr theFeature) aComposite->removeFeature(theFeature); } } + // remove feature from folder + removeFromFolder(std::list(1, theFeature)); // this must be before erase since theFeature erasing removes all information about // the feature results and groups of results // To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated @@ -451,7 +487,7 @@ void Model_Objects::createHistory(const std::string& theGroupID) } else { // it may be a folder - ObjectPtr aFolder = folder(aRefs->Value(a)); + const ObjectPtr& aFolder = folder(aRefs->Value(a)); if (aFolder.get()) { // store folder information for the Features group only if (isFeature || isFolder) { @@ -499,11 +535,12 @@ void Model_Objects::updateHistory(const std::string theGroup) } } -ObjectPtr Model_Objects::folder(TDF_Label theLabel) const +const ObjectPtr& Model_Objects::folder(TDF_Label theLabel) const { if (myFolders.IsBound(theLabel)) return myFolders.Find(theLabel); - return ObjectPtr(); + static ObjectPtr anEmptyResult; + return anEmptyResult; } FeaturePtr Model_Objects::feature(TDF_Label theLabel) const @@ -564,6 +601,9 @@ ObjectPtr Model_Objects::object(const std::string& theGroupID, return ObjectPtr(); createHistory(theGroupID); const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder); + const std::vector& aVec = myHistory[theGroupID]; + //if (aVec.size() <= theIndex) + // return aVec[aVec.size() - 1]; // too high index requested (to avoid crash in #2360) return aGroupID.empty() ? myHistory[theGroupID][theIndex] : myHistory[aGroupID][theIndex]; } @@ -784,21 +824,28 @@ void Model_Objects::synchronizeFeatures( TDF_Label& aFeatureLab = anUpdatedIter.Value(); while(aFeatureLab.Depth() > 3) aFeatureLab = aFeatureLab.Father(); - if (myFeatures.IsBound(aFeatureLab)) + if (myFeatures.IsBound(aFeatureLab) || myFolders.IsBound(aFeatureLab)) anUpdatedMap.Add(aFeatureLab); } // update all objects by checking are they on labels or not - std::set aNewFeatures, aKeptFeatures; + std::set 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 aSession = + std::dynamic_pointer_cast(ModelAPI_Session::get()); + // create a feature - aFeature = std::dynamic_pointer_cast(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(); @@ -807,7 +854,10 @@ void Model_Objects::synchronizeFeatures( } 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(aFeature)); aNewFeatures.insert(aFeature); initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS); updateHistory(aFeature); @@ -815,18 +865,25 @@ void Model_Objects::synchronizeFeatures( // 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 > anAttrs = - aFeature->data()->attributes(""); + anObject->data()->attributes(""); std::list >::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 >& aResults = aFeature->results(); std::list >::const_iterator aRIter = aResults.begin(); @@ -865,6 +922,26 @@ void Model_Objects::synchronizeFeatures( } else aFIter.Next(); } + // verify folders are checked: if not => is was removed + for (NCollection_DataMap::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()); + // reinitialize iterator because unbind may corrupt the previous order in the map + aFldIt.Initialize(myFolders); + } + } if (theUpdateReferences) { synchronizeBackRefs(); @@ -892,8 +969,8 @@ void Model_Objects::synchronizeFeatures( myHistory.clear(); } - if (theExecuteFeatures) - anOwner->executeFeatures() = false; + if (!theExecuteFeatures) + anOwner->setExecuteFeatures(false); aLoop->activateFlushes(isActive); if (theFlush) { @@ -906,8 +983,8 @@ void Model_Objects::synchronizeFeatures( aLoop->flush(aRedispEvent); aLoop->flush(aToHideEvent); } - if (theExecuteFeatures) - anOwner->executeFeatures() = true; + if (!theExecuteFeatures) + anOwner->setExecuteFeatures(true); } /// synchronises back references for the given object basing on the collected data @@ -922,7 +999,10 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set& t for(; aNewIter != theNewRefs.end(); aNewIter++) { if (aData->refsToMe().find(*aNewIter) == aData->refsToMe().end()) { FeaturePtr aRefFeat = std::dynamic_pointer_cast((*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 @@ -958,6 +1038,35 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set& t } else aCurrentIter++; } } + // for the last feature in the folder, check if it is a sub-feature, + // then refer the folder to a top-level parent composite feature + const std::set& aRefs = aData->refsToMe(); + std::set::iterator anIt = aRefs.begin(); + for (; anIt != aRefs.end(); ++anIt) + if ((*anIt)->id() == ModelAPI_Folder::LAST_FEATURE_ID()) + break; + if (anIt != aRefs.end()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); + if (aFeature) { + CompositeFeaturePtr aParent; + CompositeFeaturePtr aGrandParent = ModelAPI_Tools::compositeOwner(aFeature); + do { + aParent = aGrandParent; + if (aGrandParent) + aGrandParent = ModelAPI_Tools::compositeOwner(aParent); + } while (aGrandParent.get()); + if (aParent) { + ObjectPtr aFolder = (*anIt)->owner(); + // remove reference from the current feature + aData->removeBackReference(aFolder, ModelAPI_Folder::LAST_FEATURE_ID()); + // set reference to a top-level parent + aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(aParent); + std::shared_ptr aParentData = + std::dynamic_pointer_cast(aParent->data()); + aParentData->addBackReference(aFolder, ModelAPI_Folder::LAST_FEATURE_ID()); + } + } + } aData->updateConcealmentFlag(); } @@ -1079,8 +1188,10 @@ bool Model_Objects::hasCustomName(DataPtr theFeatureData, return false; } - theParentName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex); - return true; + std::pair aName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex); + if (aName.second) + theParentName = aName.first; + return aName.second; } void Model_Objects::storeResult(std::shared_ptr theFeatureData, @@ -1093,7 +1204,11 @@ void Model_Objects::storeResult(std::shared_ptr theFeatureData, if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name std::string aNewName = theFeatureData->name(); - if (!hasCustomName(theFeatureData, theResult, theResultIndex, aNewName)) { + if (hasCustomName(theFeatureData, theResult, theResultIndex, aNewName)) { + // if the name of result is user-defined, then, at first time, assign name of the result + // by empty string to be sure that corresponding flag in the data model is set + theResult->data()->setName(""); + } else { std::stringstream aName; aName << aNewName; // if there are several results (issue #899: any number of result), @@ -1275,9 +1390,32 @@ std::shared_ptr Model_Objects::createFolder( void Model_Objects::removeFolder(std::shared_ptr theFolder) { - /// \todo + std::shared_ptr aData = std::static_pointer_cast(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& theFeatures, const bool isLast) { FeaturePtr aFeature; @@ -1291,6 +1429,13 @@ static FeaturePtr limitingFeature(std::list& theFeatures, const bool 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 Model_Objects::findFolder( const std::list >& theFeatures, const bool theBelow) @@ -1328,14 +1473,20 @@ std::shared_ptr Model_Objects::findFolder( 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(folder(aCurLabel)); - if (aFoundFolder) { + const ObjectPtr& aFolderObj = folder(aCurLabel); + if (aFolderObj.get()) { + aFoundFolder = std::dynamic_pointer_cast(aFolderObj); AttributeReferencePtr aLastFeatAttr = aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID()); if (aLastFeatAttr) { @@ -1351,8 +1502,15 @@ std::shared_ptr Model_Objects::findFolder( } 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 - TDF_Label aLabel = aRefs->Value(aRefIndex + 1); aFoundFolder = std::dynamic_pointer_cast(folder(aLabel)); } @@ -1366,14 +1524,13 @@ std::shared_ptr Model_Objects::findFolder( !aFeatures.empty() && aRefIndex >= aRefs->Lower() && aRefIndex <= aRefs->Upper(); aRefIndex += aStep) { TDF_Label aCurLabel = aRefs->Value(aRefIndex); - TDF_Label aFeatureLabel; + // if feature is in sub-component, skip it + FeaturePtr aCurFeature = feature(aCurLabel); + if (isSkippedFeature(aCurFeature)) + continue; aLimitingFeature = limitingFeature(aFeatures, theBelow); - aData = std::static_pointer_cast(aLimitingFeature->data()); - if (aData && aData->isValid()) - aFeatureLabel = aData->label().Father(); - - if (!IsEqual(aCurLabel, aFeatureLabel)) + if (!aCurFeature->data()->isEqual(aLimitingFeature->data())) return FolderPtr(); // not a sequential list } @@ -1457,21 +1614,6 @@ bool Model_Objects::moveToFolder( return true; } -static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr) -{ - const std::set& aRefs = theFeature->data()->refsToMe(); - for (std::set::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) { - if ((*anIt)->id() != theFolderAttr) - continue; - - ObjectPtr anOwner = (*anIt)->owner(); - FolderPtr aFolder = std::dynamic_pointer_cast(anOwner); - if (aFolder.get()) - return aFolder; - } - return FolderPtr(); -} - static FolderPtr isExtractionCorrect(const FolderPtr& theFirstFeatureFolder, const FolderPtr& theLastFeatureFolder, bool& isExtractBefore) @@ -1497,8 +1639,10 @@ bool Model_Objects::removeFromFolder( 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()); + 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 = @@ -1537,15 +1681,29 @@ bool Model_Objects::removeFromFolder( 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)); + if (aFolderStartFeature.get()) { + FeaturePtr aNewStartFeature; + do { // skip all features placed in the composite features + aPrevFeatureLabel = aRefs->Value(aRefIndex++); + aNewStartFeature = + aRefIndex <= aRefs->Upper() ? feature(aRefs->Value(aRefIndex)) : FeaturePtr(); + } while (aNewStartFeature && isSkippedFeature(aNewStartFeature)); + aFolderStartFeature = aNewStartFeature; + } // 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)); + if (aFolderEndFeature.get()) { + FeaturePtr aNewEndFeature; + do { // skip all features placed in the composite features + --aRefIndex; + aNewEndFeature = + aRefIndex >= aRefs->Lower() ? feature(aRefs->Value(aRefIndex)) : FeaturePtr(); + } while (aNewEndFeature && isSkippedFeature(aNewEndFeature)); + aFolderEndFeature = aNewEndFeature; + } } // update folder references @@ -1556,6 +1714,74 @@ bool Model_Objects::removeFromFolder( 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 aData = + std::static_pointer_cast(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 (aFoundFolder) + ++theIndexInFolder; + + if (aCurLabel == aLabelToFind) { // the feature is reached + if (aFoundFolder) { + if (isSkippedFeature(theFeature)) { + theIndexInFolder = -1; + return FolderPtr(); + } + // decrease the index of the feature in the folder by the number of skipped features + for (int anIndex = theIndexInFolder - 1; anIndex > 0; anIndex--) { + aCurLabel = aRefs->Value(aRefIndex - anIndex); + if (isSkippedFeature(feature(aCurLabel))) + theIndexInFolder--; + } + } + return aFoundFolder; + } + + if (!aFoundFolder) { + // if the current label refers to a folder, feel all necessary data + const ObjectPtr& aFolderObj = folder(aCurLabel); + if (aFolderObj.get()) { + aFoundFolder = std::dynamic_pointer_cast(aFolderObj); + theIndexInFolder = -1; + + AttributeReferencePtr aLastRef = + aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID()); + if (aLastRef->value()) { + aData = std::static_pointer_cast(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 Model_Objects::feature( const std::shared_ptr& theResult) @@ -1715,9 +1941,16 @@ FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theRever std::shared_ptr aData = std::static_pointer_cast(theCurrent->data()); if (aData.get() && aData->isValid()) { TDF_Label aFeatureLabel = aData->label().Father(); - TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse); - if (!aNextLabel.IsNull()) - return feature(aNextLabel); + do { + TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse); + if (aNextLabel.IsNull()) + break; // last or something is wrong + FeaturePtr aFound = feature(aNextLabel); + if (aFound) + return aFound; // the feature is found + // if the next label is a folder, skip it + aFeatureLabel = folder(aNextLabel).get() ? aNextLabel : TDF_Label(); + } while (!aFeatureLabel.IsNull()); } return FeaturePtr(); // not found, last, or something is wrong } @@ -1735,6 +1968,11 @@ FeaturePtr Model_Objects::lastFeature() { Handle(TDataStd_ReferenceArray) aRefs; if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { + FeaturePtr aLast = feature(aRefs->Value(aRefs->Upper())); + if (!aLast.get() && aRefs->Length() != 0) { // erase the invalid feature from the array + RemoveFromRefArray(featuresLabel(), aRefs->Value(aRefs->Upper())); + return lastFeature(); // try once again, after the last was removed + } return feature(aRefs->Value(aRefs->Upper())); } return FeaturePtr(); // no features at all