1 // File: Model_Document.cxx
2 // Created: 28 Feb 2014
3 // Author: Mikhail PONIKAROV
5 #include <Model_Document.h>
6 #include <Model_Data.h>
7 #include <Model_Application.h>
8 #include <Model_PluginManager.h>
9 #include <Model_Events.h>
10 #include <Model_ResultPart.h>
11 #include <Model_ResultConstruction.h>
12 #include <Model_ResultBody.h>
13 #include <Events_Loop.h>
14 #include <Events_Error.h>
16 #include <TDataStd_Integer.hxx>
17 #include <TDataStd_Comment.hxx>
18 #include <TDF_ChildIDIterator.hxx>
19 #include <TDataStd_ReferenceArray.hxx>
20 #include <TDataStd_HLabelArray1.hxx>
21 #include <TDataStd_Name.hxx>
22 #include <TDF_Reference.hxx>
23 #include <TDF_ChildIDIterator.hxx>
24 #include <TDF_LabelMapHasher.hxx>
32 # define _separator_ '\\'
34 # define _separator_ '/'
37 static const int UNDO_LIMIT = 10; // number of possible undo operations
39 static const int TAG_GENERAL = 1; // general properties tag
40 static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
41 static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump)
44 static const int TAG_FEATURE_ARGUMENTS = 1; ///< where the arguments are located
45 static const int TAG_FEATURE_RESULTS = 2; ///< where the results are located
47 /// Returns the file name of this document by the nameof directory and identifuer of a document
48 static TCollection_ExtendedString DocFileName(const char* theFileName, const std::string& theID)
50 TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
52 aPath += theID.c_str();
53 aPath += ".cbf"; // standard binary file extension
57 bool Model_Document::load(const char* theFileName)
59 Handle(Model_Application) anApp = Model_Application::getApplication();
60 if (this == Model_PluginManager::get()->rootDocument().get()) {
61 anApp->setLoadPath(theFileName);
63 TCollection_ExtendedString aPath (DocFileName(theFileName, myID));
64 PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
67 aStatus = anApp->Open(aPath, myDoc);
69 catch (Standard_Failure)
71 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
72 Events_Error::send(std::string("Exception in opening of document: ") + aFail->GetMessageString());
75 bool isError = aStatus != PCDM_RS_OK;
80 case PCDM_RS_UnknownDocument:
81 Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownDocument")); break;
82 case PCDM_RS_AlreadyRetrieved:
83 Events_Error::send(std::string("Can not open document: PCDM_RS_AlreadyRetrieved")); break;
84 case PCDM_RS_AlreadyRetrievedAndModified:
86 std::string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified"));
88 case PCDM_RS_NoDriver:
89 Events_Error::send(std::string("Can not open document: PCDM_RS_NoDriver")); break;
90 case PCDM_RS_UnknownFileDriver:
91 Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownFileDriver")); break;
92 case PCDM_RS_OpenError:
93 Events_Error::send(std::string("Can not open document: PCDM_RS_OpenError")); break;
94 case PCDM_RS_NoVersion:
95 Events_Error::send(std::string("Can not open document: PCDM_RS_NoVersion")); break;
97 Events_Error::send(std::string("Can not open document: PCDM_RS_NoModel")); break;
98 case PCDM_RS_NoDocument:
99 Events_Error::send(std::string("Can not open document: PCDM_RS_NoDocument")); break;
100 case PCDM_RS_FormatFailure:
101 Events_Error::send(std::string("Can not open document: PCDM_RS_FormatFailure")); break;
102 case PCDM_RS_TypeNotFoundInSchema:
103 Events_Error::send(std::string("Can not open document: PCDM_RS_TypeNotFoundInSchema"));
105 case PCDM_RS_UnrecognizedFileFormat:
106 Events_Error::send(std::string("Can not open document: PCDM_RS_UnrecognizedFileFormat"));
108 case PCDM_RS_MakeFailure:
109 Events_Error::send(std::string("Can not open document: PCDM_RS_MakeFailure")); break;
110 case PCDM_RS_PermissionDenied:
111 Events_Error::send(std::string("Can not open document: PCDM_RS_PermissionDenied")); break;
112 case PCDM_RS_DriverFailure:
113 Events_Error::send(std::string("Can not open document: PCDM_RS_DriverFailure")); break;
115 Events_Error::send(std::string("Can not open document: unknown error")); break;
119 myDoc->SetUndoLimit(UNDO_LIMIT);
120 synchronizeFeatures();
125 bool Model_Document::save(const char* theFileName)
127 // create a directory in the root document if it is not yet exist
128 if (this == Model_PluginManager::get()->rootDocument().get()) {
130 CreateDirectory(theFileName, NULL);
132 mkdir(theFileName, 0x1ff);
135 // filename in the dir is id of document inside of the given directory
136 TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
137 PCDM_StoreStatus aStatus;
139 aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
141 catch (Standard_Failure) {
142 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
143 Events_Error::send(std::string("Exception in saving of document: ") + aFail->GetMessageString());
146 bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
151 case PCDM_SS_DriverFailure:
152 Events_Error::send(std::string("Can not save document: PCDM_SS_DriverFailure"));
154 case PCDM_SS_WriteFailure:
155 Events_Error::send(std::string("Can not save document: PCDM_SS_WriteFailure"));
157 case PCDM_SS_Failure:
159 Events_Error::send(std::string("Can not save document: PCDM_SS_Failure"));
163 myTransactionsAfterSave = 0;
164 if (isDone) { // save also sub-documents if any
165 std::set<std::string>::iterator aSubIter = mySubs.begin();
166 for(; aSubIter != mySubs.end() && isDone; aSubIter++)
167 isDone = subDocument(*aSubIter)->save(theFileName);
172 void Model_Document::close()
174 boost::shared_ptr<ModelAPI_PluginManager> aPM = Model_PluginManager::get();
175 if (this != aPM->rootDocument().get() &&
176 this == aPM->currentDocument().get()) {
177 aPM->setCurrentDocument(aPM->rootDocument());
180 std::set<std::string>::iterator aSubIter = mySubs.begin();
181 for(; aSubIter != mySubs.end(); aSubIter++)
182 subDocument(*aSubIter)->close();
185 /* do not close because it can be undoed
186 if (myDoc->CanClose() == CDM_CCS_OK)
188 Model_Application::getApplication()->deleteDocument(myID);
192 void Model_Document::startOperation()
194 if (myDoc->HasOpenCommand()) { // start of nested command
195 if (myNestedNum == -1) {
197 myDoc->InitDeltaCompaction();
199 myIsEmptyTr[myTransactionsAfterSave] = false;
200 myTransactionsAfterSave++;
202 } else { // start of simple command
205 // new command for all subs
206 std::set<std::string>::iterator aSubIter = mySubs.begin();
207 for(; aSubIter != mySubs.end(); aSubIter++)
208 subDocument(*aSubIter)->startOperation();
211 void Model_Document::compactNested() {
212 while(myNestedNum != -1) {
213 myTransactionsAfterSave--;
214 myIsEmptyTr.erase(myTransactionsAfterSave);
217 myIsEmptyTr[myTransactionsAfterSave] = false;
218 myTransactionsAfterSave++;
219 myDoc->PerformDeltaCompaction();
222 void Model_Document::finishOperation()
224 // just to be sure that everybody knows that changes were performed
226 if (!myDoc->HasOpenCommand() && myNestedNum != -1)
227 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
228 setCheckTransactions(false); // for nested transaction commit
229 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
230 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
231 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
232 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
233 if (!myDoc->HasOpenCommand() && myNestedNum != -1)
234 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
235 setCheckTransactions(true); // for nested transaction commit
237 if (myNestedNum != -1) // this nested transaction is owervritten
239 if (!myDoc->HasOpenCommand()) {
240 if (myNestedNum != -1) {
245 // returns false if delta is empty and no transaction was made
246 myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand() && (myNestedNum == -1);
247 myTransactionsAfterSave++;
250 // finish for all subs
251 std::set<std::string>::iterator aSubIter = mySubs.begin();
252 for(; aSubIter != mySubs.end(); aSubIter++)
253 subDocument(*aSubIter)->finishOperation();
256 void Model_Document::abortOperation()
258 if (myNestedNum > 0 && !myDoc->HasOpenCommand()) { // abort all what was done in nested
259 // first compact all nested
261 // for nested it is undo and clear redos
264 myTransactionsAfterSave--;
265 myIsEmptyTr.erase(myTransactionsAfterSave);
267 if (myNestedNum == 0) // abort only high-level
269 myDoc->AbortCommand();
271 synchronizeFeatures(true);
272 // abort for all subs
273 std::set<std::string>::iterator aSubIter = mySubs.begin();
274 for(; aSubIter != mySubs.end(); aSubIter++)
275 subDocument(*aSubIter)->abortOperation();
278 bool Model_Document::isOperation()
280 // operation is opened for all documents: no need to check subs
281 return myDoc->HasOpenCommand() == Standard_True;
284 bool Model_Document::isModified()
286 // is modified if at least one operation was commited and not undoed
287 return myTransactionsAfterSave > 0;
290 bool Model_Document::canUndo()
292 if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */)
294 // check other subs contains operation that can be undoed
295 std::set<std::string>::iterator aSubIter = mySubs.begin();
296 for(; aSubIter != mySubs.end(); aSubIter++)
297 if (subDocument(*aSubIter)->canUndo())
302 void Model_Document::undo()
304 myTransactionsAfterSave--;
305 if (myNestedNum > 0) myNestedNum--;
306 if (!myIsEmptyTr[myTransactionsAfterSave])
308 synchronizeFeatures(true);
310 std::set<std::string>::iterator aSubIter = mySubs.begin();
311 for(; aSubIter != mySubs.end(); aSubIter++)
312 subDocument(*aSubIter)->undo();
315 bool Model_Document::canRedo()
317 if (myDoc->GetAvailableRedos() > 0)
319 // check other subs contains operation that can be redoed
320 std::set<std::string>::iterator aSubIter = mySubs.begin();
321 for(; aSubIter != mySubs.end(); aSubIter++)
322 if (subDocument(*aSubIter)->canRedo())
327 void Model_Document::redo()
329 if (myNestedNum != -1) myNestedNum++;
330 if (!myIsEmptyTr[myTransactionsAfterSave])
332 myTransactionsAfterSave++;
333 synchronizeFeatures(true);
335 std::set<std::string>::iterator aSubIter = mySubs.begin();
336 for(; aSubIter != mySubs.end(); aSubIter++)
337 subDocument(*aSubIter)->redo();
340 /// Appenad to the array of references a new referenced label
341 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) {
342 Handle(TDataStd_ReferenceArray) aRefs;
343 if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
344 aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
345 aRefs->SetValue(0, theReferenced);
346 } else { // extend array by one more element
347 Handle(TDataStd_HLabelArray1) aNewArray =
348 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() + 1);
349 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
350 aNewArray->SetValue(a, aRefs->Value(a));
352 aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
353 aRefs->SetInternalArray(aNewArray);
357 FeaturePtr Model_Document::addFeature(std::string theID)
359 TDF_Label anEmptyLab;
360 FeaturePtr anEmptyFeature;
361 FeaturePtr aFeature = ModelAPI_PluginManager::get()->createFeature(theID);
362 boost::shared_ptr<Model_Document> aDocToAdd =
363 boost::dynamic_pointer_cast<Model_Document>(aFeature->documentToAdd());
365 TDF_Label aFeatureLab;
366 if (!aFeature->isAction()) {// do not add action to the data model
367 TDF_Label aFeaturesLab = aDocToAdd->featuresLabel();
368 aFeatureLab = aFeaturesLab.NewChild();
369 aDocToAdd->initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
370 // keep the feature ID to restore document later correctly
371 TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str());
372 aDocToAdd->myObjs.Bind(aFeatureLab, aFeature);
373 // store feature in the history of features array
374 if (aFeature->isInHistory()) {
375 AddToRefArray(aFeaturesLab, aFeatureLab);
378 if (!aFeature->isAction()) {// do not add action to the data model
379 // event: feature is added
380 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
381 ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
387 /// Appenad to the array of references a new referenced label.
388 /// If theIndex is not -1, removes element at thisindex, not theReferenced.
389 /// \returns the index of removed element
390 static int RemoveFromRefArray(
391 TDF_Label theArrayLab, TDF_Label theReferenced, const int theIndex = -1) {
392 int aResult = -1; // no returned
393 Handle(TDataStd_ReferenceArray) aRefs;
394 if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
395 if (aRefs->Length() == 1) { // just erase an array
396 if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
397 theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
400 } else { // reduce the array
401 Handle(TDataStd_HLabelArray1) aNewArray =
402 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() - 1);
403 int aCount = aRefs->Lower();
404 for(int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
405 if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
409 aNewArray->SetValue(aCount, aRefs->Value(a));
412 aRefs->SetInternalArray(aNewArray);
418 void Model_Document::removeFeature(FeaturePtr theFeature)
420 boost::shared_ptr<Model_Data> aData = boost::static_pointer_cast<Model_Data>(theFeature->data());
421 TDF_Label aFeatureLabel = aData->label().Father();
422 if (myObjs.IsBound(aFeatureLabel))
423 myObjs.UnBind(aFeatureLabel);
424 else return; // not found feature => do not remove
426 // erase all attributes under the label of feature
427 aFeatureLabel.ForgetAllAttributes();
428 // remove it from the references array
429 RemoveFromRefArray(featuresLabel(), aData->label());
431 // event: feature is deleted
432 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
433 // results of this feature must be redisplayed
434 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
435 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
436 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
437 for(; aRIter != aResults.cend(); aRIter++) {
438 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
439 aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
440 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
441 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), aRes->groupName());
445 FeaturePtr Model_Document::feature(TDF_Label& theLabel)
447 if (myObjs.IsBound(theLabel))
448 return myObjs.Find(theLabel);
449 return FeaturePtr(); // not found
452 ObjectPtr Model_Document::object(TDF_Label theLabel)
454 // try feature by label
455 FeaturePtr aFeature = feature(theLabel);
457 return feature(theLabel);
458 TDF_Label aFeatureLabel = theLabel.Father().Father(); // let's suppose it is result
459 aFeature = feature(aFeatureLabel);
461 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
462 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
463 for(; aRIter != aResults.cend(); aRIter++) {
464 boost::shared_ptr<Model_Data> aResData =
465 boost::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
466 if (aResData->label().Father().IsEqual(theLabel))
470 return FeaturePtr(); // not found
473 boost::shared_ptr<ModelAPI_Document> Model_Document::subDocument(std::string theDocID)
475 // just store sub-document identifier here to manage it later
476 if (mySubs.find(theDocID) == mySubs.end())
477 mySubs.insert(theDocID);
478 return Model_Application::getApplication()->getDocument(theDocID);
481 ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex)
483 if (theGroupID == ModelAPI_Feature::group()) {
484 Handle(TDataStd_ReferenceArray) aRefs;
485 if (!featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
487 if (aRefs->Lower() > theIndex || aRefs->Upper() < theIndex)
489 TDF_Label aFeatureLabel = aRefs->Value(theIndex);
490 return feature(aFeatureLabel);
492 // comment must be in any feature: it is kind
494 TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
495 for(; aLabIter.More(); aLabIter.Next()) {
496 TDF_Label aFLabel = aLabIter.Value()->Label();
497 FeaturePtr aFeature = feature(aFLabel);
498 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
499 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
500 for(; aRIter != aResults.cend(); aRIter++) {
501 if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) {
502 if (anIndex == theIndex)
513 int Model_Document::size(const std::string& theGroupID)
516 if (theGroupID == ModelAPI_Feature::group()) {
517 Handle(TDataStd_ReferenceArray) aRefs;
518 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
519 return aRefs->Length();
521 // comment must be in any feature: it is kind
522 TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
523 for(; aLabIter.More(); aLabIter.Next()) {
524 TDF_Label aFLabel = aLabIter.Value()->Label();
525 FeaturePtr aFeature = feature(aFLabel);
526 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
527 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
528 for(; aRIter != aResults.cend(); aRIter++) {
529 if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) {
535 // group is not found
539 Model_Document::Model_Document(const std::string theID)
540 : myID(theID), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format
542 myDoc->SetUndoLimit(UNDO_LIMIT);
543 myTransactionsAfterSave = 0;
545 //myDoc->SetNestedTransactionMode();
546 // to have something in the document and avoid empty doc open/save problem
547 // in transaction for nesting correct working
549 TDataStd_Integer::Set(myDoc->Main().Father(), 0);
550 myDoc->CommitCommand();
553 TDF_Label Model_Document::featuresLabel()
555 return myDoc->Main().FindChild(TAG_OBJECTS);
558 void Model_Document::setUniqueName(FeaturePtr theFeature)
560 if (!theFeature->data()->name().empty()) return; // not needed, name is already defined
561 std::string aName; // result
562 // first count all objects of such kind to start with index = count + 1
564 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
565 for(; aFIter.More(); aFIter.Next()) {
566 if (aFIter.Value()->getKind() == theFeature->getKind())
569 // generate candidate name
570 std::stringstream aNameStream;
571 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
572 aName = aNameStream.str();
573 // check this is unique, if not, increase index by 1
574 for(aFIter.Initialize(myObjs); aFIter.More(); ) {
575 FeaturePtr aFeature = aFIter.Value();
576 bool isSameName = aFeature->isInHistory() && aFeature->data()->name() == aName;
577 if (!isSameName) { // check also results to avoid same results names (actual for Parts)
578 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
579 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
580 for(; aRIter != aResults.cend(); aRIter++) {
581 isSameName = (*aRIter)->isInHistory() && (*aRIter)->data()->name() == aName;
586 std::stringstream aNameStream;
587 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
588 aName = aNameStream.str();
589 // reinitialize iterator to make sure a new name is unique
590 aFIter.Initialize(myObjs);
591 } else aFIter.Next();
593 theFeature->data()->setName(aName);
596 void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag) {
597 boost::shared_ptr<ModelAPI_Document> aThis =
598 Model_Application::getApplication()->getDocument(myID);
599 boost::shared_ptr<Model_Data> aData(new Model_Data);
600 aData->setLabel(theLab.FindChild(theTag));
601 aData->setObject(theObj);
602 theObj->setDoc(aThis);
603 theObj->setData(aData);
604 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
606 setUniqueName(aFeature); // must be before "initAttributes" because duplicate part uses name
607 aFeature->initAttributes();
611 void Model_Document::synchronizeFeatures(const bool theMarkUpdated)
613 boost::shared_ptr<ModelAPI_Document> aThis =
614 Model_Application::getApplication()->getDocument(myID);
615 // update all objects by checking are they of labels or not
616 std::set<FeaturePtr> aCheckedFeatures;
617 TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
618 for(; aLabIter.More(); aLabIter.Next()) {
619 TDF_Label aFeatureLabel = aLabIter.Value()->Label();
620 if (!myObjs.IsBound(aFeatureLabel)) { // a new feature is inserted
622 FeaturePtr aNewObj = ModelAPI_PluginManager::get()->createFeature(
623 TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
625 // this must be before "setData" to redo the sketch line correctly
626 myObjs.Bind(aFeatureLabel, aNewObj);
627 aCheckedFeatures.insert(aNewObj);
628 initData(aNewObj, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
629 aNewObj->execute(); // to restore results list
631 // event: model is updated
632 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
633 ModelAPI_EventCreator::get()->sendUpdated(aNewObj, anEvent);
634 // feature for this label is added, so go to the next label
635 } else { // nothing is changed, both iterators are incremented
636 aCheckedFeatures.insert(myObjs.Find(aFeatureLabel));
637 if (theMarkUpdated) {
638 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
639 ModelAPI_EventCreator::get()->sendUpdated(myObjs.Find(aFeatureLabel), anEvent);
643 // check all features are checked: if not => it was removed
644 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
645 while(aFIter.More()) {
646 if (aCheckedFeatures.find(aFIter.Value()) == aCheckedFeatures.end()) {
647 FeaturePtr aFeature = aFIter.Value();
648 TDF_Label aLab = aFIter.Key();
651 // event: model is updated
652 if (aFeature->isInHistory()) {
653 ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group());
655 // results of this feature must be redisplayed (hided)
656 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
657 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
658 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
659 for(; aRIter != aResults.cend(); aRIter++) {
660 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
661 aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
662 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
663 ModelAPI_EventCreator::get()->sendDeleted(aThis, aRes->groupName());
665 } else aFIter.Next();
668 // after all updates, sends a message that groups of features were created or updated
669 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
670 setCheckTransactions(false);
671 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
673 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
674 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
675 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
676 setCheckTransactions(true);
679 void Model_Document::storeResult(boost::shared_ptr<ModelAPI_Data> theFeatureData,
680 boost::shared_ptr<ModelAPI_Result> theResult, const int theResultIndex)
682 boost::shared_ptr<ModelAPI_Document> aThis =
683 Model_Application::getApplication()->getDocument(myID);
684 theResult->setDoc(aThis);
685 initData(theResult, boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->label().
686 Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1), TAG_FEATURE_ARGUMENTS);
687 if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name
688 theResult->data()->setName(theFeatureData->name());
692 boost::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction(
693 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
695 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
696 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
697 boost::shared_ptr<ModelAPI_ResultConstruction> aResult;
699 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
702 aResult = boost::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
703 storeResult(theFeatureData, aResult);
708 boost::shared_ptr<ModelAPI_ResultBody> Model_Document::createBody(
709 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
711 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
712 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
713 boost::shared_ptr<ModelAPI_ResultBody> aResult;
715 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
718 aResult = boost::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
719 storeResult(theFeatureData, aResult);
724 boost::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
725 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
727 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
728 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
729 boost::shared_ptr<ModelAPI_ResultPart> aResult;
731 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
734 aResult = boost::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
735 storeResult(theFeatureData, aResult);
740 boost::shared_ptr<ModelAPI_Feature> Model_Document::feature(
741 const boost::shared_ptr<ModelAPI_Result>& theResult)
743 boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(theResult->data());
745 TDF_Label aFeatureLab = aData->label().Father().Father().Father();
746 return feature(aFeatureLab);
751 Standard_Integer HashCode(const TDF_Label& theLab,const Standard_Integer theUpper)
753 return TDF_LabelMapHasher::HashCode(theLab, theUpper);
756 Standard_Boolean IsEqual(const TDF_Label& theLab1,const TDF_Label& theLab2)
758 return TDF_LabelMapHasher::IsEqual(theLab1, theLab2);