Salome HOME
Add Model_AttributeSelection::setId()
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
index d85df7d3e99c453da2e0aa40f427d3baa3c80e7e..92b91327c230a0cf7f2133ec39424b2241d4575b 100644 (file)
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_Tools.h>
 #include <GeomAPI_Shape.h>
 #include <GeomAPI_PlanarEdges.h>
-#include <Events_Error.h>
+#include <Events_InfoMessage.h>
 
 #include <TNaming_Selector.hxx>
 #include <TNaming_NamedShape.hxx>
 #include <TopAbs_ShapeEnum.hxx>
 #include <TopoDS_Iterator.hxx>
 #include <TNaming_Iterator.hxx>
+#include <BRep_Builder.hxx>
 using namespace std;
 //#define DEB_NAMING 1
 #ifdef DEB_NAMING
 #include <BRepTools.hxx>
 #endif
-/// adeed to the index in the packed map to signalize that the vertex of edge is seleted
+/// added to the index in the packed map to signalize that the vertex of edge is selected
 /// (multiplied by the index of the edge)
 static const int kSTART_VERTEX_DELTA = 1000000;
 // identifier that there is simple reference: selection equals to context
@@ -96,8 +98,9 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
     (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
   if (isOldShape) return; // shape is the same, so context is also unchanged
   // update the referenced object if needed
-  if (!isOldContext)
-    myRef.setValue(theContext);
+  if (!isOldContext) {
+      myRef.setValue(theContext);
+  }
 
   // do noth use naming if selected shape is result shape itself, but not sub-shape
   TDF_Label aSelLab = selectionLabel();
@@ -122,7 +125,6 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
   if (theContext->groupName() == ModelAPI_ResultBody::group()) {
     // do not select the whole shape for body:it is already must be in the data framework
     // equal and null selected objects mean the same: object is equal to context,
-    // TODO: synchronize with GUI later that it must be null always
     if (theContext->shape().get() && 
         (theContext->shape()->isEqual(theSubShape) || !theSubShape.get())) {
       aSelLab.ForgetAllAttributes(true);
@@ -135,15 +137,30 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
       // to sub, so the whole result is selected
       aSelLab.ForgetAllAttributes(true);
       TDataStd_UAttribute::Set(aSelLab, kCONSTUCTION_SIMPLE_REF_ID);
-      // For correct naming selection, put the shape into the naming structure.
-      // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
-      TNaming_Builder aBuilder(aSelLab);
-      aBuilder.Generated(theContext->shape()->impl<TopoDS_Shape>());
-      std::shared_ptr<Model_Document> aMyDoc = 
-        std::dynamic_pointer_cast<Model_Document>(owner()->document());
-      std::string aName = theContext->data()->name();
-      aMyDoc->addNamingName(aSelLab, aName);
-      TDataStd_Name::Set(aSelLab, aName.c_str());
+      ResultConstructionPtr aConstruction = 
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theContext);
+      if (aConstruction->isInfinite()) {
+        // For correct naming selection, put the shape into the naming structure.
+        // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
+        TNaming_Builder aBuilder(aSelLab);
+        aBuilder.Generated(theContext->shape()->impl<TopoDS_Shape>());
+        std::shared_ptr<Model_Document> aMyDoc = 
+          std::dynamic_pointer_cast<Model_Document>(owner()->document());
+        std::string aName = theContext->data()->name();
+        aMyDoc->addNamingName(aSelLab, aName);
+        TDataStd_Name::Set(aSelLab, aName.c_str());
+      } else {  // for sketch the naming is needed in DS
+        BRep_Builder aCompoundBuilder;
+        TopoDS_Compound aComp;
+        aCompoundBuilder.MakeCompound(aComp);
+        for(int a = 0; a < aConstruction->facesNum(); a++) {
+          TopoDS_Shape aFace = aConstruction->face(a)->impl<TopoDS_Shape>();
+          aCompoundBuilder.Add(aComp, aFace);
+        }
+        std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
+        aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aComp));
+        selectConstruction(theContext, aShape);
+      }
     } else {
       selectConstruction(theContext, theSubShape);
     }
@@ -164,11 +181,16 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
 
 std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
 {
+  GeomShapePtr aResult;
   if (myTmpContext.get() || myTmpSubShape.get()) {
-    return myTmpSubShape;
+    ResultConstructionPtr aResulConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myTmpContext);
+    if(aResulConstruction.get()) {
+      // it is just reference to construction.
+      return myTmpSubShape;
+    }
+    return myTmpSubShape.get() ? myTmpSubShape : myTmpContext->shape();
   }
 
-  std::shared_ptr<GeomAPI_Shape> aResult;
   TDF_Label aSelLab = selectionLabel();
   if (aSelLab.IsAttribute(kINVALID_SELECTION))
     return aResult;
@@ -184,20 +206,27 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
         return aResult; // empty result
     }
     if (aSelLab.IsAttribute(kPART_REF_ID)) {
-      /* TODO: implement used text here
       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(context());
       if (!aPart.get() || !aPart->isActivated())
         return std::shared_ptr<GeomAPI_Shape>(); // postponed naming needed
       Handle(TDataStd_Integer) anIndex;
       if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) {
-        return aPart->selectionValue(anIndex->Get());
-      }
-      Handle(TDataStd_Name) aName;
-      if (!selectionLabel().FindAttribute(TDataStd_Name::GetID(), aName)) {
-        return std::shared_ptr<GeomAPI_Shape>(); // something is wrong
+        if (anIndex->Get()) { // special selection attribute was created, use it
+          return aPart->selectionValue(anIndex->Get());
+        } else { // face with name is already in the data model, so try to take it by name
+          Handle(TDataStd_Name) aName;
+          if (selectionLabel().FindAttribute(TDataStd_Name::GetID(), aName)) {
+            std::string aSubShapeName(TCollection_AsciiString(aName->Get()).ToCString());
+            std::size_t aPartEnd = aSubShapeName.find('/');
+            if (aPartEnd != string::npos && aPartEnd != aSubShapeName.rfind('/')) {
+              string aNameInPart = aSubShapeName.substr(aPartEnd + 1);
+              int anIndex;
+              std::string aType; // to reuse already existing selection the type is not needed
+              return aPart->shapeInPart(aNameInPart, aType, anIndex);
+            }
+          }
+        }
       }
-      return aPart->shapeInPart(TCollection_AsciiString(aName).ToCString());
-      */
     }
 
     Handle(TNaming_NamedShape) aSelection;
@@ -223,7 +252,7 @@ bool Model_AttributeSelection::isInvalid()
 
 bool Model_AttributeSelection::isInitialized()
 {
-  if (ModelAPI_AttributeSelection::isInitialized()) { // additional checkings if it is initialized
+  if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized
     std::shared_ptr<GeomAPI_Shape> aResult;
     if (myRef.isInitialized()) {
       TDF_Label aSelLab = selectionLabel();
@@ -296,24 +325,39 @@ void Model_AttributeSelection::setObject(const std::shared_ptr<ModelAPI_Object>&
 TDF_LabelMap& Model_AttributeSelection::scope()
 {
   if (myScope.IsEmpty()) { // create a new scope if not yet done
-    // gets all featueres with named shapes that are bofore this feature label (before in history)
+    // gets all features with named shapes that are before this feature label (before in history)
     DocumentPtr aMyDoc = owner()->document();
     std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures = aMyDoc->allFeatures();
     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator aFIter = allFeatures.begin();
     bool aMePassed = false;
-    std::shared_ptr<ModelAPI_CompositeFeature> aComposite = 
+    CompositeFeaturePtr aComposite = 
       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(owner());
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+    CompositeFeaturePtr aCompositeOwner, aCompositeOwnerOwner;
+    if (aFeature.get()) {
+      aCompositeOwner = ModelAPI_Tools::compositeOwner(aFeature);
+      if (aCompositeOwner.get()) {
+         aCompositeOwnerOwner = ModelAPI_Tools::compositeOwner(aCompositeOwner);
+      }
+    }
+    // for group Scope is not limitet: this is always up to date objects
+    bool isGroup = aFeature.get() && aFeature->getKind() == "Group";
     for(; aFIter != allFeatures.end(); aFIter++) {
       if (*aFIter == owner()) {  // the left features are created later (except subs of composite)
         aMePassed = true;
         continue;
       }
+      if (isGroup) aMePassed = false;
       bool isInScope = !aMePassed;
       if (!isInScope && aComposite.get()) { // try to add sub-elements of composite if this is composite
         if (aComposite->isSub(*aFIter))
           isInScope = true;
       }
-      if (aFIter->get() && (*aFIter)->data()->isValid()) {
+      // remove the composite-owner of this feature (sketch in extrusion-cut)
+      if (isInScope && (aCompositeOwner == *aFIter || aCompositeOwnerOwner == *aFIter))
+        isInScope = false;
+
+      if (isInScope && aFIter->get() && (*aFIter)->data()->isValid()) {
         TDF_Label aFeatureLab = std::dynamic_pointer_cast<Model_Data>(
           (*aFIter)->data())->label().Father();
         TDF_ChildIDIterator aNSIter(aFeatureLab, TNaming_NamedShape::GetID(), 1);
@@ -363,20 +407,51 @@ bool Model_AttributeSelection::update()
     return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull());
   }
   if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { // it is just reference to construction, not sub-shape
+    // if there is a sketch, the sketch-naming must be updated
+    ResultConstructionPtr aConstruction = 
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
+    if (!aConstruction->isInfinite()) {
+      BRep_Builder aCompoundBuilder;
+      TopoDS_Compound aComp;
+      aCompoundBuilder.MakeCompound(aComp);
+      for(int a = 0; a < aConstruction->facesNum(); a++) {
+        TopoDS_Shape aFace = aConstruction->face(a)->impl<TopoDS_Shape>();
+        aCompoundBuilder.Add(aComp, aFace);
+      }
+      std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
+      aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aComp));
+      selectConstruction(aContext, aShape);
+    } else {
+      // For correct naming selection, put the shape into the naming structure.
+      // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
+      TNaming_Builder aBuilder(aSelLab);
+      aBuilder.Generated(aContext->shape()->impl<TopoDS_Shape>());
+      std::shared_ptr<Model_Document> aMyDoc = 
+        std::dynamic_pointer_cast<Model_Document>(owner()->document());
+      std::string aName = aContext->data()->name();
+      aMyDoc->addNamingName(aSelLab, aName);
+      TDataStd_Name::Set(aSelLab, aName.c_str());
+    }
     return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull());
   }
 
   if (aSelLab.IsAttribute(kPART_REF_ID)) { // it is reference to the part object
     std::shared_ptr<GeomAPI_Shape> aNoSelection;
-    return setInvalidIfFalse(aSelLab, selectPart(aContext, aNoSelection, true));
+    bool aResult = selectPart(aContext, aNoSelection, true);
+    aResult = setInvalidIfFalse(aSelLab, aResult);
+    if (aResult) {
+      owner()->data()->sendAttributeUpdated(this);
+    }
+    return aResult;
   }
 
   if (aContext->groupName() == ModelAPI_ResultBody::group()) {
     // body: just a named shape, use selection mechanism from OCCT
     TNaming_Selector aSelector(aSelLab);
     bool aResult = aSelector.Solve(scope()) == Standard_True;
+    aResult = setInvalidIfFalse(aSelLab, aResult); // must be before sending of updated attribute (1556)
     owner()->data()->sendAttributeUpdated(this);
-    return setInvalidIfFalse(aSelLab, aResult);
+    return aResult;
   } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
     // construction: identification by the results indexes, recompute faces and
     // take the face that more close by the indexes
@@ -406,8 +481,8 @@ bool Model_AttributeSelection::update()
         return setInvalidIfFalse(aSelLab, false);
       }
 
-      if (aShapeType == TopAbs_FACE) { // compound is for the whole sketch selection
-        // If this is a wire with plane defined thin it is a sketch-like object
+      if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) { // compound is for the whole sketch selection
+        // If this is a wire with plane defined then it is a sketch-like object
         if (!aConstructionContext->facesNum()) // no faces, update can not work correctly
           return setInvalidIfFalse(aSelLab, false);
         // if there is no edges indexes, any face can be used: take the first
@@ -415,7 +490,7 @@ bool Model_AttributeSelection::update()
         if (aNoIndexes) {
           aNewSelected = aConstructionContext->face(0);
         } else { // searching for most looks-like initial face by the indexes
-          // prepare edges of the current resut for the fast searching
+          // prepare edges of the current result for the fast searching
           NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
           const int aSubNum = aComposite->numberOfSubs();
           for(int a = 0; a < aSubNum; a++) {
@@ -445,7 +520,7 @@ bool Model_AttributeSelection::update()
               }
             }
           }
-          double aBestFound = 0; // best percentage of found edges
+          int aBestFound = 0; // best number of found edges (not percentage: issue 1019)
           int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation
           for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) {
             int aFound = 0, aNotFound = 0, aSameOrientation = 0;
@@ -474,12 +549,9 @@ bool Model_AttributeSelection::update()
               }
             }
             if (aFound + aNotFound != 0) {
-              double aSum = aFound + aNotFound;
-               // aSameOrientation: if edges are same, take where orientation is better
-              double aPercentage = double(aFound) / double(aFound + aNotFound);
-              if (aPercentage > aBestFound || 
-                  (aPercentage == aBestFound && aSameOrientation > aBestOrient)) {
-                aBestFound = aPercentage;
+              if (aFound > aBestFound || 
+                  (aFound == aBestFound && aSameOrientation > aBestOrient)) {
+                aBestFound = aFound;
                 aBestOrient = aSameOrientation;
                 aNewSelected = aConstructionContext->face(aFaceIndex);
               }
@@ -487,9 +559,17 @@ bool Model_AttributeSelection::update()
           }
         }
         if (aNewSelected) { // store this new selection
+          if (aShapeType == TopAbs_WIRE) { // just get a wire from face to have wire
+            TopExp_Explorer aWireExp(aNewSelected->impl<TopoDS_Shape>(), TopAbs_WIRE);
+            if (aWireExp.More()) {
+              aNewSelected.reset(new GeomAPI_Shape);
+              aNewSelected->setImpl<TopoDS_Shape>(new TopoDS_Shape(aWireExp.Current()));
+            }
+          }
           selectConstruction(aContext, aNewSelected);
+          setInvalidIfFalse(aSelLab, true);
           owner()->data()->sendAttributeUpdated(this);
-          return setInvalidIfFalse(aSelLab, true);
+          return true;
         } else { // if the selection is not found, put the empty shape: it's better to have disappeared shape, than the old, the lost one
           TNaming_Builder anEmptyBuilder(selectionLabel());
           return setInvalidIfFalse(aSelLab, false);
@@ -509,8 +589,9 @@ bool Model_AttributeSelection::update()
                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
               if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
                 selectConstruction(aContext, aRes->shape());
+                setInvalidIfFalse(aSelLab, true);
                 owner()->data()->sendAttributeUpdated(this);
-                return setInvalidIfFalse(aSelLab, true);
+                return true;
               }
             }
           }
@@ -538,8 +619,9 @@ bool Model_AttributeSelection::update()
                 if (aRes && aRes->shape()) {
                   if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
                     selectConstruction(aContext, aRes->shape());
+                    setInvalidIfFalse(aSelLab, true);
                     owner()->data()->sendAttributeUpdated(this);
-                    return setInvalidIfFalse(aSelLab, true);
+                    return true;
                   } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
                     const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
                     int aVIndex = 1;
@@ -548,8 +630,9 @@ bool Model_AttributeSelection::update()
                         std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
                         aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
                         selectConstruction(aContext, aVertex);
+                        setInvalidIfFalse(aSelLab, true);
                         owner()->data()->sendAttributeUpdated(this);
-                        return setInvalidIfFalse(aSelLab, true);
+                        return true;
                       }
                       aVIndex++;
                     }
@@ -561,8 +644,9 @@ bool Model_AttributeSelection::update()
       }
     } else { // simple construction element: the selected is that needed
       selectConstruction(aContext, aContext->shape());
+      setInvalidIfFalse(aSelLab, true);
       owner()->data()->sendAttributeUpdated(this);
-      return setInvalidIfFalse(aSelLab, true);
+      return true;
     }
   }
   return setInvalidIfFalse(aSelLab, false); // unknown case
@@ -585,17 +669,15 @@ void Model_AttributeSelection::selectBody(
     if (aResult) {
       aContext = aResult->shape()->impl<TopoDS_Shape>();
     } else {
-      Events_Error::send("A result with shape is expected");
+      Events_InfoMessage("Model_AttributeSelection", "A result with shape is expected").send();
       return;
     }
   }
   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : aContext;
   /// fix for issue 411: result modified shapes must not participate in this selection mechanism
-  /*
   FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
   if (aFeatureOwner.get())
     aFeatureOwner->eraseResults();
-    */
   if (!aContext.IsNull()) {
     aSel.Select(aNewShape, aContext); 
   }
@@ -623,6 +705,7 @@ static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape,
   if (!theAdditionalName.empty())
     aName<<theAdditionalName<<"/";
   if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face";
+  else if (theShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
   else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
   else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
 
@@ -632,7 +715,7 @@ static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape,
       aName<<"f";
     else if (theOrientation == -1)
       aName<<"r";
-  } else { // make a compisite name from all sub-elements indexes: "1_2_3_4"
+  } else { // make a composite name from all sub-elements indexes: "1_2_3_4"
     TColStd_MapIteratorOfPackedMapOfInteger aRef(theRefs->GetMap());
     for(; aRef.More(); aRef.Next()) {
       aName<<"-"<<aRef.Key();
@@ -668,7 +751,7 @@ void Model_AttributeSelection::selectConstruction(
   }
   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(owner()->data());
   TDF_Label aLab = myRef.myRef->Label();
-  // identify the reuslts of sub-object of the composite by edges
+  // identify the results of sub-object of the composite by edges
   // save type of the selected shape in integer attribute
   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
   TDataStd_Integer::Set(aLab, (int)aShapeType);
@@ -729,7 +812,7 @@ void Model_AttributeSelection::selectConstruction(
             if (allCurves.Contains(aCurve)) {
               int anID = aComposite->subFeatureId(a);
               aRefs->Add(anID);
-              if (aShapeType != TopAbs_EDGE) { // face nneds the sub-edges on sub-labels
+              if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
                 // add edges to sub-label to support naming for edges selection
                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
@@ -788,7 +871,7 @@ bool Model_AttributeSelection::selectPart(
     }
     return true; // nothing to do, referencing just by name
   }
-  // store the shape (in case part is not loaded it should be usefull
+  // store the shape (in case part is not loaded it should be useful
   TopoDS_Shape aShape;
   std::string aName = theContext->data()->name();
   if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected
@@ -835,6 +918,24 @@ void Model_AttributeSelection::selectSubShape(
 {
   if(theSubShapeName.empty() || theType.empty()) return;
 
+  // check this is Part-name: 2 delimiters in the name
+  std::size_t aPartEnd = theSubShapeName.find('/');
+  if (aPartEnd != string::npos && aPartEnd != theSubShapeName.rfind('/')) {
+    std::string aPartName = theSubShapeName.substr(0, aPartEnd);
+    ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
+    if (aFound.get()) { // found such part, so asking it for the name
+      ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFound);
+      string aNameInPart = theSubShapeName.substr(aPartEnd + 1);
+      int anIndex;
+      std::shared_ptr<GeomAPI_Shape> aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex);
+      if (aSelected.get()) {
+        setValue(aPart, aSelected);
+        TDataStd_Integer::Set(selectionLabel(), anIndex);
+        return;
+      }
+    }
+  }
+
   Model_SelectionNaming aSelNaming(selectionLabel());
   std::shared_ptr<Model_Document> aDoc = 
     std::dynamic_pointer_cast<Model_Document>(owner()->document());
@@ -847,17 +948,70 @@ void Model_AttributeSelection::selectSubShape(
 
 int Model_AttributeSelection::Id()
 {
+  int anID = 0;
   std::shared_ptr<GeomAPI_Shape> aSelection = value();
   std::shared_ptr<GeomAPI_Shape> aContext = context()->shape();
-  const TopoDS_Shape& aMainShape = aContext->impl<TopoDS_Shape>();
+  // support for compsolids:
+  if (context().get() && ModelAPI_Tools::compSolidOwner(context()).get())
+    aContext = ModelAPI_Tools::compSolidOwner(context())->shape();
+
+
+  TopoDS_Shape aMainShape = aContext->impl<TopoDS_Shape>();
   const TopoDS_Shape& aSubShape = aSelection->impl<TopoDS_Shape>();
-  int anID = 0;
+  // searching for the latest main shape
   if (aSelection && !aSelection->isNull() &&
     aContext   && !aContext->isNull())
   {
+    std::shared_ptr<Model_Document> aDoc =
+      std::dynamic_pointer_cast<Model_Document>(context()->document());
+    if (aDoc.get()) {
+      Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
+      if (!aNS.IsNull()) {
+        aMainShape = TNaming_Tool::CurrentShape(aNS);
+      }
+    }
+
     TopTools_IndexedMapOfShape aSubShapesMap;
     TopExp::MapShapes(aMainShape, aSubShapesMap);
     anID = aSubShapesMap.FindIndex(aSubShape);
   }
   return anID;
 }
+
+void Model_AttributeSelection::setId(int theID)
+{
+  const ResultPtr& aContext = context();
+  std::shared_ptr<GeomAPI_Shape> aSelection;
+
+  std::shared_ptr<GeomAPI_Shape> aContextShape = aContext->shape();
+  // support for compsolids:
+  if (aContext.get() && ModelAPI_Tools::compSolidOwner(aContext).get())
+    aContextShape = ModelAPI_Tools::compSolidOwner(aContext)->shape();
+
+  TopoDS_Shape aMainShape = aContextShape->impl<TopoDS_Shape>();
+  // searching for the latest main shape
+  if (theID > 0 &&
+      aContextShape && !aContextShape->isNull())
+  {
+    std::shared_ptr<Model_Document> aDoc =
+      std::dynamic_pointer_cast<Model_Document>(aContext->document());
+    if (aDoc.get()) {
+      Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
+      if (!aNS.IsNull()) {
+        aMainShape = TNaming_Tool::CurrentShape(aNS);
+      }
+    }
+
+    TopTools_IndexedMapOfShape aSubShapesMap;
+    TopExp::MapShapes(aMainShape, aSubShapesMap);
+    const TopoDS_Shape& aSelShape = aSubShapesMap.FindKey(theID);
+
+    std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
+    aResult->setImpl(new TopoDS_Shape(aSelShape));
+
+    aSelection = aResult;
+  }
+
+  setValue(aContext, aSelection);
+}
+