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