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