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
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 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(string("Exception in opening of document: ") + aFail->GetMessageString());
75 bool isError = aStatus != PCDM_RS_OK;
80 case PCDM_RS_UnknownDocument:
81 Events_Error::send(string("Can not open document: PCDM_RS_UnknownDocument")); break;
82 case PCDM_RS_AlreadyRetrieved:
83 Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrieved")); break;
84 case PCDM_RS_AlreadyRetrievedAndModified:
85 Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified")); break;
86 case PCDM_RS_NoDriver:
87 Events_Error::send(string("Can not open document: PCDM_RS_NoDriver")); break;
88 case PCDM_RS_UnknownFileDriver:
89 Events_Error::send(string("Can not open document: PCDM_RS_UnknownFileDriver")); break;
90 case PCDM_RS_OpenError:
91 Events_Error::send(string("Can not open document: PCDM_RS_OpenError")); break;
92 case PCDM_RS_NoVersion:
93 Events_Error::send(string("Can not open document: PCDM_RS_NoVersion")); break;
95 Events_Error::send(string("Can not open document: PCDM_RS_NoModel")); break;
96 case PCDM_RS_NoDocument:
97 Events_Error::send(string("Can not open document: PCDM_RS_NoDocument")); break;
98 case PCDM_RS_FormatFailure:
99 Events_Error::send(string("Can not open document: PCDM_RS_FormatFailure")); break;
100 case PCDM_RS_TypeNotFoundInSchema:
101 Events_Error::send(string("Can not open document: PCDM_RS_TypeNotFoundInSchema")); break;
102 case PCDM_RS_UnrecognizedFileFormat:
103 Events_Error::send(string("Can not open document: PCDM_RS_UnrecognizedFileFormat")); break;
104 case PCDM_RS_MakeFailure:
105 Events_Error::send(string("Can not open document: PCDM_RS_MakeFailure")); break;
106 case PCDM_RS_PermissionDenied:
107 Events_Error::send(string("Can not open document: PCDM_RS_PermissionDenied")); break;
108 case PCDM_RS_DriverFailure:
109 Events_Error::send(string("Can not open document: PCDM_RS_DriverFailure")); break;
111 Events_Error::send(string("Can not open document: unknown error")); break;
115 myDoc->SetUndoLimit(UNDO_LIMIT);
116 synchronizeFeatures();
121 bool Model_Document::save(const char* theFileName)
123 // create a directory in the root document if it is not yet exist
124 if (this == Model_PluginManager::get()->rootDocument().get()) {
126 CreateDirectory(theFileName, NULL);
128 mkdir(theFileName, 0x1ff);
131 // filename in the dir is id of document inside of the given directory
132 TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
133 PCDM_StoreStatus aStatus;
135 aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
137 catch (Standard_Failure) {
138 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
139 Events_Error::send(string("Exception in saving of document: ") + aFail->GetMessageString());
142 bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
147 case PCDM_SS_DriverFailure:
148 Events_Error::send(string("Can not save document: PCDM_SS_DriverFailure"));
150 case PCDM_SS_WriteFailure:
151 Events_Error::send(string("Can not save document: PCDM_SS_WriteFailure"));
153 case PCDM_SS_Failure:
155 Events_Error::send(string("Can not save document: PCDM_SS_Failure"));
159 myTransactionsAfterSave = 0;
160 if (isDone) { // save also sub-documents if any
161 set<string>::iterator aSubIter = mySubs.begin();
162 for(; aSubIter != mySubs.end() && isDone; aSubIter++)
163 isDone = subDocument(*aSubIter)->save(theFileName);
168 void Model_Document::close()
170 boost::shared_ptr<ModelAPI_PluginManager> aPM = Model_PluginManager::get();
171 if (this != aPM->rootDocument().get() &&
172 this == aPM->currentDocument().get()) {
173 aPM->setCurrentDocument(aPM->rootDocument());
176 set<string>::iterator aSubIter = mySubs.begin();
177 for(; aSubIter != mySubs.end(); aSubIter++)
178 subDocument(*aSubIter)->close();
181 /* do not close because it can be undoed
182 if (myDoc->CanClose() == CDM_CCS_OK)
184 Model_Application::getApplication()->deleteDocument(myID);
188 void Model_Document::startOperation()
190 if (myDoc->HasOpenCommand()) { // start of nested command
191 if (myNestedNum == -1) {
193 myDoc->InitDeltaCompaction();
195 myIsEmptyTr[myTransactionsAfterSave] = false;
196 myTransactionsAfterSave++;
198 } else { // start of simple command
201 // new command for all subs
202 set<string>::iterator aSubIter = mySubs.begin();
203 for(; aSubIter != mySubs.end(); aSubIter++)
204 subDocument(*aSubIter)->startOperation();
207 void Model_Document::compactNested() {
208 while(myNestedNum != -1) {
209 myTransactionsAfterSave--;
210 myIsEmptyTr.erase(myTransactionsAfterSave);
213 myIsEmptyTr[myTransactionsAfterSave] = false;
214 myTransactionsAfterSave++;
215 myDoc->PerformDeltaCompaction();
218 void Model_Document::finishOperation()
220 // just to be sure that everybody knows that changes were performed
221 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
222 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
223 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
225 if (myNestedNum != -1) // this nested transaction is owervritten
227 if (!myDoc->HasOpenCommand()) {
228 if (myNestedNum != -1) {
233 // returns false if delta is empty and no transaction was made
234 myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand() && (myNestedNum == -1);
235 myTransactionsAfterSave++;
238 // finish for all subs
239 set<string>::iterator aSubIter = mySubs.begin();
240 for(; aSubIter != mySubs.end(); aSubIter++)
241 subDocument(*aSubIter)->finishOperation();
244 void Model_Document::abortOperation()
246 if (myNestedNum > 0 && !myDoc->HasOpenCommand()) { // abort all what was done in nested
247 // first compact all nested
249 // for nested it is undo and clear redos
252 myTransactionsAfterSave--;
253 myIsEmptyTr.erase(myTransactionsAfterSave);
255 if (myNestedNum == 0) // abort only high-level
257 myDoc->AbortCommand();
259 synchronizeFeatures(true);
260 // abort for all subs
261 set<string>::iterator aSubIter = mySubs.begin();
262 for(; aSubIter != mySubs.end(); aSubIter++)
263 subDocument(*aSubIter)->abortOperation();
266 bool Model_Document::isOperation()
268 // operation is opened for all documents: no need to check subs
269 return myDoc->HasOpenCommand() == Standard_True;
272 bool Model_Document::isModified()
274 // is modified if at least one operation was commited and not undoed
275 return myTransactionsAfterSave > 0;
278 bool Model_Document::canUndo()
280 if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */)
282 // check other subs contains operation that can be undoed
283 set<string>::iterator aSubIter = mySubs.begin();
284 for(; aSubIter != mySubs.end(); aSubIter++)
285 if (subDocument(*aSubIter)->canUndo())
290 void Model_Document::undo()
292 myTransactionsAfterSave--;
293 if (myNestedNum > 0) myNestedNum--;
294 if (!myIsEmptyTr[myTransactionsAfterSave])
296 synchronizeFeatures(true);
298 set<string>::iterator aSubIter = mySubs.begin();
299 for(; aSubIter != mySubs.end(); aSubIter++)
300 subDocument(*aSubIter)->undo();
303 bool Model_Document::canRedo()
305 if (myDoc->GetAvailableRedos() > 0)
307 // check other subs contains operation that can be redoed
308 set<string>::iterator aSubIter = mySubs.begin();
309 for(; aSubIter != mySubs.end(); aSubIter++)
310 if (subDocument(*aSubIter)->canRedo())
315 void Model_Document::redo()
317 if (myNestedNum != -1) myNestedNum++;
318 if (!myIsEmptyTr[myTransactionsAfterSave])
320 myTransactionsAfterSave++;
321 synchronizeFeatures(true);
323 set<string>::iterator aSubIter = mySubs.begin();
324 for(; aSubIter != mySubs.end(); aSubIter++)
325 subDocument(*aSubIter)->redo();
328 /// Appenad to the array of references a new referenced label
329 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) {
330 Handle(TDataStd_ReferenceArray) aRefs;
331 if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
332 aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
333 aRefs->SetValue(0, theReferenced);
334 } else { // extend array by one more element
335 Handle(TDataStd_HLabelArray1) aNewArray =
336 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() + 1);
337 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
338 aNewArray->SetValue(a, aRefs->Value(a));
340 aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
341 aRefs->SetInternalArray(aNewArray);
346 FeaturePtr Model_Document::addFeature(string theID)
348 TDF_Label anEmptyLab;
349 FeaturePtr anEmptyFeature;
350 FeaturePtr aFeature = ModelAPI_PluginManager::get()->createFeature(theID);
352 TDF_Label aFeatureLab;
353 if (!aFeature->isAction()) {// do not add action to the data model
354 TDF_Label aFeaturesLab = groupLabel(ModelAPI_Feature::group());
355 aFeatureLab = aFeaturesLab.NewChild();
356 initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
357 // keep the feature ID to restore document later correctly
358 TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str());
359 myObjs[ModelAPI_Feature::group()].push_back(aFeature);
360 // store feature in the history of features array
361 if (aFeature->isInHistory()) {
362 AddToRefArray(aFeaturesLab, aFeatureLab);
365 setUniqueName(aFeature);
366 if (!aFeature->isAction()) {// do not add action to the data model
367 // event: feature is added
368 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
369 ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
375 void Model_Document::storeResult(boost::shared_ptr<ModelAPI_Feature> theFeature,
376 boost::shared_ptr<ModelAPI_Result> theResult, const int theResultIndex)
378 initData(theResult, boost::dynamic_pointer_cast<Model_Data>(theFeature->data())->
379 label().Father().FindChild(TAG_FEATURE_RESULTS), theResultIndex);
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());
436 /// returns the object group name by the object label
437 static string groupName(TDF_Label theObjectLabel) {
438 TDF_Label aGroupLab = theObjectLabel.Father();
439 Handle(TDataStd_Comment) aComment;
440 if (aGroupLab.FindAttribute(TDataStd_Comment::GetID(), aComment))
441 return string(TCollection_AsciiString(aComment->Get()).ToCString());
442 return ""; // not found
445 FeaturePtr Model_Document::feature(TDF_Label& theLabel)
447 // iterate all features, may be optimized later by keeping labels-map
448 std::vector<ObjectPtr>& aVec = myObjs[ModelAPI_Feature::group()];
449 vector<ObjectPtr>::iterator aFIter = aVec.begin();
450 for(; aFIter != aVec.end(); aFIter++) {
451 boost::shared_ptr<Model_Data> aData =
452 boost::dynamic_pointer_cast<Model_Data>((*aFIter)->data());
453 if (aData->label().IsEqual(theLabel))
454 return boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
456 return FeaturePtr(); // not found
459 boost::shared_ptr<ModelAPI_Document> Model_Document::subDocument(string theDocID)
461 // just store sub-document identifier here to manage it later
462 if (mySubs.find(theDocID) == mySubs.end())
463 mySubs.insert(theDocID);
464 return Model_Application::getApplication()->getDocument(theDocID);
467 ObjectPtr Model_Document::object(const string& theGroupID, const int theIndex)
469 if (theGroupID == ModelAPI_Feature::group()) {
470 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind = myObjs.find(theGroupID);
471 if (aFind != myObjs.end()) {
472 int aSize = aFind->second.size();
473 if (theIndex >= 0 && theIndex < aSize)
474 return aFind->second[theIndex];
477 // iterate all features in order to find the needed result
478 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind = myObjs.find(ModelAPI_Feature::group());
479 if (aFind != myObjs.end()) {
480 vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
481 for(int anIndex = 0; aFIter != aFind->second.end(); aFIter++) {
482 const list<boost::shared_ptr<ModelAPI_Result> >& aResults =
483 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
484 list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
485 for(; aRIter != aResults.cend(); aRIter++) {
486 if ((*aRIter)->isInHistory() && (*aRIter)->group() == theGroupID) {
487 if (anIndex == theIndex)
499 int Model_Document::size(const string& theGroupID)
502 if (theGroupID == ModelAPI_Feature::group()) {
503 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind = myObjs.find(theGroupID);
504 if (aFind != myObjs.end()) {
505 aResult = aFind->second.size();
508 // iterate all features in order to find the needed result
509 std::map<std::string, std::vector<ObjectPtr> >::iterator aFind = myObjs.find(ModelAPI_Feature::group());
510 if (aFind != myObjs.end()) {
511 vector<ObjectPtr>::iterator aFIter = aFind->second.begin();
512 for(; aFIter != aFind->second.end(); aFIter++) {
513 const list<boost::shared_ptr<ModelAPI_Result> >& aResults =
514 boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter)->results();
515 list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
516 for(; aRIter != aResults.cend(); aRIter++) {
517 if ((*aRIter)->isInHistory() && (*aRIter)->group() == theGroupID) {
524 // group is not found
528 Model_Document::Model_Document(const std::string theID)
529 : myID(theID), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format
531 myDoc->SetUndoLimit(UNDO_LIMIT);
532 myTransactionsAfterSave = 0;
534 //myDoc->SetNestedTransactionMode();
535 // to have something in the document and avoid empty doc open/save problem
536 // in transaction for nesting correct working
538 TDataStd_Integer::Set(myDoc->Main().Father(), 0);
539 myDoc->CommitCommand();
542 TDF_Label Model_Document::groupLabel(const string theGroup)
544 // searching for existing
545 TCollection_ExtendedString aGroup(theGroup.c_str());
546 TDF_ChildIDIterator aGroupIter(myDoc->Main().FindChild(TAG_OBJECTS), TDataStd_Comment::GetID());
547 for(; aGroupIter.More(); aGroupIter.Next()) {
548 Handle(TDataStd_Comment) aName = Handle(TDataStd_Comment)::DownCast(aGroupIter.Value());
549 if (aName->Get() == aGroup)
550 return aGroupIter.Value()->Label();
553 TDF_Label aNew = myDoc->Main().FindChild(TAG_OBJECTS).NewChild();
554 TDataStd_Comment::Set(aNew, aGroup);
558 void Model_Document::setUniqueName(FeaturePtr theFeature)
560 string aName; // result
561 // first count all objects of such kind to start with index = count + 1
562 int a, aNumObjects = 0;
563 int aSize = size(ModelAPI_Feature::group());
564 for(a = 0; a < aSize; a++) {
565 if (boost::dynamic_pointer_cast<ModelAPI_Feature>(object(ModelAPI_Feature::group(), a))->getKind()
566 == theFeature->getKind())
569 // generate candidate name
570 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(a = 0; a < aSize;) {
575 if (boost::dynamic_pointer_cast<ModelAPI_Feature>(object(ModelAPI_Feature::group(), a))
576 ->data()->name() == aName) {
578 stringstream aNameStream;
579 aNameStream<<theFeature->getKind()<<"_"<<aNumObjects + 1;
580 aName = aNameStream.str();
581 // reinitialize iterator to make sure a new name is unique
585 theFeature->data()->setName(aName);
588 void Model_Document::initData(ObjectPtr theObj, TDF_Label& theLab, const int theTag) {
589 boost::shared_ptr<ModelAPI_Document> aThis =
590 Model_Application::getApplication()->getDocument(myID);
591 boost::shared_ptr<Model_Data> aData(new Model_Data);
592 aData->setLabel(theLab.FindChild(theTag));
593 aData->setObject(theObj);
594 theObj->setDoc(aThis);
595 theObj->setData(aData);
596 FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
597 if (aFeature) aFeature->initAttributes();
600 void Model_Document::synchronizeFeatures(const bool theMarkUpdated)
602 boost::shared_ptr<ModelAPI_Document> aThis =
603 Model_Application::getApplication()->getDocument(myID);
604 // update all objects: iterate from the end: as they appeared in the list
605 map<string, vector<ObjectPtr> >::reverse_iterator aGroupIter = myObjs.rbegin();
606 for(; aGroupIter != myObjs.rend(); aGroupIter++) {
607 vector<ObjectPtr>::iterator anObjIter = aGroupIter->second.begin();
608 // and in parallel iterate labels of features
609 const string& aGroupName = aGroupIter->first;
610 TDF_ChildIDIterator aLabIter(groupLabel(aGroupName), TDataStd_Comment::GetID());
611 while(anObjIter != aGroupIter->second.end() || aLabIter.More()) {
612 static const int INFINITE_TAG = INT_MAX; // no label means that it exists somwhere in infinite
613 int aFeatureTag = INFINITE_TAG;
614 if (anObjIter != aGroupIter->second.end()) { // existing tag for feature
615 boost::shared_ptr<Model_Data> aData =
616 boost::dynamic_pointer_cast<Model_Data>((*anObjIter)->data());
617 aFeatureTag = aData->label().Tag();
619 int aDSTag = INFINITE_TAG;
620 if (aLabIter.More()) { // next label in DS is existing
621 aDSTag = aLabIter.Value()->Label().Tag();
623 if (aDSTag > aFeatureTag) { // feature is removed
624 ObjectPtr anObj = *anObjIter;
625 anObjIter = aGroupIter->second.erase(anObjIter);
626 // event: model is updated
627 if (anObj->isInHistory()) {
628 ModelAPI_EventCreator::get()->sendDeleted(aThis, aGroupName);
630 ModelAPI_EventCreator::get()->sendDeleted(aThis, aGroupName);
631 } else if (aDSTag < aFeatureTag) { // a new feature is inserted
633 TDF_Label aLab = aLabIter.Value()->Label();
634 ObjectPtr aNewObj = ModelAPI_PluginManager::get()->createFeature(
635 TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
637 // this must be before "setData" to redo the sketch line correctly
638 if (anObjIter == aGroupIter->second.end()) {
639 aGroupIter->second.push_back(aNewObj);
640 anObjIter = aGroupIter->second.end();
643 aGroupIter->second.insert(anObjIter, aNewObj);
645 initData(aNewObj, aLab, TAG_FEATURE_ARGUMENTS);
647 // event: model is updated
648 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
649 ModelAPI_EventCreator::get()->sendUpdated(aNewObj, anEvent);
650 // feature for this label is added, so go to the next label
652 } else { // nothing is changed, both iterators are incremented
653 if (theMarkUpdated) {
654 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
655 ModelAPI_EventCreator::get()->sendUpdated(*anObjIter, anEvent);
662 // after all updates, sends a message that groups of features were created or updated
663 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
664 setCheckTransactions(false);
665 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
667 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
668 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
669 boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
670 setCheckTransactions(true);
673 boost::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction()
675 boost::shared_ptr<ModelAPI_ResultConstruction> aResult(new Model_ResultConstruction());