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_Label.hxx>
25 #include <boost/shared_ptr.hpp>
33 # define _separator_ '\\'
35 # define _separator_ '/'
38 static const int UNDO_LIMIT = 10; // number of possible undo operations
40 static const int TAG_GENERAL = 1; // general properties tag
41 static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
42 static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump)
45 static const int TAG_FEATURE_ARGUMENTS = 1; ///< where the arguments are located
46 static const int TAG_FEATURE_RESULTS = 2; ///< where the results are located
48 /// Returns the file name of this document by the nameof directory and identifuer of a document
49 static TCollection_ExtendedString DocFileName(const char* theFileName, const std::string& theID)
51 TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
53 aPath += theID.c_str();
54 aPath += ".cbf"; // standard binary file extension
58 bool Model_Document::load(const char* theFileName)
60 Handle(Model_Application) anApp = Model_Application::getApplication();
61 if (this == Model_PluginManager::get()->rootDocument().get()) {
62 anApp->setLoadPath(theFileName);
64 TCollection_ExtendedString aPath (DocFileName(theFileName, myID));
65 PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
68 aStatus = anApp->Open(aPath, myDoc);
70 catch (Standard_Failure)
72 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
73 Events_Error::send(std::string("Exception in opening of document: ") + aFail->GetMessageString());
76 bool isError = aStatus != PCDM_RS_OK;
81 case PCDM_RS_UnknownDocument:
82 Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownDocument")); break;
83 case PCDM_RS_AlreadyRetrieved:
84 Events_Error::send(std::string("Can not open document: PCDM_RS_AlreadyRetrieved")); break;
85 case PCDM_RS_AlreadyRetrievedAndModified:
87 std::string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified"));
89 case PCDM_RS_NoDriver:
90 Events_Error::send(std::string("Can not open document: PCDM_RS_NoDriver")); break;
91 case PCDM_RS_UnknownFileDriver:
92 Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownFileDriver")); break;
93 case PCDM_RS_OpenError:
94 Events_Error::send(std::string("Can not open document: PCDM_RS_OpenError")); break;
95 case PCDM_RS_NoVersion:
96 Events_Error::send(std::string("Can not open document: PCDM_RS_NoVersion")); break;
98 Events_Error::send(std::string("Can not open document: PCDM_RS_NoModel")); break;
99 case PCDM_RS_NoDocument:
100 Events_Error::send(std::string("Can not open document: PCDM_RS_NoDocument")); break;
101 case PCDM_RS_FormatFailure:
102 Events_Error::send(std::string("Can not open document: PCDM_RS_FormatFailure")); break;
103 case PCDM_RS_TypeNotFoundInSchema:
104 Events_Error::send(std::string("Can not open document: PCDM_RS_TypeNotFoundInSchema"));
106 case PCDM_RS_UnrecognizedFileFormat:
107 Events_Error::send(std::string("Can not open document: PCDM_RS_UnrecognizedFileFormat"));
109 case PCDM_RS_MakeFailure:
110 Events_Error::send(std::string("Can not open document: PCDM_RS_MakeFailure")); break;
111 case PCDM_RS_PermissionDenied:
112 Events_Error::send(std::string("Can not open document: PCDM_RS_PermissionDenied")); break;
113 case PCDM_RS_DriverFailure:
114 Events_Error::send(std::string("Can not open document: PCDM_RS_DriverFailure")); break;
116 Events_Error::send(std::string("Can not open document: unknown error")); break;
120 myDoc->SetUndoLimit(UNDO_LIMIT);
121 synchronizeFeatures();
126 bool Model_Document::save(const char* theFileName)
128 // create a directory in the root document if it is not yet exist
129 if (this == Model_PluginManager::get()->rootDocument().get()) {
131 CreateDirectory(theFileName, NULL);
133 mkdir(theFileName, 0x1ff);
136 // filename in the dir is id of document inside of the given directory
137 TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
138 PCDM_StoreStatus aStatus;
140 aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
142 catch (Standard_Failure) {
143 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
144 Events_Error::send(std::string("Exception in saving of document: ") + aFail->GetMessageString());
147 bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
152 case PCDM_SS_DriverFailure:
153 Events_Error::send(std::string("Can not save document: PCDM_SS_DriverFailure"));
155 case PCDM_SS_WriteFailure:
156 Events_Error::send(std::string("Can not save document: PCDM_SS_WriteFailure"));
158 case PCDM_SS_Failure:
160 Events_Error::send(std::string("Can not save document: PCDM_SS_Failure"));
164 myTransactionsAfterSave = 0;
165 if (isDone) { // save also sub-documents if any
166 std::set<std::string>::iterator aSubIter = mySubs.begin();
167 for(; aSubIter != mySubs.end() && isDone; aSubIter++)
168 isDone = subDocument(*aSubIter)->save(theFileName);
173 void Model_Document::close()
175 boost::shared_ptr<ModelAPI_PluginManager> aPM = Model_PluginManager::get();
176 if (this != aPM->rootDocument().get() &&
177 this == aPM->currentDocument().get()) {
178 aPM->setCurrentDocument(aPM->rootDocument());
181 std::set<std::string>::iterator aSubIter = mySubs.begin();
182 for(; aSubIter != mySubs.end(); aSubIter++)
183 subDocument(*aSubIter)->close();
186 /* do not close because it can be undoed
187 if (myDoc->CanClose() == CDM_CCS_OK)
189 Model_Application::getApplication()->deleteDocument(myID);
193 void Model_Document::startOperation()
195 if (myDoc->HasOpenCommand()) { // start of nested command
196 if (myNestedNum == -1) {
198 myDoc->InitDeltaCompaction();
200 myIsEmptyTr[myTransactionsAfterSave] = false;
201 myTransactionsAfterSave++;
203 } else { // start of simple command
206 // new command for all subs
207 std::set<std::string>::iterator aSubIter = mySubs.begin();
208 for(; aSubIter != mySubs.end(); aSubIter++)
209 subDocument(*aSubIter)->startOperation();
212 void Model_Document::compactNested() {
213 while(myNestedNum != -1) {
214 myTransactionsAfterSave--;
215 myIsEmptyTr.erase(myTransactionsAfterSave);
218 myIsEmptyTr[myTransactionsAfterSave] = false;
219 myTransactionsAfterSave++;
220 myDoc->PerformDeltaCompaction();
223 void Model_Document::finishOperation()
225 // just to be sure that everybody knows that changes were performed
226 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
227 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
228 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
229 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
231 if (myNestedNum != -1) // this nested transaction is owervritten
233 if (!myDoc->HasOpenCommand()) {
234 if (myNestedNum != -1) {
239 // returns false if delta is empty and no transaction was made
240 myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand() && (myNestedNum == -1);
241 myTransactionsAfterSave++;
244 // finish for all subs
245 std::set<std::string>::iterator aSubIter = mySubs.begin();
246 for(; aSubIter != mySubs.end(); aSubIter++)
247 subDocument(*aSubIter)->finishOperation();
250 void Model_Document::abortOperation()
252 if (myNestedNum > 0 && !myDoc->HasOpenCommand()) { // abort all what was done in nested
253 // first compact all nested
255 // for nested it is undo and clear redos
258 myTransactionsAfterSave--;
259 myIsEmptyTr.erase(myTransactionsAfterSave);
261 if (myNestedNum == 0) // abort only high-level
263 myDoc->AbortCommand();
265 synchronizeFeatures(true);
266 // abort for all subs
267 std::set<std::string>::iterator aSubIter = mySubs.begin();
268 for(; aSubIter != mySubs.end(); aSubIter++)
269 subDocument(*aSubIter)->abortOperation();
272 bool Model_Document::isOperation()
274 // operation is opened for all documents: no need to check subs
275 return myDoc->HasOpenCommand() == Standard_True;
278 bool Model_Document::isModified()
280 // is modified if at least one operation was commited and not undoed
281 return myTransactionsAfterSave > 0;
284 bool Model_Document::canUndo()
286 if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */)
288 // check other subs contains operation that can be undoed
289 std::set<std::string>::iterator aSubIter = mySubs.begin();
290 for(; aSubIter != mySubs.end(); aSubIter++)
291 if (subDocument(*aSubIter)->canUndo())
296 void Model_Document::undo()
298 myTransactionsAfterSave--;
299 if (myNestedNum > 0) myNestedNum--;
300 if (!myIsEmptyTr[myTransactionsAfterSave])
302 synchronizeFeatures(true);
304 std::set<std::string>::iterator aSubIter = mySubs.begin();
305 for(; aSubIter != mySubs.end(); aSubIter++)
306 subDocument(*aSubIter)->undo();
309 bool Model_Document::canRedo()
311 if (myDoc->GetAvailableRedos() > 0)
313 // check other subs contains operation that can be redoed
314 std::set<std::string>::iterator aSubIter = mySubs.begin();
315 for(; aSubIter != mySubs.end(); aSubIter++)
316 if (subDocument(*aSubIter)->canRedo())
321 void Model_Document::redo()
323 if (myNestedNum != -1) myNestedNum++;
324 if (!myIsEmptyTr[myTransactionsAfterSave])
326 myTransactionsAfterSave++;
327 synchronizeFeatures(true);
329 std::set<std::string>::iterator aSubIter = mySubs.begin();
330 for(; aSubIter != mySubs.end(); aSubIter++)
331 subDocument(*aSubIter)->redo();
334 /// Appenad to the array of references a new referenced label
335 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) {
336 Handle(TDataStd_ReferenceArray) aRefs;
337 if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
338 aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
339 aRefs->SetValue(0, theReferenced);
340 } else { // extend array by one more element
341 Handle(TDataStd_HLabelArray1) aNewArray =
342 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() + 1);
343 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
344 aNewArray->SetValue(a, aRefs->Value(a));
346 aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
347 aRefs->SetInternalArray(aNewArray);
351 FeaturePtr Model_Document::addFeature(std::string theID)
353 TDF_Label anEmptyLab;
354 FeaturePtr anEmptyFeature;
355 FeaturePtr aFeature = ModelAPI_PluginManager::get()->createFeature(theID);
356 boost::shared_ptr<Model_Document> aDocToAdd =
357 boost::dynamic_pointer_cast<Model_Document>(aFeature->documentToAdd());
359 TDF_Label aFeatureLab;
360 if (!aFeature->isAction()) {// do not add action to the data model
361 TDF_Label aFeaturesLab = aDocToAdd->groupLabel(ModelAPI_Feature::group());
362 aFeatureLab = aFeaturesLab.NewChild();
363 aDocToAdd->initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
364 // keep the feature ID to restore document later correctly
365 TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str());
366 aDocToAdd->setUniqueName(aFeature);
367 aDocToAdd->myObjs[ModelAPI_Feature::group()].push_back(aFeature);
368 // store feature in the history of features array
369 if (aFeature->isInHistory()) {
370 AddToRefArray(aFeaturesLab, aFeatureLab);
373 if (!aFeature->isAction()) {// do not add action to the data model
374 // event: feature is added
375 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
376 ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
382 /// Appenad to the array of references a new referenced label.
383 /// If theIndex is not -1, removes element at thisindex, not theReferenced.
384 /// \returns the index of removed element
385 static int RemoveFromRefArray(
386 TDF_Label theArrayLab, TDF_Label theReferenced, const int theIndex = -1) {
387 int aResult = -1; // no returned
388 Handle(TDataStd_ReferenceArray) aRefs;
389 if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
390 if (aRefs->Length() == 1) { // just erase an array
391 if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
392 theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
395 } else { // reduce the array
396 Handle(TDataStd_HLabelArray1) aNewArray =
397 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() - 1);
398 int aCount = aRefs->Lower();
399 for(int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
400 if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
404 aNewArray->SetValue(aCount, aRefs->Value(a));
407 aRefs->SetInternalArray(aNewArray);
413 void Model_Document::removeFeature(FeaturePtr theFeature)
415 boost::shared_ptr<Model_Data> aData = boost::static_pointer_cast<Model_Data>(theFeature->data());
416 TDF_Label aFeatureLabel = aData->label().Father();
417 // remove feature from the myObjects list
418 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
419 std::vector<ObjectPtr>::iterator anIter = aVec.begin();
420 while(anIter != aVec.end()) {
421 if (*anIter == theFeature) {
422 anIter = aVec.erase(anIter);
427 // erase all attributes under the label of feature
428 aFeatureLabel.ForgetAllAttributes();
429 // remove it from the references array
430 RemoveFromRefArray(groupLabel(ModelAPI_Feature::group()), aData->label());
432 // event: feature is deleted
433 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
434 // results of this feature must be redisplayed
435 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
436 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
437 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
438 for(; aRIter != aResults.cend(); aRIter++) {
439 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
440 aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
441 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
442 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), aRes->groupName());
446 /// returns the object group name by the object label
447 static std::string groupName(TDF_Label theObjectLabel) {
448 TDF_Label aGroupLab = theObjectLabel.Father();
449 Handle(TDataStd_Comment) aComment;
450 if (aGroupLab.FindAttribute(TDataStd_Comment::GetID(), aComment))
451 return std::string(TCollection_AsciiString(aComment->Get()).ToCString());
452 return ""; // not found
455 FeaturePtr Model_Document::feature(TDF_Label& theLabel)
457 // iterate all features, may be optimized later by keeping labels-map
458 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
459 std::vector<ObjectPtr>::iterator aFIter = aVec.begin();
460 for(; aFIter != aVec.end(); aFIter++) {
461 boost::shared_ptr<Model_Data> aData =
462 boost::dynamic_pointer_cast<Model_Data>((*aFIter)->data());
463 if (aData->label().IsEqual(theLabel))
464 return boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
466 return FeaturePtr(); // not found
469 ObjectPtr Model_Document::object(TDF_Label theLabel)
471 // iterate all features, may be optimized later by keeping labels-map
472 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
473 std::vector<ObjectPtr>::iterator aFIter = aVec.begin();
474 for(; aFIter != aVec.end(); aFIter++) {
475 boost::shared_ptr<Model_Data> aData =
476 boost::dynamic_pointer_cast<Model_Data>((*aFIter)->data());
477 if (aData->label().IsEqual(theLabel))
479 std::list<boost::shared_ptr<ModelAPI_Result> >& aResults =
480 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
481 std::list<boost::shared_ptr<ModelAPI_Result> >::iterator aRIter = aResults.begin();
482 for(; aRIter != aResults.end(); aRIter++) {
483 boost::shared_ptr<Model_Data> aResData =
484 boost::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
485 if (aResData->label().IsEqual(theLabel))
489 return FeaturePtr(); // not found
492 boost::shared_ptr<ModelAPI_Document> Model_Document::subDocument(std::string theDocID)
494 // just store sub-document identifier here to manage it later
495 if (mySubs.find(theDocID) == mySubs.end())
496 mySubs.insert(theDocID);
497 return Model_Application::getApplication()->getDocument(theDocID);
500 ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex)
502 if (theGroupID == ModelAPI_Feature::group()) {
503 // features may be not in history but in the myObjs, so, iterate all
505 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
506 myObjs.find(ModelAPI_Feature::group());
507 if (aFind != myObjs.end()) {
508 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
509 for(; aFIter != aFind->second.end(); aFIter++) {
510 if ((*aFIter)->isInHistory()) {
511 if (theIndex == anIndex)
518 // iterate all features in order to find the needed result
519 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
520 myObjs.find(ModelAPI_Feature::group());
521 if (aFind != myObjs.end()) {
522 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
523 for(int anIndex = 0; aFIter != aFind->second.end(); aFIter++) {
524 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults =
525 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
526 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
527 for(; aRIter != aResults.cend(); aRIter++) {
528 if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) {
529 if (anIndex == theIndex)
541 int Model_Document::size(const std::string& theGroupID)
544 if (theGroupID == ModelAPI_Feature::group()) {
545 // features may be not in history but in the myObjs, so, iterate all
546 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
547 myObjs.find(ModelAPI_Feature::group());
548 if (aFind != myObjs.end()) {
549 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
550 for(; aFIter != aFind->second.end(); aFIter++) {
551 if ((*aFIter)->isInHistory()) {
557 // iterate all features in order to find the needed result
558 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
559 myObjs.find(ModelAPI_Feature::group());
560 if (aFind != myObjs.end()) {
561 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
562 for(; aFIter != aFind->second.end(); aFIter++) {
563 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults =
564 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
565 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
566 for(; aRIter != aResults.cend(); aRIter++) {
567 if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) {
574 // group is not found
578 Model_Document::Model_Document(const std::string theID)
579 : myID(theID), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format
581 myDoc->SetUndoLimit(UNDO_LIMIT);
582 myTransactionsAfterSave = 0;
584 //myDoc->SetNestedTransactionMode();
585 // to have something in the document and avoid empty doc open/save problem
586 // in transaction for nesting correct working
588 TDataStd_Integer::Set(myDoc->Main().Father(), 0);
589 myDoc->CommitCommand();
592 TDF_Label Model_Document::groupLabel(const std::string theGroup)
594 // searching for existing
595 TCollection_ExtendedString aGroup(theGroup.c_str());
596 TDF_ChildIDIterator aGroupIter(myDoc->Main().FindChild(TAG_OBJECTS), TDataStd_Comment::GetID());
597 for(; aGroupIter.More(); aGroupIter.Next()) {
598 Handle(TDataStd_Comment) aName = Handle(TDataStd_Comment)::DownCast(aGroupIter.Value());
599 if (aName->Get() == aGroup)
600 return aGroupIter.Value()->Label();
603 TDF_Label aNew = myDoc->Main().FindChild(TAG_OBJECTS).NewChild();
604 TDataStd_Comment::Set(aNew, aGroup);
608 void Model_Document::setUniqueName(FeaturePtr theFeature)
610 std::string aName; // result
611 // first count all objects of such kind to start with index = count + 1
612 int a, aNumObjects = 0;
613 int aSize = myObjs.find(ModelAPI_Feature::group()) == myObjs.end() ?
614 0 : myObjs[ModelAPI_Feature::group()].size();
615 for(a = 0; a < aSize; a++) {
616 if (boost::dynamic_pointer_cast<ModelAPI_Feature>(myObjs[ModelAPI_Feature::group()][a])->
617 getKind() == theFeature->getKind())
620 // generate candidate name
621 std::stringstream aNameStream;
622 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
623 aName = aNameStream.str();
624 // check this is unique, if not, increase index by 1
625 for(a = 0; a < aSize;) {
626 FeaturePtr aFeature =
627 boost::dynamic_pointer_cast<ModelAPI_Feature>(myObjs[ModelAPI_Feature::group()][a]);
628 bool isSameName = aFeature->isInHistory() && aFeature->data()->name() == aName;
629 if (!isSameName) { // check also results to avoid same results names (actual for Parts)
630 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
631 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
632 for(; aRIter != aResults.cend(); aRIter++) {
633 isSameName = (*aRIter)->isInHistory() && (*aRIter)->data()->name() == aName;
638 std::stringstream aNameStream;
639 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
640 aName = aNameStream.str();
641 // reinitialize iterator to make sure a new name is unique
645 theFeature->data()->setName(aName);
648 void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag) {
649 boost::shared_ptr<ModelAPI_Document> aThis =
650 Model_Application::getApplication()->getDocument(myID);
651 boost::shared_ptr<Model_Data> aData(new Model_Data);
652 aData->setLabel(theLab.FindChild(theTag + 1));
653 aData->setObject(theObj);
654 theObj->setDoc(aThis);
655 theObj->setData(aData);
656 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
657 if (aFeature) aFeature->initAttributes();
660 void Model_Document::synchronizeFeatures(const bool theMarkUpdated)
662 boost::shared_ptr<ModelAPI_Document> aThis =
663 Model_Application::getApplication()->getDocument(myID);
664 // update all objects: iterate from the end: as they appeared in the list
665 std::map<std::string, std::vector<ObjectPtr> >::reverse_iterator aGroupIter = myObjs.rbegin();
666 for(; aGroupIter != myObjs.rend(); aGroupIter++) {
667 std::vector<ObjectPtr>::iterator anObjIter = aGroupIter->second.begin();
668 // and in parallel iterate labels of features+
669 const std::string& aGroupName = aGroupIter->first;
670 TDF_ChildIDIterator aLabIter(groupLabel(aGroupName), TDataStd_Comment::GetID());
671 while(anObjIter != aGroupIter->second.end() || aLabIter.More()) {
672 static const int INFINITE_TAG = INT_MAX; // no label means that it exists somwhere in infinite
673 int aFeatureTag = INFINITE_TAG;
674 if (anObjIter != aGroupIter->second.end()) { // existing tag for feature
675 boost::shared_ptr<Model_Data> aData =
676 boost::dynamic_pointer_cast<Model_Data>((*anObjIter)->data());
677 aFeatureTag = aData->label().Tag();
679 int aDSTag = INFINITE_TAG;
680 if (aLabIter.More()) { // next label in DS is existing
681 aDSTag = aLabIter.Value()->Label().Tag();
683 if (aDSTag > aFeatureTag) { // feature is removed
684 ObjectPtr anObj = *anObjIter;
685 anObjIter = aGroupIter->second.erase(anObjIter);
686 // event: model is updated
687 if (anObj->isInHistory()) {
688 ModelAPI_EventCreator::get()->sendDeleted(aThis, aGroupName);
690 // results of this feature must be redisplayed (hided)
691 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
692 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = boost::dynamic_pointer_cast<ModelAPI_Feature>(anObj)->results();
693 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
694 for(; aRIter != aResults.cend(); aRIter++) {
695 boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
696 aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
697 ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
698 ModelAPI_EventCreator::get()->sendDeleted(aThis, aRes->groupName());
700 } else if (aDSTag < aFeatureTag) { // a new feature is inserted
702 TDF_Label aLab = aLabIter.Value()->Label();
703 ObjectPtr aNewObj = ModelAPI_PluginManager::get()->createFeature(
704 TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
706 // this must be before "setData" to redo the sketch line correctly
707 if (anObjIter == aGroupIter->second.end()) {
708 aGroupIter->second.push_back(aNewObj);
709 anObjIter = aGroupIter->second.end();
712 aGroupIter->second.insert(anObjIter, aNewObj);
714 initData(aNewObj, aLab, TAG_FEATURE_ARGUMENTS);
716 // event: model is updated
717 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
718 ModelAPI_EventCreator::get()->sendUpdated(aNewObj, anEvent);
719 // feature for this label is added, so go to the next label
721 } else { // nothing is changed, both iterators are incremented
722 if (theMarkUpdated) {
723 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
724 ModelAPI_EventCreator::get()->sendUpdated(*anObjIter, anEvent);
731 // after all updates, sends a message that groups of features were created or updated
732 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
733 setCheckTransactions(false);
734 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
736 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
737 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
738 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
739 setCheckTransactions(true);
742 void Model_Document::storeResult(boost::shared_ptr<ModelAPI_Data> theFeatureData,
743 boost::shared_ptr<ModelAPI_Result> theResult, const int theResultIndex)
745 boost::shared_ptr<ModelAPI_Document> aThis =
746 Model_Application::getApplication()->getDocument(myID);
747 theResult->setDoc(aThis);
748 initData(theResult, boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
749 label().Father().FindChild(TAG_FEATURE_RESULTS), theResultIndex);
750 if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name
751 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
752 ModelAPI_EventCreator::get()->sendUpdated(theResult, anEvent);
753 theResult->data()->setName(theFeatureData->name());
757 boost::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction(
758 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
760 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
761 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
762 boost::shared_ptr<ModelAPI_ResultConstruction> aResult;
764 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
767 aResult = boost::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
768 storeResult(theFeatureData, aResult);
773 boost::shared_ptr<ModelAPI_ResultBody> Model_Document::createBody(
774 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
776 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
777 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
778 boost::shared_ptr<ModelAPI_ResultBody> aResult;
780 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
783 aResult = boost::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
784 storeResult(theFeatureData, aResult);
789 boost::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
790 const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
792 ObjectPtr anOldObject = object(boost::dynamic_pointer_cast<Model_Data>(theFeatureData)->
793 label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1));
794 boost::shared_ptr<ModelAPI_ResultPart> aResult;
796 aResult = boost::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
799 aResult = boost::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
800 storeResult(theFeatureData, aResult);
805 boost::shared_ptr<ModelAPI_Feature> Model_Document::feature(
806 const boost::shared_ptr<ModelAPI_Result>& theResult)
808 // iterate all features in order to find the needed result
809 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind =
810 myObjs.find(ModelAPI_Feature::group());
811 if (aFind != myObjs.end()) {
812 std::vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
813 for(; aFIter != aFind->second.end(); aFIter++) {
814 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
815 const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
816 std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
817 for(; aRIter != aResults.cend(); aRIter++) {
818 if (*aRIter == theResult) {