X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Objects.cpp;h=b3b21793043789b434d0c4b7a51e2f4123786290;hb=e85bb4f7065e5750e48a7c77056c80c0fa18e559;hp=92b57970c79b32ad74c0852767437b952861d5d7;hpb=5495266766c85977f72b748cf674f0cf8b039a51;p=modules%2Fshaper.git diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 92b57970c..b3b217930 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -60,6 +59,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 +96,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 +175,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 +210,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 +314,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 +486,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 +534,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 @@ -519,41 +555,54 @@ ObjectPtr Model_Objects::object(TDF_Label theLabel) FeaturePtr aFeature = feature(theLabel); if (aFeature.get()) return feature(theLabel); - TDF_Label aFeatureLabel = theLabel.Father().Father(); // let's suppose it is result - aFeature = feature(aFeatureLabel); - bool isSubResult = false; - if (!aFeature.get() && aFeatureLabel.Depth() > 1) { // let's suppose this is sub-result of result + TDF_Label aFeatureLabel = theLabel; // let's suppose it is result of this feature + TDF_LabelList aSubLabs; // sub - labels from higher level to lower level of result + while(!aFeature.get() && aFeatureLabel.Depth() > 1) { + aSubLabs.Prepend(aFeatureLabel); aFeatureLabel = aFeatureLabel.Father().Father(); aFeature = feature(aFeatureLabel); - isSubResult = true; } if (aFeature.get()) { - const std::list >& aResults = aFeature->results(); - std::list >::const_iterator aRIter = aResults.cbegin(); - for (; aRIter != aResults.cend(); aRIter++) { - if (isSubResult) { - ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast(*aRIter); - if (aCompRes.get()) { - int aNumSubs = aCompRes->numberOfSubs(); - for(int a = 0; a < aNumSubs; a++) { - ResultPtr aSub = aCompRes->subResult(a); - if (aSub.get()) { - std::shared_ptr aSubData = std::dynamic_pointer_cast( - aSub->data()); - if (aSubData->label().Father().IsEqual(theLabel)) - return aSub; + ResultPtr aCurrentResult; + // searching for results then sub-results label by label + for(TDF_ListIteratorOfLabelList aSubLab(aSubLabs); aSubLab.More(); aSubLab.Next()) { + if (aCurrentResult.get()) { // iterate sub-results of result + ResultBodyPtr anOwner = std::dynamic_pointer_cast(aCurrentResult); + if (!anOwner) + return ObjectPtr(); // only Body can have sub-results + int a, aNumSubs = anOwner->numberOfSubs(); + for(a = 0; a < aNumSubs; a++) { + ResultPtr aSub = anOwner->subResult(a); + if (aSub.get()) { + std::shared_ptr aSubData = std::dynamic_pointer_cast( + aSub->data()); + const TDF_Label& aSubLabVal = aSubLab.ChangeValue(); + if (aSubData->label().Father().IsEqual(aSubLabVal)) { + aCurrentResult = aSub; + break; } } } - } else { - std::shared_ptr aResData = std::dynamic_pointer_cast( - (*aRIter)->data()); - if (aResData->label().Father().IsEqual(theLabel)) - return *aRIter; + if (a == aNumSubs) // not found an appropriate sub-result of result + return ObjectPtr(); + } else { // iterate results of feature + const std::list& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.cbegin(); + for(; aRIter != aResults.cend(); aRIter++) { + std::shared_ptr aResData = + std::dynamic_pointer_cast((*aRIter)->data()); + if (aResData->label().Father().IsEqual(aSubLab.ChangeValue())) { + aCurrentResult = *aRIter; + break; + } + } + if (aRIter == aResults.cend()) // not found an appropriate result of feature + return ObjectPtr(); } } + return aCurrentResult; } - return FeaturePtr(); // not found + return ObjectPtr(); // not found } ObjectPtr Model_Objects::object(const std::string& theGroupID, @@ -564,6 +613,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]; } @@ -582,24 +634,12 @@ std::shared_ptr Model_Objects::objectByName( std::list > allObjs = allFeatures(); std::list >::iterator anObjIter = allObjs.begin(); for(; anObjIter != allObjs.end(); anObjIter++) { - const std::list >& aResults = (*anObjIter)->results(); - std::list >::const_iterator aRIter = aResults.cbegin(); - for (; aRIter != aResults.cend(); aRIter++) { - if (aRIter->get() && (*aRIter)->groupName() == theGroupID) { - if ((*aRIter)->data()->name() == theName) - return *aRIter; - ResultCompSolidPtr aCompRes = - std::dynamic_pointer_cast(*aRIter); - if (aCompRes.get()) { - int aNumSubs = aCompRes->numberOfSubs(); - for(int a = 0; a < aNumSubs; a++) { - ResultPtr aSub = aCompRes->subResult(a); - if (aSub.get() && aSub->groupName() == theGroupID) { - if (aSub->data()->name() == theName) - return aSub; - } - } - } + std::list allRes; + ModelAPI_Tools::allResults(*anObjIter, allRes); + for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + if (aRes->get() && (*aRes)->groupName() == theGroupID) { + if ((*aRes)->data()->name() == theName) + return *aRes; } } } @@ -638,6 +678,21 @@ int Model_Objects::size(const std::string& theGroupID, const bool theAllowFolder return aGroupID.empty() ? int(myHistory[theGroupID].size()) : int(myHistory[aGroupID].size()); } +std::shared_ptr Model_Objects::parent( + const std::shared_ptr theChild) +{ + if (theChild.get()) { + std::shared_ptr aData = std::dynamic_pointer_cast(theChild->data()); + TDF_Label aLab = aData->label(); + if (!aLab.IsNull() && aLab.Depth() > 2) { + ObjectPtr anObj = object(aLab.Father().Father().Father()); + return anObj; + } + } + return ObjectPtr(); +} + + void Model_Objects::allResults(const std::string& theGroupID, std::list& theResults) { // iterate the array of references and get feature by feature from the array @@ -784,21 +839,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 +869,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 +880,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 +937,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 +984,8 @@ void Model_Objects::synchronizeFeatures( myHistory.clear(); } - if (theExecuteFeatures) - anOwner->executeFeatures() = false; + if (!theExecuteFeatures) + anOwner->setExecuteFeatures(false); aLoop->activateFlushes(isActive); if (theFlush) { @@ -906,8 +998,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 +1014,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 +1053,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(); } @@ -1057,10 +1181,10 @@ bool Model_Objects::hasCustomName(DataPtr theFeatureData, int theResultIndex, std::string& theParentName) const { - ResultCompSolidPtr aCompSolidRes = - std::dynamic_pointer_cast(theFeatureData->owner()); - if (aCompSolidRes) { - FeaturePtr anOwner = ModelAPI_Feature::feature(theResult->data()->owner()); + ResultBodyPtr aBodyRes = std::dynamic_pointer_cast(theFeatureData->owner()); + if (aBodyRes && std::dynamic_pointer_cast(theFeatureData)->label().Depth() < 7) { + // only for top-results (works for the cases when results are not yet added to the feature) + FeaturePtr anOwner = ModelAPI_Feature::feature(theResult); // names of sub-solids in CompSolid should be default (for example, // result of boolean operation 'Boolean_1' is a CompSolid which is renamed to 'MyBOOL', @@ -1068,19 +1192,21 @@ bool Model_Objects::hasCustomName(DataPtr theFeatureData, std::ostringstream aDefaultName; aDefaultName << anOwner->name(); // compute default name of CompSolid (name of feature + index of CompSolid's result) - int aCompSolidResultIndex = 0; + int aBodyResultIndex = 0; const std::list& aResults = anOwner->results(); - for (std::list::const_iterator anIt = aResults.begin(); - anIt != aResults.end(); ++anIt, ++aCompSolidResultIndex) - if (aCompSolidRes == *anIt) + std::list::const_iterator anIt = aResults.begin(); + for(; anIt != aResults.end(); ++anIt, ++aBodyResultIndex) + if(aBodyRes == *anIt) break; - aDefaultName << "_" << (aCompSolidResultIndex + 1); + aDefaultName << "_" << (aBodyResultIndex + 1); theParentName = aDefaultName.str(); return false; } - theParentName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex); - return true; + std::pair aName = ModelAPI_Tools::getDefaultName(theResult); + if (aName.second) + theParentName = aName.first; + return aName.second; } void Model_Objects::storeResult(std::shared_ptr theFeatureData, @@ -1093,7 +1219,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), @@ -1127,27 +1257,14 @@ std::shared_ptr Model_Objects::createBody( const std::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - // for feature create compsolid, but for result sub create body: - // only one level of recursion is supported now - ResultPtr aResultOwner = std::dynamic_pointer_cast(theFeatureData->owner()); - ObjectPtr anOldObject; - if (aResultOwner.get()) { - TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); - } else { // in compsolid (higher level result) old object probably may be found - TDataStd_Comment::Set(aLab, ModelAPI_ResultCompSolid::group().c_str()); - anOldObject = object(aLab); - } + TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); + ObjectPtr anOldObject = object(aLab); std::shared_ptr aResult; if (anOldObject.get()) { aResult = std::dynamic_pointer_cast(anOldObject); } if (!aResult.get()) { - // create compsolid anyway; if it is compsolid, it will create sub-bodies internally - if (aResultOwner.get()) { - aResult = std::shared_ptr(new Model_ResultBody); - } else { - aResult = std::shared_ptr(new Model_ResultCompSolid); - } + aResult = std::shared_ptr(new Model_ResultBody); storeResult(theFeatureData, aResult, theIndex); } return aResult; @@ -1300,6 +1417,7 @@ void Model_Objects::removeFolder(std::shared_ptr theFolder) updateHistory(ModelAPI_Feature::group()); } +// Returns one of the limiting features of the list static FeaturePtr limitingFeature(std::list& theFeatures, const bool isLast) { FeaturePtr aFeature; @@ -1313,6 +1431,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) @@ -1350,14 +1475,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) { @@ -1373,8 +1504,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)); } @@ -1388,14 +1526,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 } @@ -1479,21 +1616,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) @@ -1561,15 +1683,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 @@ -1580,6 +1716,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) @@ -1588,7 +1792,7 @@ std::shared_ptr Model_Objects::feature( if (aData.get()) { TDF_Label aFeatureLab = aData->label().Father().Father().Father(); FeaturePtr aFeature = feature(aFeatureLab); - if (!aFeature.get() && aFeatureLab.Depth() > 1) { // this may be sub-result of result + while(!aFeature.get() && aFeatureLab.Depth() > 1) { // this may be sub-result of result aFeatureLab = aFeatureLab.Father().Father(); aFeature = feature(aFeatureLab); } @@ -1661,8 +1865,7 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set& t TDF_Label anArgLab = aLabIter.Value(); Handle(TDataStd_Comment) aGroup; if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) { - if (aGroup->Get() == ModelAPI_ResultBody::group().c_str() || - aGroup->Get() == ModelAPI_ResultCompSolid::group().c_str()) { + if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) { aNewBody = createBody(theFeature->data(), aResIndex); } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) { std::shared_ptr aNewP = createPart(theFeature->data(), aResIndex); @@ -1688,6 +1891,15 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set& t } } } + if (aResSize > 0) { // check there exist a body that must be updated + std::list::const_iterator aRes = theFeature->results().cbegin(); + for (; aResSize && aRes != theFeature->results().cend(); aRes++, aResSize++) { + if ((*aRes)->data()->isValid() && (*aRes)->groupName() == ModelAPI_ResultBody::group()) { + ResultBodyPtr aBody = std::dynamic_pointer_cast(*aRes); + aBody->updateSubs(aBody->shape()); + } + } + } } ResultPtr Model_Objects::findByName(const std::string theName) @@ -1739,9 +1951,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 } @@ -1759,6 +1978,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