Salome HOME
Fix: using wron label for expression
[modules/shaper.git] / src / Model / Model_Data.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_Data.hxx
4 // Created:     21 Mar 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include <Model_Data.h>
8 #include <Model_AttributeDocRef.h>
9 #include <Model_AttributeInteger.h>
10 #include <Model_AttributeDouble.h>
11 #include <Model_AttributeReference.h>
12 #include <Model_AttributeRefAttr.h>
13 #include <Model_AttributeRefList.h>
14 #include <Model_AttributeBoolean.h>
15 #include <Model_AttributeString.h>
16 #include <Model_AttributeSelection.h>
17 #include <Model_AttributeSelectionList.h>
18 #include <Model_AttributeIntArray.h>
19 #include <Model_Events.h>
20 #include <Model_Expression.h>
21 #include <ModelAPI_Feature.h>
22 #include <ModelAPI_Result.h>
23 #include <ModelAPI_Validator.h>
24 #include <ModelAPI_Session.h>
25 #include <ModelAPI_ResultPart.h>
26
27 #include <GeomData_Point.h>
28 #include <GeomData_Point2D.h>
29 #include <GeomData_Dir.h>
30 #include <Events_Loop.h>
31 #include <Events_Error.h>
32
33 #include <TDataStd_Name.hxx>
34 #include <TDataStd_AsciiString.hxx>
35 #include <TDataStd_IntegerArray.hxx>
36 #include <TDF_AttributeIterator.hxx>
37 #include <TDF_ChildIterator.hxx>
38 #include <TDF_RelocationTable.hxx>
39
40 #include <string>
41
42 // myLab contains:
43 // TDataStd_Name - name of the object
44 // TDataStd_IntegerArray - state of the object execution, transaction ID of update
45 // TDataStd_BooleanArray - array of flags of this data:
46 //                             0 - is in history or not
47 static const int kFlagInHistory = 0;
48 //                             1 - is displayed or not
49 static const int kFlagDisplayed = 1;
50
51 // invalid data
52 const static std::shared_ptr<ModelAPI_Data> kInvalid(new Model_Data());
53
54 Model_Data::Model_Data() : mySendAttributeUpdated(true)
55 {
56 }
57
58 void Model_Data::setLabel(TDF_Label theLab)
59 {
60   myLab = theLab;
61   // set or get the default flags
62   if (!myLab.FindAttribute(TDataStd_BooleanArray::GetID(), myFlags)) {
63     // set default values if not found
64     myFlags = TDataStd_BooleanArray::Set(myLab, 0, 1);
65     myFlags->SetValue(kFlagInHistory, Standard_True); // is in history by default is true
66     myFlags->SetValue(kFlagDisplayed, Standard_True); // is displayed by default is true
67   }
68 }
69
70 std::string Model_Data::name()
71 {
72   Handle(TDataStd_Name) aName;
73   if (myLab.FindAttribute(TDataStd_Name::GetID(), aName))
74     return std::string(TCollection_AsciiString(aName->Get()).ToCString());
75   return "";  // not defined
76 }
77
78 void Model_Data::setName(const std::string& theName)
79 {
80   bool isModified = false;
81   std::string anOldName = name();
82   Handle(TDataStd_Name) aName;
83   if (!myLab.FindAttribute(TDataStd_Name::GetID(), aName)) {
84     TDataStd_Name::Set(myLab, theName.c_str());
85     isModified = true;
86   } else {
87     isModified = !aName->Get().IsEqual(theName.c_str());
88     if (isModified)
89       aName->Set(theName.c_str());
90   }
91   if (mySendAttributeUpdated && isModified)
92     ModelAPI_ObjectRenamedMessage::send(myObject, anOldName, theName, this);
93 }
94
95 AttributePtr Model_Data::addAttribute(const std::string& theID, const std::string theAttrType)
96 {
97   AttributePtr aResult;
98   TDF_Label anAttrLab = myLab.FindChild(myAttrs.size() + 1);
99   ModelAPI_Attribute* anAttr = 0;
100   if (theAttrType == ModelAPI_AttributeDocRef::typeId()) {
101     anAttr = new Model_AttributeDocRef(anAttrLab);
102   } else if (theAttrType == Model_AttributeInteger::typeId()) {
103     anAttr = new Model_AttributeInteger(anAttrLab);
104   } else if (theAttrType == ModelAPI_AttributeDouble::typeId()) {
105     Model_AttributeDouble* anAttribute = new Model_AttributeDouble(anAttrLab);
106     TDF_Label anExpressionLab = anAttrLab.FindChild(anAttrLab.NbChildren() + 1);
107     anAttribute->myExpression.reset(new Model_Expression(anExpressionLab));
108     anAttribute->myIsInitialized = anAttribute->myIsInitialized && anAttribute->myExpression->isInitialized(); 
109     anAttr = anAttribute;
110   } else if (theAttrType == Model_AttributeBoolean::typeId()) {
111     anAttr = new Model_AttributeBoolean(anAttrLab);
112   } else if (theAttrType == Model_AttributeString::typeId()) {
113     anAttr = new Model_AttributeString(anAttrLab);
114   } else if (theAttrType == ModelAPI_AttributeReference::typeId()) {
115     anAttr = new Model_AttributeReference(anAttrLab);
116   } else if (theAttrType == ModelAPI_AttributeSelection::typeId()) {
117     anAttr = new Model_AttributeSelection(anAttrLab);
118   } else if (theAttrType == ModelAPI_AttributeSelectionList::typeId()) {
119     anAttr = new Model_AttributeSelectionList(anAttrLab);
120   } else if (theAttrType == ModelAPI_AttributeRefAttr::typeId()) {
121     anAttr = new Model_AttributeRefAttr(anAttrLab);
122   } else if (theAttrType == ModelAPI_AttributeRefList::typeId()) {
123     anAttr = new Model_AttributeRefList(anAttrLab);
124   } else if (theAttrType == ModelAPI_AttributeIntArray::typeId()) {
125     anAttr = new Model_AttributeIntArray(anAttrLab);
126   } 
127   // create also GeomData attributes here because only here the OCAF structure is known
128   else if (theAttrType == GeomData_Point::typeId()) {
129     GeomData_Point* anAttribute = new GeomData_Point(anAttrLab);
130     for (int aComponent = 0; aComponent < GeomData_Point::NUM_COMPONENTS; ++aComponent) {
131       TDF_Label anExpressionLab = anAttrLab.FindChild(anAttrLab.NbChildren() + 1);
132       anAttribute->myExpression[aComponent].reset(new Model_Expression(anExpressionLab));
133       anAttribute->myIsInitialized = anAttribute->myIsInitialized && anAttribute->myExpression[aComponent]->isInitialized(); 
134     }
135     anAttr = anAttribute;
136   } else if (theAttrType == GeomData_Dir::typeId()) {
137     anAttr = new GeomData_Dir(anAttrLab);
138   } else if (theAttrType == GeomData_Point2D::typeId()) {
139     GeomData_Point2D* anAttribute = new GeomData_Point2D(anAttrLab);
140     for (int aComponent = 0; aComponent < GeomData_Point2D::NUM_COMPONENTS; ++aComponent) {
141       TDF_Label anExpressionLab = anAttrLab.FindChild(anAttrLab.NbChildren() + 1);
142       anAttribute->myExpression[aComponent].reset(new Model_Expression(anExpressionLab));
143       anAttribute->myIsInitialized = anAttribute->myIsInitialized && anAttribute->myExpression[aComponent]->isInitialized(); 
144     }
145     anAttr = anAttribute;
146   }
147   if (anAttr) {
148     aResult = std::shared_ptr<ModelAPI_Attribute>(anAttr);
149     myAttrs[theID] = aResult;
150     anAttr->setObject(myObject);
151     anAttr->setID(theID);
152   } else {
153     Events_Error::send("Can not create unknown type of attribute " + theAttrType);
154   }
155   return aResult;
156 }
157
158 // macro for gthe generic returning of the attribute by the ID
159 #define GET_ATTRIBUTE_BY_ID(ATTR_TYPE, METHOD_NAME) \
160   std::shared_ptr<ATTR_TYPE> Model_Data::METHOD_NAME(const std::string& theID) { \
161     std::shared_ptr<ATTR_TYPE> aRes; \
162     std::map<std::string, AttributePtr >::iterator aFound = \
163       myAttrs.find(theID); \
164     if (aFound != myAttrs.end()) { \
165       aRes = std::dynamic_pointer_cast<ATTR_TYPE>(aFound->second); \
166     } \
167     return aRes; \
168   }
169 // implement nice getting methods for all ModelAPI attributes
170 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeDocRef, document);
171 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeDouble, real);
172 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeInteger, integer);
173 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeBoolean, boolean);
174 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeString, string);
175 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeReference, reference);
176 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeSelection, selection);
177 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeSelectionList, selectionList);
178 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeRefAttr, refattr);
179 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeRefList, reflist);
180 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeIntArray, intArray);
181
182 std::shared_ptr<ModelAPI_Attribute> Model_Data::attribute(const std::string& theID)
183 {
184   std::shared_ptr<ModelAPI_Attribute> aResult;
185   if (myAttrs.find(theID) == myAttrs.end())  // no such attribute
186     return aResult;
187   return myAttrs[theID];
188 }
189
190 const std::string& Model_Data::id(const std::shared_ptr<ModelAPI_Attribute>& theAttr)
191 {
192   std::map<std::string, std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = 
193     myAttrs.begin();
194   for (; anAttr != myAttrs.end(); anAttr++) {
195     if (anAttr->second == theAttr)
196       return anAttr->first;
197   }
198   // not found
199   static std::string anEmpty;
200   return anEmpty;
201 }
202
203 bool Model_Data::isEqual(const std::shared_ptr<ModelAPI_Data>& theData)
204 {
205   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theData);
206   if (aData)
207     return myLab.IsEqual(aData->myLab) == Standard_True ;
208   return false;
209 }
210
211 bool Model_Data::isValid()
212 {
213   return !myLab.IsNull() && myLab.HasAttribute();
214 }
215
216 std::list<std::shared_ptr<ModelAPI_Attribute> > Model_Data::attributes(const std::string& theType)
217 {
218   std::list<std::shared_ptr<ModelAPI_Attribute> > aResult;
219   std::map<std::string, std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrsIter = 
220     myAttrs.begin();
221   for (; anAttrsIter != myAttrs.end(); anAttrsIter++) {
222     if (theType.empty() || anAttrsIter->second->attributeType() == theType) {
223       aResult.push_back(anAttrsIter->second);
224     }
225   }
226   return aResult;
227 }
228
229 std::list<std::string> Model_Data::attributesIDs(const std::string& theType) 
230 {
231   std::list<std::string> aResult;
232   std::map<std::string, std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrsIter = 
233     myAttrs.begin();
234   for (; anAttrsIter != myAttrs.end(); anAttrsIter++) {
235     if (theType.empty() || anAttrsIter->second->attributeType() == theType) {
236       aResult.push_back(anAttrsIter->first);
237     }
238   }
239   return aResult;
240 }
241
242 void Model_Data::sendAttributeUpdated(ModelAPI_Attribute* theAttr)
243 {
244   theAttr->setInitialized();
245   if (theAttr->isArgument()) {
246     static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
247     ModelAPI_EventCreator::get()->sendUpdated(myObject, anEvent);
248     if (mySendAttributeUpdated && myObject) {
249       myObject->attributeChanged(theAttr->id());
250     }
251   }
252 }
253
254 void Model_Data::blockSendAttributeUpdated(const bool theBlock)
255 {
256   mySendAttributeUpdated = !theBlock;
257 }
258
259 void Model_Data::erase()
260 {
261   if (!myLab.IsNull())
262     myLab.ForgetAllAttributes();
263 }
264
265 // indexes in the state array
266 enum StatesIndexes {
267   STATE_INDEX_STATE = 1, // the state type itself
268   STATE_INDEX_TRANSACTION = 2, // transaction ID
269 };
270
271 /// Returns the label array, initialises it by default values if not exists
272 static Handle(TDataStd_IntegerArray) stateArray(TDF_Label& theLab)
273 {
274   Handle(TDataStd_IntegerArray) aStateArray;
275   if (!theLab.FindAttribute(TDataStd_IntegerArray::GetID(), aStateArray)) {
276     aStateArray = TDataStd_IntegerArray::Set(theLab, 1, 2);
277     aStateArray->SetValue(STATE_INDEX_STATE, ModelAPI_StateMustBeUpdated); // default state
278     aStateArray->SetValue(STATE_INDEX_TRANSACTION, 0); // default transaction ID (not existing)
279   }
280   return aStateArray;
281 }
282
283 void Model_Data::execState(const ModelAPI_ExecState theState)
284 {
285   if (theState != ModelAPI_StateNothing) {
286     stateArray(myLab)->SetValue(STATE_INDEX_STATE, (int)theState);
287   }
288 }
289
290 ModelAPI_ExecState Model_Data::execState()
291 {
292   return ModelAPI_ExecState(stateArray(myLab)->Value(STATE_INDEX_STATE));
293 }
294
295 int Model_Data::updateID()
296 {
297   return stateArray(myLab)->Value(STATE_INDEX_TRANSACTION);
298 }
299
300 void Model_Data::setUpdateID(const int theID)
301 {
302   stateArray(myLab)->SetValue(STATE_INDEX_TRANSACTION, theID);
303 }
304
305 void Model_Data::setError(const std::string& theError, bool theSend)
306 {
307   execState(ModelAPI_StateExecFailed);
308   if (theSend) {
309     Events_Error::send(theError);
310   }
311   TDataStd_AsciiString::Set(myLab, theError.c_str());
312 }
313
314 std::string Model_Data::error() const
315 {
316   Handle(TDataStd_AsciiString) anErrorAttr;
317   if (myLab.FindAttribute(TDataStd_AsciiString::GetID(), anErrorAttr)) {
318     return std::string(anErrorAttr->Get().ToCString());
319   }
320   return std::string();
321 }
322
323 int Model_Data::featureId() const
324 {
325   return myLab.Father().Tag(); // tag of the feature label
326 }
327
328 void Model_Data::eraseBackReferences()
329 {
330   myRefsToMe.clear();
331   std::shared_ptr<ModelAPI_Result> aRes = 
332     std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
333   if (aRes)
334     aRes->setIsConcealed(false);
335 }
336
337 void Model_Data::removeBackReference(FeaturePtr theFeature, std::string theAttrID)
338 {
339   AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
340   if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
341     return;
342
343   myRefsToMe.erase(anAttribute);
344
345   // remove concealment immideately: on deselection it must be posible to reselect in GUI the same
346   if (ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
347     updateConcealmentFlag();
348   }
349 }
350
351 void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID, 
352    const bool theApplyConcealment)
353 {
354   // do not add the same attribute twice
355   AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
356   if (myRefsToMe.find(anAttribute) != myRefsToMe.end())
357     return;
358
359   myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
360   if (theApplyConcealment && 
361       ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
362     std::shared_ptr<ModelAPI_Result> aRes = 
363       std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
364     // the second condition is for history upper than concealment causer, so the feature result may
365     // be displayed and previewed; also for avoiding of quick show/hide on history
366     // moving deep down
367     if (aRes && !theFeature->isDisabled()) {
368       aRes->setIsConcealed(true);
369     }
370   }
371 }
372
373 void Model_Data::updateConcealmentFlag()
374 {
375   std::set<AttributePtr>::iterator aRefsIter = myRefsToMe.begin();
376   for(; aRefsIter != myRefsToMe.end(); aRefsIter++) {
377     if (aRefsIter->get()) {
378       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefsIter)->owner());
379       if (aFeature.get() && !aFeature->isDisabled()) {
380         if (ModelAPI_Session::get()->validators()->isConcealed(
381               aFeature->getKind(), (*aRefsIter)->id())) {
382           return; // it is still concealed, nothing to do
383         }
384       }
385     }
386   }
387   // thus, no concealment references anymore => make not-concealed
388   std::shared_ptr<ModelAPI_Result> aRes = 
389     std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
390   if (aRes.get()) {
391     aRes->setIsConcealed(false);
392     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
393     ModelAPI_EventCreator::get()->sendUpdated(aRes, anEvent);
394     Events_Loop::loop()->flush(anEvent);
395   }
396 }
397
398 #include <Model_Validator.h>
399
400 void Model_Data::referencesToObjects(
401   std::list<std::pair<std::string, std::list<ObjectPtr> > >& theRefs)
402 {
403   static Model_ValidatorsFactory* aValidators = 
404     static_cast<Model_ValidatorsFactory*>(ModelAPI_Session::get()->validators());
405   FeaturePtr aMyFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myObject);
406
407   std::map<std::string, std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = myAttrs.begin();
408   std::list<ObjectPtr> aReferenced; // not inside of cycle to avoid excess memory management
409   for(; anAttr != myAttrs.end(); anAttr++) {
410     // skip not-case attributes, that really may refer to anything not-used (issue 671)
411     if (aMyFeature.get() && !aValidators->isCase(aMyFeature, anAttr->second->id()))
412       continue;
413
414     std::string aType = anAttr->second->attributeType();
415     if (aType == ModelAPI_AttributeReference::typeId()) { // reference to object
416       std::shared_ptr<ModelAPI_AttributeReference> aRef = std::dynamic_pointer_cast<
417           ModelAPI_AttributeReference>(anAttr->second);
418       aReferenced.push_back(aRef->value());
419     } else if (aType == ModelAPI_AttributeRefAttr::typeId()) { // reference to attribute or object
420       std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = std::dynamic_pointer_cast<
421           ModelAPI_AttributeRefAttr>(anAttr->second);
422       aReferenced.push_back(aRef->isObject() ? aRef->object() : aRef->attr()->owner());
423     } else if (aType == ModelAPI_AttributeRefList::typeId()) { // list of references
424       aReferenced = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(anAttr->second)->list();
425     } else if (aType == ModelAPI_AttributeSelection::typeId()) { // selection attribute
426       std::shared_ptr<ModelAPI_AttributeSelection> aRef = std::dynamic_pointer_cast<
427           ModelAPI_AttributeSelection>(anAttr->second);
428       aReferenced.push_back(aRef->context());
429     } else if (aType == ModelAPI_AttributeSelectionList::typeId()) { // list of selection attributes
430       std::shared_ptr<ModelAPI_AttributeSelectionList> aRef = std::dynamic_pointer_cast<
431           ModelAPI_AttributeSelectionList>(anAttr->second);
432       for(int a = aRef->size() - 1; a >= 0; a--) {
433         aReferenced.push_back(aRef->value(a)->context());
434       }
435     } else
436       continue; // nothing to do, not reference
437
438     if (!aReferenced.empty()) {
439       theRefs.push_back(std::pair<std::string, std::list<ObjectPtr> >(anAttr->first, aReferenced));
440       aReferenced.clear();
441     }
442   }
443 }
444
445 /// makes copy of all attributes on the given label and all sub-labels
446 static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
447   TDF_AttributeIterator anAttrIter(theSource);
448   for(; anAttrIter.More(); anAttrIter.Next()) {
449     Handle(TDF_Attribute) aTargetAttr;
450     if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
451       // create a new attribute if not yet exists in the destination
452             aTargetAttr = anAttrIter.Value()->NewEmpty();
453       theDestination.AddAttribute(aTargetAttr);
454     }
455     Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(); // no relocation, empty map
456     anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
457   }
458   // copy the sub-labels content
459   TDF_ChildIterator aSubLabsIter(theSource);
460   for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
461     copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()));
462   }
463 }
464
465 void Model_Data::copyTo(std::shared_ptr<ModelAPI_Data> theTarget)
466 {
467   TDF_Label aTargetRoot = std::dynamic_pointer_cast<Model_Data>(theTarget)->label();
468   copyAttrs(myLab, aTargetRoot);
469   // make initialized the initialized attributes
470   std::map<std::string, std::shared_ptr<ModelAPI_Attribute> >::iterator aMyIter = myAttrs.begin();
471   for(; aMyIter != myAttrs.end(); aMyIter++) {
472     if (aMyIter->second->isInitialized()) {
473       theTarget->attribute(aMyIter->first)->setInitialized();
474     }
475   }
476 }
477
478 bool Model_Data::isInHistory()
479 {
480   return myFlags->Value(kFlagInHistory) == Standard_True;
481 }
482
483 void Model_Data::setIsInHistory(const bool theFlag)
484 {
485   return myFlags->SetValue(kFlagInHistory, theFlag);
486 }
487
488 bool Model_Data::isDisplayed()
489 {
490   if (!myObject.get() || !myObject->document().get() || // object is in valid
491       myFlags->Value(kFlagDisplayed) != Standard_True) // or it was not displayed before
492     return false;
493   if (myObject->document()->isActive()) // for active documents it must be ok anyway
494     return true;
495   // any object from the root document except part result may be displayed
496   if (myObject->document() == ModelAPI_Session::get()->moduleDocument() &&
497       myObject->groupName() != ModelAPI_ResultPart::group())
498     return true;
499   return false;
500 }
501
502 void Model_Data::setDisplayed(const bool theDisplay)
503 {
504   if (theDisplay != isDisplayed()) {
505     myFlags->SetValue(kFlagDisplayed, theDisplay);
506     static Events_Loop* aLoop = Events_Loop::loop();
507     static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
508     static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
509     aECreator->sendUpdated(myObject, EVENT_DISP);
510   }
511 }
512
513 std::shared_ptr<ModelAPI_Data> Model_Data::invalidPtr()
514 {
515   return kInvalid;
516 }
517
518 std::shared_ptr<ModelAPI_Data> Model_Data::invalidData()
519 {
520   return kInvalid;
521 }
522
523 bool Model_Data::isOwner(ModelAPI_Object* theOwner)
524 {
525   return theOwner == myObject.get();
526 }