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