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