Salome HOME
238b0f3e624669cd1a21872bb1a4e8b26754b31e
[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       setCurrentFeature(aFeature); // after all this feature stays in the document, so make it current
603     } else { // feature must be executed
604        // no creation event => updater not working, problem with remove part
605       aFeature->execute();
606     }
607   }
608   return aFeature;
609 }
610
611 /// Appenad to the array of references a new referenced label.
612 /// If theIndex is not -1, removes element at this index, not theReferenced.
613 /// \returns the index of removed element
614 static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, 
615   const int theIndex = -1)
616 {
617   int aResult = -1;  // no returned
618   Handle(TDataStd_ReferenceArray) aRefs;
619   if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
620     if (aRefs->Length() == 1) {  // just erase an array
621       if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
622         theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
623       }
624       aResult = 0;
625     } else {  // reduce the array
626       Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
627                                                                           aRefs->Upper() - 1);
628       int aCount = aRefs->Lower();
629       for (int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
630         if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
631           aCount--;
632           aResult = a;
633         } else {
634           aNewArray->SetValue(aCount, aRefs->Value(a));
635         }
636       }
637       aRefs->SetInternalArray(aNewArray);
638     }
639   }
640   return aResult;
641 }
642
643 void Model_Document::refsToFeature(FeaturePtr theFeature,
644                                    std::set<std::shared_ptr<ModelAPI_Feature> >& theRefs,
645                                    const bool isSendError)
646 {
647   // check the feature: it must have no depended objects on it
648   // the dependencies can be in the feature results
649   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
650   for(; aResIter != theFeature->results().cend(); aResIter++) {
651     ResultPtr aResult = (*aResIter);
652     std::shared_ptr<Model_Data> aData = 
653       std::dynamic_pointer_cast<Model_Data>(aResult->data());
654     if (aData.get() != NULL) {
655       const std::set<AttributePtr>& aRefs = aData->refsToMe();
656       std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
657       for(; aRefIt != aRefLast; aRefIt++) {
658         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
659         if (aFeature.get() != NULL)
660           theRefs.insert(aFeature);
661       }
662     }
663   }
664   // the dependencies can be in the feature itself
665   std::shared_ptr<Model_Data> aData = 
666       std::dynamic_pointer_cast<Model_Data>(theFeature->data());
667   if (aData && !aData->refsToMe().empty()) {
668     const std::set<AttributePtr>& aRefs = aData->refsToMe();
669     std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
670     for(; aRefIt != aRefLast; aRefIt++) {
671       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
672       if (aFeature.get() != NULL)
673         theRefs.insert(aFeature);
674     }
675   }
676
677   if (!theRefs.empty() && isSendError) {
678     Events_Error::send(
679       "Feature '" + theFeature->data()->name() + "' is used and can not be deleted");
680   }
681 }
682
683 void Model_Document::removeFeature(FeaturePtr theFeature/*, const bool theCheck*/)
684 {
685   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFeature->data());
686   if (aData) {
687     TDF_Label aFeatureLabel = aData->label().Father();
688     if (myObjs.IsBound(aFeatureLabel))
689       myObjs.UnBind(aFeatureLabel);
690     else
691       return;  // not found feature => do not remove
692
693     // checking that the sub-element of composite feature is removed: if yes, inform the owner
694     std::set<std::shared_ptr<ModelAPI_Feature> > aRefs;
695     refsToFeature(theFeature, aRefs, false);
696     std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aRefIter = aRefs.begin();
697     for(; aRefIter != aRefs.end(); aRefIter++) {
698       std::shared_ptr<ModelAPI_CompositeFeature> aComposite = 
699         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
700       if (aComposite.get()) {
701         aComposite->removeFeature(theFeature);
702       }
703     }
704     // if this feature is current, make the current the previous feature
705     if (theFeature == currentFeature()) {
706       int aCurrentIndex = index(theFeature);
707       if (aCurrentIndex != -1) {
708         setCurrentFeature(std::dynamic_pointer_cast<ModelAPI_Feature>(
709           object(ModelAPI_Feature::group(), aCurrentIndex - 1)));
710       }
711     }
712
713     // erase fields
714     theFeature->erase();
715     static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
716     ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
717     // erase all attributes under the label of feature
718     aFeatureLabel.ForgetAllAttributes();
719     // remove it from the references array
720     if (theFeature->isInHistory()) {
721       RemoveFromRefArray(featuresLabel(), aFeatureLabel);
722     }
723     // event: feature is deleted
724     ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
725     // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
726     Events_Loop::loop()->flush(EVENT_DISP);
727   }
728 }
729
730 void Model_Document::addToHistory(const std::shared_ptr<ModelAPI_Object> theObject)
731 {
732   TDF_Label aFeaturesLab = featuresLabel();
733   std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theObject->data());
734   if (!aData) {
735       return;  // not found feature => do not remove
736   }
737   TDF_Label aFeatureLabel = aData->label().Father();
738   // store feature in the history of features array
739   if (theObject->isInHistory()) {
740     AddToRefArray(aFeaturesLab, aFeatureLabel);
741   } else {
742     RemoveFromRefArray(aFeaturesLab, aFeatureLabel);
743   }
744 }
745
746 FeaturePtr Model_Document::feature(TDF_Label& theLabel) const
747 {
748   if (myObjs.IsBound(theLabel))
749     return myObjs.Find(theLabel);
750   return FeaturePtr();  // not found
751 }
752
753 ObjectPtr Model_Document::object(TDF_Label theLabel)
754 {
755   // try feature by label
756   FeaturePtr aFeature = feature(theLabel);
757   if (aFeature)
758     return feature(theLabel);
759   TDF_Label aFeatureLabel = theLabel.Father().Father();  // let's suppose it is result
760   aFeature = feature(aFeatureLabel);
761   if (aFeature) {
762     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
763     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
764     for (; aRIter != aResults.cend(); aRIter++) {
765       std::shared_ptr<Model_Data> aResData = std::dynamic_pointer_cast<Model_Data>(
766           (*aRIter)->data());
767       if (aResData->label().Father().IsEqual(theLabel))
768         return *aRIter;
769     }
770   }
771   return FeaturePtr();  // not found
772 }
773
774 std::shared_ptr<ModelAPI_Document> Model_Document::subDocument(std::string theDocID)
775 {
776   return Model_Application::getApplication()->getDocument(theDocID);
777 }
778
779 const std::set<std::string> Model_Document::subDocuments(const bool theActivatedOnly) const
780 {
781   std::set<std::string> aResult;
782   // comment must be in any feature: it is kind
783   int anIndex = 0;
784   TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
785   for (; aLabIter.More(); aLabIter.Next()) {
786     TDF_Label aFLabel = aLabIter.Value()->Label();
787     FeaturePtr aFeature = feature(aFLabel);
788     if (aFeature.get()) { // if document is closed the feature may be not in myObjs map
789       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
790       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
791       for (; aRIter != aResults.cend(); aRIter++) {
792         if ((*aRIter)->groupName() != ModelAPI_ResultPart::group()) continue;
793         if ((*aRIter)->isInHistory()) {
794           ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRIter);
795           if (aPart && (!theActivatedOnly || aPart->isActivated()))
796             aResult.insert(aPart->data()->name());
797         }
798       }
799     }
800   }
801   return aResult;
802 }
803
804 std::shared_ptr<Model_Document> Model_Document::subDoc(std::string theDocID)
805 {
806   // just store sub-document identifier here to manage it later
807   return std::dynamic_pointer_cast<Model_Document>(
808     Model_Application::getApplication()->getDocument(theDocID));
809 }
810
811 ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex,
812                                  const bool theHidden)
813 {
814   if (theGroupID == ModelAPI_Feature::group()) {
815     if (theHidden) {
816       int anIndex = 0;
817       TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
818       for (; aLabIter.More(); aLabIter.Next()) {
819         if (theIndex == anIndex) {
820           TDF_Label aFLabel = aLabIter.Value()->Label();
821           return feature(aFLabel);
822         }
823         anIndex++;
824       }
825     } else {
826       Handle(TDataStd_ReferenceArray) aRefs;
827       if (!featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
828         return ObjectPtr();
829       if (aRefs->Lower() > theIndex || aRefs->Upper() < theIndex)
830         return ObjectPtr();
831       TDF_Label aFeatureLabel = aRefs->Value(theIndex);
832       return feature(aFeatureLabel);
833     }
834   } else {
835     // comment must be in any feature: it is kind
836     int anIndex = 0;
837     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
838     for (; aLabIter.More(); aLabIter.Next()) {
839       TDF_Label aFLabel = aLabIter.Value()->Label();
840       FeaturePtr aFeature = feature(aFLabel);
841       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
842       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
843       for (; aRIter != aResults.cend(); aRIter++) {
844         if ((*aRIter)->groupName() != theGroupID) continue;
845         bool isIn = theHidden && (*aRIter)->isInHistory();
846         if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result
847           isIn = !(*aRIter)->isConcealed();
848         }
849         if (isIn) {
850           if (anIndex == theIndex)
851             return *aRIter;
852           anIndex++;
853         }
854       }
855     }
856   }
857   // not found
858   return ObjectPtr();
859 }
860
861 std::shared_ptr<ModelAPI_Object> Model_Document::objectByName(
862     const std::string& theGroupID, const std::string& theName)
863 {
864   if (theGroupID == ModelAPI_Feature::group()) {
865     int anIndex = 0;
866     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
867     for (; aLabIter.More(); aLabIter.Next()) {
868       TDF_Label aFLabel = aLabIter.Value()->Label();
869       FeaturePtr aFeature = feature(aFLabel);
870       if (aFeature && aFeature->name() == theName)
871         return aFeature;
872     }
873   } else {
874     // comment must be in any feature: it is kind
875     int anIndex = 0;
876     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
877     for (; aLabIter.More(); aLabIter.Next()) {
878       TDF_Label aFLabel = aLabIter.Value()->Label();
879       FeaturePtr aFeature = feature(aFLabel);
880       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
881       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
882       for (; aRIter != aResults.cend(); aRIter++) {
883         if ((*aRIter)->groupName() == theGroupID && (*aRIter)->data()->name() == theName)
884           return *aRIter;
885       }
886     }
887   }
888   // not found
889   return ObjectPtr();
890 }
891
892 const int Model_Document::index(std::shared_ptr<ModelAPI_Object> theObject)
893 {
894   const std::string aGroupName = theObject->groupName();
895   if (aGroupName == ModelAPI_Feature::group()) {
896     int anIndex = 0;
897     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
898     for (; aLabIter.More(); aLabIter.Next()) {
899       TDF_Label aFLabel = aLabIter.Value()->Label();
900       FeaturePtr aFeature = feature(aFLabel);
901       if (aFeature == theObject)
902         return anIndex;
903       if (aFeature->isInHistory())
904         anIndex++;
905     }
906   } else {
907     // comment must be in any feature: it is kind
908     int anIndex = 0;
909     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
910     for (; aLabIter.More(); aLabIter.Next()) {
911       TDF_Label aFLabel = aLabIter.Value()->Label();
912       FeaturePtr aFeature = feature(aFLabel);
913       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
914       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
915       for (; aRIter != aResults.cend(); aRIter++) {
916         if (*aRIter == theObject)
917           return anIndex;
918         if ((*aRIter)->groupName() == aGroupName) {
919           bool isIn = (*aRIter)->isInHistory() && !(*aRIter)->isConcealed();
920           if (isIn) {
921             anIndex++;
922           }
923         }
924       }
925     }
926   }
927   // not found
928   return -1;
929 }
930
931 int Model_Document::size(const std::string& theGroupID, const bool theHidden)
932 {
933   int aResult = 0;
934   if (theGroupID == ModelAPI_Feature::group()) {
935     if (theHidden) {
936       return myObjs.Size();
937     } else {
938       Handle(TDataStd_ReferenceArray) aRefs;
939       if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
940         return aRefs->Length();
941     }
942   } else {
943     // comment must be in any feature: it is kind
944     TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
945     for (; aLabIter.More(); aLabIter.Next()) {
946       TDF_Label aFLabel = aLabIter.Value()->Label();
947       FeaturePtr aFeature = feature(aFLabel);
948       if (!aFeature) // may be on close
949         continue;
950       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
951       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
952       for (; aRIter != aResults.cend(); aRIter++) {
953         if ((*aRIter)->groupName() != theGroupID) continue;
954         bool isIn = theHidden;
955         if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result
956           isIn = !(*aRIter)->isConcealed();
957         }
958         if (isIn)
959           aResult++;
960       }
961     }
962   }
963   // group is not found
964   return aResult;
965 }
966
967 std::shared_ptr<ModelAPI_Feature> Model_Document::currentFeature()
968 {
969   TDF_Label aRefLab = generalLabel().FindChild(TAG_CURRENT_FEATURE);
970   Handle(TDF_Reference) aRef;
971   if (aRefLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
972     TDF_Label aLab = aRef->Get();
973     return feature(aLab);
974   }
975   return std::shared_ptr<ModelAPI_Feature>(); // null feature means the higher than first
976 }
977
978 void Model_Document::setCurrentFeature(std::shared_ptr<ModelAPI_Feature> theCurrent)
979 {
980   TDF_Label aRefLab = generalLabel().FindChild(TAG_CURRENT_FEATURE);
981   if (theCurrent.get()) {
982     std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
983     if (aData.get()) {
984       TDF_Label aFeatureLabel = aData->label().Father();
985       Handle(TDF_Reference) aRef;
986       if (aRefLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
987         aRef->Set(aFeatureLabel);
988       } else {
989         aRef = TDF_Reference::Set(aRefLab, aFeatureLabel);
990       }
991     }
992   } else { // remove reference for the null feature
993     aRefLab.ForgetAttribute(TDF_Reference::GetID());
994   }
995   // make all features after this feature disabled in reversed order (to remove results without deps)
996   bool aPassed = false; // flag that the current object is already passed in cycle
997   int aSize = size(ModelAPI_Feature::group(), true);
998   for(int a = aSize - 1; a >= 0; a--) {
999     FeaturePtr aFeature = 
1000       std::dynamic_pointer_cast<ModelAPI_Feature>(object(ModelAPI_Feature::group(), a, true));
1001     if (aFeature->setDisabled(!aPassed)) {
1002       // state of feature is changed => so feature become updated
1003       static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1004       ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
1005
1006     }
1007     // check this only after passed become enabled: the current feature is enabled!
1008     if (aFeature == theCurrent) aPassed = true;
1009   }
1010 }
1011
1012 TDF_Label Model_Document::featuresLabel() const
1013 {
1014   return myDoc->Main().FindChild(TAG_OBJECTS);
1015 }
1016
1017 TDF_Label Model_Document::generalLabel() const
1018 {
1019   return myDoc->Main().FindChild(TAG_GENERAL);
1020 }
1021
1022 void Model_Document::setUniqueName(FeaturePtr theFeature)
1023 {
1024   if (!theFeature->data()->name().empty())
1025     return;  // not needed, name is already defined
1026   std::string aName;  // result
1027   // first count all objects of such kind to start with index = count + 1
1028   int aNumObjects = 0;
1029   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
1030   for (; aFIter.More(); aFIter.Next()) {
1031     if (aFIter.Value()->getKind() == theFeature->getKind())
1032       aNumObjects++;
1033   }
1034   // generate candidate name
1035   std::stringstream aNameStream;
1036   aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
1037   aName = aNameStream.str();
1038   // check this is unique, if not, increase index by 1
1039   for (aFIter.Initialize(myObjs); aFIter.More();) {
1040     FeaturePtr aFeature = aFIter.Value();
1041     bool isSameName = aFeature->data()->name() == aName;
1042     if (!isSameName) {  // check also results to avoid same results names (actual for Parts)
1043       const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
1044       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
1045       for (; aRIter != aResults.cend(); aRIter++) {
1046         isSameName = (*aRIter)->data()->name() == aName;
1047       }
1048     }
1049     if (isSameName) {
1050       aNumObjects++;
1051       std::stringstream aNameStream;
1052       aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
1053       aName = aNameStream.str();
1054       // reinitialize iterator to make sure a new name is unique
1055       aFIter.Initialize(myObjs);
1056     } else
1057       aFIter.Next();
1058   }
1059   theFeature->data()->setName(aName);
1060 }
1061
1062 void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag)
1063 {
1064   std::shared_ptr<ModelAPI_Document> aThis = Model_Application::getApplication()->getDocument(
1065       myID);
1066   std::shared_ptr<Model_Data> aData(new Model_Data);
1067   aData->setLabel(theLab.FindChild(theTag));
1068   aData->setObject(theObj);
1069   theObj->setDoc(aThis);
1070   theObj->setData(aData);
1071   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
1072   if (aFeature) {
1073     setUniqueName(aFeature);  // must be before "initAttributes" because duplicate part uses name
1074   }
1075   theObj->initAttributes();
1076 }
1077
1078 void Model_Document::synchronizeFeatures(
1079   const bool theMarkUpdated, const bool theUpdateReferences, const bool theFlush)
1080 {
1081   std::shared_ptr<ModelAPI_Document> aThis = 
1082     Model_Application::getApplication()->getDocument(myID);
1083   // after all updates, sends a message that groups of features were created or updated
1084   Events_Loop* aLoop = Events_Loop::loop();
1085   static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1086   static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
1087   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
1088   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1089   static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
1090   static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1091   aLoop->activateFlushes(false);
1092
1093   // update all objects by checking are they on labels or not
1094   std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
1095   TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
1096   for (; aLabIter.More(); aLabIter.Next()) {
1097     TDF_Label aFeatureLabel = aLabIter.Value()->Label();
1098     FeaturePtr aFeature;
1099     if (!myObjs.IsBound(aFeatureLabel)) {  // a new feature is inserted
1100       // create a feature
1101       aFeature = std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get())->createFeature(
1102         TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
1103         .ToCString(), this);
1104       if (!aFeature) {  // somethig is wrong, most probably, the opened document has invalid structure
1105         Events_Error::send("Invalid type of object in the document");
1106         aLabIter.Value()->Label().ForgetAllAttributes();
1107         continue;
1108       }
1109       // this must be before "setData" to redo the sketch line correctly
1110       myObjs.Bind(aFeatureLabel, aFeature);
1111       aNewFeatures.insert(aFeature);
1112       initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
1113
1114       // event: model is updated
1115       ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
1116     } else {  // nothing is changed, both iterators are incremented
1117       aFeature = myObjs.Find(aFeatureLabel);
1118       aKeptFeatures.insert(aFeature);
1119       if (theMarkUpdated) {
1120         ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
1121       }
1122     }
1123   }
1124   // update results of the features (after features created because they may be connected, like sketch and sub elements)
1125   std::list<FeaturePtr> aComposites; // composites must be updated after their subs (issue 360)
1126   TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
1127   for (; aLabIter2.More(); aLabIter2.Next()) {
1128     TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
1129     if (myObjs.IsBound(aFeatureLabel)) {  // a new feature is inserted
1130       FeaturePtr aFeature = myObjs.Find(aFeatureLabel);
1131       if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature).get())
1132         aComposites.push_back(aFeature);
1133       updateResults(aFeature);
1134     }
1135   }
1136   std::list<FeaturePtr>::iterator aComposite = aComposites.begin();
1137   for(; aComposite != aComposites.end(); aComposite++) {
1138     updateResults(*aComposite);
1139   }
1140
1141   // check all features are checked: if not => it was removed
1142   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
1143   while (aFIter.More()) {
1144     if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end()
1145       && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) {
1146         FeaturePtr aFeature = aFIter.Value();
1147         // event: model is updated
1148         //if (aFeature->isInHistory()) {
1149         ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group());
1150         //}
1151         // results of this feature must be redisplayed (hided)
1152         // redisplay also removed feature (used for sketch and AISObject)
1153         ModelAPI_EventCreator::get()->sendUpdated(aFeature, aRedispEvent);
1154         aFeature->erase();
1155         // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
1156         myObjs.UnBind(aFIter.Key());
1157         // reinitialize iterator because unbind may corrupt the previous order in the map
1158         aFIter.Initialize(myObjs);
1159     } else
1160       aFIter.Next();
1161   }
1162
1163   if (theUpdateReferences) {
1164     synchronizeBackRefs();
1165   }
1166
1167   myExecuteFeatures = false;
1168   aLoop->activateFlushes(true);
1169
1170   if (theFlush) {
1171     aLoop->flush(aCreateEvent);
1172     aLoop->flush(aDeleteEvent);
1173     aLoop->flush(anUpdateEvent);
1174     aLoop->flush(aRedispEvent);
1175     aLoop->flush(aToHideEvent);
1176   }
1177   myExecuteFeatures = true;
1178 }
1179
1180 void Model_Document::synchronizeBackRefs()
1181 {
1182   std::shared_ptr<ModelAPI_Document> aThis = 
1183     Model_Application::getApplication()->getDocument(myID);
1184   // keeps the concealed flags of result to catch the change and create created/deleted events
1185   std::list<std::pair<ResultPtr, bool> > aConcealed;
1186   // first cycle: erase all data about back-references
1187   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myObjs);
1188   for(; aFeatures.More(); aFeatures.Next()) {
1189     FeaturePtr aFeature = aFeatures.Value();
1190     std::shared_ptr<Model_Data> aFData = 
1191       std::dynamic_pointer_cast<Model_Data>(aFeature->data());
1192     if (aFData) {
1193       aFData->eraseBackReferences();
1194     }
1195     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
1196     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
1197     for (; aRIter != aResults.cend(); aRIter++) {
1198       std::shared_ptr<Model_Data> aResData = 
1199         std::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
1200       if (aResData) {
1201         aConcealed.push_back(std::pair<ResultPtr, bool>(*aRIter, (*aRIter)->isConcealed()));
1202         aResData->eraseBackReferences();
1203       }
1204     }
1205   }
1206
1207   // second cycle: set new back-references: only features may have reference, iterate only them
1208   ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
1209   for(aFeatures.Initialize(myObjs); aFeatures.More(); aFeatures.Next()) {
1210     FeaturePtr aFeature = aFeatures.Value();
1211     std::shared_ptr<Model_Data> aFData = 
1212       std::dynamic_pointer_cast<Model_Data>(aFeature->data());
1213     if (aFData) {
1214       std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
1215       aFData->referencesToObjects(aRefs);
1216       std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator 
1217         aRefsIter = aRefs.begin();
1218       for(; aRefsIter != aRefs.end(); aRefsIter++) {
1219         std::list<ObjectPtr>::iterator aRefTo = aRefsIter->second.begin();
1220         for(; aRefTo != aRefsIter->second.end(); aRefTo++) {
1221           if (*aRefTo) {
1222             std::shared_ptr<Model_Data> aRefData = 
1223               std::dynamic_pointer_cast<Model_Data>((*aRefTo)->data());
1224             aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated
1225           }
1226         }
1227       }
1228     }
1229   }
1230   std::list<std::pair<ResultPtr, bool> >::iterator aCIter = aConcealed.begin();
1231   for(; aCIter != aConcealed.end(); aCIter++) {
1232     if (aCIter->first->isConcealed() != aCIter->second) { // somethign is changed => produce event
1233       if (aCIter->second) { // was concealed become not => creation event
1234         static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
1235         ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, anEvent);
1236       } else { // was not concealed become concealed => delete event
1237         ModelAPI_EventCreator::get()->sendDeleted(aThis, aCIter->first->groupName());
1238         // redisplay for the viewer (it must be disappeared also)
1239         static Events_ID EVENT_DISP = 
1240           Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1241         ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, EVENT_DISP);
1242       }
1243     }
1244   }
1245 }
1246
1247 TDF_Label Model_Document::resultLabel(
1248   const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theResultIndex) 
1249 {
1250   const std::shared_ptr<Model_Data>& aData = 
1251     std::dynamic_pointer_cast<Model_Data>(theFeatureData);
1252   return aData->label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1);
1253 }
1254
1255 void Model_Document::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
1256                                  std::shared_ptr<ModelAPI_Result> theResult,
1257                                  const int theResultIndex)
1258 {
1259   std::shared_ptr<ModelAPI_Document> aThis = 
1260     Model_Application::getApplication()->getDocument(myID);
1261   theResult->setDoc(aThis);
1262   initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS);
1263   if (theResult->data()->name().empty()) {  // if was not initialized, generate event and set a name
1264     std::stringstream aNewName;
1265     aNewName<<theFeatureData->name();
1266     if (theResultIndex > 0) // if there are several results, add unique prefix starting from second
1267       aNewName<<"_"<<theResultIndex + 1;
1268     theResult->data()->setName(aNewName.str());
1269   }
1270 }
1271
1272 std::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction(
1273     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1274 {
1275   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1276   TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::group().c_str());
1277   ObjectPtr anOldObject = object(aLab);
1278   std::shared_ptr<ModelAPI_ResultConstruction> aResult;
1279   if (anOldObject) {
1280     aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
1281   }
1282   if (!aResult) {
1283     aResult = std::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
1284     storeResult(theFeatureData, aResult, theIndex);
1285   }
1286   return aResult;
1287 }
1288
1289 std::shared_ptr<ModelAPI_ResultBody> Model_Document::createBody(
1290     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1291 {
1292   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1293   TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
1294   ObjectPtr anOldObject = object(aLab);
1295   std::shared_ptr<ModelAPI_ResultBody> aResult;
1296   if (anOldObject) {
1297     aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
1298   }
1299   if (!aResult) {
1300     aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
1301     storeResult(theFeatureData, aResult, theIndex);
1302   }
1303   return aResult;
1304 }
1305
1306 std::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
1307     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1308 {
1309   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1310   TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str());
1311   ObjectPtr anOldObject = object(aLab);
1312   std::shared_ptr<ModelAPI_ResultPart> aResult;
1313   if (anOldObject) {
1314     aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
1315   }
1316   if (!aResult) {
1317     aResult = std::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
1318     storeResult(theFeatureData, aResult, theIndex);
1319   }
1320   return aResult;
1321 }
1322
1323 std::shared_ptr<ModelAPI_ResultGroup> Model_Document::createGroup(
1324     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1325 {
1326   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1327   TDataStd_Comment::Set(aLab, ModelAPI_ResultGroup::group().c_str());
1328   ObjectPtr anOldObject = object(aLab);
1329   std::shared_ptr<ModelAPI_ResultGroup> aResult;
1330   if (anOldObject) {
1331     aResult = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anOldObject);
1332   }
1333   if (!aResult) {
1334     aResult = std::shared_ptr<ModelAPI_ResultGroup>(new Model_ResultGroup(theFeatureData));
1335     storeResult(theFeatureData, aResult, theIndex);
1336   }
1337   return aResult;
1338 }
1339
1340 std::shared_ptr<ModelAPI_ResultParameter> Model_Document::createParameter(
1341       const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
1342 {
1343   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
1344   TDataStd_Comment::Set(aLab, ModelAPI_ResultParameter::group().c_str());
1345   ObjectPtr anOldObject = object(aLab);
1346   std::shared_ptr<ModelAPI_ResultParameter> aResult;
1347   if (anOldObject) {
1348     aResult = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(anOldObject);
1349   }
1350   if (!aResult) {
1351     aResult = std::shared_ptr<ModelAPI_ResultParameter>(new Model_ResultParameter);
1352     storeResult(theFeatureData, aResult, theIndex);
1353   }
1354   return aResult;
1355 }
1356
1357 std::shared_ptr<ModelAPI_Feature> Model_Document::feature(
1358     const std::shared_ptr<ModelAPI_Result>& theResult)
1359 {
1360   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theResult->data());
1361   if (aData) {
1362     TDF_Label aFeatureLab = aData->label().Father().Father().Father();
1363     return feature(aFeatureLab);
1364   }
1365   return FeaturePtr();
1366 }
1367
1368 void Model_Document::updateResults(FeaturePtr theFeature)
1369 {
1370   // for not persistent is will be done by parametric updater automatically
1371   //if (!theFeature->isPersistentResult()) return;
1372   // check the existing results and remove them if there is nothing on the label
1373   std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
1374   while(aResIter != theFeature->results().cend()) {
1375     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(*aResIter);
1376     if (aBody) {
1377       if (!aBody->data()->isValid()) { 
1378         // found a disappeared result => remove it
1379         theFeature->removeResult(aBody);
1380         // start iterate from beginning because iterator is corrupted by removing
1381         aResIter = theFeature->results().cbegin();
1382         continue;
1383       }
1384     }
1385     aResIter++;
1386   }
1387   // it may be on undo
1388   if (!theFeature->data() || !theFeature->data()->isValid())
1389     return;
1390   // check that results are presented on all labels
1391   int aResSize = theFeature->results().size();
1392   TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
1393   for(; aLabIter.More(); aLabIter.Next()) {
1394     // here must be GUID of the feature
1395     int aResIndex = aLabIter.Value().Tag() - 1;
1396     ResultPtr aNewBody;
1397     if (aResSize <= aResIndex) {
1398       TDF_Label anArgLab = aLabIter.Value();
1399       Handle(TDataStd_Comment) aGroup;
1400       if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
1401         if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) {
1402           aNewBody = createBody(theFeature->data(), aResIndex);
1403         } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
1404           aNewBody = createPart(theFeature->data(), aResIndex);
1405         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
1406           theFeature->execute(); // construction shapes are needed for sketch solver
1407           break;
1408         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
1409           aNewBody = createGroup(theFeature->data(), aResIndex);
1410         } else if (aGroup->Get() == ModelAPI_ResultParameter::group().c_str()) {
1411           theFeature->attributeChanged("expression"); // just produce a value
1412           break;
1413         } else {
1414           Events_Error::send(std::string("Unknown type of result is found in the document:") +
1415             TCollection_AsciiString(aGroup->Get()).ToCString());
1416         }
1417       }
1418       if (aNewBody) {
1419         theFeature->setResult(aNewBody, aResIndex);
1420       }
1421     }
1422   }
1423 }
1424
1425 Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper)
1426 {
1427   return TDF_LabelMapHasher::HashCode(theLab, theUpper);
1428
1429 }
1430 Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2)
1431 {
1432   return TDF_LabelMapHasher::IsEqual(theLab1, theLab2);
1433 }
1434
1435 void Model_Document::addNamingName(const TDF_Label theLabel, std::string theName)
1436 {
1437   myNamingNames[theName] = theLabel;
1438 }
1439
1440 TDF_Label Model_Document::findNamingName(std::string theName)
1441 {
1442   std::map<std::string, TDF_Label>::iterator aFind = myNamingNames.find(theName);
1443   if (aFind == myNamingNames.end())
1444     return TDF_Label(); // not found
1445   return aFind->second;
1446 }
1447
1448 ResultPtr Model_Document::findByName(const std::string theName)
1449 {
1450   NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator anObjIter(myObjs);
1451   for(; anObjIter.More(); anObjIter.Next()) {
1452     FeaturePtr& aFeature = anObjIter.ChangeValue();
1453     if (!aFeature) // may be on close
1454       continue;
1455     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
1456     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
1457     for (; aRIter != aResults.cend(); aRIter++) {
1458       if (aRIter->get() && (*aRIter)->data() && (*aRIter)->data()->isValid() &&
1459           (*aRIter)->data()->name() == theName) {
1460         return *aRIter;
1461       }
1462     }
1463   }
1464   // not found
1465   return ResultPtr();
1466 }