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