Salome HOME
Fixes for issue #1956 and issue #2104 : correctly remove features on part remove.
[modules/shaper.git] / src / Model / Model_Objects.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_Objects.cxx
4 // Created:     15 May 2015
5 // Author:      Mikhail PONIKAROV
6
7 #include <Model_Objects.h>
8 #include <Model_Data.h>
9 #include <Model_Document.h>
10 #include <Model_Events.h>
11 #include <Model_Session.h>
12 #include <Model_ResultPart.h>
13 #include <Model_ResultConstruction.h>
14 #include <Model_ResultBody.h>
15 #include <Model_ResultCompSolid.h>
16 #include <Model_ResultGroup.h>
17 #include <Model_ResultField.h>
18 #include <Model_ResultParameter.h>
19 #include <ModelAPI_Validator.h>
20 #include <ModelAPI_CompositeFeature.h>
21 #include <ModelAPI_Tools.h>
22
23 #include <Events_Loop.h>
24 #include <Events_InfoMessage.h>
25
26 #include <TDataStd_Integer.hxx>
27 #include <TDataStd_Comment.hxx>
28 #include <TDF_ChildIDIterator.hxx>
29 #include <TDataStd_ReferenceArray.hxx>
30 #include <TDataStd_HLabelArray1.hxx>
31 #include <TDataStd_Name.hxx>
32 #include <TDF_Reference.hxx>
33 #include <TDF_ChildIDIterator.hxx>
34 #include <TDF_LabelMapHasher.hxx>
35 #include <TDF_LabelMap.hxx>
36 #include <TDF_ListIteratorOfLabelList.hxx>
37
38 static const int TAG_OBJECTS = 2;  // tag of the objects sub-tree (features, results)
39
40 // feature sub-labels
41 static const int TAG_FEATURE_ARGUMENTS = 1;  ///< where the arguments are located
42 static const int TAG_FEATURE_RESULTS = 2;  ///< where the results are located
43
44 ///
45 /// 0:1:2 - where features are located
46 /// 0:1:2:N:1 - data of the feature N
47 /// 0:1:2:N:2:K:1 - data of the K result of the feature N
48
49 Model_Objects::Model_Objects(TDF_Label theMainLab) : myMain(theMainLab)
50 {
51 }
52
53 void Model_Objects::setOwner(DocumentPtr theDoc)
54 {
55   myDoc = theDoc;
56   // update all fields and recreate features and result objects if needed
57   TDF_LabelList aNoUpdated;
58   synchronizeFeatures(aNoUpdated, true, true, true, true);
59   myHistory.clear();
60 }
61
62 Model_Objects::~Model_Objects()
63 {
64   // delete all features of this document
65   Events_Loop* aLoop = Events_Loop::loop();
66   // erase one by one to avoid access from the feature destructor itself from he map
67   // blocks the flush signals to avoid the temporary objects visualization in the viewer
68   // they should not be shown in order to do not lose highlight by erasing them
69   bool isActive = aLoop->activateFlushes(false);
70
71   while(!myFeatures.IsEmpty()) {
72     NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeaturesIter(myFeatures);
73     FeaturePtr aFeature = aFeaturesIter.Value();
74     static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
75     ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group());
76     ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
77     aFeature->removeResults(0, false);
78     aFeature->erase();
79     myFeatures.UnBind(aFeaturesIter.Key());
80   }
81   myHistory.clear();
82   aLoop->activateFlushes(isActive);
83   // erase update, because features are destroyed and update should not performed for them anywhere
84   aLoop->eraseMessages(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
85   aLoop->eraseMessages(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
86   // deleted and redisplayed is correctly performed: they know that features are destroyed
87   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
88   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
89
90 }
91
92 /// Appends to the array of references a new referenced label
93 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced, TDF_Label& thePrevLab)
94 {
95   Handle(TDataStd_ReferenceArray) aRefs;
96   if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
97     aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
98     aRefs->SetValue(0, theReferenced);
99   } else {  // extend array by one more element
100     Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
101                                                                         aRefs->Upper() + 1);
102     int aPassedPrev = 0; // prev feature is found and passed
103     if (thePrevLab.IsNull()) { // null means that inserted feature must be the first
104       aNewArray->SetValue(aRefs->Lower(), theReferenced);
105       aPassedPrev = 1;
106     }
107     for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
108       aNewArray->SetValue(a + aPassedPrev, aRefs->Value(a));
109       if (!aPassedPrev && aRefs->Value(a).IsEqual(thePrevLab)) {
110         aPassedPrev = 1;
111         aNewArray->SetValue(a + 1, theReferenced);
112       }
113     }
114     if (!aPassedPrev) // not found: unknown situation
115       aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
116     aRefs->SetInternalArray(aNewArray);
117   }
118 }
119
120 void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterThis)
121 {
122   if (!theFeature->isAction()) {  // do not add action to the data model
123     TDF_Label aFeaturesLab = featuresLabel();
124     TDF_Label aFeatureLab = aFeaturesLab.NewChild();
125     // store feature in the features array: before "initData" because in macro features
126     // in initData it creates new features, appeared later than this
127     TDF_Label aPrevFeateureLab;
128     if (theAfterThis.get()) { // searching for the previous feature label
129       std::shared_ptr<Model_Data> aPrevData =
130         std::dynamic_pointer_cast<Model_Data>(theAfterThis->data());
131       if (aPrevData.get()) {
132         aPrevFeateureLab = aPrevData->label().Father();
133       }
134     }
135     AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab);
136
137     // keep the feature ID to restore document later correctly
138     TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str());
139     myFeatures.Bind(aFeatureLab, theFeature);
140     // must be before the event sending: for OB the feature is already added
141     updateHistory(ModelAPI_Feature::group());
142     // do not change the order:
143     // initData()
144     // sendUpdated()
145     // during python script with fillet constraint feature data should be
146     // initialized before using it in GUI
147
148     // must be after binding to the map because of "Box" macro feature that
149     // creates other features in "initData"
150     initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
151     // event: feature is added, mist be before "initData" to update OB correctly on Duplicate:
152     // first new part, then the content
153     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
154     ModelAPI_EventCreator::get()->sendUpdated(theFeature, anEvent);
155   } else { // make feature has not-null data anyway
156     theFeature->setData(Model_Data::invalidData());
157     theFeature->setDoc(myDoc);
158   }
159 }
160
161 /// Appends to the array of references a new referenced label.
162 /// If theIndex is not -1, removes element at this index, not theReferenced.
163 /// \returns the index of removed element
164 static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced,
165   const int theIndex = -1)
166 {
167   int aResult = -1;  // no returned
168   Handle(TDataStd_ReferenceArray) aRefs;
169   if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
170     if (aRefs->Length() == 1) {  // just erase an array
171       if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
172         theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
173       }
174       aResult = 0;
175     } else {  // reduce the array
176       Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
177                                                                           aRefs->Upper() - 1);
178       int aCount = aRefs->Lower();
179       for (int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
180         if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
181           aCount--;
182           aResult = a;
183         } else {
184           aNewArray->SetValue(aCount, aRefs->Value(a));
185         }
186       }
187       aRefs->SetInternalArray(aNewArray);
188     }
189   }
190   return aResult;
191 }
192
193 void Model_Objects::refsToFeature(FeaturePtr theFeature,
194   std::set<std::shared_ptr<ModelAPI_Feature> >& theRefs, const bool isSendError)
195 {
196   // check the feature: it must have no depended objects on it
197   // the dependencies can be in the feature results
198   std::list<ResultPtr> aResults;
199   ModelAPI_Tools::allResults(theFeature, aResults);
200   std::list<ResultPtr>::const_iterator aResIter = aResults.cbegin();
201   for (; aResIter != aResults.cend(); aResIter++) {
202     ResultPtr aResult = (*aResIter);
203     std::shared_ptr<Model_Data> aData =
204         std::dynamic_pointer_cast<Model_Data>(aResult->data());
205     if (aData.get() != NULL) {
206       const std::set<AttributePtr>& aRefs = aData->refsToMe();
207       std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
208       for (; aRefIt != aRefLast; aRefIt++) {
209         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
210         if (aFeature.get() != NULL)
211           theRefs.insert(aFeature);
212       }
213     }
214   }
215   // the dependencies can be in the feature itself
216   std::shared_ptr<Model_Data> aData =
217       std::dynamic_pointer_cast<Model_Data>(theFeature->data());
218   if (aData.get() && !aData->refsToMe().empty()) {
219     const std::set<AttributePtr>& aRefs = aData->refsToMe();
220     std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
221     for (; aRefIt != aRefLast; aRefIt++) {
222       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
223       if (aFeature.get() != NULL)
224         theRefs.insert(aFeature);
225     }
226   }
227
228   if (!theRefs.empty() && isSendError) {
229     Events_InfoMessage("Model_Objects",
230       "Feature '%1' is used and can not be deleted").arg(theFeature->data()->name()).send();
231   }
232 }
233
234 void Model_Objects::removeFeature(FeaturePtr theFeature)
235 {
236   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFeature->data());
237   if (aData.get() && aData->isValid()) {
238     // checking that the sub-element of composite feature is removed: if yes, inform the owner
239     std::set<std::shared_ptr<ModelAPI_Feature> > aRefs;
240     refsToFeature(theFeature, aRefs, false);
241     std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aRefIter = aRefs.begin();
242     for(; aRefIter != aRefs.end(); aRefIter++) {
243       std::shared_ptr<ModelAPI_CompositeFeature> aComposite =
244         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
245       if (aComposite.get() && aComposite->isSub(theFeature)) {
246         aComposite->removeFeature(theFeature);
247       }
248     }
249     // this must be before erase since theFeature erasing removes all information about
250     // the feature results and groups of results
251     // To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated
252     clearHistory(theFeature);
253     // erase fields
254     theFeature->erase();
255
256     TDF_Label aFeatureLabel = aData->label().Father();
257     if (myFeatures.IsBound(aFeatureLabel))
258       myFeatures.UnBind(aFeatureLabel);
259
260     static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
261     ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
262     // erase all attributes under the label of feature
263     aFeatureLabel.ForgetAllAttributes();
264     // remove it from the references array
265     RemoveFromRefArray(featuresLabel(), aFeatureLabel);
266     // event: feature is deleted
267     ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
268     updateHistory(ModelAPI_Feature::group());
269   }
270 }
271
272 void Model_Objects::eraseAllFeatures()
273 {
274   static Events_ID kDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
275   static const ModelAPI_EventCreator* kCreator = ModelAPI_EventCreator::get();
276   // make all features invalid (like deleted)
277   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
278   for(; aFIter.More(); aFIter.Next()) {
279     FeaturePtr aFeature = aFIter.Value();
280     std::list<ResultPtr> aResList;
281     ModelAPI_Tools::allResults(aFeature, aResList);
282     std::list<ResultPtr>::iterator aRIter = aResList.begin();
283     for(; aRIter != aResList.end(); aRIter++) {
284       ResultPtr aRes = *aRIter;
285       if (aRes && aRes->data()->isValid()) {
286         kCreator->sendDeleted(myDoc, aRes->groupName());
287         kCreator->sendUpdated(aRes, kDispEvent);
288         aRes->setData(aRes->data()->invalidPtr());
289
290       }
291     }
292     kCreator->sendUpdated(aFeature, kDispEvent);
293     aFeature->setData(aFeature->data()->invalidPtr());
294   }
295   kCreator->sendDeleted(myDoc, ModelAPI_Feature::group());
296   myFeatures.Clear(); // just remove features without modification of DS
297   updateHistory(ModelAPI_Feature::group());
298 }
299
300 void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
301 {
302   TDF_Label aFeaturesLab = featuresLabel();
303   Handle(TDataStd_ReferenceArray) aRefs;
304   if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
305     return;
306   TDF_Label anAfterLab, aMovedLab =
307     std::dynamic_pointer_cast<Model_Data>(theMoved->data())->label().Father();
308   if (theAfterThis.get())
309     anAfterLab = std::dynamic_pointer_cast<Model_Data>(theAfterThis->data())->label().Father();
310
311   Handle(TDataStd_HLabelArray1) aNewArray =
312     new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper());
313   int aPassedMovedFrom = 0; // the prev feature location is found and passed
314   int aPassedMovedTo = 0; // the feature is added and this location is passed
315   if (!theAfterThis.get()) { // null means that inserted feature must be the first
316     aNewArray->SetValue(aRefs->Lower(), aMovedLab);
317     aPassedMovedTo = 1;
318   }
319   for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
320     if (aPassedMovedTo == 0 && aRefs->Value(a) == anAfterLab) { // add two
321       aPassedMovedTo++;
322       aNewArray->SetValue(a - aPassedMovedFrom, anAfterLab);
323       if (a + 1 - aPassedMovedFrom <= aRefs->Upper())
324         aNewArray->SetValue(a + 1 - aPassedMovedFrom, aMovedLab);
325     } else if (aPassedMovedFrom == 0 && aRefs->Value(a) == aMovedLab) { // skip
326       aPassedMovedFrom++;
327     } else { // just copy one
328       if (a - aPassedMovedFrom + aPassedMovedTo <= aRefs->Upper())
329         aNewArray->SetValue(a - aPassedMovedFrom + aPassedMovedTo, aRefs->Value(a));
330     }
331   }
332   if (!aPassedMovedFrom || !aPassedMovedTo) {// not found: unknown situation
333     if (!aPassedMovedFrom) {
334       static std::string aMovedFromError("The moved feature is not found");
335       Events_InfoMessage("Model_Objects", aMovedFromError).send();
336     } else {
337       static std::string aMovedToError("The 'after' feature for movement is not found");
338       Events_InfoMessage("Model_Objects", aMovedToError).send();
339     }
340     return;
341   }
342   // store the new array
343   aRefs->SetInternalArray(aNewArray);
344   // update the feature and the history
345   clearHistory(theMoved);
346   // make sure all (selection) attributes of moved feature will be updated
347   static Events_ID kUpdateSelection = Events_Loop::loop()->eventByName(EVENT_UPDATE_SELECTION);
348   ModelAPI_EventCreator::get()->sendUpdated(theMoved, kUpdateSelection, false);
349   ModelAPI_EventCreator::get()->sendReordered(theMoved);
350 }
351
352 void Model_Objects::clearHistory(ObjectPtr theObj)
353 {
354   if (theObj.get()) {
355     const std::string aGroup = theObj->groupName();
356     std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(aGroup);
357     if (aHIter != myHistory.end())
358       myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
359     if (theObj->groupName() == ModelAPI_Feature::group()) { // clear results group of the feature
360       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
361       std::string aResultGroup = featureResultGroup(aFeature);
362       if (!aResultGroup.empty()) {
363         std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter =
364           myHistory.find(aResultGroup);
365         if (aHIter != myHistory.end())
366           myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
367       }
368     }
369   }
370 }
371
372 void Model_Objects::createHistory(const std::string& theGroupID)
373 {
374   std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroupID);
375   if (aHIter == myHistory.end()) {
376     std::vector<ObjectPtr> aResult = std::vector<ObjectPtr>();
377     // iterate the array of references and get feature by feature from the array
378     bool isFeature = theGroupID == ModelAPI_Feature::group();
379     Handle(TDataStd_ReferenceArray) aRefs;
380     if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
381       for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
382         FeaturePtr aFeature = feature(aRefs->Value(a));
383         if (aFeature.get()) {
384           // if feature is in sub-component, remove it from history:
385           // it is in sub-tree of sub-component
386           bool isSub = ModelAPI_Tools::compositeOwner(aFeature).get() != NULL;
387           if (isFeature) { // here may be also disabled features
388             if (!isSub && aFeature->isInHistory()) {
389               aResult.push_back(aFeature);
390             }
391           } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
392             // construction results of sub-features should not be in the tree
393             if (!isSub || theGroupID != ModelAPI_ResultConstruction::group()) {
394               // do not use reference to the list here since results can be changed by "isConcealed"
395               const std::list<std::shared_ptr<ModelAPI_Result> > aResults = aFeature->results();
396               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator
397                 aRIter = aResults.begin();
398               for (; aRIter != aResults.cend(); aRIter++) {
399                 ResultPtr aRes = *aRIter;
400                 if (aRes->groupName() != theGroupID) break; // feature have only same group results
401                 if (!aRes->isDisabled() && aRes->isInHistory() && !aRes->isConcealed()) {
402                   aResult.push_back(*aRIter);
403                 }
404               }
405             }
406           }
407         }
408       }
409     }
410     // to be sure that isConcealed did not update the history (issue 1089) during the iteration
411     if (myHistory.find(theGroupID) == myHistory.end())
412       myHistory[theGroupID] = aResult;
413   }
414 }
415
416 void Model_Objects::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
417 {
418   clearHistory(theObject);
419 }
420
421 void Model_Objects::updateHistory(const std::string theGroup)
422 {
423   std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroup);
424   if (aHIter != myHistory.end())
425     myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
426 }
427
428 FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
429 {
430   if (myFeatures.IsBound(theLabel))
431     return myFeatures.Find(theLabel);
432   return FeaturePtr();  // not found
433 }
434
435 ObjectPtr Model_Objects::object(TDF_Label theLabel)
436 {
437   // try feature by label
438   FeaturePtr aFeature = feature(theLabel);
439   if (aFeature.get())
440     return feature(theLabel);
441   TDF_Label aFeatureLabel = theLabel.Father().Father();  // let's suppose it is result
442   aFeature = feature(aFeatureLabel);
443   bool isSubResult = false;
444   if (!aFeature.get() && aFeatureLabel.Depth() > 1) { // let's suppose this is sub-result of result
445     aFeatureLabel = aFeatureLabel.Father().Father();
446     aFeature = feature(aFeatureLabel);
447     isSubResult = true;
448   }
449   if (aFeature.get()) {
450     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
451     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
452     for (; aRIter != aResults.cend(); aRIter++) {
453       if (isSubResult) {
454         ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
455         if (aCompRes.get()) {
456           int aNumSubs = aCompRes->numberOfSubs();
457           for(int a = 0; a < aNumSubs; a++) {
458             ResultPtr aSub = aCompRes->subResult(a);
459             if (aSub.get()) {
460               std::shared_ptr<Model_Data> aSubData = std::dynamic_pointer_cast<Model_Data>(
461                   aSub->data());
462               if (aSubData->label().Father().IsEqual(theLabel))
463                 return aSub;
464             }
465           }
466         }
467       } else {
468         std::shared_ptr<Model_Data> aResData = std::dynamic_pointer_cast<Model_Data>(
469             (*aRIter)->data());
470         if (aResData->label().Father().IsEqual(theLabel))
471           return *aRIter;
472       }
473     }
474   }
475   return FeaturePtr();  // not found
476 }
477
478 ObjectPtr Model_Objects::object(const std::string& theGroupID, const int theIndex)
479 {
480   if (theIndex == -1)
481     return ObjectPtr();
482   createHistory(theGroupID);
483   return myHistory[theGroupID][theIndex];
484 }
485
486 std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
487     const std::string& theGroupID, const std::string& theName)
488 {
489   createHistory(theGroupID);
490   if (theGroupID == ModelAPI_Feature::group()) { // searching among features (in history or not)
491     std::list<std::shared_ptr<ModelAPI_Feature> > allObjs = allFeatures();
492     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator anObjIter = allObjs.begin();
493     for(; anObjIter != allObjs.end(); anObjIter++) {
494       if ((*anObjIter)->data()->name() == theName)
495         return *anObjIter;
496     }
497   } else { // searching among results (concealed or not)
498     std::list<std::shared_ptr<ModelAPI_Feature> > allObjs = allFeatures();
499     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator anObjIter = allObjs.begin();
500     for(; anObjIter != allObjs.end(); anObjIter++) {
501       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = (*anObjIter)->results();
502       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
503       for (; aRIter != aResults.cend(); aRIter++) {
504         if (aRIter->get() && (*aRIter)->groupName() == theGroupID) {
505           if ((*aRIter)->data()->name() == theName)
506             return *aRIter;
507           ResultCompSolidPtr aCompRes =
508             std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
509           if (aCompRes.get()) {
510             int aNumSubs = aCompRes->numberOfSubs();
511             for(int a = 0; a < aNumSubs; a++) {
512               ResultPtr aSub = aCompRes->subResult(a);
513               if (aSub.get() && aSub->groupName() == theGroupID) {
514                 if (aSub->data()->name() == theName)
515                   return aSub;
516               }
517             }
518           }
519         }
520       }
521     }
522   }
523   // not found
524   return ObjectPtr();
525 }
526
527 const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
528 {
529   std::string aGroup = theObject->groupName();
530   createHistory(aGroup);
531   std::vector<ObjectPtr>& allObjs = myHistory[aGroup];
532   std::vector<ObjectPtr>::iterator anObjIter = allObjs.begin(); // iterate to search object
533   for(int anIndex = 0; anObjIter != allObjs.end(); anObjIter++, anIndex++) {
534     if ((*anObjIter) == theObject)
535       return anIndex;
536   }
537   // not found
538   return -1;
539 }
540
541 int Model_Objects::size(const std::string& theGroupID)
542 {
543   createHistory(theGroupID);
544   return int(myHistory[theGroupID].size());
545 }
546
547 void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
548 {
549   // iterate the array of references and get feature by feature from the array
550   Handle(TDataStd_ReferenceArray) aRefs;
551   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
552     for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
553       FeaturePtr aFeature = feature(aRefs->Value(a));
554       if (aFeature.get()) {
555         const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
556         std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
557         for (; aRIter != aResults.cend(); aRIter++) {
558           ResultPtr aRes = *aRIter;
559           if (aRes->groupName() != theGroupID) break; // feature have only same group results
560           // iterate also concealed: ALL RESULTS (for translation parts undo/redo management)
561           //if (aRes->isInHistory() && !aRes->isConcealed()) {
562             theResults.push_back(*aRIter);
563           //}
564         }
565       }
566     }
567   }
568 }
569
570
571 TDF_Label Model_Objects::featuresLabel() const
572 {
573   return myMain.FindChild(TAG_OBJECTS);
574 }
575
576 void Model_Objects::setUniqueName(FeaturePtr theFeature)
577 {
578   if (!theFeature->data()->name().empty())
579     return;  // not needed, name is already defined
580   std::string aName;  // result
581   // first count all features of such kind to start with index = count + 1
582   int aNumObjects = -1; // this feature is already in this map
583   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
584   for (; aFIter.More(); aFIter.Next()) {
585     if (aFIter.Value()->getKind() == theFeature->getKind())
586       aNumObjects++;
587   }
588   // generate candidate name
589   std::stringstream aNameStream;
590   aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
591   aName = aNameStream.str();
592   // check this is unique, if not, increase index by 1
593   for (aFIter.Initialize(myFeatures); aFIter.More();) {
594     FeaturePtr aFeature = aFIter.Value();
595     bool isSameName = aFeature->data()->name() == aName;
596     if (!isSameName) {  // check also results to avoid same results names (actual for Parts)
597       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
598       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
599       for (; aRIter != aResults.cend(); aRIter++) {
600         isSameName = (*aRIter)->data()->name() == aName;
601       }
602     }
603
604     if (isSameName) {
605       aNumObjects++;
606       std::stringstream aNameStream;
607       aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
608       aName = aNameStream.str();
609       // reinitialize iterator to make sure a new name is unique
610       aFIter.Initialize(myFeatures);
611     } else
612       aFIter.Next();
613   }
614   theFeature->data()->setName(aName);
615 }
616
617 void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag)
618 {
619   std::shared_ptr<Model_Data> aData(new Model_Data);
620   aData->setLabel(theLab.FindChild(theTag));
621   aData->setObject(theObj);
622   theObj->setDoc(myDoc);
623   theObj->setData(aData);
624   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
625   if (aFeature.get()) {
626     setUniqueName(aFeature);  // must be before "initAttributes" because duplicate part uses name
627   }
628   theObj->initAttributes();
629 }
630
631 std::shared_ptr<ModelAPI_Feature> Model_Objects::featureById(const int theId)
632 {
633   if (theId > 0) {
634     TDF_Label aLab = featuresLabel().FindChild(theId, Standard_False);
635     return feature(aLab);
636   }
637   return std::shared_ptr<ModelAPI_Feature>(); // not found
638 }
639
640 void Model_Objects::synchronizeFeatures(
641   const TDF_LabelList& theUpdated, const bool theUpdateReferences,
642   const bool theExecuteFeatures, const bool theOpen, const bool theFlush)
643 {
644   Model_Document* anOwner = std::dynamic_pointer_cast<Model_Document>(myDoc).get();
645   if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize
646     return;
647   // after all updates, sends a message that groups of features were created or updated
648   Events_Loop* aLoop = Events_Loop::loop();
649   static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
650   static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
651   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
652   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
653   static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
654   static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
655   bool isActive = aLoop->activateFlushes(false);
656
657   // collect all updated labels map
658   TDF_LabelMap anUpdatedMap;
659   TDF_ListIteratorOfLabelList anUpdatedIter(theUpdated);
660   for(; anUpdatedIter.More(); anUpdatedIter.Next()) {
661     TDF_Label& aFeatureLab = anUpdatedIter.Value();
662     while(aFeatureLab.Depth() > 3)
663       aFeatureLab = aFeatureLab.Father();
664     if (myFeatures.IsBound(aFeatureLab))
665       anUpdatedMap.Add(aFeatureLab);
666   }
667
668   // update all objects by checking are they on labels or not
669   std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
670   TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
671   for (; aLabIter.More(); aLabIter.Next()) {
672     TDF_Label aFeatureLabel = aLabIter.Value()->Label();
673     FeaturePtr aFeature;
674     if (!myFeatures.IsBound(aFeatureLabel)) {  // a new feature is inserted
675       // create a feature
676       aFeature = std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get())->createFeature(
677         TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
678         .ToCString(), anOwner);
679       if (!aFeature.get()) {
680         // somethig is wrong, most probably, the opened document has invalid structure
681         Events_InfoMessage("Model_Objects", "Invalid type of object in the document").send();
682         aLabIter.Value()->Label().ForgetAllAttributes();
683         continue;
684       }
685       aFeature->init();
686       // this must be before "setData" to redo the sketch line correctly
687       myFeatures.Bind(aFeatureLabel, aFeature);
688       aNewFeatures.insert(aFeature);
689       initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
690       updateHistory(aFeature);
691
692       // event: model is updated
693       ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
694     } else {  // nothing is changed, both iterators are incremented
695       aFeature = myFeatures.Find(aFeatureLabel);
696       aKeptFeatures.insert(aFeature);
697       if (anUpdatedMap.Contains(aFeatureLabel)) {
698         if (!theOpen) { // on abort/undo/redo reinitialize attributes if something is changed
699           std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs =
700             aFeature->data()->attributes("");
701           std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
702           for(; anAttr != anAttrs.end(); anAttr++)
703             (*anAttr)->reinit();
704         }
705         ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
706         if (aFeature->getKind() == "Parameter") {
707           // if parameters are changed, update the results (issue 937)
708           const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
709           std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
710           for (; aRIter != aResults.cend(); aRIter++) {
711             std::shared_ptr<ModelAPI_Result> aRes = *aRIter;
712             if (aRes->data()->isValid() && !aRes->isDisabled()) {
713               ModelAPI_EventCreator::get()->sendUpdated(aRes, anUpdateEvent);
714             }
715           }
716         }
717       }
718     }
719   }
720
721   // check all features are checked: if not => it was removed
722   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
723   while (aFIter.More()) {
724     if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end()
725       && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) {
726         FeaturePtr aFeature = aFIter.Value();
727         // event: model is updated
728         //if (aFeature->isInHistory()) {
729         ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group());
730         //}
731         // results of this feature must be redisplayed (hided)
732         // redisplay also removed feature (used for sketch and AISObject)
733         ModelAPI_EventCreator::get()->sendUpdated(aFeature, aRedispEvent);
734         updateHistory(aFeature);
735         aFeature->erase();
736
737         // unbind after the "erase" call: on abort sketch
738         // is removes sub-objects that corrupts aFIter
739         myFeatures.UnBind(aFIter.Key());
740         // reinitialize iterator because unbind may corrupt the previous order in the map
741         aFIter.Initialize(myFeatures);
742     } else
743       aFIter.Next();
744   }
745
746   if (theUpdateReferences) {
747     synchronizeBackRefs();
748   }
749   // update results of the features (after features created because
750   // they may be connected, like sketch and sub elements)
751   // After synchronisation of back references because sketch
752   // must be set in sub-elements before "execute" by updateResults
753   std::set<FeaturePtr> aProcessed; // composites must be updated after their subs (issue 360)
754   TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
755   for (; aLabIter2.More(); aLabIter2.Next()) {
756     TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
757     if (myFeatures.IsBound(aFeatureLabel)) {  // a new feature is inserted
758       FeaturePtr aFeature = myFeatures.Find(aFeatureLabel);
759       updateResults(aFeature, aProcessed);
760     }
761   }
762   // the synchronize should be done after updateResults
763   // in order to correct back references of updated results
764   if (theUpdateReferences) {
765     synchronizeBackRefs();
766   }
767   if (!theUpdated.IsEmpty()) {
768     // this means there is no control what was modified => remove history cash
769     myHistory.clear();
770   }
771
772   if (theExecuteFeatures)
773     anOwner->executeFeatures() = false;
774   aLoop->activateFlushes(isActive);
775
776   if (theFlush) {
777     aLoop->flush(aDeleteEvent);
778     // delete should be emitted before create to reacts to aborted feature
779     aLoop->flush(aCreateEvent);
780     aLoop->flush(anUpdateEvent);
781     aLoop->flush(aCreateEvent); // after update of features, there could be results created
782     aLoop->flush(aDeleteEvent); // or deleted
783     aLoop->flush(aRedispEvent);
784     aLoop->flush(aToHideEvent);
785   }
786   if (theExecuteFeatures)
787     anOwner->executeFeatures() = true;
788 }
789
790 /// synchronises back references for the given object basing on the collected data
791 void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& theNewRefs,
792   ObjectPtr theObject)
793 {
794   if (!theObject.get() || !theObject->data()->isValid())
795     return; // invalid
796   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
797   // iterate new list to compare with curent
798   std::set<AttributePtr>::iterator aNewIter = theNewRefs.begin();
799   for(; aNewIter != theNewRefs.end(); aNewIter++) {
800     if (aData->refsToMe().find(*aNewIter) == aData->refsToMe().end()) {
801       FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aNewIter)->owner());
802       aData->addBackReference(aRefFeat, (*aNewIter)->id());
803     }
804   }
805   if (theNewRefs.size() != aData->refsToMe().size()) { // some back ref must be removed
806     std::set<AttributePtr>::iterator aCurrentIter = aData->refsToMe().begin();
807     while(aCurrentIter != aData->refsToMe().end()) {
808       if (theNewRefs.find(*aCurrentIter) == theNewRefs.end()) {
809         // for external references from other documents this system
810         // is not working: refs are collected from
811         // different Model_Objects, so before remove check this
812         // external object exists and still referenced
813         bool aLeaveIt = false;
814         if ((*aCurrentIter)->owner().get() && (*aCurrentIter)->owner()->document() != myDoc &&
815             (*aCurrentIter)->owner()->data().get() && (*aCurrentIter)->owner()->data()->isValid()) {
816           std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aRefs;
817           (*aCurrentIter)->owner()->data()->referencesToObjects(aRefs);
818           std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> >>>::iterator
819             aRefIter = aRefs.begin();
820           for(; aRefIter != aRefs.end(); aRefIter++) {
821             if ((*aCurrentIter)->id() == aRefIter->first) {
822               std::list<std::shared_ptr<ModelAPI_Object> >::iterator anOIt;
823               for(anOIt = aRefIter->second.begin(); anOIt != aRefIter->second.end(); anOIt++) {
824                 if (*anOIt == theObject) {
825                   aLeaveIt = true;
826                 }
827               }
828             }
829           }
830         }
831         if (!aLeaveIt) {
832           aData->removeBackReference(*aCurrentIter);
833           aCurrentIter = aData->refsToMe().begin(); // reinitialize iteration after delete
834         } else aCurrentIter++;
835       } else aCurrentIter++;
836     }
837   }
838   aData->updateConcealmentFlag();
839 }
840
841 void Model_Objects::synchronizeBackRefs()
842 {
843   // collect all back references in the separated container: to update everything at once,
844   // without additional Concealment switchin on and off: only the final modification
845
846   // referenced (slave) objects to referencing attirbutes
847   std::map<ObjectPtr, std::set<AttributePtr> > allRefs;
848   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
849   for(; aFeatures.More(); aFeatures.Next()) {
850     FeaturePtr aFeature = aFeatures.Value();
851     std::shared_ptr<Model_Data> aFData = std::dynamic_pointer_cast<Model_Data>(aFeature->data());
852     if (aFData.get()) {
853       std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
854       aFData->referencesToObjects(aRefs);
855       std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefsIt = aRefs.begin();
856       for(; aRefsIt != aRefs.end(); aRefsIt++) {
857         std::list<ObjectPtr>::iterator aRefTo = aRefsIt->second.begin();
858         for(; aRefTo != aRefsIt->second.end(); aRefTo++) {
859           if (*aRefTo) {
860             std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(*aRefTo);
861             if (aFound == allRefs.end()) {
862               allRefs[*aRefTo] = std::set<AttributePtr>();
863               aFound = allRefs.find(*aRefTo);
864             }
865             aFound->second.insert(aFeature->data()->attribute(aRefsIt->first));
866           }
867         }
868       }
869     }
870   }
871   // second iteration: just compare back-references with existing in features and results
872   for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
873     FeaturePtr aFeature = aFeatures.Value();
874     static std::set<AttributePtr> anEmpty;
875     std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(aFeature);
876     if (aFound == allRefs.end()) { // not found => erase all back references
877       synchronizeBackRefsForObject(anEmpty, aFeature);
878     } else {
879       synchronizeBackRefsForObject(aFound->second, aFeature);
880       allRefs.erase(aFound); // to check that all refs are counted
881     }
882     // also for results
883     std::list<ResultPtr> aResults;
884     ModelAPI_Tools::allResults(aFeature, aResults);
885     std::list<ResultPtr>::iterator aRIter = aResults.begin();
886     for(; aRIter != aResults.cend(); aRIter++) {
887       aFound = allRefs.find(*aRIter);
888       if (aFound == allRefs.end()) { // not found => erase all back references
889         synchronizeBackRefsForObject(anEmpty, *aRIter);
890       } else {
891         synchronizeBackRefsForObject(aFound->second, *aRIter);
892         allRefs.erase(aFound); // to check that all refs are counted
893       }
894     }
895   }
896   for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
897     FeaturePtr aFeature = aFeatures.Value();
898     std::list<ResultPtr> aResults;
899     ModelAPI_Tools::allResults(aFeature, aResults);
900     // update the concealment status for disply in isConcealed of ResultBody
901     std::list<ResultPtr>::iterator aRIter = aResults.begin();
902     for(; aRIter != aResults.cend(); aRIter++) {
903       (*aRIter)->isConcealed();
904     }
905   }
906   // the rest all refs means that feature references to the external document feature:
907   // process also them
908   std::map<ObjectPtr, std::set<AttributePtr> >::iterator anExtIter = allRefs.begin();
909   for(; anExtIter != allRefs.end(); anExtIter++) {
910     synchronizeBackRefsForObject(anExtIter->second, anExtIter->first);
911   }
912 }
913
914 TDF_Label Model_Objects::resultLabel(
915   const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theResultIndex)
916 {
917   const std::shared_ptr<Model_Data>& aData =
918     std::dynamic_pointer_cast<Model_Data>(theFeatureData);
919   return aData->label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1);
920 }
921
922 void Model_Objects::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
923                                  std::shared_ptr<ModelAPI_Result> theResult,
924                                  const int theResultIndex)
925 {
926   theResult->init();
927   theResult->setDoc(myDoc);
928   initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS);
929   if (theResult->data()->name().empty()) {
930     // if was not initialized, generate event and set a name
931     std::stringstream aNewName;
932     aNewName<<theFeatureData->name();
933     // if there are several results (issue #899: any number of result),
934     // add unique prefix starting from second
935     if (theResultIndex > 0 || theResult->groupName() == ModelAPI_ResultBody::group())
936       aNewName<<"_"<<theResultIndex + 1;
937     theResult->data()->setName(aNewName.str());
938   }
939 }
940
941 std::shared_ptr<ModelAPI_ResultConstruction> Model_Objects::createConstruction(
942     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
943 {
944   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
945   TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::group().c_str());
946   ObjectPtr anOldObject = object(aLab);
947   std::shared_ptr<ModelAPI_ResultConstruction> aResult;
948   if (anOldObject.get()) {
949     aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
950   }
951   if (!aResult.get()) {
952     aResult = std::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
953     storeResult(theFeatureData, aResult, theIndex);
954   }
955   return aResult;
956 }
957
958 std::shared_ptr<ModelAPI_ResultBody> Model_Objects::createBody(
959     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
960 {
961   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
962   // for feature create compsolid, but for result sub create body:
963   // only one level of recursion is supported now
964   ResultPtr aResultOwner = std::dynamic_pointer_cast<ModelAPI_Result>(theFeatureData->owner());
965   ObjectPtr anOldObject;
966   if (aResultOwner.get()) {
967     TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
968   } else { // in compsolid (higher level result) old object probably may be found
969     TDataStd_Comment::Set(aLab, ModelAPI_ResultCompSolid::group().c_str());
970     anOldObject = object(aLab);
971   }
972   std::shared_ptr<ModelAPI_ResultBody> aResult;
973   if (anOldObject.get()) {
974     aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
975   }
976   if (!aResult.get()) {
977     // create compsolid anyway; if it is compsolid, it will create sub-bodies internally
978     if (aResultOwner.get()) {
979       aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
980     } else {
981       aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultCompSolid);
982     }
983     storeResult(theFeatureData, aResult, theIndex);
984   }
985   return aResult;
986 }
987
988 std::shared_ptr<ModelAPI_ResultPart> Model_Objects::createPart(
989     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
990 {
991   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
992   TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str());
993   ObjectPtr anOldObject = object(aLab);
994   std::shared_ptr<ModelAPI_ResultPart> aResult;
995   if (anOldObject.get()) {
996     aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
997   }
998   if (!aResult.get()) {
999     aResult = std::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
1000     storeResult(theFeatureData, aResult, theIndex);
1001   }
1002   return aResult;
1003 }
1004
1005 std::shared_ptr<ModelAPI_ResultPart> Model_Objects::copyPart(
1006     const std::shared_ptr<ModelAPI_ResultPart>& theOrigin,
1007     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1008 {
1009   std::shared_ptr<ModelAPI_ResultPart> aResult = createPart(theFeatureData, theIndex);
1010   aResult->data()->reference(Model_ResultPart::BASE_REF_ID())->setValue(theOrigin);
1011   return aResult;
1012 }
1013
1014 std::shared_ptr<ModelAPI_ResultGroup> Model_Objects::createGroup(
1015     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1016 {
1017   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1018   TDataStd_Comment::Set(aLab, ModelAPI_ResultGroup::group().c_str());
1019   ObjectPtr anOldObject = object(aLab);
1020   std::shared_ptr<ModelAPI_ResultGroup> aResult;
1021   if (anOldObject.get()) {
1022     aResult = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anOldObject);
1023   }
1024   if (!aResult.get()) {
1025     aResult = std::shared_ptr<ModelAPI_ResultGroup>(new Model_ResultGroup(theFeatureData));
1026     storeResult(theFeatureData, aResult, theIndex);
1027   }
1028   return aResult;
1029 }
1030
1031 std::shared_ptr<ModelAPI_ResultField> Model_Objects::createField(
1032     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1033 {
1034   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1035   TDataStd_Comment::Set(aLab, ModelAPI_ResultField::group().c_str());
1036   ObjectPtr anOldObject = object(aLab);
1037   std::shared_ptr<ModelAPI_ResultField> aResult;
1038   if (anOldObject.get()) {
1039     aResult = std::dynamic_pointer_cast<ModelAPI_ResultField>(anOldObject);
1040   }
1041   if (!aResult.get()) {
1042     aResult = std::shared_ptr<ModelAPI_ResultField>(new Model_ResultField(theFeatureData));
1043     storeResult(theFeatureData, aResult, theIndex);
1044   }
1045   return aResult;
1046 }
1047
1048 std::shared_ptr<ModelAPI_ResultParameter> Model_Objects::createParameter(
1049       const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1050 {
1051   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1052   TDataStd_Comment::Set(aLab, ModelAPI_ResultParameter::group().c_str());
1053   ObjectPtr anOldObject = object(aLab);
1054   std::shared_ptr<ModelAPI_ResultParameter> aResult;
1055   if (anOldObject.get()) {
1056     aResult = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(anOldObject);
1057   }
1058   if (!aResult.get()) {
1059     aResult = std::shared_ptr<ModelAPI_ResultParameter>(new Model_ResultParameter);
1060     storeResult(theFeatureData, aResult, theIndex);
1061   }
1062   return aResult;
1063 }
1064
1065 std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
1066     const std::shared_ptr<ModelAPI_Result>& theResult)
1067 {
1068   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theResult->data());
1069   if (aData.get()) {
1070     TDF_Label aFeatureLab = aData->label().Father().Father().Father();
1071     FeaturePtr aFeature = feature(aFeatureLab);
1072     if (!aFeature.get() && aFeatureLab.Depth() > 1) { // this may be sub-result of result
1073       aFeatureLab = aFeatureLab.Father().Father();
1074       aFeature = feature(aFeatureLab);
1075     }
1076     return aFeature;
1077   }
1078   return FeaturePtr();
1079 }
1080
1081 std::string Model_Objects::featureResultGroup(FeaturePtr theFeature)
1082 {
1083   if (theFeature->data()->isValid()) {
1084     TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
1085     if (aLabIter.More()) {
1086       TDF_Label anArgLab = aLabIter.Value();
1087       Handle(TDataStd_Comment) aGroup;
1088       if (aLabIter.Value().FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
1089         return TCollection_AsciiString(aGroup->Get()).ToCString();
1090       }
1091     }
1092   }
1093   static std::string anEmpty;
1094   return anEmpty; // not found
1095 }
1096
1097 void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& theProcessed)
1098 {
1099   if (theProcessed.find(theFeature) != theProcessed.end())
1100     return;
1101   theProcessed.insert(theFeature);
1102   // for composites update subs recursively (sketch elements results are needed for the sketch)
1103   CompositeFeaturePtr aComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
1104   if (aComp.get() && aComp->getKind() != "Part") { // don't go inside of parts sub-features
1105     // update subs of composites first
1106     int aSubNum = aComp->numberOfSubs();
1107     for(int a = 0; a < aSubNum; a++) {
1108       FeaturePtr aSub = aComp->subFeature(a);
1109       updateResults(aComp->subFeature(a), theProcessed);
1110     }
1111   }
1112
1113   // for not persistent is will be done by parametric updater automatically
1114   //if (!theFeature->isPersistentResult()) return;
1115   // check the existing results and remove them if there is nothing on the label
1116   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
1117   while(aResIter != theFeature->results().cend()) {
1118     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(*aResIter);
1119     if (aBody.get()) {
1120       std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(aBody->data());
1121       if (!aData.get() || !aData->isValid() || (!aBody->isDisabled() && aData->isDeleted())) {
1122         // found a disappeared result => remove it
1123         theFeature->eraseResultFromList(aBody);
1124         // start iterate from beginning because iterator is corrupted by removing
1125         aResIter = theFeature->results().cbegin();
1126         continue;
1127       }
1128     }
1129     aResIter++;
1130   }
1131   // it may be on undo
1132   if (!theFeature->data() || !theFeature->data()->isValid() || theFeature->isDisabled())
1133     return;
1134   // check that results are presented on all labels
1135   int aResSize = int(theFeature->results().size());
1136   TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
1137   for(; aLabIter.More(); aLabIter.Next()) {
1138     // here must be GUID of the feature
1139     int aResIndex = aLabIter.Value().Tag() - 1;
1140     ResultPtr aNewBody;
1141     if (aResSize <= aResIndex) {
1142       TDF_Label anArgLab = aLabIter.Value();
1143       Handle(TDataStd_Comment) aGroup;
1144       if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
1145         if (aGroup->Get() == ModelAPI_ResultBody::group().c_str() ||
1146             aGroup->Get() == ModelAPI_ResultCompSolid::group().c_str()) {
1147           aNewBody = createBody(theFeature->data(), aResIndex);
1148         } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
1149           std::shared_ptr<ModelAPI_ResultPart> aNewP = createPart(theFeature->data(), aResIndex);
1150           theFeature->setResult(aNewP, aResIndex);
1151           if (!aNewP->partDoc().get())
1152             // create the part result: it is better to restore the previous result if it is possible
1153             theFeature->execute();
1154         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
1155           theFeature->execute(); // construction shapes are needed for sketch solver
1156         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
1157           aNewBody = createGroup(theFeature->data(), aResIndex);
1158         } else if (aGroup->Get() == ModelAPI_ResultField::group().c_str()) {
1159           aNewBody = createField(theFeature->data(), aResIndex);
1160         } else if (aGroup->Get() == ModelAPI_ResultParameter::group().c_str()) {
1161           theFeature->attributeChanged("expression"); // just produce a value
1162         } else {
1163           Events_InfoMessage("Model_Objects", "Unknown type of result is found in the document:")
1164             .arg(TCollection_AsciiString(aGroup->Get()).ToCString()).send();
1165         }
1166       }
1167       if (aNewBody && !aNewBody->data()->isDeleted()) {
1168         theFeature->setResult(aNewBody, aResIndex);
1169       }
1170     }
1171   }
1172 }
1173
1174 ResultPtr Model_Objects::findByName(const std::string theName)
1175 {
1176   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator anObjIter(myFeatures);
1177   for(; anObjIter.More(); anObjIter.Next()) {
1178     FeaturePtr& aFeature = anObjIter.ChangeValue();
1179     if (!aFeature.get() || aFeature->isDisabled()) // may be on close
1180       continue;
1181     std::list<ResultPtr> allResults;
1182     ModelAPI_Tools::allResults(aFeature, allResults);
1183     std::list<ResultPtr>::iterator aRIter = allResults.begin();
1184     for (; aRIter != allResults.cend(); aRIter++) {
1185       ResultPtr aRes = *aRIter;
1186       if (aRes.get() && aRes->data() && aRes->data()->isValid() && !aRes->isDisabled() &&
1187           aRes->data()->name() == theName) {
1188         return aRes;
1189       }
1190     }
1191   }
1192   // not found
1193   return ResultPtr();
1194 }
1195
1196 FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theReverse)
1197 {
1198   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
1199   if (aData.get() && aData->isValid()) {
1200     TDF_Label aFeatureLabel = aData->label().Father();
1201     Handle(TDataStd_ReferenceArray) aRefs;
1202     if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1203       for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
1204         TDF_Label aCurLab = aRefs->Value(a);
1205         if (aCurLab.IsEqual(aFeatureLabel)) {
1206           a += theReverse ? -1 : 1;
1207           if (a >= aRefs->Lower() && a <= aRefs->Upper())
1208             return feature(aRefs->Value(a));
1209           break; // finish iiteration: it's last feature
1210         }
1211       }
1212     }
1213   }
1214   return FeaturePtr(); // not found, last, or something is wrong
1215 }
1216
1217 FeaturePtr Model_Objects::firstFeature()
1218 {
1219   Handle(TDataStd_ReferenceArray) aRefs;
1220   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1221     return feature(aRefs->Value(aRefs->Lower()));
1222   }
1223   return FeaturePtr(); // no features at all
1224 }
1225
1226 FeaturePtr Model_Objects::lastFeature()
1227 {
1228   Handle(TDataStd_ReferenceArray) aRefs;
1229   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1230     return feature(aRefs->Value(aRefs->Upper()));
1231   }
1232   return FeaturePtr(); // no features at all
1233 }
1234
1235 bool Model_Objects::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const
1236 {
1237   std::shared_ptr<Model_Data> aLaterD = std::static_pointer_cast<Model_Data>(theLater->data());
1238   std::shared_ptr<Model_Data> aCurrentD = std::static_pointer_cast<Model_Data>(theCurrent->data());
1239   if (aLaterD.get() && aLaterD->isValid() && aCurrentD.get() && aCurrentD->isValid()) {
1240     TDF_Label aLaterL = aLaterD->label().Father();
1241     TDF_Label aCurrentL = aCurrentD->label().Father();
1242     int aLaterI = -1, aCurentI = -1; // not found yet state
1243     Handle(TDataStd_ReferenceArray) aRefs;
1244     if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1245       for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
1246         TDF_Label aCurLab = aRefs->Value(a);
1247         if (aCurLab.IsEqual(aLaterL)) {
1248           aLaterI = a;
1249         } else if (aCurLab.IsEqual(aCurrentL)) {
1250           aCurentI = a;
1251         } else continue;
1252         if (aLaterI != -1 && aCurentI != -1) // both are found
1253           return aLaterI > aCurentI;
1254       }
1255     }
1256   }
1257   return false; // not found, or something is wrong
1258 }
1259
1260 std::list<std::shared_ptr<ModelAPI_Feature> > Model_Objects::allFeatures()
1261 {
1262   std::list<std::shared_ptr<ModelAPI_Feature> > aResult;
1263   Handle(TDataStd_ReferenceArray) aRefs;
1264   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1265     for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
1266       FeaturePtr aFeature = feature(aRefs->Value(a));
1267       if (aFeature.get())
1268         aResult.push_back(aFeature);
1269     }
1270   }
1271   return aResult;
1272 }
1273
1274 int Model_Objects::numInternalFeatures()
1275 {
1276   Handle(TDataStd_ReferenceArray) aRefs;
1277   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1278     return aRefs->Upper() - aRefs->Lower() + 1;
1279   }
1280   return 0; // invalid
1281 }
1282
1283 std::shared_ptr<ModelAPI_Feature> Model_Objects::internalFeature(const int theIndex)
1284 {
1285   Handle(TDataStd_ReferenceArray) aRefs;
1286   if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1287     return feature(aRefs->Value(aRefs->Lower() + theIndex));
1288   }
1289   return FeaturePtr(); // invalid
1290 }
1291
1292 Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper)
1293 {
1294   return TDF_LabelMapHasher::HashCode(theLab, theUpper);
1295
1296 }
1297 Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2)
1298 {
1299   return TDF_LabelMapHasher::IsEqual(theLab1, theLab2);
1300 }