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