Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom.git into Dev_1.1.0
[modules/shaper.git] / src / Model / Model_Document.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_Document.cxx
4 // Created:     28 Feb 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include <Model_Document.h>
8 #include <Model_Data.h>
9 #include <Model_Application.h>
10 #include <Model_Session.h>
11 #include <Model_Events.h>
12 #include <Model_ResultPart.h>
13 #include <Model_ResultConstruction.h>
14 #include <Model_ResultBody.h>
15 #include <Model_ResultGroup.h>
16 #include <ModelAPI_Validator.h>
17 #include <ModelAPI_CompositeFeature.h>
18
19 #include <Events_Loop.h>
20 #include <Events_Error.h>
21
22 #include <TDataStd_Integer.hxx>
23 #include <TDataStd_Comment.hxx>
24 #include <TDF_ChildIDIterator.hxx>
25 #include <TDataStd_ReferenceArray.hxx>
26 #include <TDataStd_HLabelArray1.hxx>
27 #include <TDataStd_Name.hxx>
28 #include <TDF_Reference.hxx>
29 #include <TDF_ChildIDIterator.hxx>
30 #include <TDF_LabelMapHasher.hxx>
31 #include <OSD_File.hxx>
32 #include <OSD_Path.hxx>
33
34 #include <climits>
35 #ifndef WIN32
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef WIN32
40 # define _separator_ '\\'
41 #else
42 # define _separator_ '/'
43 #endif
44
45 static const int UNDO_LIMIT = 1000;  // number of possible undo operations (big for sketcher)
46
47 static const int TAG_GENERAL = 1;  // general properties tag
48 static const int TAG_OBJECTS = 2;  // tag of the objects sub-tree (features, results)
49 static const int TAG_HISTORY = 3;  // tag of the history sub-tree (python dump)
50
51 // feature sub-labels
52 static const int TAG_FEATURE_ARGUMENTS = 1;  ///< where the arguments are located
53 static const int TAG_FEATURE_RESULTS = 2;  ///< where the results are located
54
55 ///
56 /// 0:1:2 - where features are located
57 /// 0:1:2:N:1 - data of the feature N
58 /// 0:1:2:N:2:K:1 - data of the K result of the feature N
59
60 Model_Document::Model_Document(const std::string theID, const std::string theKind)
61     : myID(theID), myKind(theKind),
62       myDoc(new TDocStd_Document("BinOcaf"))  // binary OCAF format
63 {
64   myDoc->SetUndoLimit(UNDO_LIMIT);  
65   myTransactionSave = 0;
66   myExecuteFeatures = true;
67   // to have something in the document and avoid empty doc open/save problem
68   // in transaction for nesting correct working
69   myDoc->NewCommand();
70   TDataStd_Integer::Set(myDoc->Main().Father(), 0);
71   myDoc->CommitCommand();
72 }
73
74 /// Returns the file name of this document by the nameof directory and identifuer of a document
75 static TCollection_ExtendedString DocFileName(const char* theFileName, const std::string& theID)
76 {
77   TCollection_ExtendedString aPath((const Standard_CString) theFileName);
78   // remove end-separators
79   while(aPath.Length() && 
80         (aPath.Value(aPath.Length()) == '\\' || aPath.Value(aPath.Length()) == '/'))
81     aPath.Remove(aPath.Length());
82   aPath += _separator_;
83   aPath += theID.c_str();
84   aPath += ".cbf";  // standard binary file extension
85   return aPath;
86 }
87
88 bool Model_Document::isRoot() const
89 {
90   return this == Model_Session::get()->moduleDocument().get();
91 }
92
93 bool Model_Document::load(const char* theFileName)
94 {
95   Handle(Model_Application) anApp = Model_Application::getApplication();
96   if (isRoot()) {
97     anApp->setLoadPath(theFileName);
98   }
99   TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
100   PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
101   try {
102     aStatus = anApp->Open(aPath, myDoc);
103   } catch (Standard_Failure) {
104     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
105     Events_Error::send(
106         std::string("Exception in opening of document: ") + aFail->GetMessageString());
107     return false;
108   }
109   bool isError = aStatus != PCDM_RS_OK;
110   if (isError) {
111     switch (aStatus) {
112       case PCDM_RS_UnknownDocument:
113         Events_Error::send(std::string("Can not open document"));
114         break;
115       case PCDM_RS_AlreadyRetrieved:
116         Events_Error::send(std::string("Can not open document: already opened"));
117         break;
118       case PCDM_RS_AlreadyRetrievedAndModified:
119         Events_Error::send(
120             std::string("Can not open document: already opened and modified"));
121         break;
122       case PCDM_RS_NoDriver:
123         Events_Error::send(std::string("Can not open document: driver library is not found"));
124         break;
125       case PCDM_RS_UnknownFileDriver:
126         Events_Error::send(std::string("Can not open document: unknown driver for opening"));
127         break;
128       case PCDM_RS_OpenError:
129         Events_Error::send(std::string("Can not open document: file open error"));
130         break;
131       case PCDM_RS_NoVersion:
132         Events_Error::send(std::string("Can not open document: invalid version"));
133         break;
134       case PCDM_RS_NoModel:
135         Events_Error::send(std::string("Can not open document: no data model"));
136         break;
137       case PCDM_RS_NoDocument:
138         Events_Error::send(std::string("Can not open document: no document inside"));
139         break;
140       case PCDM_RS_FormatFailure:
141         Events_Error::send(std::string("Can not open document: format failure"));
142         break;
143       case PCDM_RS_TypeNotFoundInSchema:
144         Events_Error::send(std::string("Can not open document: invalid object"));
145         break;
146       case PCDM_RS_UnrecognizedFileFormat:
147         Events_Error::send(std::string("Can not open document: unrecognized file format"));
148         break;
149       case PCDM_RS_MakeFailure:
150         Events_Error::send(std::string("Can not open document: make failure"));
151         break;
152       case PCDM_RS_PermissionDenied:
153         Events_Error::send(std::string("Can not open document: permission denied"));
154         break;
155       case PCDM_RS_DriverFailure:
156         Events_Error::send(std::string("Can not open document: driver failure"));
157         break;
158       default:
159         Events_Error::send(std::string("Can not open document: unknown error"));
160         break;
161     }
162   }
163   if (!isError) {
164     myDoc->SetUndoLimit(UNDO_LIMIT);
165     // to avoid the problem that feature is created in the current, not this, document
166     std::shared_ptr<Model_Session> aSession = 
167       std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
168     aSession->setActiveDocument(anApp->getDocument(myID), false);
169     aSession->setCheckTransactions(false);
170     synchronizeFeatures(false, true, true);
171     aSession->setCheckTransactions(true);
172     aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false);
173     aSession->setActiveDocument(anApp->getDocument(myID), true);
174   }
175   return !isError;
176 }
177
178 bool Model_Document::save(const char* theFileName, std::list<std::string>& theResults)
179 {
180   // create a directory in the root document if it is not yet exist
181   Handle(Model_Application) anApp = Model_Application::getApplication();
182   if (isRoot()) {
183 #ifdef WIN32
184     CreateDirectory(theFileName, NULL);
185 #else
186     mkdir(theFileName, 0x1ff);
187 #endif
188   }
189   // filename in the dir is id of document inside of the given directory
190   TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
191   PCDM_StoreStatus aStatus;
192   try {
193     aStatus = anApp->SaveAs(myDoc, aPath);
194   } catch (Standard_Failure) {
195     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
196     Events_Error::send(
197         std::string("Exception in saving of document: ") + aFail->GetMessageString());
198     return false;
199   }
200   bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
201   if (!isDone) {
202     switch (aStatus) {
203       case PCDM_SS_DriverFailure:
204         Events_Error::send(std::string("Can not save document: save driver-library failure"));
205         break;
206       case PCDM_SS_WriteFailure:
207         Events_Error::send(std::string("Can not save document: file writing failure"));
208         break;
209       case PCDM_SS_Failure:
210       default:
211         Events_Error::send(std::string("Can not save document"));
212         break;
213     }
214   }
215   myTransactionSave = myTransactions.size();
216   if (isDone) {  // save also sub-documents if any
217     theResults.push_back(TCollection_AsciiString(aPath).ToCString());
218     const std::set<std::string> aSubs = subDocuments(false);
219     std::set<std::string>::iterator aSubIter = aSubs.begin();
220     for (; aSubIter != aSubs.end() && isDone; aSubIter++) {
221       if (anApp->isLoadByDemand(*aSubIter)) { 
222         // copy not-activated document that is not in the memory
223         std::string aDocName = *aSubIter;
224         if (!aDocName.empty()) {
225           // just copy file
226           TCollection_AsciiString aSubPath(DocFileName(anApp->loadPath().c_str(), aDocName));
227           OSD_Path aPath(aSubPath);
228           OSD_File aFile(aPath);
229           if (aFile.Exists()) {
230             TCollection_AsciiString aDestinationDir(DocFileName(theFileName, aDocName));
231             OSD_Path aDestination(aDestinationDir);
232             aFile.Copy(aDestination);
233             theResults.push_back(aDestinationDir.ToCString());
234           } else {
235             Events_Error::send(
236               std::string("Can not open file ") + aSubPath.ToCString() + " for saving");
237           }
238         }
239       } else { // simply save opened document
240         isDone = subDoc(*aSubIter)->save(theFileName, theResults);
241       }
242     }
243   }
244   return isDone;
245 }
246
247 void Model_Document::close(const bool theForever)
248 {
249   std::shared_ptr<ModelAPI_Session> aPM = Model_Session::get();
250   if (!isRoot() && this == aPM->activeDocument().get()) {
251     aPM->setActiveDocument(aPM->moduleDocument());
252   } else if (isRoot()) {
253     // erase the active document if root is closed
254     aPM->setActiveDocument(DocumentPtr());
255   }
256   // close all subs
257   const std::set<std::string> aSubs = subDocuments(true);
258   std::set<std::string>::iterator aSubIter = aSubs.begin();
259   for (; aSubIter != aSubs.end(); aSubIter++)
260     subDoc(*aSubIter)->close(theForever);
261
262   // close for thid document needs no transaction in this document
263   std::static_pointer_cast<Model_Session>(Model_Session::get())->setCheckTransactions(false);
264
265   // delete all features of this document
266   std::shared_ptr<ModelAPI_Document> aThis = 
267     Model_Application::getApplication()->getDocument(myID);
268   Events_Loop* aLoop = Events_Loop::loop();
269   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeaturesIter(myObjs);
270   for(; aFeaturesIter.More(); aFeaturesIter.Next()) {
271     FeaturePtr aFeature = aFeaturesIter.Value();
272     static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
273     ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group());
274     ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
275     aFeature->eraseResults();
276     if (theForever) { // issue #294: do not delete content of the document until it can be redone
277       aFeature->erase();
278     } else {
279       aFeature->data()->execState(ModelAPI_StateMustBeUpdated);
280     }
281   }
282   if (theForever) {
283     myObjs.Clear();
284   }
285   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
286   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
287
288   // close all only if it is really asked, otherwise it can be undoed/redoed
289   if (theForever) {
290     if (myDoc->CanClose() == CDM_CCS_OK)
291       myDoc->Close();
292   }
293
294   std::static_pointer_cast<Model_Session>(Model_Session::get())->setCheckTransactions(true);
295 }
296
297 void Model_Document::startOperation()
298 {
299   if (myDoc->HasOpenCommand()) {  // start of nested command
300     if (myDoc->CommitCommand()) { // commit the current: it will contain all nested after compactification
301       myTransactions.rbegin()->myOCAFNum++; // if has open command, the list is not empty
302     }
303     myNestedNum.push_back(0); // start of nested operation with zero transactions inside yet
304     myDoc->OpenCommand();
305   } else {  // start the simple command
306     myDoc->NewCommand();
307   }
308   // starts a new operation
309   myTransactions.push_back(Transaction());
310   if (!myNestedNum.empty())
311     (*myNestedNum.rbegin())++;
312   myRedos.clear();
313   // new command for all subs
314   const std::set<std::string> aSubs = subDocuments(true);
315   std::set<std::string>::iterator aSubIter = aSubs.begin();
316   for (; aSubIter != aSubs.end(); aSubIter++)
317     subDoc(*aSubIter)->startOperation();
318 }
319
320 void Model_Document::compactNested()
321 {
322   if (!myNestedNum.empty()) {
323     int aNumToCompact = *(myNestedNum.rbegin());
324     int aSumOfTransaction = 0;
325     for(int a = 0; a < aNumToCompact; a++) {
326       aSumOfTransaction += myTransactions.rbegin()->myOCAFNum;
327       myTransactions.pop_back();
328     }
329     // the latest transaction is the start of lower-level operation which startes the nested
330     myTransactions.rbegin()->myOCAFNum += aSumOfTransaction;
331     myNestedNum.pop_back();
332   }
333 }
334
335 bool Model_Document::finishOperation()
336 {
337   bool isNestedClosed = !myDoc->HasOpenCommand() && !myNestedNum.empty();
338   static std::shared_ptr<Model_Session> aSession = 
339     std::static_pointer_cast<Model_Session>(Model_Session::get());
340   synchronizeBackRefs();
341   Events_Loop* aLoop = Events_Loop::loop();
342   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
343   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
344   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
345   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TOHIDE));
346   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
347   // this must be here just after everything is finished but before real transaction stop
348   // to avoid messages about modifications outside of the transaction
349   // and to rebuild everything after all updates and creates
350   if (isRoot()) { // once for root document
351     Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
352     static std::shared_ptr<Events_Message> aFinishMsg
353       (new Events_Message(Events_Loop::eventByName("FinishOperation")));
354     Events_Loop::loop()->send(aFinishMsg);
355     Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), false);
356   }
357   // to avoid "updated" message appearance by updater
358   //aLoop->clear(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
359
360   // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside
361   bool aResult = false;
362   const std::set<std::string> aSubs = subDocuments(true);
363   std::set<std::string>::iterator aSubIter = aSubs.begin();
364   for (; aSubIter != aSubs.end(); aSubIter++)
365     if (subDoc(*aSubIter)->finishOperation())
366       aResult = true;
367
368   // transaction may be empty if this document was created during this transaction (create part)
369   if (!myTransactions.empty() && myDoc->CommitCommand()) { // if commit is successfull, just increment counters
370     myTransactions.rbegin()->myOCAFNum++;
371     aResult = true;
372   }
373
374   if (isNestedClosed) {
375     compactNested();
376   }
377   if (!aResult && !myTransactions.empty() /* it can be for just created part document */)
378     aResult = myTransactions.rbegin()->myOCAFNum != 0;
379
380   if (!aResult && isRoot()) {
381     // nothing inside in all documents, so remove this transaction from the transactions list
382     undoInternal(true, false);
383     myDoc->ClearRedos();
384     myRedos.clear();
385   }
386   return aResult;
387 }
388
389 void Model_Document::abortOperation()
390 {
391   if (!myNestedNum.empty() && !myDoc->HasOpenCommand()) {  // abort all what was done in nested
392     compactNested();
393     undoInternal(false, false);
394     myDoc->ClearRedos();
395     myRedos.clear();
396   } else { // abort the current
397     int aNumTransactions = myTransactions.rbegin()->myOCAFNum;
398     myTransactions.pop_back();
399     if (!myNestedNum.empty())
400       (*myNestedNum.rbegin())--;
401     // roll back the needed number of transactions
402     myDoc->AbortCommand();
403     for(int a = 0; a < aNumTransactions; a++)
404       myDoc->Undo();
405     myDoc->ClearRedos();
406   }
407   // references may be changed because they are set in attributes on the fly
408   synchronizeFeatures(true, true, isRoot());
409   // abort for all subs
410   const std::set<std::string> aSubs = subDocuments(true);
411   std::set<std::string>::iterator aSubIter = aSubs.begin();
412   for (; aSubIter != aSubs.end(); aSubIter++)
413     subDoc(*aSubIter)->abortOperation();
414 }
415
416 bool Model_Document::isOperation() const
417 {
418   // operation is opened for all documents: no need to check subs
419   return myDoc->HasOpenCommand() == Standard_True ;
420 }
421
422 bool Model_Document::isModified()
423 {
424   // is modified if at least one operation was commited and not undoed
425   return myTransactions.size() != myTransactionSave || isOperation();
426 }
427
428 bool Model_Document::canUndo()
429 {
430   // issue 406 : if transaction is opened, but nothing to undo behind, can not undo
431   int aCurrentNum = isOperation() ? 1 : 0;
432   if (myDoc->GetAvailableUndos() > 0 && 
433       (myNestedNum.empty() || *myNestedNum.rbegin() - aCurrentNum > 0) && // there is something to undo in nested
434       myTransactions.size() - aCurrentNum > 0 /* for omitting the first useless transaction */)
435     return true;
436   // check other subs contains operation that can be undoed
437   const std::set<std::string> aSubs = subDocuments(true);
438   std::set<std::string>::iterator aSubIter = aSubs.begin();
439   for (; aSubIter != aSubs.end(); aSubIter++)
440     if (subDoc(*aSubIter)->canUndo())
441       return true;
442   return false;
443 }
444
445 void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchronize)
446 {
447   int aNumTransactions = myTransactions.rbegin()->myOCAFNum;
448   myRedos.push_back(*myTransactions.rbegin());
449   myTransactions.pop_back();
450   if (!myNestedNum.empty())
451     (*myNestedNum.rbegin())--;
452   // roll back the needed number of transactions
453   for(int a = 0; a < aNumTransactions; a++)
454     myDoc->Undo();
455
456   if (theWithSubs) {
457     // undo for all subs
458     const std::set<std::string> aSubs = subDocuments(true);
459     std::set<std::string>::iterator aSubIter = aSubs.begin();
460     for (; aSubIter != aSubs.end(); aSubIter++)
461       subDoc(*aSubIter)->undoInternal(theWithSubs, theSynchronize);
462   }
463   // after redo of all sub-documents to avoid updates on not-modified data (issue 370)
464   if (theSynchronize)
465     synchronizeFeatures(true, true, isRoot());
466 }
467
468 void Model_Document::undo()
469 {
470   undoInternal(true, true);
471 }
472
473 bool Model_Document::canRedo()
474 {
475   if (!myRedos.empty())
476     return true;
477   // check other subs contains operation that can be redoed
478   const std::set<std::string> aSubs = subDocuments(true);
479   std::set<std::string>::iterator aSubIter = aSubs.begin();
480   for (; aSubIter != aSubs.end(); aSubIter++)
481     if (subDoc(*aSubIter)->canRedo())
482       return true;
483   return false;
484 }
485
486 void Model_Document::redo()
487 {
488   if (!myNestedNum.empty())
489     (*myNestedNum.rbegin())++;
490   int aNumRedos = myRedos.rbegin()->myOCAFNum;
491   myTransactions.push_back(*myRedos.rbegin());
492   myRedos.pop_back();
493   for(int a = 0; a < aNumRedos; a++)
494     myDoc->Redo();
495
496   // redo for all subs
497   const std::set<std::string> aSubs = subDocuments(true);
498   std::set<std::string>::iterator aSubIter = aSubs.begin();
499   for (; aSubIter != aSubs.end(); aSubIter++)
500     subDoc(*aSubIter)->redo();
501
502   // after redo of all sub-documents to avoid updates on not-modified data (issue 370)
503   synchronizeFeatures(true, true, isRoot());
504 }
505
506 std::list<std::string> Model_Document::undoList() const
507 {
508   std::list<std::string> aResult;
509   // the number of skipped current operations (on undo they will be aborted)
510   int aSkipCurrent = isOperation() ? 1 : 0;
511   std::list<Transaction>::const_reverse_iterator aTrIter = myTransactions.crbegin();
512   int aNumUndo = myTransactions.size();
513   if (!myNestedNum.empty())
514     aNumUndo = *myNestedNum.rbegin();
515   for( ; aNumUndo > 0; aTrIter++, aNumUndo--) {
516     if (aSkipCurrent == 0) aResult.push_back(aTrIter->myId);
517     else aSkipCurrent--;
518   }
519   return aResult;
520 }
521
522 std::list<std::string> Model_Document::redoList() const
523 {
524   std::list<std::string> aResult;
525   std::list<Transaction>::const_reverse_iterator aTrIter = myRedos.crbegin();
526   for( ; aTrIter != myRedos.crend(); aTrIter++) {
527     aResult.push_back(aTrIter->myId);
528   }
529   return aResult;
530 }
531
532 void Model_Document::operationId(const std::string& theId)
533 {
534   myTransactions.rbegin()->myId = theId;
535 }
536
537 /// Append to the array of references a new referenced label
538 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced)
539 {
540   Handle(TDataStd_ReferenceArray) aRefs;
541   if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
542     aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
543     aRefs->SetValue(0, theReferenced);
544   } else {  // extend array by one more element
545     Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
546                                                                         aRefs->Upper() + 1);
547     for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
548       aNewArray->SetValue(a, aRefs->Value(a));
549     }
550     aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
551     aRefs->SetInternalArray(aNewArray);
552   }
553 }
554
555 FeaturePtr Model_Document::addFeature(std::string theID)
556 {
557   TDF_Label anEmptyLab;
558   FeaturePtr anEmptyFeature;
559   FeaturePtr aFeature = ModelAPI_Session::get()->createFeature(theID);
560   if (!aFeature)
561     return aFeature;
562   Model_Document* aDocToAdd;
563   if (aFeature->documentToAdd().get()) { // use the customized document to add
564     aDocToAdd = std::dynamic_pointer_cast<Model_Document>(aFeature->documentToAdd()).get();
565   } else { // if customized is not presented, add to "this" document
566     aDocToAdd = this;
567   }
568   if (aFeature) {
569     TDF_Label aFeatureLab;
570     if (!aFeature->isAction()) {  // do not add action to the data model
571       TDF_Label aFeaturesLab = aDocToAdd->featuresLabel();
572       aFeatureLab = aFeaturesLab.NewChild();
573       aDocToAdd->initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
574       // keep the feature ID to restore document later correctly
575       TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str());
576       aDocToAdd->myObjs.Bind(aFeatureLab, aFeature);
577       // store feature in the history of features array
578       if (aFeature->isInHistory()) {
579         AddToRefArray(aFeaturesLab, aFeatureLab);
580       }
581     }
582     if (!aFeature->isAction()) {  // do not add action to the data model
583       // event: feature is added
584       static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
585       ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
586     } else { // feature must be executed
587        // no creation event => updater not working, problem with remove part
588       aFeature->execute();
589     }
590   }
591   return aFeature;
592 }
593
594 /// Appenad to the array of references a new referenced label.
595 /// If theIndex is not -1, removes element at this index, not theReferenced.
596 /// \returns the index of removed element
597 static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, 
598   const int theIndex = -1)
599 {
600   int aResult = -1;  // no returned
601   Handle(TDataStd_ReferenceArray) aRefs;
602   if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
603     if (aRefs->Length() == 1) {  // just erase an array
604       if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
605         theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
606       }
607       aResult = 0;
608     } else {  // reduce the array
609       Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
610                                                                           aRefs->Upper() - 1);
611       int aCount = aRefs->Lower();
612       for (int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
613         if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
614           aCount--;
615           aResult = a;
616         } else {
617           aNewArray->SetValue(aCount, aRefs->Value(a));
618         }
619       }
620       aRefs->SetInternalArray(aNewArray);
621     }
622   }
623   return aResult;
624 }
625
626 void Model_Document::refsToFeature(FeaturePtr theFeature,
627                                    std::set<std::shared_ptr<ModelAPI_Feature> >& theRefs,
628                                    const bool isSendError)
629 {
630   // check the feature: it must have no depended objects on it
631   // the dependencies can be in the feature results
632   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
633   for(; aResIter != theFeature->results().cend(); aResIter++) {
634     ResultPtr aResult = (*aResIter);
635     std::shared_ptr<Model_Data> aData = 
636       std::dynamic_pointer_cast<Model_Data>(aResult->data());
637     if (aData.get() != NULL) {
638       const std::set<AttributePtr>& aRefs = aData->refsToMe();
639       std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
640       for(; aRefIt != aRefLast; aRefIt++) {
641         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
642         if (aFeature.get() != NULL)
643           theRefs.insert(aFeature);
644       }
645     }
646   }
647   // the dependencies can be in the feature itself
648   std::shared_ptr<Model_Data> aData = 
649       std::dynamic_pointer_cast<Model_Data>(theFeature->data());
650   if (aData && !aData->refsToMe().empty()) {
651     const std::set<AttributePtr>& aRefs = aData->refsToMe();
652     std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
653     for(; aRefIt != aRefLast; aRefIt++) {
654       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
655       if (aFeature.get() != NULL)
656         theRefs.insert(aFeature);
657     }
658   }
659
660   if (!theRefs.empty() && isSendError) {
661     Events_Error::send(
662       "Feature '" + theFeature->data()->name() + "' is used and can not be deleted");
663   }
664 }
665
666 void Model_Document::removeFeature(FeaturePtr theFeature/*, const bool theCheck*/)
667 {
668   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFeature->data());
669   if (aData) {
670     TDF_Label aFeatureLabel = aData->label().Father();
671     if (myObjs.IsBound(aFeatureLabel))
672       myObjs.UnBind(aFeatureLabel);
673     else
674       return;  // not found feature => do not remove
675
676     // checking that the sub-element of composite feature is removed: if yes, inform the owner
677     std::set<std::shared_ptr<ModelAPI_Feature> > aRefs;
678     refsToFeature(theFeature, aRefs, false);
679     std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aRefIter = aRefs.begin();
680     for(; aRefIter != aRefs.end(); aRefIter++) {
681       std::shared_ptr<ModelAPI_CompositeFeature> aComposite = 
682         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
683       if (aComposite.get()) {
684         aComposite->removeFeature(theFeature);
685       }
686     }
687
688     // erase fields
689     theFeature->erase();
690     static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
691     ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
692     // erase all attributes under the label of feature
693     aFeatureLabel.ForgetAllAttributes();
694     // remove it from the references array
695     if (theFeature->isInHistory()) {
696       RemoveFromRefArray(featuresLabel(), aFeatureLabel);
697     }
698     // event: feature is deleted
699     ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
700     // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
701     Events_Loop::loop()->flush(EVENT_DISP);
702   }
703 }
704
705 void Model_Document::addToHistory(const std::shared_ptr<ModelAPI_Object> theObject)
706 {
707   TDF_Label aFeaturesLab = featuresLabel();
708   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theObject->data());
709   if (!aData) {
710       return;  // not found feature => do not remove
711   }
712   TDF_Label aFeatureLabel = aData->label().Father();
713   // store feature in the history of features array
714   if (theObject->isInHistory()) {
715     AddToRefArray(aFeaturesLab, aFeatureLabel);
716   } else {
717     RemoveFromRefArray(aFeaturesLab, aFeatureLabel);
718   }
719 }
720
721 FeaturePtr Model_Document::feature(TDF_Label& theLabel) const
722 {
723   if (myObjs.IsBound(theLabel))
724     return myObjs.Find(theLabel);
725   return FeaturePtr();  // not found
726 }
727
728 ObjectPtr Model_Document::object(TDF_Label theLabel)
729 {
730   // try feature by label
731   FeaturePtr aFeature = feature(theLabel);
732   if (aFeature)
733     return feature(theLabel);
734   TDF_Label aFeatureLabel = theLabel.Father().Father();  // let's suppose it is result
735   aFeature = feature(aFeatureLabel);
736   if (aFeature) {
737     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
738     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
739     for (; aRIter != aResults.cend(); aRIter++) {
740       std::shared_ptr<Model_Data> aResData = std::dynamic_pointer_cast<Model_Data>(
741           (*aRIter)->data());
742       if (aResData->label().Father().IsEqual(theLabel))
743         return *aRIter;
744     }
745   }
746   return FeaturePtr();  // not found
747 }
748
749 std::shared_ptr<ModelAPI_Document> Model_Document::subDocument(std::string theDocID)
750 {
751   return Model_Application::getApplication()->getDocument(theDocID);
752 }
753
754 const std::set<std::string> Model_Document::subDocuments(const bool theActivatedOnly) const
755 {
756   std::set<std::string> aResult;
757   // comment must be in any feature: it is kind
758   int anIndex = 0;
759   TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
760   for (; aLabIter.More(); aLabIter.Next()) {
761     TDF_Label aFLabel = aLabIter.Value()->Label();
762     FeaturePtr aFeature = feature(aFLabel);
763     if (aFeature.get()) { // if document is closed the feature may be not in myObjs map
764       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
765       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
766       for (; aRIter != aResults.cend(); aRIter++) {
767         if ((*aRIter)->groupName() != ModelAPI_ResultPart::group()) continue;
768         if ((*aRIter)->isInHistory()) {
769           ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRIter);
770           if (aPart && (!theActivatedOnly || aPart->isActivated()))
771             aResult.insert(aPart->data()->name());
772         }
773       }
774     }
775   }
776   return aResult;
777 }
778
779 std::shared_ptr<Model_Document> Model_Document::subDoc(std::string theDocID)
780 {
781   // just store sub-document identifier here to manage it later
782   return std::dynamic_pointer_cast<Model_Document>(
783     Model_Application::getApplication()->getDocument(theDocID));
784 }
785
786 ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex,
787                                  const bool theHidden)
788 {
789   if (theGroupID == ModelAPI_Feature::group()) {
790     if (theHidden) {
791       int anIndex = 0;
792       TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
793       for (; aLabIter.More(); aLabIter.Next()) {
794         if (theIndex == anIndex) {
795           TDF_Label aFLabel = aLabIter.Value()->Label();
796           return feature(aFLabel);
797         }
798         anIndex++;
799       }
800     } else {
801       Handle(TDataStd_ReferenceArray) aRefs;
802       if (!featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
803         return ObjectPtr();
804       if (aRefs->Lower() > theIndex || aRefs->Upper() < theIndex)
805         return ObjectPtr();
806       TDF_Label aFeatureLabel = aRefs->Value(theIndex);
807       return feature(aFeatureLabel);
808     }
809   } else {
810     // comment must be in any feature: it is kind
811     int anIndex = 0;
812     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
813     for (; aLabIter.More(); aLabIter.Next()) {
814       TDF_Label aFLabel = aLabIter.Value()->Label();
815       FeaturePtr aFeature = feature(aFLabel);
816       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
817       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
818       for (; aRIter != aResults.cend(); aRIter++) {
819         if ((*aRIter)->groupName() != theGroupID) continue;
820         bool isIn = theHidden && (*aRIter)->isInHistory();
821         if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result
822           isIn = !(*aRIter)->isConcealed();
823         }
824         if (isIn) {
825           if (anIndex == theIndex)
826             return *aRIter;
827           anIndex++;
828         }
829       }
830     }
831   }
832   // not found
833   return ObjectPtr();
834 }
835
836 std::shared_ptr<ModelAPI_Object> Model_Document::objectByName(
837     const std::string& theGroupID, const std::string& theName)
838 {
839   if (theGroupID == ModelAPI_Feature::group()) {
840     int anIndex = 0;
841     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
842     for (; aLabIter.More(); aLabIter.Next()) {
843       TDF_Label aFLabel = aLabIter.Value()->Label();
844       FeaturePtr aFeature = feature(aFLabel);
845       if (aFeature && aFeature->name() == theName)
846         return aFeature;
847     }
848   } else {
849     // comment must be in any feature: it is kind
850     int anIndex = 0;
851     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
852     for (; aLabIter.More(); aLabIter.Next()) {
853       TDF_Label aFLabel = aLabIter.Value()->Label();
854       FeaturePtr aFeature = feature(aFLabel);
855       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
856       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
857       for (; aRIter != aResults.cend(); aRIter++) {
858         if ((*aRIter)->groupName() == theGroupID && (*aRIter)->data()->name() == theName)
859           return *aRIter;
860       }
861     }
862   }
863   // not found
864   return ObjectPtr();
865 }
866
867 int Model_Document::size(const std::string& theGroupID, const bool theHidden)
868 {
869   int aResult = 0;
870   if (theGroupID == ModelAPI_Feature::group()) {
871     if (theHidden) {
872       return myObjs.Size();
873     } else {
874       Handle(TDataStd_ReferenceArray) aRefs;
875       if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
876         return aRefs->Length();
877     }
878   } else {
879     // comment must be in any feature: it is kind
880     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
881     for (; aLabIter.More(); aLabIter.Next()) {
882       TDF_Label aFLabel = aLabIter.Value()->Label();
883       FeaturePtr aFeature = feature(aFLabel);
884       if (!aFeature) // may be on close
885         continue;
886       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
887       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
888       for (; aRIter != aResults.cend(); aRIter++) {
889         if ((*aRIter)->groupName() != theGroupID) continue;
890         bool isIn = theHidden;
891         if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result
892           isIn = !(*aRIter)->isConcealed();
893         }
894         if (isIn)
895           aResult++;
896       }
897     }
898   }
899   // group is not found
900   return aResult;
901 }
902
903 TDF_Label Model_Document::featuresLabel() const
904 {
905   return myDoc->Main().FindChild(TAG_OBJECTS);
906 }
907
908 void Model_Document::setUniqueName(FeaturePtr theFeature)
909 {
910   if (!theFeature->data()->name().empty())
911     return;  // not needed, name is already defined
912   std::string aName;  // result
913   // first count all objects of such kind to start with index = count + 1
914   int aNumObjects = 0;
915   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
916   for (; aFIter.More(); aFIter.Next()) {
917     if (aFIter.Value()->getKind() == theFeature->getKind())
918       aNumObjects++;
919   }
920   // generate candidate name
921   std::stringstream aNameStream;
922   aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
923   aName = aNameStream.str();
924   // check this is unique, if not, increase index by 1
925   for (aFIter.Initialize(myObjs); aFIter.More();) {
926     FeaturePtr aFeature = aFIter.Value();
927     bool isSameName = aFeature->data()->name() == aName;
928     if (!isSameName) {  // check also results to avoid same results names (actual for Parts)
929       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
930       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
931       for (; aRIter != aResults.cend(); aRIter++) {
932         isSameName = (*aRIter)->data()->name() == aName;
933       }
934     }
935     if (isSameName) {
936       aNumObjects++;
937       std::stringstream aNameStream;
938       aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
939       aName = aNameStream.str();
940       // reinitialize iterator to make sure a new name is unique
941       aFIter.Initialize(myObjs);
942     } else
943       aFIter.Next();
944   }
945   theFeature->data()->setName(aName);
946 }
947
948 void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag)
949 {
950   std::shared_ptr<ModelAPI_Document> aThis = Model_Application::getApplication()->getDocument(
951       myID);
952   std::shared_ptr<Model_Data> aData(new Model_Data);
953   aData->setLabel(theLab.FindChild(theTag));
954   aData->setObject(theObj);
955   theObj->setDoc(aThis);
956   theObj->setData(aData);
957   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
958   if (aFeature) {
959     setUniqueName(aFeature);  // must be before "initAttributes" because duplicate part uses name
960   }
961   theObj->initAttributes();
962 }
963
964 void Model_Document::synchronizeFeatures(
965   const bool theMarkUpdated, const bool theUpdateReferences, const bool theFlush)
966 {
967   std::shared_ptr<ModelAPI_Document> aThis = 
968     Model_Application::getApplication()->getDocument(myID);
969   // after all updates, sends a message that groups of features were created or updated
970   Events_Loop* aLoop = Events_Loop::loop();
971   static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
972   static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
973   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
974   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
975   static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
976   static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
977   aLoop->activateFlushes(false);
978
979   // update all objects by checking are they on labels or not
980   std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
981   TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
982   for (; aLabIter.More(); aLabIter.Next()) {
983     TDF_Label aFeatureLabel = aLabIter.Value()->Label();
984     FeaturePtr aFeature;
985     if (!myObjs.IsBound(aFeatureLabel)) {  // a new feature is inserted
986       // create a feature
987       aFeature = ModelAPI_Session::get()->createFeature(
988         TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
989         .ToCString());
990       if (!aFeature) {  // somethig is wrong, most probably, the opened document has invalid structure
991         Events_Error::send("Invalid type of object in the document");
992         aLabIter.Value()->Label().ForgetAllAttributes();
993         continue;
994       }
995       // this must be before "setData" to redo the sketch line correctly
996       myObjs.Bind(aFeatureLabel, aFeature);
997       aNewFeatures.insert(aFeature);
998       initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
999
1000       // event: model is updated
1001       ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
1002     } else {  // nothing is changed, both iterators are incremented
1003       aFeature = myObjs.Find(aFeatureLabel);
1004       aKeptFeatures.insert(aFeature);
1005       if (theMarkUpdated) {
1006         ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
1007       }
1008     }
1009   }
1010   // update results of the features (after features created because they may be connected, like sketch and sub elements)
1011   std::list<FeaturePtr> aComposites; // composites must be updated after their subs (issue 360)
1012   TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
1013   for (; aLabIter2.More(); aLabIter2.Next()) {
1014     TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
1015     if (myObjs.IsBound(aFeatureLabel)) {  // a new feature is inserted
1016       FeaturePtr aFeature = myObjs.Find(aFeatureLabel);
1017       if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature).get())
1018         aComposites.push_back(aFeature);
1019       updateResults(aFeature);
1020     }
1021   }
1022   std::list<FeaturePtr>::iterator aComposite = aComposites.begin();
1023   for(; aComposite != aComposites.end(); aComposite++) {
1024     updateResults(*aComposite);
1025   }
1026
1027   // check all features are checked: if not => it was removed
1028   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
1029   while (aFIter.More()) {
1030     if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end()
1031       && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) {
1032         FeaturePtr aFeature = aFIter.Value();
1033         // event: model is updated
1034         //if (aFeature->isInHistory()) {
1035         ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group());
1036         //}
1037         // results of this feature must be redisplayed (hided)
1038         // redisplay also removed feature (used for sketch and AISObject)
1039         ModelAPI_EventCreator::get()->sendUpdated(aFeature, aRedispEvent);
1040         aFeature->erase();
1041         // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
1042         myObjs.UnBind(aFIter.Key());
1043         // reinitialize iterator because unbind may corrupt the previous order in the map
1044         aFIter.Initialize(myObjs);
1045     } else
1046       aFIter.Next();
1047   }
1048
1049   if (theUpdateReferences) {
1050     synchronizeBackRefs();
1051   }
1052
1053   myExecuteFeatures = false;
1054   aLoop->activateFlushes(true);
1055
1056   if (theFlush) {
1057     aLoop->flush(aCreateEvent);
1058     aLoop->flush(aDeleteEvent);
1059     aLoop->flush(anUpdateEvent);
1060     aLoop->flush(aRedispEvent);
1061     aLoop->flush(aToHideEvent);
1062   }
1063   myExecuteFeatures = true;
1064 }
1065
1066 void Model_Document::synchronizeBackRefs()
1067 {
1068   std::shared_ptr<ModelAPI_Document> aThis = 
1069     Model_Application::getApplication()->getDocument(myID);
1070   // keeps the concealed flags of result to catch the change and create created/deleted events
1071   std::list<std::pair<ResultPtr, bool> > aConcealed;
1072   // first cycle: erase all data about back-references
1073   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myObjs);
1074   for(; aFeatures.More(); aFeatures.Next()) {
1075     FeaturePtr aFeature = aFeatures.Value();
1076     std::shared_ptr<Model_Data> aFData = 
1077       std::dynamic_pointer_cast<Model_Data>(aFeature->data());
1078     if (aFData) {
1079       aFData->eraseBackReferences();
1080     }
1081     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
1082     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
1083     for (; aRIter != aResults.cend(); aRIter++) {
1084       std::shared_ptr<Model_Data> aResData = 
1085         std::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
1086       if (aResData) {
1087         aConcealed.push_back(std::pair<ResultPtr, bool>(*aRIter, (*aRIter)->isConcealed()));
1088         aResData->eraseBackReferences();
1089       }
1090     }
1091   }
1092
1093   // second cycle: set new back-references: only features may have reference, iterate only them
1094   ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
1095   for(aFeatures.Initialize(myObjs); aFeatures.More(); aFeatures.Next()) {
1096     FeaturePtr aFeature = aFeatures.Value();
1097     std::shared_ptr<Model_Data> aFData = 
1098       std::dynamic_pointer_cast<Model_Data>(aFeature->data());
1099     if (aFData) {
1100       std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
1101       aFData->referencesToObjects(aRefs);
1102       std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator 
1103         aRefsIter = aRefs.begin();
1104       for(; aRefsIter != aRefs.end(); aRefsIter++) {
1105         std::list<ObjectPtr>::iterator aRefTo = aRefsIter->second.begin();
1106         for(; aRefTo != aRefsIter->second.end(); aRefTo++) {
1107           if (*aRefTo) {
1108             std::shared_ptr<Model_Data> aRefData = 
1109               std::dynamic_pointer_cast<Model_Data>((*aRefTo)->data());
1110             aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated
1111           }
1112         }
1113       }
1114     }
1115   }
1116   std::list<std::pair<ResultPtr, bool> >::iterator aCIter = aConcealed.begin();
1117   for(; aCIter != aConcealed.end(); aCIter++) {
1118     if (aCIter->first->isConcealed() != aCIter->second) { // somethign is changed => produce event
1119       if (aCIter->second) { // was concealed become not => creation event
1120         static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
1121         ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, anEvent);
1122       } else { // was not concealed become concealed => delete event
1123         ModelAPI_EventCreator::get()->sendDeleted(aThis, aCIter->first->groupName());
1124         // redisplay for the viewer (it must be disappeared also)
1125         static Events_ID EVENT_DISP = 
1126           Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1127         ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, EVENT_DISP);
1128       }
1129     }
1130   }
1131 }
1132
1133 TDF_Label Model_Document::resultLabel(
1134   const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theResultIndex) 
1135 {
1136   const std::shared_ptr<Model_Data>& aData = 
1137     std::dynamic_pointer_cast<Model_Data>(theFeatureData);
1138   return aData->label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1);
1139 }
1140
1141 void Model_Document::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
1142                                  std::shared_ptr<ModelAPI_Result> theResult,
1143                                  const int theResultIndex)
1144 {
1145   std::shared_ptr<ModelAPI_Document> aThis = 
1146     Model_Application::getApplication()->getDocument(myID);
1147   theResult->setDoc(aThis);
1148   initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS);
1149   if (theResult->data()->name().empty()) {  // if was not initialized, generate event and set a name
1150     std::stringstream aNewName;
1151     aNewName<<theFeatureData->name();
1152     if (theResultIndex > 0) // if there are several results, add unique prefix starting from second
1153       aNewName<<"_"<<theResultIndex + 1;
1154     theResult->data()->setName(aNewName.str());
1155   }
1156 }
1157
1158 std::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction(
1159     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1160 {
1161   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1162   TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::group().c_str());
1163   ObjectPtr anOldObject = object(aLab);
1164   std::shared_ptr<ModelAPI_ResultConstruction> aResult;
1165   if (anOldObject) {
1166     aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
1167   }
1168   if (!aResult) {
1169     aResult = std::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
1170     storeResult(theFeatureData, aResult, theIndex);
1171   }
1172   return aResult;
1173 }
1174
1175 std::shared_ptr<ModelAPI_ResultBody> Model_Document::createBody(
1176     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1177 {
1178   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1179   TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
1180   ObjectPtr anOldObject = object(aLab);
1181   std::shared_ptr<ModelAPI_ResultBody> aResult;
1182   if (anOldObject) {
1183     aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
1184   }
1185   if (!aResult) {
1186     aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
1187     storeResult(theFeatureData, aResult, theIndex);
1188   }
1189   return aResult;
1190 }
1191
1192 std::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
1193     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1194 {
1195   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1196   TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str());
1197   ObjectPtr anOldObject = object(aLab);
1198   std::shared_ptr<ModelAPI_ResultPart> aResult;
1199   if (anOldObject) {
1200     aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
1201   }
1202   if (!aResult) {
1203     aResult = std::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
1204     storeResult(theFeatureData, aResult, theIndex);
1205   }
1206   return aResult;
1207 }
1208
1209 std::shared_ptr<ModelAPI_ResultGroup> Model_Document::createGroup(
1210     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1211 {
1212   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1213   TDataStd_Comment::Set(aLab, ModelAPI_ResultGroup::group().c_str());
1214   ObjectPtr anOldObject = object(aLab);
1215   std::shared_ptr<ModelAPI_ResultGroup> aResult;
1216   if (anOldObject) {
1217     aResult = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anOldObject);
1218   }
1219   if (!aResult) {
1220     aResult = std::shared_ptr<ModelAPI_ResultGroup>(new Model_ResultGroup(theFeatureData));
1221     storeResult(theFeatureData, aResult, theIndex);
1222   }
1223   return aResult;
1224 }
1225
1226 std::shared_ptr<ModelAPI_ResultParameter> Model_Document::createParameter(
1227       const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1228 {
1229   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1230   TDataStd_Comment::Set(aLab, ModelAPI_ResultParameter::group().c_str());
1231   ObjectPtr anOldObject = object(aLab);
1232   std::shared_ptr<ModelAPI_ResultParameter> aResult;
1233   if (anOldObject) {
1234     aResult = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(anOldObject);
1235   }
1236   if (!aResult) {
1237     aResult = std::shared_ptr<ModelAPI_ResultParameter>(new ModelAPI_ResultParameter);
1238     storeResult(theFeatureData, aResult, theIndex);
1239   }
1240   return aResult;
1241 }
1242
1243 std::shared_ptr<ModelAPI_Feature> Model_Document::feature(
1244     const std::shared_ptr<ModelAPI_Result>& theResult)
1245 {
1246   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theResult->data());
1247   if (aData) {
1248     TDF_Label aFeatureLab = aData->label().Father().Father().Father();
1249     return feature(aFeatureLab);
1250   }
1251   return FeaturePtr();
1252 }
1253
1254 void Model_Document::updateResults(FeaturePtr theFeature)
1255 {
1256   // for not persistent is will be done by parametric updater automatically
1257   //if (!theFeature->isPersistentResult()) return;
1258   // check the existing results and remove them if there is nothing on the label
1259   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
1260   while(aResIter != theFeature->results().cend()) {
1261     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(*aResIter);
1262     if (aBody) {
1263       if (!aBody->data()->isValid()) { 
1264         // found a disappeared result => remove it
1265         theFeature->removeResult(aBody);
1266         // start iterate from beginning because iterator is corrupted by removing
1267         aResIter = theFeature->results().cbegin();
1268         continue;
1269       }
1270     }
1271     aResIter++;
1272   }
1273   // it may be on undo
1274   if (!theFeature->data() || !theFeature->data()->isValid())
1275     return;
1276   // check that results are presented on all labels
1277   int aResSize = theFeature->results().size();
1278   TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
1279   for(; aLabIter.More(); aLabIter.Next()) {
1280     // here must be GUID of the feature
1281     int aResIndex = aLabIter.Value().Tag() - 1;
1282     ResultPtr aNewBody;
1283     if (aResSize <= aResIndex) {
1284       TDF_Label anArgLab = aLabIter.Value();
1285       Handle(TDataStd_Comment) aGroup;
1286       if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
1287         if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) {
1288           aNewBody = createBody(theFeature->data(), aResIndex);
1289         } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
1290           aNewBody = createPart(theFeature->data(), aResIndex);
1291         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
1292           theFeature->execute(); // construction shapes are needed for sketch solver
1293           break;
1294         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
1295           aNewBody = createGroup(theFeature->data(), aResIndex);
1296         } else {
1297           Events_Error::send(std::string("Unknown type of result is found in the document:") +
1298             TCollection_AsciiString(aGroup->Get()).ToCString());
1299         }
1300       }
1301       if (aNewBody) {
1302         theFeature->setResult(aNewBody, aResIndex);
1303       }
1304     }
1305   }
1306 }
1307
1308 Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper)
1309 {
1310   return TDF_LabelMapHasher::HashCode(theLab, theUpper);
1311
1312 }
1313 Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2)
1314 {
1315   return TDF_LabelMapHasher::IsEqual(theLab1, theLab2);
1316 }
1317
1318 void Model_Document::addNamingName(const TDF_Label theLabel, std::string theName)
1319 {
1320   myNamingNames[theName] = theLabel;
1321 }
1322
1323 TDF_Label Model_Document::findNamingName(std::string theName)
1324 {
1325   std::map<std::string, TDF_Label>::iterator aFind = myNamingNames.find(theName);
1326   if (aFind == myNamingNames.end())
1327     return TDF_Label(); // not found
1328   return aFind->second;
1329 }
1330
1331 ResultPtr Model_Document::findByName(const std::string theName)
1332 {
1333   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator anObjIter(myObjs);
1334   for(; anObjIter.More(); anObjIter.Next()) {
1335     FeaturePtr& aFeature = anObjIter.ChangeValue();
1336     if (!aFeature) // may be on close
1337       continue;
1338     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
1339     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
1340     for (; aRIter != aResults.cend(); aRIter++) {
1341       if (aRIter->get() && (*aRIter)->data() && (*aRIter)->data()->isValid() &&
1342           (*aRIter)->data()->name() == theName) {
1343         return *aRIter;
1344       }
1345     }
1346   }
1347   // not found
1348   return ResultPtr();
1349 }