1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: Model_Objects.cxx
4 // Created: 15 May 2015
5 // Author: Mikhail PONIKAROV
7 #include <Model_Objects.h>
8 #include <Model_Data.h>
9 #include <Model_Document.h>
10 #include <Model_Events.h>
11 #include <Model_Session.h>
12 #include <Model_ResultPart.h>
13 #include <Model_ResultConstruction.h>
14 #include <Model_ResultBody.h>
15 #include <Model_ResultGroup.h>
16 #include <Model_ResultParameter.h>
17 #include <ModelAPI_Validator.h>
18 #include <ModelAPI_CompositeFeature.h>
19 #include <ModelAPI_Tools.h>
21 #include <Events_Loop.h>
22 #include <Events_Error.h>
24 #include <TDataStd_Integer.hxx>
25 #include <TDataStd_Comment.hxx>
26 #include <TDF_ChildIDIterator.hxx>
27 #include <TDataStd_ReferenceArray.hxx>
28 #include <TDataStd_HLabelArray1.hxx>
29 #include <TDataStd_Name.hxx>
30 #include <TDF_Reference.hxx>
31 #include <TDF_ChildIDIterator.hxx>
32 #include <TDF_LabelMapHasher.hxx>
34 static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
37 static const int TAG_FEATURE_ARGUMENTS = 1; ///< where the arguments are located
38 static const int TAG_FEATURE_RESULTS = 2; ///< where the results are located
41 /// 0:1:2 - where features are located
42 /// 0:1:2:N:1 - data of the feature N
43 /// 0:1:2:N:2:K:1 - data of the K result of the feature N
45 Model_Objects::Model_Objects(TDF_Label theMainLab) : myMain(theMainLab)
49 void Model_Objects::setOwner(DocumentPtr theDoc)
52 // update all fields and recreate features and result objects if needed
53 synchronizeFeatures(false, true, true);
57 Model_Objects::~Model_Objects()
59 // delete all features of this document
60 Events_Loop* aLoop = Events_Loop::loop();
61 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeaturesIter(myFeatures);
62 for(; aFeaturesIter.More(); aFeaturesIter.Next()) {
63 FeaturePtr aFeature = aFeaturesIter.Value();
64 static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
65 ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group());
66 ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
67 aFeature->eraseResults();
71 aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
72 aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
76 /// Appends to the array of references a new referenced label
77 static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced, TDF_Label& thePrevLab)
79 Handle(TDataStd_ReferenceArray) aRefs;
80 if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
81 aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0);
82 aRefs->SetValue(0, theReferenced);
83 } else { // extend array by one more element
84 Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
86 int aPassedPrev = 0; // prev feature is found and passed
87 if (thePrevLab.IsNull()) { // null means that inserted feature must be the first
88 aNewArray->SetValue(aRefs->Lower(), theReferenced);
91 for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
92 aNewArray->SetValue(a + aPassedPrev, aRefs->Value(a));
93 if (!aPassedPrev && aRefs->Value(a).IsEqual(thePrevLab)) {
95 aNewArray->SetValue(a + 1, theReferenced);
98 if (!aPassedPrev) // not found: unknown situation
99 aNewArray->SetValue(aRefs->Upper() + 1, theReferenced);
100 aRefs->SetInternalArray(aNewArray);
104 void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterThis)
106 if (!theFeature->isAction()) { // do not add action to the data model
107 TDF_Label aFeaturesLab = featuresLabel();
108 TDF_Label aFeatureLab = aFeaturesLab.NewChild();
109 // store feature in the features array: before "initData" because in macro features
110 // in initData it creates new features, appeared later than this
111 TDF_Label aPrevFeateureLab;
112 if (theAfterThis.get()) { // searching for the previous feature label
113 std::shared_ptr<Model_Data> aPrevData =
114 std::dynamic_pointer_cast<Model_Data>(theAfterThis->data());
115 if (aPrevData.get()) {
116 aPrevFeateureLab = aPrevData->label().Father();
119 AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab);
121 initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
122 // keep the feature ID to restore document later correctly
123 TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str());
124 myFeatures.Bind(aFeatureLab, theFeature);
125 // event: feature is added
126 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
127 ModelAPI_EventCreator::get()->sendUpdated(theFeature, anEvent);
128 theFeature->setDisabled(false); // by default created feature is enabled
129 updateHistory(ModelAPI_Feature::group());
130 } else { // make feature has not-null data anyway
131 theFeature->setData(Model_Data::invalidData());
132 theFeature->setDoc(myDoc);
136 /// Appends to the array of references a new referenced label.
137 /// If theIndex is not -1, removes element at this index, not theReferenced.
138 /// \returns the index of removed element
139 static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced,
140 const int theIndex = -1)
142 int aResult = -1; // no returned
143 Handle(TDataStd_ReferenceArray) aRefs;
144 if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
145 if (aRefs->Length() == 1) { // just erase an array
146 if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
147 theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
150 } else { // reduce the array
151 Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(),
153 int aCount = aRefs->Lower();
154 for (int a = aCount; a <= aRefs->Upper(); a++, aCount++) {
155 if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) {
159 aNewArray->SetValue(aCount, aRefs->Value(a));
162 aRefs->SetInternalArray(aNewArray);
168 void Model_Objects::refsToFeature(FeaturePtr theFeature,
169 std::set<std::shared_ptr<ModelAPI_Feature> >& theRefs, const bool isSendError)
171 // check the feature: it must have no depended objects on it
172 // the dependencies can be in the feature results
173 std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
174 for(; aResIter != theFeature->results().cend(); aResIter++) {
175 ResultPtr aResult = (*aResIter);
176 std::shared_ptr<Model_Data> aData =
177 std::dynamic_pointer_cast<Model_Data>(aResult->data());
178 if (aData.get() != NULL) {
179 const std::set<AttributePtr>& aRefs = aData->refsToMe();
180 std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
181 for(; aRefIt != aRefLast; aRefIt++) {
182 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
183 if (aFeature.get() != NULL)
184 theRefs.insert(aFeature);
188 // the dependencies can be in the feature itself
189 std::shared_ptr<Model_Data> aData =
190 std::dynamic_pointer_cast<Model_Data>(theFeature->data());
191 if (aData && !aData->refsToMe().empty()) {
192 const std::set<AttributePtr>& aRefs = aData->refsToMe();
193 std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end();
194 for(; aRefIt != aRefLast; aRefIt++) {
195 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
196 if (aFeature.get() != NULL)
197 theRefs.insert(aFeature);
201 if (!theRefs.empty() && isSendError) {
203 "Feature '" + theFeature->data()->name() + "' is used and can not be deleted");
207 void Model_Objects::removeFeature(FeaturePtr theFeature)
209 std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theFeature->data());
210 if (aData && aData->isValid()) {
211 // checking that the sub-element of composite feature is removed: if yes, inform the owner
212 std::set<std::shared_ptr<ModelAPI_Feature> > aRefs;
213 refsToFeature(theFeature, aRefs, false);
214 std::set<std::shared_ptr<ModelAPI_Feature> >::iterator aRefIter = aRefs.begin();
215 for(; aRefIter != aRefs.end(); aRefIter++) {
216 std::shared_ptr<ModelAPI_CompositeFeature> aComposite =
217 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
218 if (aComposite.get()) {
219 aComposite->removeFeature(theFeature);
222 // this must be before erase since theFeature erasing removes all information about
223 // the feature results and groups of results
224 // To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated
225 clearHistory(theFeature);
229 TDF_Label aFeatureLabel = aData->label().Father();
230 if (myFeatures.IsBound(aFeatureLabel))
231 myFeatures.UnBind(aFeatureLabel);
233 static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
234 ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
235 // erase all attributes under the label of feature
236 aFeatureLabel.ForgetAllAttributes();
237 // remove it from the references array
238 RemoveFromRefArray(featuresLabel(), aFeatureLabel);
239 // event: feature is deleted
240 ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
241 // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
242 Events_Loop::loop()->flush(EVENT_DISP);
243 updateHistory(ModelAPI_Feature::group());
247 void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
249 TDF_Label aFeaturesLab = featuresLabel();
250 Handle(TDataStd_ReferenceArray) aRefs;
251 if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs))
253 TDF_Label anAfterLab, aMovedLab =
254 std::dynamic_pointer_cast<Model_Data>(theMoved->data())->label().Father();
255 if (theAfterThis.get())
256 anAfterLab = std::dynamic_pointer_cast<Model_Data>(theAfterThis->data())->label().Father();
258 Handle(TDataStd_HLabelArray1) aNewArray =
259 new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper());
260 int aPassedMovedFrom = 0; // the prev feature location is found and passed
261 int aPassedMovedTo = 0; // the feature is added and this location is passed
262 if (!theAfterThis.get()) { // null means that inserted feature must be the first
263 aNewArray->SetValue(aRefs->Lower(), aMovedLab);
266 for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
267 if (aPassedMovedTo == 0 && aRefs->Value(a) == anAfterLab) { // add two
269 aNewArray->SetValue(a - aPassedMovedFrom, anAfterLab);
270 if (a + 1 - aPassedMovedFrom <= aRefs->Upper())
271 aNewArray->SetValue(a + 1 - aPassedMovedFrom, aMovedLab);
272 } else if (aPassedMovedFrom == 0 && aRefs->Value(a) == aMovedLab) { // skip
274 } else { // just copy one
275 if (a - aPassedMovedFrom + aPassedMovedTo <= aRefs->Upper())
276 aNewArray->SetValue(a - aPassedMovedFrom + aPassedMovedTo, aRefs->Value(a));
279 if (!aPassedMovedFrom || !aPassedMovedTo) {// not found: unknown situation
280 if (!aPassedMovedFrom) {
281 static std::string aMovedFromError("The moved feature is not found");
282 Events_Error::send(aMovedFromError);
284 static std::string aMovedToError("The 'after' feature for movement is not found");
285 Events_Error::send(aMovedToError);
289 // store the new array
290 aRefs->SetInternalArray(aNewArray);
291 // update the feature and the history
292 clearHistory(theMoved);
293 static Events_ID EVENT_UPD = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED);
294 ModelAPI_EventCreator::get()->sendUpdated(theMoved, EVENT_UPD);
297 void Model_Objects::clearHistory(ObjectPtr theObj)
300 const std::string aGroup = theObj->groupName();
301 std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(aGroup);
302 if (aHIter != myHistory.end())
303 myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
304 if (theObj->groupName() == ModelAPI_Feature::group()) { // clear results group of the feature
305 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
306 std::string aResultGroup = featureResultGroup(aFeature);
307 if (!aResultGroup.empty()) {
308 std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter =
309 myHistory.find(aResultGroup);
310 if (aHIter != myHistory.end())
311 myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
317 void Model_Objects::createHistory(const std::string& theGroupID)
319 std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroupID);
320 if (aHIter == myHistory.end()) {
321 myHistory[theGroupID] = std::vector<ObjectPtr>();
322 std::vector<ObjectPtr>& aResult = myHistory[theGroupID];
323 // iterate the array of references and get feature by feature from the array
324 bool isFeature = theGroupID == ModelAPI_Feature::group();
325 Handle(TDataStd_ReferenceArray) aRefs;
326 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
327 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
328 FeaturePtr aFeature = feature(aRefs->Value(a));
329 if (aFeature.get()) {
330 // if feature is in sub-component, remove it from history: it is in sub-tree of sub-component
331 if (!ModelAPI_Tools::compositeOwner(aFeature).get()) {
332 if (isFeature) { // here may be also disabled features
333 if (aFeature->isInHistory()) {
334 aResult.push_back(aFeature);
336 } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
337 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
338 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
339 for (; aRIter != aResults.cend(); aRIter++) {
340 ResultPtr aRes = *aRIter;
341 if (aRes->groupName() != theGroupID) break; // feature have only same group results
342 if (!aRes->isDisabled() && aRes->isInHistory() && !aRes->isConcealed()) {
343 aResult.push_back(*aRIter);
354 void Model_Objects::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
356 clearHistory(theObject);
359 void Model_Objects::updateHistory(const std::string theGroup)
361 std::map<std::string, std::vector<ObjectPtr> >::iterator aHIter = myHistory.find(theGroup);
362 if (aHIter != myHistory.end())
363 myHistory.erase(aHIter); // erase from map => this means that it is not synchronized
366 FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
368 if (myFeatures.IsBound(theLabel))
369 return myFeatures.Find(theLabel);
370 return FeaturePtr(); // not found
373 ObjectPtr Model_Objects::object(TDF_Label theLabel)
375 // try feature by label
376 FeaturePtr aFeature = feature(theLabel);
378 return feature(theLabel);
379 TDF_Label aFeatureLabel = theLabel.Father().Father(); // let's suppose it is result
380 aFeature = feature(aFeatureLabel);
382 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
383 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
384 for (; aRIter != aResults.cend(); aRIter++) {
385 std::shared_ptr<Model_Data> aResData = std::dynamic_pointer_cast<Model_Data>(
387 if (aResData->label().Father().IsEqual(theLabel))
391 return FeaturePtr(); // not found
394 ObjectPtr Model_Objects::object(const std::string& theGroupID, const int theIndex)
398 createHistory(theGroupID);
399 return myHistory[theGroupID][theIndex];
402 std::shared_ptr<ModelAPI_Object> Model_Objects::objectByName(
403 const std::string& theGroupID, const std::string& theName)
405 createHistory(theGroupID);
406 std::vector<ObjectPtr>& allObjs = myHistory[theGroupID];
407 std::vector<ObjectPtr>::iterator anObjIter = allObjs.begin();
408 for(; anObjIter != allObjs.end(); anObjIter++) {
409 if ((*anObjIter)->data()->name() == theName)
416 const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
418 std::string aGroup = theObject->groupName();
419 createHistory(aGroup);
420 std::vector<ObjectPtr>& allObjs = myHistory[aGroup];
421 std::vector<ObjectPtr>::iterator anObjIter = allObjs.begin(); // iterate to search object
422 for(int anIndex = 0; anObjIter != allObjs.end(); anObjIter++, anIndex++) {
423 if ((*anObjIter) == theObject)
430 int Model_Objects::size(const std::string& theGroupID)
432 createHistory(theGroupID);
433 return myHistory[theGroupID].size();
436 void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
438 // iterate the array of references and get feature by feature from the array
439 Handle(TDataStd_ReferenceArray) aRefs;
440 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
441 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
442 FeaturePtr aFeature = feature(aRefs->Value(a));
443 if (aFeature.get()) {
444 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
445 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
446 for (; aRIter != aResults.cend(); aRIter++) {
447 ResultPtr aRes = *aRIter;
448 if (aRes->groupName() != theGroupID) break; // feature have only same group results
449 if (aRes->isInHistory() && !aRes->isConcealed()) {
450 theResults.push_back(*aRIter);
459 TDF_Label Model_Objects::featuresLabel() const
461 return myMain.FindChild(TAG_OBJECTS);
464 void Model_Objects::setUniqueName(FeaturePtr theFeature)
466 if (!theFeature->data()->name().empty())
467 return; // not needed, name is already defined
468 std::string aName; // result
469 // first count all features of such kind to start with index = count + 1
471 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
472 for (; aFIter.More(); aFIter.Next()) {
473 if (aFIter.Value()->getKind() == theFeature->getKind())
476 // generate candidate name
477 std::stringstream aNameStream;
478 aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
479 aName = aNameStream.str();
480 // check this is unique, if not, increase index by 1
481 for (aFIter.Initialize(myFeatures); aFIter.More();) {
482 FeaturePtr aFeature = aFIter.Value();
483 bool isSameName = aFeature->data()->name() == aName;
484 if (!isSameName) { // check also results to avoid same results names (actual for Parts)
485 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
486 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
487 for (; aRIter != aResults.cend(); aRIter++) {
488 isSameName = (*aRIter)->data()->name() == aName;
493 std::stringstream aNameStream;
494 aNameStream << theFeature->getKind() << "_" << aNumObjects + 1;
495 aName = aNameStream.str();
496 // reinitialize iterator to make sure a new name is unique
497 aFIter.Initialize(myFeatures);
501 theFeature->data()->setName(aName);
504 void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag)
506 std::shared_ptr<Model_Data> aData(new Model_Data);
507 aData->setLabel(theLab.FindChild(theTag));
508 aData->setObject(theObj);
509 theObj->setDoc(myDoc);
510 theObj->setData(aData);
511 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
513 setUniqueName(aFeature); // must be before "initAttributes" because duplicate part uses name
515 theObj->initAttributes();
518 void Model_Objects::synchronizeFeatures(
519 const bool theMarkUpdated, const bool theUpdateReferences, const bool theFlush)
521 Model_Document* anOwner = std::dynamic_pointer_cast<Model_Document>(myDoc).get();
522 if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize
524 // after all updates, sends a message that groups of features were created or updated
525 Events_Loop* aLoop = Events_Loop::loop();
526 static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
527 static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
528 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
529 static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
530 static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
531 static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
532 bool isActive = aLoop->activateFlushes(false);
534 // update all objects by checking are they on labels or not
535 std::set<FeaturePtr> aNewFeatures, aKeptFeatures;
536 TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
537 for (; aLabIter.More(); aLabIter.Next()) {
538 TDF_Label aFeatureLabel = aLabIter.Value()->Label();
540 if (!myFeatures.IsBound(aFeatureLabel)) { // a new feature is inserted
542 aFeature = std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get())->createFeature(
543 TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
544 .ToCString(), anOwner);
545 if (!aFeature) { // somethig is wrong, most probably, the opened document has invalid structure
546 Events_Error::send("Invalid type of object in the document");
547 aLabIter.Value()->Label().ForgetAllAttributes();
550 // this must be before "setData" to redo the sketch line correctly
551 myFeatures.Bind(aFeatureLabel, aFeature);
552 aNewFeatures.insert(aFeature);
553 initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS);
554 updateHistory(aFeature);
555 aFeature->setDisabled(false); // by default created feature is enabled (this allows to recreate the results before "setCurrent" is called)
557 // event: model is updated
558 ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent);
559 } else { // nothing is changed, both iterators are incremented
560 aFeature = myFeatures.Find(aFeatureLabel);
561 aKeptFeatures.insert(aFeature);
562 if (theMarkUpdated) {
563 ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent);
568 // check all features are checked: if not => it was removed
569 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
570 while (aFIter.More()) {
571 if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end()
572 && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) {
573 FeaturePtr aFeature = aFIter.Value();
574 // event: model is updated
575 //if (aFeature->isInHistory()) {
576 ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group());
578 // results of this feature must be redisplayed (hided)
579 // redisplay also removed feature (used for sketch and AISObject)
580 ModelAPI_EventCreator::get()->sendUpdated(aFeature, aRedispEvent);
581 updateHistory(aFeature);
583 // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
584 myFeatures.UnBind(aFIter.Key());
585 // reinitialize iterator because unbind may corrupt the previous order in the map
586 aFIter.Initialize(myFeatures);
591 if (theUpdateReferences) {
592 synchronizeBackRefs();
594 // update results of the features (after features created because they may be connected, like sketch and sub elements)
595 // After synchronisation of back references because sketch must be set in sub-elements before "execute" by updateResults
596 std::list<FeaturePtr> aComposites; // composites must be updated after their subs (issue 360)
597 TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
598 for (; aLabIter2.More(); aLabIter2.Next()) {
599 TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
600 if (myFeatures.IsBound(aFeatureLabel)) { // a new feature is inserted
601 FeaturePtr aFeature = myFeatures.Find(aFeatureLabel);
602 if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature).get())
603 aComposites.push_back(aFeature);
604 updateResults(aFeature);
607 std::list<FeaturePtr>::iterator aComposite = aComposites.begin();
608 for(; aComposite != aComposites.end(); aComposite++) {
609 updateResults(*aComposite);
612 // the synchronize should be done after updateResults in order to correct back references of updated results
613 if (theUpdateReferences) {
614 synchronizeBackRefs();
616 if (theMarkUpdated) { // this means there is no control what was modified => remove history cash
620 anOwner->executeFeatures() = false;
621 aLoop->activateFlushes(isActive);
624 aLoop->flush(aCreateEvent);
625 aLoop->flush(aDeleteEvent);
626 aLoop->flush(anUpdateEvent);
627 aLoop->flush(aRedispEvent);
628 aLoop->flush(aToHideEvent);
630 anOwner->executeFeatures() = true;
633 void Model_Objects::synchronizeBackRefs()
635 // keeps the concealed flags of result to catch the change and create created/deleted events
636 std::list<std::pair<ResultPtr, bool> > aConcealed;
637 // first cycle: erase all data about back-references
638 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
639 for(; aFeatures.More(); aFeatures.Next()) {
640 FeaturePtr aFeature = aFeatures.Value();
641 std::shared_ptr<Model_Data> aFData =
642 std::dynamic_pointer_cast<Model_Data>(aFeature->data());
644 aFData->eraseBackReferences();
646 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
647 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
648 for (; aRIter != aResults.cend(); aRIter++) {
649 std::shared_ptr<Model_Data> aResData =
650 std::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
652 aConcealed.push_back(std::pair<ResultPtr, bool>(*aRIter, (*aRIter)->isConcealed()));
653 aResData->eraseBackReferences();
658 // second cycle: set new back-references: only features may have reference, iterate only them
659 ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
660 for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
661 FeaturePtr aFeature = aFeatures.Value();
662 std::shared_ptr<Model_Data> aFData =
663 std::dynamic_pointer_cast<Model_Data>(aFeature->data());
665 std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
666 aFData->referencesToObjects(aRefs);
667 std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator
668 aRefsIter = aRefs.begin();
669 for(; aRefsIter != aRefs.end(); aRefsIter++) {
670 std::list<ObjectPtr>::iterator aRefTo = aRefsIter->second.begin();
671 for(; aRefTo != aRefsIter->second.end(); aRefTo++) {
673 std::shared_ptr<Model_Data> aRefData =
674 std::dynamic_pointer_cast<Model_Data>((*aRefTo)->data());
675 aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated
676 // update enable/disable status: the nested status must be equal to the composite
677 CompositeFeaturePtr aComp =
678 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
680 FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>(*aRefTo);
681 if (aReferenced.get()) {
682 aReferenced->setDisabled(aComp->isDisabled());
690 std::list<std::pair<ResultPtr, bool> >::iterator aCIter = aConcealed.begin();
691 for(; aCIter != aConcealed.end(); aCIter++) {
692 if (aCIter->first->isConcealed() != aCIter->second) { // somethign is changed => produce event
693 if (aCIter->second) { // was concealed become not => creation event
694 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
695 ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, anEvent);
696 } else { // was not concealed become concealed => delete event
697 ModelAPI_EventCreator::get()->sendDeleted(myDoc, aCIter->first->groupName());
698 // redisplay for the viewer (it must be disappeared also)
699 static Events_ID EVENT_DISP =
700 Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
701 ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, EVENT_DISP);
707 TDF_Label Model_Objects::resultLabel(
708 const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theResultIndex)
710 const std::shared_ptr<Model_Data>& aData =
711 std::dynamic_pointer_cast<Model_Data>(theFeatureData);
712 return aData->label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1);
715 void Model_Objects::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
716 std::shared_ptr<ModelAPI_Result> theResult,
717 const int theResultIndex)
719 theResult->setDoc(myDoc);
720 initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS);
721 if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name
722 std::stringstream aNewName;
723 aNewName<<theFeatureData->name();
724 if (theResultIndex > 0) // if there are several results, add unique prefix starting from second
725 aNewName<<"_"<<theResultIndex + 1;
726 theResult->data()->setName(aNewName.str());
730 std::shared_ptr<ModelAPI_ResultConstruction> Model_Objects::createConstruction(
731 const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
733 TDF_Label aLab = resultLabel(theFeatureData, theIndex);
734 TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::group().c_str());
735 ObjectPtr anOldObject = object(aLab);
736 std::shared_ptr<ModelAPI_ResultConstruction> aResult;
738 aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anOldObject);
741 aResult = std::shared_ptr<ModelAPI_ResultConstruction>(new Model_ResultConstruction);
742 storeResult(theFeatureData, aResult, theIndex);
747 std::shared_ptr<ModelAPI_ResultBody> Model_Objects::createBody(
748 const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
750 TDF_Label aLab = resultLabel(theFeatureData, theIndex);
751 TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
752 ObjectPtr anOldObject = object(aLab);
753 std::shared_ptr<ModelAPI_ResultBody> aResult;
755 aResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anOldObject);
758 aResult = std::shared_ptr<ModelAPI_ResultBody>(new Model_ResultBody);
759 storeResult(theFeatureData, aResult, theIndex);
764 std::shared_ptr<ModelAPI_ResultPart> Model_Objects::createPart(
765 const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
767 TDF_Label aLab = resultLabel(theFeatureData, theIndex);
768 TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str());
769 ObjectPtr anOldObject = object(aLab);
770 std::shared_ptr<ModelAPI_ResultPart> aResult;
772 aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anOldObject);
775 aResult = std::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
776 storeResult(theFeatureData, aResult, theIndex);
781 std::shared_ptr<ModelAPI_ResultPart> Model_Objects::copyPart(
782 const std::shared_ptr<ModelAPI_Result>& theOldPart,
783 const std::shared_ptr<ModelAPI_ResultPart>& theOrigin, const int theIndex)
785 std::shared_ptr<ModelAPI_ResultPart> aResult;
786 if (theOldPart.get()) {
787 aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(theOldPart);
790 aResult = std::shared_ptr<ModelAPI_ResultPart>(new Model_ResultPart);
791 aResult->setDoc(myDoc);
792 aResult->setData(theOrigin->data());
797 std::shared_ptr<ModelAPI_ResultGroup> Model_Objects::createGroup(
798 const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
800 TDF_Label aLab = resultLabel(theFeatureData, theIndex);
801 TDataStd_Comment::Set(aLab, ModelAPI_ResultGroup::group().c_str());
802 ObjectPtr anOldObject = object(aLab);
803 std::shared_ptr<ModelAPI_ResultGroup> aResult;
805 aResult = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anOldObject);
808 aResult = std::shared_ptr<ModelAPI_ResultGroup>(new Model_ResultGroup(theFeatureData));
809 storeResult(theFeatureData, aResult, theIndex);
814 std::shared_ptr<ModelAPI_ResultParameter> Model_Objects::createParameter(
815 const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
817 TDF_Label aLab = resultLabel(theFeatureData, theIndex);
818 TDataStd_Comment::Set(aLab, ModelAPI_ResultParameter::group().c_str());
819 ObjectPtr anOldObject = object(aLab);
820 std::shared_ptr<ModelAPI_ResultParameter> aResult;
822 aResult = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(anOldObject);
825 aResult = std::shared_ptr<ModelAPI_ResultParameter>(new Model_ResultParameter);
826 storeResult(theFeatureData, aResult, theIndex);
831 std::shared_ptr<ModelAPI_Feature> Model_Objects::feature(
832 const std::shared_ptr<ModelAPI_Result>& theResult)
834 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theResult->data());
836 TDF_Label aFeatureLab = aData->label().Father().Father().Father();
837 return feature(aFeatureLab);
842 std::string Model_Objects::featureResultGroup(FeaturePtr theFeature)
844 if (theFeature->data()->isValid()) {
845 TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
846 if (aLabIter.More()) {
847 TDF_Label anArgLab = aLabIter.Value();
848 Handle(TDataStd_Comment) aGroup;
849 if (aLabIter.Value().FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
850 return TCollection_AsciiString(aGroup->Get()).ToCString();
854 static std::string anEmpty;
855 return anEmpty; // not found
858 void Model_Objects::updateResults(FeaturePtr theFeature)
860 // for not persistent is will be done by parametric updater automatically
861 //if (!theFeature->isPersistentResult()) return;
862 // check the existing results and remove them if there is nothing on the label
863 std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
864 while(aResIter != theFeature->results().cend()) {
865 ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(*aResIter);
867 if (!aBody->data()->isValid()) {
868 // found a disappeared result => remove it
869 theFeature->eraseResultFromList(aBody);
870 // start iterate from beginning because iterator is corrupted by removing
871 aResIter = theFeature->results().cbegin();
878 if (!theFeature->data() || !theFeature->data()->isValid() || theFeature->isDisabled())
880 // check that results are presented on all labels
881 int aResSize = theFeature->results().size();
882 TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
883 for(; aLabIter.More(); aLabIter.Next()) {
884 // here must be GUID of the feature
885 int aResIndex = aLabIter.Value().Tag() - 1;
887 if (aResSize <= aResIndex) {
888 TDF_Label anArgLab = aLabIter.Value();
889 Handle(TDataStd_Comment) aGroup;
890 if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
891 if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) {
892 aNewBody = createBody(theFeature->data(), aResIndex);
893 } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
894 std::shared_ptr<ModelAPI_ResultPart> aNewP = createPart(theFeature->data(), aResIndex);
895 theFeature->setResult(aNewP, aResIndex);
896 if (!aNewP->partDoc().get())
897 theFeature->execute(); // create the part result: it is better to restore the previous result if it is possible
899 } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
900 theFeature->execute(); // construction shapes are needed for sketch solver
902 } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
903 aNewBody = createGroup(theFeature->data(), aResIndex);
904 } else if (aGroup->Get() == ModelAPI_ResultParameter::group().c_str()) {
905 theFeature->attributeChanged("expression"); // just produce a value
908 Events_Error::send(std::string("Unknown type of result is found in the document:") +
909 TCollection_AsciiString(aGroup->Get()).ToCString());
913 theFeature->setResult(aNewBody, aResIndex);
919 ResultPtr Model_Objects::findByName(const std::string theName)
921 NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator anObjIter(myFeatures);
922 for(; anObjIter.More(); anObjIter.Next()) {
923 FeaturePtr& aFeature = anObjIter.ChangeValue();
924 if (!aFeature.get() || aFeature->isDisabled()) // may be on close
926 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
927 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
928 for (; aRIter != aResults.cend(); aRIter++) {
929 ResultPtr aRes = *aRIter;
930 if (aRes.get() && aRes->data() && aRes->data()->isValid() && !aRes->isDisabled() &&
931 aRes->data()->name() == theName) {
940 FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theReverse)
942 std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
943 if (aData && aData->isValid()) {
944 TDF_Label aFeatureLabel = aData->label().Father();
945 Handle(TDataStd_ReferenceArray) aRefs;
946 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
947 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features
948 if (aRefs->Value(a).IsEqual(aFeatureLabel)) {
949 a += theReverse ? -1 : 1;
950 if (a >= aRefs->Lower() && a <= aRefs->Upper())
951 return feature(aRefs->Value(a));
952 break; // finish iiteration: it's last feature
957 return FeaturePtr(); // not found, last, or something is wrong
960 FeaturePtr Model_Objects::firstFeature()
962 Handle(TDataStd_ReferenceArray) aRefs;
963 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
964 return feature(aRefs->Value(aRefs->Lower()));
966 return FeaturePtr(); // no features at all
969 FeaturePtr Model_Objects::lastFeature()
971 Handle(TDataStd_ReferenceArray) aRefs;
972 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
973 return feature(aRefs->Value(aRefs->Upper()));
975 return FeaturePtr(); // no features at all
978 std::list<std::shared_ptr<ModelAPI_Feature> > Model_Objects::allFeatures()
980 std::list<std::shared_ptr<ModelAPI_Feature> > aResult;
981 Handle(TDataStd_ReferenceArray) aRefs;
982 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
983 for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) {
984 FeaturePtr aFeature = feature(aRefs->Value(a));
986 aResult.push_back(aFeature);
992 int Model_Objects::numInternalFeatures()
994 Handle(TDataStd_ReferenceArray) aRefs;
995 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
996 return aRefs->Upper() - aRefs->Lower() + 1;
1001 std::shared_ptr<ModelAPI_Feature> Model_Objects::internalFeature(const int theIndex)
1003 Handle(TDataStd_ReferenceArray) aRefs;
1004 if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
1005 return feature(aRefs->Value(aRefs->Lower() + theIndex));
1007 return FeaturePtr(); // invalid
1010 Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper)
1012 return TDF_LabelMapHasher::HashCode(theLab, theUpper);
1015 Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2)
1017 return TDF_LabelMapHasher::IsEqual(theLab1, theLab2);