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