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>
30 # define _separator_ '\\'
32 # define _separator_ '/'
35 static const int UNDO_LIMIT = 10; // number of possible undo operations
37 static const int TAG_GENERAL = 1; // general properties tag
38 static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
39 static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump)
42 static const int TAG_FEATURE_ARGUMENTS = 1; ///< where the arguments are located
43 static const int TAG_FEATURE_RESULTS = 2; ///< where the results are located
45 /// Returns the file name of this document by the nameof directory and identifuer of a document
46 static TCollection_ExtendedString DocFileName(const char* theFileName, const std::string& theID)
48 TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
50 aPath += theID.c_str();
51 aPath += ".cbf"; // standard binary file extension
55 bool Model_Document::load(const char* theFileName)
57 Handle(Model_Application) anApp = Model_Application::getApplication();
58 if (this == Model_PluginManager::get()->rootDocument().get()) {
59 anApp->setLoadPath(theFileName);
61 TCollection_ExtendedString aPath (DocFileName(theFileName, myID));
62 PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
65 aStatus = anApp->Open(aPath, myDoc);
67 catch (Standard_Failure)
69 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
70 Events_Error::send(std::string("Exception in opening of document: ") + aFail->GetMessageString());
73 bool isError = aStatus != PCDM_RS_OK;
78 case PCDM_RS_UnknownDocument:
79 Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownDocument")); break;
80 case PCDM_RS_AlreadyRetrieved:
81 Events_Error::send(std::string("Can not open document: PCDM_RS_AlreadyRetrieved")); break;
82 case PCDM_RS_AlreadyRetrievedAndModified:
84 std::string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified"));
86 case PCDM_RS_NoDriver:
87 Events_Error::send(std::string("Can not open document: PCDM_RS_NoDriver")); break;
88 case PCDM_RS_UnknownFileDriver:
89 Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownFileDriver")); break;
90 case PCDM_RS_OpenError:
91 Events_Error::send(std::string("Can not open document: PCDM_RS_OpenError")); break;
92 case PCDM_RS_NoVersion:
93 Events_Error::send(std::string("Can not open document: PCDM_RS_NoVersion")); break;
95 Events_Error::send(std::string("Can not open document: PCDM_RS_NoModel")); break;
96 case PCDM_RS_NoDocument:
97 Events_Error::send(std::string("Can not open document: PCDM_RS_NoDocument")); break;
98 case PCDM_RS_FormatFailure:
99 Events_Error::send(std::string("Can not open document: PCDM_RS_FormatFailure")); break;
100 case PCDM_RS_TypeNotFoundInSchema:
101 Events_Error::send(std::string("Can not open document: PCDM_RS_TypeNotFoundInSchema"));
103 case PCDM_RS_UnrecognizedFileFormat:
104 Events_Error::send(std::string("Can not open document: PCDM_RS_UnrecognizedFileFormat"));
106 case PCDM_RS_MakeFailure:
107 Events_Error::send(std::string("Can not open document: PCDM_RS_MakeFailure")); break;
108 case PCDM_RS_PermissionDenied:
109 Events_Error::send(std::string("Can not open document: PCDM_RS_PermissionDenied")); break;
110 case PCDM_RS_DriverFailure:
111 Events_Error::send(std::string("Can not open document: PCDM_RS_DriverFailure")); break;
113 Events_Error::send(std::string("Can not open document: unknown error")); break;
117 myDoc->SetUndoLimit(UNDO_LIMIT);
118 synchronizeFeatures();
123 bool Model_Document::save(const char* theFileName)
125 // create a directory in the root document if it is not yet exist
126 if (this == Model_PluginManager::get()->rootDocument().get()) {
128 CreateDirectory(theFileName, NULL);
130 mkdir(theFileName, 0x1ff);
133 // filename in the dir is id of document inside of the given directory
134 TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
135 PCDM_StoreStatus aStatus;
137 aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
139 catch (Standard_Failure) {
140 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
141 Events_Error::send(std::string("Exception in saving of document: ") + aFail->GetMessageString());
144 bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
149 case PCDM_SS_DriverFailure:
150 Events_Error::send(std::string("Can not save document: PCDM_SS_DriverFailure"));
152 case PCDM_SS_WriteFailure:
153 Events_Error::send(std::string("Can not save document: PCDM_SS_WriteFailure"));
155 case PCDM_SS_Failure:
157 Events_Error::send(std::string("Can not save document: PCDM_SS_Failure"));
161 myTransactionsAfterSave = 0;
162 if (isDone) { // save also sub-documents if any
163 std::set<std::string>::iterator aSubIter = mySubs.begin();
164 for(; aSubIter != mySubs.end() && isDone; aSubIter++)
165 isDone = subDocument(*aSubIter)->save(theFileName);
170 void Model_Document::close()
172 boost::shared_ptr<ModelAPI_PluginManager> aPM = Model_PluginManager::get();
173 if (this != aPM->rootDocument().get() &&
174 this == aPM->currentDocument().get()) {
175 aPM->setCurrentDocument(aPM->rootDocument());
178 std::set<std::string>::iterator aSubIter = mySubs.begin();
179 for(; aSubIter != mySubs.end(); aSubIter++)
180 subDocument(*aSubIter)->close();
183 /* do not close because it can be undoed
184 if (myDoc->CanClose() == CDM_CCS_OK)
186 Model_Application::getApplication()->deleteDocument(myID);
190 void Model_Document::startOperation()
192 if (myDoc->HasOpenCommand()) { // start of nested command
193 if (myNestedNum == -1) {
195 myDoc->InitDeltaCompaction();
197 myIsEmptyTr[myTransactionsAfterSave] = false;
198 myTransactionsAfterSave++;
200 } else { // start of simple command
203 // new command for all subs
204 std::set<std::string>::iterator aSubIter = mySubs.begin();
205 for(; aSubIter != mySubs.end(); aSubIter++)
206 subDocument(*aSubIter)->startOperation();
209 void Model_Document::compactNested() {
210 while(myNestedNum != -1) {
211 myTransactionsAfterSave--;
212 myIsEmptyTr.erase(myTransactionsAfterSave);
215 myIsEmptyTr[myTransactionsAfterSave] = false;
216 myTransactionsAfterSave++;
217 myDoc->PerformDeltaCompaction();
220 void Model_Document::finishOperation()
222 // just to be sure that everybody knows that changes were performed
223 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
224 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
225 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
226 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
228 if (myNestedNum != -1) // this nested transaction is owervritten
230 if (!myDoc->HasOpenCommand()) {
231 if (myNestedNum != -1) {
236 // returns false if delta is empty and no transaction was made
237 myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand() && (myNestedNum == -1);
238 myTransactionsAfterSave++;
241 // finish for all subs
242 std::set<std::string>::iterator aSubIter = mySubs.begin();
243 for(; aSubIter != mySubs.end(); aSubIter++)
244 subDocument(*aSubIter)->finishOperation();
247 void Model_Document::abortOperation()
249 if (myNestedNum > 0 && !myDoc->HasOpenCommand()) { // abort all what was done in nested
250 // first compact all nested
252 // for nested it is undo and clear redos
255 myTransactionsAfterSave--;
256 myIsEmptyTr.erase(myTransactionsAfterSave);
258 if (myNestedNum == 0) // abort only high-level
260 myDoc->AbortCommand();
262 synchronizeFeatures(true);
263 // abort for all subs
264 std::set<std::string>::iterator aSubIter = mySubs.begin();
265 for(; aSubIter != mySubs.end(); aSubIter++)
266 subDocument(*aSubIter)->abortOperation();
269 bool Model_Document::isOperation()
271 // operation is opened for all documents: no need to check subs
272 return myDoc->HasOpenCommand() == Standard_True;
275 bool Model_Document::isModified()
277 // is modified if at least one operation was commited and not undoed
278 return myTransactionsAfterSave > 0;
281 bool Model_Document::canUndo()
283 if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */)
285 // check other subs contains operation that can be undoed
286 std::set<std::string>::iterator aSubIter = mySubs.begin();
287 for(; aSubIter != mySubs.end(); aSubIter++)
288 if (subDocument(*aSubIter)->canUndo())
293 void Model_Document::undo()
295 myTransactionsAfterSave--;
296 if (myNestedNum > 0) myNestedNum--;
297 if (!myIsEmptyTr[myTransactionsAfterSave])
299 synchronizeFeatures(true);
301 std::set<std::string>::iterator aSubIter = mySubs.begin();
302 for(; aSubIter != mySubs.end(); aSubIter++)
303 subDocument(*aSubIter)->undo();
306 bool Model_Document::canRedo()
308 if (myDoc->GetAvailableRedos() > 0)
310 // check other subs contains operation that can be redoed
311 std::set<std::string>::iterator aSubIter = mySubs.begin();
312 for(; aSubIter != mySubs.end(); aSubIter++)
313 if (subDocument(*aSubIter)->canRedo())
318 void Model_Document::redo()
320 if (myNestedNum != -1) myNestedNum++;
321 if (!myIsEmptyTr[myTransactionsAfterSave])
323 myTransactionsAfterSave++;
324 synchronizeFeatures(true);
326 std::set<std::string>::iterator aSubIter = mySubs.begin();
327 for(; aSubIter != mySubs.end(); aSubIter++)
328 subDocument(*aSubIter)->redo();
331 /// Appenad to the array of references a new referenced label
332 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) {
333 Handle(TDataStd_ReferenceArray) aRefs;
334 if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
335 aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
336 aRefs->SetValue(0, theReferenced);
337 } else { // extend array by one more element
338 Handle(TDataStd_HLabelArray1) aNewArray =
339 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() + 1);
340 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
341 aNewArray->SetValue(a, aRefs->Value(a));
343 aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
344 aRefs->SetInternalArray(aNewArray);
348 FeaturePtr Model_Document::addFeature(std::string theID)
350 TDF_Label anEmptyLab;
351 FeaturePtr anEmptyFeature;
352 FeaturePtr aFeature = ModelAPI_PluginManager::get()->createFeature(theID);
353 boost::shared_ptr<Model_Document> aDocToAdd =
354 boost::dynamic_pointer_cast<Model_Document>(aFeature->documentToAdd());
356 TDF_Label aFeatureLab;
357 if (!aFeature->isAction()) {// do not add action to the data model
358 TDF_Label aFeaturesLab = aDocToAdd->groupLabel(ModelAPI_Feature::group());
359 aFeatureLab = aFeaturesLab.NewChild();
360 aDocToAdd->initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
361 // keep the feature ID to restore document later correctly
362 TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str());
363 aDocToAdd->setUniqueName(aFeature);
364 aDocToAdd->myObjs[ModelAPI_Feature::group()].push_back(aFeature);
365 // store feature in the history of features array
366 if (aFeature->isInHistory()) {
367 AddToRefArray(aFeaturesLab, aFeatureLab);
370 if (!aFeature->isAction()) {// do not add action to the data model
371 // event: feature is added
372 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
373 ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
379 /// Appenad to the array of references a new referenced label.
380 /// If theIndex is not -1, removes element at thisindex, not theReferenced.
381 /// \returns the index of removed element
382 static int RemoveFromRefArray(
383 TDF_Label theArrayLab, TDF_Label theReferenced, const int theIndex = -1) {
384 int aResult = -1; // no returned
385 Handle(TDataStd_ReferenceArray) aRefs;
386 if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
387 if (aRefs->Length() == 1) { // just erase an array
388 if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
389 theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
392 } else { // reduce the array
393 Handle(TDataStd_HLabelArray1) aNewArray =
394 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() - 1);
395 int aCount = aRefs->Lower();
396 for(int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
397 if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
401 aNewArray->SetValue(aCount, aRefs->Value(a));
404 aRefs->SetInternalArray(aNewArray);
410 void Model_Document::removeFeature(FeaturePtr theFeature)
412 boost::shared_ptr<Model_Data> aData = boost::static_pointer_cast<Model_Data>(theFeature->data());
413 TDF_Label aFeatureLabel = aData->label().Father();
414 // remove feature from the myObjects list
415 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
416 std::vector<ObjectPtr>::iterator anIter = aVec.begin();
417 while(anIter != aVec.end()) {
418 if (*anIter == theFeature) {
419 anIter = aVec.erase(anIter);
424 // erase all attributes under the label of feature
425 aFeatureLabel.ForgetAllAttributes();
426 // remove it from the references array
427 RemoveFromRefArray(groupLabel(ModelAPI_Feature::group()), aData->label());
429 // event: feature is deleted
430 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
431 // results of this feature must be redisplayed
432 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
433 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
434 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
435 for(; aRIter != aResults.cend(); aRIter++) {
436 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
437 aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
438 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
439 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), aRes->groupName());
443 /// returns the object group name by the object label
444 static std::string groupName(TDF_Label theObjectLabel) {
445 TDF_Label aGroupLab = theObjectLabel.Father();
446 Handle(TDataStd_Comment) aComment;
447 if (aGroupLab.FindAttribute(TDataStd_Comment::GetID(), aComment))
448 return std::string(TCollection_AsciiString(aComment->Get()).ToCString());
449 return ""; // not found
452 FeaturePtr Model_Document::feature(TDF_Label& theLabel)
454 // iterate all features, may be optimized later by keeping labels-map
455 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
456 std::vector<ObjectPtr>::iterator aFIter = aVec.begin();
457 for(; aFIter != aVec.end(); aFIter++) {
458 boost::shared_ptr<Model_Data> aData =
459 boost::dynamic_pointer_cast<Model_Data>((*aFIter)->data());
460 if (aData->label().IsEqual(theLabel))
461 return boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
463 return FeaturePtr(); // not found
466 ObjectPtr Model_Document::object(TDF_Label& theLabel)
468 // iterate all features, may be optimized later by keeping labels-map
469 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
470 std::vector<ObjectPtr>::iterator aFIter = aVec.begin();
471 for(; aFIter != aVec.end(); aFIter++) {
472 boost::shared_ptr<Model_Data> aData =
473 boost::dynamic_pointer_cast<Model_Data>((*aFIter)->data());
474 if (aData->label().IsEqual(theLabel))
476 std::list<boost::shared_ptr<ModelAPI_Result> >& aResults =
477 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
478 std::list<boost::shared_ptr<ModelAPI_Result> >::iterator aRIter = aResults.begin();
479 for(; aRIter != aResults.end(); aRIter++) {
480 boost::shared_ptr<Model_Data> aResData =
481 boost::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
482 if (aResData->label().IsEqual(theLabel))
486 return FeaturePtr(); // not found
489 boost::shared_ptr<ModelAPI_Document> Model_Document::subDocument(std::string theDocID)
491 // just store sub-document identifier here to manage it later
492 if (mySubs.find(theDocID) == mySubs.end())
493 mySubs.insert(theDocID);
494 return Model_Application::getApplication()->getDocument(theDocID);
497 ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex)
499 if (theGroupID == ModelAPI_Feature::group()) {
500 // features may be not in history but in the myObjs, so, iterate all
502 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
503 myObjs.find(ModelAPI_Feature::group());
504 if (aFind != myObjs.end()) {
505 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
506 for(; aFIter != aFind->second.end(); aFIter++) {
507 if ((*aFIter)->isInHistory()) {
508 if (theIndex == anIndex)
515 // iterate all features in order to find the needed result
516 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
517 myObjs.find(ModelAPI_Feature::group());
518 if (aFind != myObjs.end()) {
519 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
520 for(int anIndex = 0; aFIter != aFind->second.end(); aFIter++) {
521 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults =
522 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
523 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
524 for(; aRIter != aResults.cend(); aRIter++) {
525 if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) {
526 if (anIndex == theIndex)
538 int Model_Document::size(const std::string& theGroupID)
541 if (theGroupID == ModelAPI_Feature::group()) {
542 // features may be not in history but in the myObjs, so, iterate all
543 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
544 myObjs.find(ModelAPI_Feature::group());
545 if (aFind != myObjs.end()) {
546 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
547 for(; aFIter != aFind->second.end(); aFIter++) {
548 if ((*aFIter)->isInHistory()) {
554 // iterate all features in order to find the needed result
555 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
556 myObjs.find(ModelAPI_Feature::group());
557 if (aFind != myObjs.end()) {
558 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
559 for(; aFIter != aFind->second.end(); aFIter++) {
560 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults =
561 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
562 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
563 for(; aRIter != aResults.cend(); aRIter++) {
564 if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) {
571 // group is not found
575 Model_Document::Model_Document(const std::string theID)
576 : myID(theID), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format
578 myDoc->SetUndoLimit(UNDO_LIMIT);
579 myTransactionsAfterSave = 0;
581 //myDoc->SetNestedTransactionMode();
582 // to have something in the document and avoid empty doc open/save problem
583 // in transaction for nesting correct working
585 TDataStd_Integer::Set(myDoc->Main().Father(), 0);
586 myDoc->CommitCommand();
589 TDF_Label Model_Document::groupLabel(const std::string theGroup)
591 // searching for existing
592 TCollection_ExtendedString aGroup(theGroup.c_str());
593 TDF_ChildIDIterator aGroupIter(myDoc->Main().FindChild(TAG_OBJECTS), TDataStd_Comment::GetID());
594 for(; aGroupIter.More(); aGroupIter.Next()) {
595 Handle(TDataStd_Comment) aName = Handle(TDataStd_Comment)::DownCast(aGroupIter.Value());
596 if (aName->Get() == aGroup)
597 return aGroupIter.Value()->Label();
600 TDF_Label aNew = myDoc->Main().FindChild(TAG_OBJECTS).NewChild();
601 TDataStd_Comment::Set(aNew, aGroup);
605 void Model_Document::setUniqueName(FeaturePtr theFeature)
607 std::string aName; // result
608 // first count all objects of such kind to start with index = count + 1
609 int a, aNumObjects = 0;
610 int aSize = myObjs.find(ModelAPI_Feature::group()) == myObjs.end() ?
611 0 : myObjs[ModelAPI_Feature::group()].size();
612 for(a = 0; a < aSize; a++) {
613 if (boost::dynamic_pointer_cast<ModelAPI_Feature>(myObjs[ModelAPI_Feature::group()][a])->
614 getKind() == theFeature->getKind())
617 // generate candidate name
618 std::stringstream aNameStream;
619 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
620 aName = aNameStream.str();
621 // check this is unique, if not, increase index by 1
622 for(a = 0; a < aSize;) {
623 FeaturePtr aFeature =
624 boost::dynamic_pointer_cast<ModelAPI_Feature>(myObjs[ModelAPI_Feature::group()][a]);
625 bool isSameName = aFeature->isInHistory() && aFeature->data()->name() == aName;
626 if (!isSameName) { // check also results to avoid same results names (actual for Parts)
627 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
628 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
629 for(; aRIter != aResults.cend(); aRIter++) {
630 isSameName = (*aRIter)->isInHistory() && (*aRIter)->data()->name() == aName;
635 std::stringstream aNameStream;
636 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
637 aName = aNameStream.str();
638 // reinitialize iterator to make sure a new name is unique
642 theFeature->data()->setName(aName);
645 void Model_Document::initData(ObjectPtr theObj, TDF_Label& theLab, const int theTag) {
646 boost::shared_ptr<ModelAPI_Document> aThis =
647 Model_Application::getApplication()->getDocument(myID);
648 boost::shared_ptr<Model_Data> aData(new Model_Data);
649 aData->setLabel(theLab.FindChild(theTag + 1));
650 aData->setObject(theObj);
651 theObj->setDoc(aThis);
652 theObj->setData(aData);
653 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
654 if (aFeature) aFeature->initAttributes();
657 void Model_Document::synchronizeFeatures(const bool theMarkUpdated)
659 boost::shared_ptr<ModelAPI_Document> aThis =
660 Model_Application::getApplication()->getDocument(myID);
661 // update all objects: iterate from the end: as they appeared in the list
662 std::map<std::string, std::vector<ObjectPtr> >::reverse_iterator aGroupIter = myObjs.rbegin();
663 for(; aGroupIter != myObjs.rend(); aGroupIter++) {
664 std::vector<ObjectPtr>::iterator anObjIter = aGroupIter->second.begin();
665 // and in parallel iterate labels of features
666 const std::string& aGroupName = aGroupIter->first;
667 TDF_ChildIDIterator aLabIter(groupLabel(aGroupName), TDataStd_Comment::GetID());
668 while(anObjIter != aGroupIter->second.end() || aLabIter.More()) {
669 static const int INFINITE_TAG = INT_MAX; // no label means that it exists somwhere in infinite
670 int aFeatureTag = INFINITE_TAG;
671 if (anObjIter != aGroupIter->second.end()) { // existing tag for feature
672 boost::shared_ptr<Model_Data> aData =
673 boost::dynamic_pointer_cast<Model_Data>((*anObjIter)->data());
674 aFeatureTag = aData->label().Tag();
676 int aDSTag = INFINITE_TAG;
677 if (aLabIter.More()) { // next label in DS is existing
678 aDSTag = aLabIter.Value()->Label().Tag();
680 if (aDSTag > aFeatureTag) { // feature is removed
681 ObjectPtr anObj = *anObjIter;
682 anObjIter = aGroupIter->second.erase(anObjIter);
683 // event: model is updated
684 if (anObj->isInHistory()) {
685 ModelAPI_EventCreator::get()->sendDeleted(aThis, aGroupName);
687 // results of this feature must be redisplayed (hided)
688 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
689 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = boost::dynamic_pointer_cast<ModelAPI_Feature>(anObj)->results();
690 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
691 for(; aRIter != aResults.cend(); aRIter++) {
692 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
693 aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
694 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
695 ModelAPI_EventCreator::get()->sendDeleted(aThis, aRes->groupName());
697 } else if (aDSTag < aFeatureTag) { // a new feature is inserted
699 TDF_Label aLab = aLabIter.Value()->Label();
700 ObjectPtr aNewObj = ModelAPI_PluginManager::get()->createFeature(
701 TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
703 // this must be before "setData" to redo the sketch line correctly
704 if (anObjIter == aGroupIter->second.end()) {
705 aGroupIter->second.push_back(aNewObj);
706 anObjIter = aGroupIter->second.end();
709 aGroupIter->second.insert(anObjIter, aNewObj);
711 initData(aNewObj, aLab, TAG_FEATURE_ARGUMENTS);
713 // event: model is updated
714 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
715 ModelAPI_EventCreator::get()->sendUpdated(aNewObj, anEvent);
716 // feature for this label is added, so go to the next label
718 } else { // nothing is changed, both iterators are incremented
719 if (theMarkUpdated) {
720 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
721 ModelAPI_EventCreator::get()->sendUpdated(*anObjIter, anEvent);
728 // after all updates, sends a message that groups of features were created or updated
729 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
730 setCheckTransactions(false);
731 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
733 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
734 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
735 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
736 setCheckTransactions(true);
739 void Model_Document::storeResult(boost::shared_ptr<ModelAPI_Data> theFeatureData,
740 boost::shared_ptr<ModelAPI_Result> theResult, const int theResultIndex)
742 boost::shared_ptr<ModelAPI_Document> aThis =
743 Model_Application::getApplication()->getDocument(myID);
744 theResult->setDoc(aThis);
745 initData(theResult, boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
746 label().Father().FindChild(TAG_FEATURE_RESULTS), theResultIndex);
747 if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name
748 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
749 ModelAPI_EventCreator::get()->sendUpdated(theResult, anEvent);
750 theResult->data()->setName(theFeatureData->name());
754 boost::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction(
755 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
757 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
758 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
759 boost::shared_ptr<ModelAPI_ResultConstruction> aResult;
761 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
764 aResult = boost::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
765 storeResult(theFeatureData, aResult);
770 boost::shared_ptr<ModelAPI_ResultBody> Model_Document::createBody(
771 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
773 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
774 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
775 boost::shared_ptr<ModelAPI_ResultBody> aResult;
777 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
780 aResult = boost::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
781 storeResult(theFeatureData, aResult);
786 boost::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
787 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
789 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
790 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
791 boost::shared_ptr<ModelAPI_ResultPart> aResult;
793 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
796 aResult = boost::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
797 storeResult(theFeatureData, aResult);
802 boost::shared_ptr<ModelAPI_Feature> Model_Document::feature(
803 const boost::shared_ptr<ModelAPI_Result>& theResult)
805 // iterate all features in order to find the needed result
806 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
807 myObjs.find(ModelAPI_Feature::group());
808 if (aFind != myObjs.end()) {
809 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
810 for(; aFIter != aFind->second.end(); aFIter++) {
811 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
812 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
813 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
814 for(; aRIter != aResults.cend(); aRIter++) {
815 if (*aRIter == theResult) {