+ std::map<std::string, std::list<TDF_Label> >::iterator aFind = myNamingNames.find(theName);
+
+ if (aFind != myNamingNames.end()) { // to avoid duplicate-labels
+ // to keep correct order inspite of history line management
+ std::list<TDF_Label>::iterator anAddAfterThis = aFind->second.end();
+ FeaturePtr anAddedFeature = featureByLab(theLabel);
+ std::list<TDF_Label>::iterator aLabIter = aFind->second.begin();
+ while(aLabIter != aFind->second.end()) {
+ if (theLabel.IsEqual(*aLabIter)) {
+ std::list<TDF_Label>::iterator aTmpIter = aLabIter;
+ aLabIter++;
+ aFind->second.erase(aTmpIter);
+ } else {
+ FeaturePtr aCurFeature = featureByLab(*aLabIter);
+ if (aCurFeature.get() && anAddedFeature.get() &&
+ myObjs->isLater(anAddedFeature, aCurFeature))
+ anAddAfterThis = aLabIter;
+
+ aLabIter++;
+ }
+ }
+ if (anAddAfterThis != aFind->second.end()) {
+ anAddAfterThis++;
+ if (anAddAfterThis != aFind->second.end()) {
+ myNamingNames[theName].insert(anAddAfterThis, theLabel); // inserts before anAddAfterThis
+ return;
+ }
+ }
+ }
+ myNamingNames[theName].push_back(theLabel);
+}
+
+void Model_Document::changeNamingName(const std::string theOldName,
+ const std::string theNewName,
+ const TDF_Label& theLabel)
+{
+ std::map<std::string, std::list<TDF_Label> >::iterator aFind = myNamingNames.find(theOldName);
+ if (aFind != myNamingNames.end()) {
+ std::list<TDF_Label>::iterator aLabIter = aFind->second.begin();
+ for(; aLabIter != aFind->second.end(); aLabIter++) {
+ if (theLabel.IsEqual(*aLabIter)) { // found the label
+ myNamingNames[theNewName].push_back(theLabel);
+ if (aFind->second.size() == 1) { // only one element, so, just change the name
+ myNamingNames.erase(theOldName);
+ } else { // remove from the list
+ aFind->second.erase(aLabIter);
+ }
+ return;
+ }
+ }
+ }
+}
+
+TDF_Label Model_Document::findNamingName(std::string theName, ResultPtr theContext)
+{
+ std::map<std::string, std::list<TDF_Label> >::iterator aFind = myNamingNames.find(theName);
+ if (aFind != myNamingNames.end()) {
+ std::list<TDF_Label>::reverse_iterator aLabIter = aFind->second.rbegin();
+ for(; aLabIter != aFind->second.rend(); aLabIter++) {
+ if (theContext.get()) {
+ // context is defined and not like this, so, skip
+ if (theContext == myObjs->object(aLabIter->Father()))
+ return *aLabIter;
+ }
+ }
+ return *(aFind->second.rbegin()); // no more variannts, so, return the last
+ }
+ // not found exact name, try to find by sub-components
+ std::string::size_type aSlash = theName.rfind('/');
+ if (aSlash != std::string::npos) {
+ std::string anObjName = theName.substr(0, aSlash);
+ aFind = myNamingNames.find(anObjName);
+ if (aFind != myNamingNames.end()) {
+ TCollection_ExtendedString aSubName(theName.substr(aSlash + 1).c_str());
+ // iterate all possible same-named labels starting from the last one (the recent)
+ std::list<TDF_Label>::reverse_iterator aLabIter = aFind->second.rbegin();
+ for(; aLabIter != aFind->second.rend(); aLabIter++) {
+ if (theContext.get()) {
+ // context is defined and not like this, so, skip
+ if (theContext != myObjs->object(aLabIter->Father()))
+ continue;
+ }
+ // copy aSubName to avoid incorrect further processing after its suffix cutting
+ TCollection_ExtendedString aSubNameCopy(aSubName);
+ // searching sub-labels with this name
+ TDF_ChildIDIterator aNamesIter(*aLabIter, TDataStd_Name::GetID(), Standard_True);
+ for(; aNamesIter.More(); aNamesIter.Next()) {
+ Handle(TDataStd_Name) aName = Handle(TDataStd_Name)::DownCast(aNamesIter.Value());
+ if (aName->Get() == aSubNameCopy)
+ return aName->Label();
+ }
+ // If not found child label with the exact sub-name, then try to find compound with
+ // such sub-name without suffix.
+ Standard_Integer aSuffixPos = aSubNameCopy.SearchFromEnd('_');
+ if (aSuffixPos != -1 && aSuffixPos != aSubNameCopy.Length()) {
+ TCollection_ExtendedString anIndexStr = aSubNameCopy.Split(aSuffixPos);
+ aSubNameCopy.Remove(aSuffixPos);
+ aNamesIter.Initialize(*aLabIter, TDataStd_Name::GetID(), Standard_True);
+ for(; aNamesIter.More(); aNamesIter.Next()) {
+ Handle(TDataStd_Name) aName = Handle(TDataStd_Name)::DownCast(aNamesIter.Value());
+ if (aName->Get() == aSubNameCopy) {
+ return aName->Label();
+ }
+ }
+ // check also "this" label
+ Handle(TDataStd_Name) aName;
+ if (aLabIter->FindAttribute(TDataStd_Name::GetID(), aName)) {
+ if (aName->Get() == aSubNameCopy) {
+ return aName->Label();
+ }
+ }
+ }
+ }
+ // verify context's name is same as sub-component's and use context's label
+ if (aSubName.IsEqual(anObjName.c_str()))
+ return *(aFind->second.rbegin());
+ }
+ }
+ return TDF_Label(); // not found
+}
+
+bool Model_Document::isLaterByDep(FeaturePtr theThis, FeaturePtr theOther) {
+ // check dependencies first: if theOther depends on theThis, theThis is not later
+ std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aRefs;
+ theOther->data()->referencesToObjects(aRefs);
+ std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >::iterator
+ aRefIt = aRefs.begin();
+ for(; aRefIt != aRefs.end(); aRefIt++) {
+ std::list<ObjectPtr>::iterator aRefObjIt = aRefIt->second.begin();
+ for(; aRefObjIt != aRefIt->second.end(); aRefObjIt++) {
+ ObjectPtr aRefObj = *aRefObjIt;
+ if (aRefObj.get()) {
+ FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObj);
+ if (!aRefFeat.get()) { // take feature of the result
+ aRefFeat = feature(std::dynamic_pointer_cast<ModelAPI_Result>(aRefObj));
+ }
+ if (aRefFeat.get()) {
+ if (aRefFeat == theThis)
+ return false; // other references to this, so other later than this
+ if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aRefFeat)) {
+ if (!isLaterByDep(theThis, aRefFeat)) // nested composites: recursion
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return myObjs->isLater(theThis, theOther);
+}
+
+int Model_Document::numberOfNameInHistory(
+ const ObjectPtr& theNameObject, const TDF_Label& theStartFrom)
+{
+ std::map<std::string, std::list<TDF_Label> >::iterator aFind =
+ myNamingNames.find(theNameObject->data()->name());
+ if (aFind == myNamingNames.end() || aFind->second.size() < 2) {
+ return 1; // no need to specify the name by additional identifiers
+ }
+ // get the feature of the object for relative compare
+ FeaturePtr aStart = myObjs->feature(theStartFrom);
+ if (!aStart.get()) // strange, but can not find feature by the label
+ return 1;
+ // feature that contain result with this name
+ FeaturePtr aNameFeature;
+ ResultPtr aNameResult = std::dynamic_pointer_cast<ModelAPI_Result>(theNameObject);
+ if (aNameResult)
+ aNameFeature = myObjs->feature(aNameResult);
+ else
+ aNameFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theNameObject);
+ // iterate all labels with this name to find the nearest just before or equal relative
+ std::list<TDF_Label>::reverse_iterator aLabIter = aFind->second.rbegin();
+ for(; aLabIter != aFind->second.rend(); aLabIter++) {
+ FeaturePtr aLabFeat = featureByLab(*aLabIter);
+ if (!aLabFeat.get())
+ continue;
+ if (isLaterByDep(aStart, aLabFeat)) // skip also start: its result don't used
+ break;
+ }
+ int aResIndex = 1;
+ for(; aLabIter != aFind->second.rend(); aLabIter++) {
+ FeaturePtr aLabFeat = featureByLab(*aLabIter);
+ if (!aLabFeat.get())
+ continue;
+ if (aLabFeat == aNameFeature || isLaterByDep(aNameFeature, aLabFeat))
+ return aResIndex;
+ aResIndex++;
+ }
+ return aResIndex; // strange
+}
+
+ResultPtr Model_Document::findByName(
+ std::string& theName, std::string& theSubShapeName, bool& theUniqueContext)
+{
+ int aNumInHistory = 0;
+ std::string aName = theName;
+ ResultPtr aRes = myObjs->findByName(aName);
+ theUniqueContext = !(aRes.get() && myNamingNames.find(aName) != myNamingNames.end());
+ while(!aRes.get() && aName[0] == '_') { // this may be theContext with the history index
+ aNumInHistory++;
+ aName = aName.substr(1);
+ aRes = myObjs->findByName(aName);
+ }
+ if (aNumInHistory) {
+ std::map<std::string, std::list<TDF_Label> >::iterator aFind = myNamingNames.find(aName);
+ if (aFind != myNamingNames.end() && aFind->second.size() > aNumInHistory) {
+ std::list<TDF_Label>::reverse_iterator aLibIt = aFind->second.rbegin();
+ for(; aNumInHistory != 0; aNumInHistory--)
+ aLibIt++;
+ const TDF_Label& aResultLab = *aLibIt;
+ aRes = std::dynamic_pointer_cast<ModelAPI_Result>(myObjs->object(aResultLab.Father()));
+ if (aRes) { // modify the incoming names
+ if (!theSubShapeName.empty())
+ theSubShapeName = theSubShapeName.substr(theName.size() - aName.size());
+ theName = aName;
+ }
+ }
+ }
+ return aRes;
+}
+
+std::list<std::shared_ptr<ModelAPI_Feature> > Model_Document::allFeatures()
+{
+ 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) {
+ myIsActive = theFlag;
+ // redisplay all the objects of this part
+ static Events_Loop* aLoop = Events_Loop::loop();
+ static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+
+ for(int a = size(ModelAPI_Feature::group()) - 1; a >= 0; a--) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(
+ object(ModelAPI_Feature::group(), a));
+ if (aFeature.get() && aFeature->data()->isValid()) {
+ std::list<ResultPtr> aResults;
+ ModelAPI_Tools::allResults(aFeature, aResults);
+ for (std::list<ResultPtr>::iterator aRes = aResults.begin();
+ aRes != aResults.end(); aRes++) {
+ ModelAPI_EventCreator::get()->sendUpdated(*aRes, aRedispEvent);
+ }
+ }
+ }
+ }
+}
+
+bool Model_Document::isActive() const
+{
+ return myIsActive;
+}
+
+int Model_Document::transactionID()
+{
+ Handle(TDataStd_Integer) anIndex;
+ if (!generalLabel().FindChild(TAG_CURRENT_TRANSACTION).
+ FindAttribute(TDataStd_Integer::GetID(), anIndex)) {
+ anIndex = TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), 1);
+ }
+ return anIndex->Get();
+}
+
+void Model_Document::incrementTransactionID()
+{
+ int aNewVal = transactionID() + 1;
+ TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal);
+}
+void Model_Document::decrementTransactionID()
+{
+ int aNewVal = transactionID() - 1;
+ TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal);
+}
+
+TDF_Label Model_Document::extConstructionsLabel() const
+{
+ return myDoc->Main().FindChild(TAG_EXTERNAL_CONSTRUCTIONS);
+}
+
+bool Model_Document::isOpened()
+{
+ return myObjs && !myDoc.IsNull();
+}
+
+int Model_Document::numInternalFeatures()
+{
+ return myObjs->numInternalFeatures();
+}
+
+std::shared_ptr<ModelAPI_Feature> Model_Document::internalFeature(const int theIndex)
+{
+ return myObjs->internalFeature(theIndex);
+}
+
+std::shared_ptr<ModelAPI_Feature> Model_Document::featureById(const int theId)
+{
+ return myObjs->featureById(theId);
+}
+
+void Model_Document::synchronizeTransactions()
+{
+ Model_Document* aRoot =
+ std::dynamic_pointer_cast<Model_Document>(ModelAPI_Session::get()->moduleDocument()).get();
+ if (aRoot == this)
+ return; // don't need to synchronise root with root
+
+ std::shared_ptr<Model_Session> aSession =
+ std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
+ while(myRedos.size() > aRoot->myRedos.size()) { // remove redos in this
+ aSession->setCheckTransactions(false);
+ redo();
+ aSession->setCheckTransactions(true);
+ }
+ /* this case can not be reproduced in any known case for the current moment, so, just comment
+ while(myRedos.size() < aRoot->myRedos.size()) { // add more redos in this
+ undoInternal(false, true);
+ }*/
+}
+
+/// Feature that is used for selection in the Part document by the external request
+class Model_SelectionInPartFeature : public ModelAPI_Feature {
+public:
+ /// Nothing to do in constructor
+ Model_SelectionInPartFeature() : ModelAPI_Feature() {}
+
+ /// Returns the unique kind of a feature
+ virtual const std::string& getKind() {
+ static std::string MY_KIND("InternalSelectionInPartFeature");
+ return MY_KIND;
+ }
+ /// Request for initialization of data model of the object: adding all attributes
+ virtual void initAttributes() {
+ data()->addAttribute("selection", ModelAPI_AttributeSelectionList::typeId());
+ }
+ /// Nothing to do in the execution function
+ virtual void execute() {}
+
+};
+
+//! Returns the feature that is used for calculation of selection externally from the document
+AttributeSelectionListPtr Model_Document::selectionInPartFeature()
+{
+ // return already created, otherwise create
+ if (!mySelectionFeature.get() || !mySelectionFeature->data()->isValid()) {
+ // create a new one
+ mySelectionFeature = FeaturePtr(new Model_SelectionInPartFeature);
+
+ TDF_Label aFeatureLab = generalLabel().FindChild(TAG_SELECTION_FEATURE);
+ std::shared_ptr<Model_Data> aData(new Model_Data);
+ aData->setLabel(aFeatureLab.FindChild(1));
+ aData->setObject(mySelectionFeature);
+ mySelectionFeature->setDoc(myObjs->owner());
+ mySelectionFeature->setData(aData);
+ std::string aName = id() + "_Part";
+ mySelectionFeature->data()->setName(aName);
+ mySelectionFeature->setDoc(myObjs->owner());
+ mySelectionFeature->initAttributes();
+ mySelectionFeature->init(); // to make it enabled and Update correctly
+ // this update may cause recomputation of the part after selection on it, that is not needed
+ mySelectionFeature->data()->blockSendAttributeUpdated(true);
+ }
+ return mySelectionFeature->selectionList("selection");
+}
+
+FeaturePtr Model_Document::lastFeature()
+{
+ if (myObjs)
+ return myObjs->lastFeature();
+ return FeaturePtr();
+}
+
+static Handle(TNaming_NamedShape) searchForOriginalShape(TopoDS_Shape theShape, TDF_Label aMain) {
+ Handle(TNaming_NamedShape) aResult;
+ while(!theShape.IsNull()) { // searching for the very initial shape that produces this one
+ TopoDS_Shape aShape = theShape;
+ theShape.Nullify();
+ // to avoid crash of TNaming_SameShapeIterator if pure shape does not exists
+ if (!TNaming_Tool::HasLabel(aMain, aShape))
+ break;
+ for(TNaming_SameShapeIterator anIter(aShape, aMain); anIter.More(); anIter.Next()) {
+ TDF_Label aNSLab = anIter.Label();
+ Handle(TNaming_NamedShape) aNS;
+ if (aNSLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+ for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) {
+ if (aShapesIter.Evolution() == TNaming_SELECTED ||
+ aShapesIter.Evolution() == TNaming_DELETE)
+ continue; // don't use the selection evolution
+ if (aShapesIter.NewShape().IsSame(aShape)) { // found the original shape
+ aResult = aNS;
+ if (aResult->Evolution() == TNaming_MODIFY)
+ theShape = aShapesIter.OldShape();
+ // otherwise may me searching for another item of this shape with longer history
+ if (!theShape.IsNull())
+ break;
+ }
+ }
+ }
+ }
+ }
+ return aResult;
+}
+
+std::shared_ptr<ModelAPI_Feature> Model_Document::producedByFeature(
+ std::shared_ptr<ModelAPI_Result> theResult,
+ const std::shared_ptr<GeomAPI_Shape>& theShape)
+{
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
+ if (!aBody.get()) {
+ return feature(theResult); // for not-body just returns the feature that produced this result
+ }
+ // otherwise get the shape and search the very initial label for it
+ TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
+ if (aShape.IsNull())
+ return FeaturePtr();
+
+ // for compsolids and compounds all the naming is located in the main object, so, try to use
+ // it first
+ ResultBodyPtr aMain = ModelAPI_Tools::bodyOwner(theResult);
+ while (aMain.get()) { // get the top-most main
+ ResultBodyPtr aNextMain = ModelAPI_Tools::bodyOwner(aMain);
+ if (aNextMain.get())
+ aMain = aNextMain;
+ else break;
+ }
+ if (aMain.get()) {
+ FeaturePtr aMainRes = producedByFeature(aMain, theShape);
+ if (aMainRes)
+ return aMainRes;
+ }
+
+ std::shared_ptr<Model_Data> aBodyData = std::dynamic_pointer_cast<Model_Data>(theResult->data());
+ if (!aBodyData.get() || !aBodyData->isValid())
+ return FeaturePtr();
+
+ TopoDS_Shape anOldShape; // old shape in the pair oldshape->theShape in the named shape
+ TopoDS_Shape aShapeContainer; // old shape of the shape that contains aShape as sub-element
+ Handle(TNaming_NamedShape) aCandidatInThis, aCandidatContainer;
+ TDF_Label aBodyLab = aBodyData->label();
+ // use childs and this label (the lowest priority)
+ TDF_ChildIDIterator aNSIter(aBodyLab, TNaming_NamedShape::GetID(), Standard_True);
+ bool aUseThis = !aNSIter.More();
+ while(anOldShape.IsNull() && (aNSIter.More() || aUseThis)) {
+ Handle(TNaming_NamedShape) aNS;
+ if (aUseThis) {
+ if (!aBodyLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
+ break;
+ } else {
+ aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value());
+ }
+ for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) {
+ if (aShapesIter.Evolution() == TNaming_SELECTED || aShapesIter.Evolution() == TNaming_DELETE)
+ continue; // don't use the selection evolution
+ if (aShapesIter.NewShape().IsSame(aShape)) { // found the original shape
+ aCandidatInThis = aNS;
+ if (aCandidatInThis->Evolution() == TNaming_MODIFY)
+ anOldShape = aShapesIter.OldShape();
+ // otherwise may me searching for another item of this shape with longer history
+ if (!anOldShape.IsNull())
+ break;
+ }
+ // check that the shape contains aShape as sub-shape to fill container
+ if (aShapesIter.NewShape().ShapeType() < aShape.ShapeType() && aCandidatContainer.IsNull()) {
+ TopExp_Explorer anExp(aShapesIter.NewShape(), aShape.ShapeType());
+ for(; anExp.More(); anExp.Next()) {
+ if (aShape.IsSame(anExp.Current())) {
+ aCandidatContainer = aNS;
+ aShapeContainer = aShapesIter.NewShape();
+ }
+ }
+ }
+ }
+ // iterate to the next label or to the body label in the end
+ if (!aUseThis)
+ aNSIter.Next();
+ if (!aNSIter.More()) {
+ if (aUseThis)
+ break;
+ aUseThis = true;
+ }
+ }
+ if (aCandidatInThis.IsNull()) {
+ // to fix 1512: searching for original shape of this shape
+ // if modification of it is not in this result
+ aCandidatInThis = searchForOriginalShape(aShape, myDoc->Main());
+ if (aCandidatInThis.IsNull()) {
+ if (aCandidatContainer.IsNull())
+ return FeaturePtr();
+ // with the lower priority use the higher level shape that contains aShape
+ aCandidatInThis = aCandidatContainer;
+ anOldShape = aShapeContainer;
+ } else {
+ // to stop the searching by the following searchForOriginalShape
+ anOldShape.Nullify();
+ }
+ }
+
+ Handle(TNaming_NamedShape) aNS = searchForOriginalShape(anOldShape, myDoc->Main());
+ if (!aNS.IsNull())
+ aCandidatInThis = aNS;
+
+ FeaturePtr aResult;
+ TDF_Label aResultLab = aCandidatInThis->Label();
+ while(aResultLab.Depth() > 3)
+ aResultLab = aResultLab.Father();
+ FeaturePtr aFeature = myObjs->feature(aResultLab);
+ if (aFeature.get()) {
+ if (!aResult.get() || myObjs->isLater(aResult, aFeature)) {
+ aResult = aFeature;
+ }
+ }
+ return aResult;
+}
+
+bool Model_Document::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const
+{
+ return myObjs->isLater(theLater, theCurrent);
+}
+
+void Model_Document::storeNodesState(const std::list<bool>& theStates)
+{
+ TDF_Label aLab = generalLabel().FindChild(TAG_NODES_STATE);
+ aLab.ForgetAllAttributes();
+ if (!theStates.empty()) {
+ Handle(TDataStd_BooleanArray) anArray =
+ TDataStd_BooleanArray::Set(aLab, 0, int(theStates.size()) - 1);
+ std::list<bool>::const_iterator aState = theStates.begin();
+ for(int anIndex = 0; aState != theStates.end(); aState++, anIndex++) {
+ anArray->SetValue(anIndex, *aState);
+ }
+ }
+}
+
+void Model_Document::restoreNodesState(std::list<bool>& theStates) const
+{
+ TDF_Label aLab = generalLabel().FindChild(TAG_NODES_STATE);
+ Handle(TDataStd_BooleanArray) anArray;
+ if (aLab.FindAttribute(TDataStd_BooleanArray::GetID(), anArray)) {
+ int anUpper = anArray->Upper();
+ for(int anIndex = 0; anIndex <= anUpper; anIndex++) {
+ theStates.push_back(anArray->Value(anIndex) == Standard_True);
+ }
+ }