1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: ModelAPI_AttributeRefList.cxx
5 // Author: Mikhail PONIKAROV
7 #include "Model_AttributeRefList.h"
8 #include "Model_Application.h"
9 #include "Model_Data.h"
10 #include "Model_Objects.h"
11 #include <ModelAPI_Feature.h>
12 #include <TDF_ListIteratorOfLabelList.hxx>
13 #include <TDF_Tool.hxx>
14 #include <TDataStd_ListIteratorOfListOfExtendedString.hxx>
18 void Model_AttributeRefList::append(ObjectPtr theObject)
20 if (owner()->document() == theObject->document()) {
21 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
22 myRef->Append(aData->label().Father()); // store label of the object
23 } else if (theObject.get() && theObject->data()->isValid()) { // reference to the other document
24 myRef->Append(myRef->Label());
25 // if these attributes exist, the link is external: keep reference to access the label
26 std::ostringstream anIdString; // string with document Id
27 anIdString<<theObject->document()->id();
28 myExtDocRef->Append(anIdString.str().c_str());
29 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
30 TCollection_AsciiString anEntry;
31 TDF_Tool::Entry(aData->label().Father(), anEntry);
32 myExtDocRef->Append(anEntry);
33 } else return; // something is wrong
35 // do it before the transaction finish to make just created/removed objects know dependencies
36 // and reference from composite feature is removed automatically
37 ADD_BACK_REF(theObject);
38 owner()->data()->sendAttributeUpdated(this);
41 void Model_AttributeRefList::remove(ObjectPtr theObject)
43 if (theObject.get() != NULL) {
44 if (owner()->document() == theObject->document()) {
45 std::shared_ptr<Model_Data> aData;
46 aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
47 myRef->Remove(aData->label().Father());
48 REMOVE_BACK_REF(theObject);
49 owner()->data()->sendAttributeUpdated(this);
51 // create new lists because for the current moment remove one of the duplicated elements
52 // from the list is buggy
53 TDF_LabelList anOldList = myRef->List();
55 TDataStd_ListOfExtendedString anOldExts = myExtDocRef->List();
58 std::ostringstream anIdString; // string with document Id
59 anIdString<<theObject->document()->id();
60 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
61 TCollection_AsciiString anEntry;
62 TDF_Tool::Entry(aData->label().Father(), anEntry);
64 TDataStd_ListIteratorOfListOfExtendedString anExtIter(anOldExts);
65 for (TDF_ListIteratorOfLabelList aLIter(anOldList); aLIter.More(); aLIter.Next()) {
66 if (aLIter.Value() == myRef->Label()) {
67 if (anExtIter.Value() == anIdString.str().c_str()) {
68 TDataStd_ListIteratorOfListOfExtendedString anExtIter2 = anExtIter;
70 if (anExtIter2.Value() == anEntry) { // fully maches, so, remove(don't copy)
75 myExtDocRef->Append(anExtIter.Value());
77 myExtDocRef->Append(anExtIter.Value());
80 myRef->Append(aLIter.Value());
83 REMOVE_BACK_REF(theObject);
84 owner()->data()->sendAttributeUpdated(this);
88 else { // in case of empty object remove, the first empty object is removed from the list
89 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
92 const TDF_LabelList& aList = myRef->List();
93 for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
94 ObjectPtr anObj = aDoc->objects()->object(aLIter.Value());
95 if (anObj.get() == NULL) {
96 myRef->Remove(aLIter.Value());
97 REMOVE_BACK_REF(theObject);
98 owner()->data()->sendAttributeUpdated(this);
106 void Model_AttributeRefList::clear()
108 std::list<ObjectPtr> anOldList = list();
110 std::list<ObjectPtr>::iterator anOldIter = anOldList.begin();
111 for(; anOldIter != anOldList.end(); anOldIter++) {
112 REMOVE_BACK_REF((*anOldIter));
114 myExtDocRef->Clear();
115 owner()->data()->sendAttributeUpdated(this);
118 int Model_AttributeRefList::size(const bool theWithEmpty) const
121 return myRef->Extent();
123 const TDF_LabelList& aList = myRef->List();
124 for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
125 if (!aLIter.Value().IsNull() && !aLIter.Value().IsRoot()) aResult++;
130 bool Model_AttributeRefList::isInitialized()
132 if (size(false) == 0) {
133 // empty list is not initialized list: sketch will be not valid after add/undo
136 return ModelAPI_AttributeRefList::isInitialized();
139 ObjectPtr Model_AttributeRefList::iteratedObject(TDF_ListIteratorOfLabelList& theLIter,
140 TDataStd_ListIteratorOfListOfExtendedString& theExtIter,
141 std::shared_ptr<Model_Document> theDoc) const
144 if (!theLIter.Value().IsNull() && !theLIter.Value().IsRoot()) {
145 if (theLIter.Value() == myRef->Label()) { // external document object
146 int anID = atoi(TCollection_AsciiString(theExtIter.Value()).ToCString());
148 DocumentPtr aRefDoc = Model_Application::getApplication()->document(anID);
150 std::shared_ptr<Model_Document> aDR = std::dynamic_pointer_cast<Model_Document>(aRefDoc);
152 TDF_Tool::Label(aDR->objects()->featuresLabel().Data(),
153 TCollection_AsciiString(theExtIter.Value()).ToCString(), aRefLab);
154 if (!aRefLab.IsNull()) {
155 anObj = aDR->objects()->object(aRefLab);
159 } else { // internal document object
160 anObj = theDoc->objects()->object(theLIter.Value());
166 list<ObjectPtr> Model_AttributeRefList::list()
168 std::list<ObjectPtr> aResult;
169 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
170 owner()->document());
172 const TDF_LabelList& aList = myRef->List();
173 TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
174 for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
175 aResult.push_back(iteratedObject(aLIter, anExtIter, aDoc));
181 bool Model_AttributeRefList::isInList(const ObjectPtr& theObj)
186 if (theObj->document() == owner()->document()) { // this document object
187 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
188 owner()->document());
190 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
191 if (aData.get() && aData->isValid()) {
192 TDF_Label anObjLab = aData->label().Father();
193 const TDF_LabelList& aList = myRef->List();
194 for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
195 if (aLIter.Value().IsEqual(anObjLab)) {
201 } else { // external document object
202 // create new lists because for the current moment remove one of the duplicated elements
203 // from the list is buggy
204 std::ostringstream anIdString; // string with document Id
205 anIdString<<theObj->document()->id();
206 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
207 TCollection_AsciiString anEntry;
208 TDF_Tool::Entry(aData->label().Father(), anEntry);
210 TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
211 for (; anExtIter.More(); anExtIter.Next()) {
212 if (anExtIter.Value() == anIdString.str().c_str()) {
214 if (anExtIter.Value() == anEntry) { // fully maches
225 ObjectPtr Model_AttributeRefList::object(const int theIndex, const bool theWithEmpty) const
227 std::shared_ptr<Model_Document> aDoc =
228 std::dynamic_pointer_cast<Model_Document>(owner()->document());
231 TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
232 for (TDF_ListIteratorOfLabelList aLIter(myRef->List()); aLIter.More(); aLIter.Next()) {
233 if (theWithEmpty || (!aLIter.Value().IsNull() && !aLIter.Value().IsRoot()))
235 if (anIndex == theIndex) {
236 return iteratedObject(aLIter, anExtIter, aDoc);
238 if (aLIter.Value() == myRef->Label()) {
247 void Model_AttributeRefList::substitute(const ObjectPtr& theCurrent, const ObjectPtr& theNew)
249 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
250 owner()->document());
252 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theCurrent->data());
253 if (aData.get() && aData->isValid()) {
254 TDF_Label aCurrentLab = aData->label().Father();
256 if (theNew.get() && theNew->data()->isValid()) { // the new may be null
257 std::shared_ptr<Model_Data> aNewData =
258 std::dynamic_pointer_cast<Model_Data>(theNew->data());
259 aNewLab = aNewData->label().Father();
261 aNewLab = aCurrentLab.Root(); // root means null object
263 // do the substitution
264 ADD_BACK_REF(theNew);
265 if (myRef->InsertAfter(aNewLab, aCurrentLab)) {
266 myRef->Remove(aCurrentLab);
267 REMOVE_BACK_REF(theCurrent);
269 owner()->data()->sendAttributeUpdated(this);
274 void Model_AttributeRefList::exchange(const ObjectPtr& theObject1, const ObjectPtr& theObject2)
276 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
277 owner()->document());
279 std::shared_ptr<Model_Data> aData1 = std::dynamic_pointer_cast<Model_Data>(theObject1->data());
280 if (aData1.get() && aData1->isValid()) {
281 TDF_Label aLab1 = aData1->label().Father();
282 if (theObject2.get() && theObject2->data()->isValid()) { // the new may be null
283 std::shared_ptr<Model_Data> aData2 =
284 std::dynamic_pointer_cast<Model_Data>(theObject2->data());
285 if (aData2.get() && aData2->isValid()) {
286 TDF_Label aLab2 = aData2->label().Father();
287 // do the substitution: use the temporary label, as usually in exchange
288 TDF_Label aTmpLab = aLab1.Root();
289 if (myRef->InsertAfter(aTmpLab, aLab1)) {
290 myRef->Remove(aLab1);
292 if (myRef->InsertAfter(aLab1, aLab2)) {
293 myRef->Remove(aLab2);
295 if (myRef->InsertAfter(aLab2, aTmpLab)) {
296 myRef->Remove(aTmpLab);
298 owner()->data()->sendAttributeUpdated(this);
305 void Model_AttributeRefList::removeLast()
307 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
308 owner()->document());
309 if (aDoc && !myRef->IsEmpty()) {
310 ObjectPtr anObj = aDoc->objects()->object(myRef->Last());
312 myRef->Remove(myRef->Last());
313 REMOVE_BACK_REF(anObj);
314 owner()->data()->sendAttributeUpdated(this);
319 void Model_AttributeRefList::remove(const std::set<int>& theIndices)
321 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
322 owner()->document());
323 if (aDoc && !myRef->IsEmpty()) {
324 // collet labels that will be removed
325 TDF_LabelList aLabelsToRemove;
326 TDF_ListIteratorOfLabelList aLabIter(myRef->List());
327 for(int aCurrent = 0; aLabIter.More(); aLabIter.Next(), aCurrent++) {
328 if (theIndices.find(aCurrent) != theIndices.end())
329 aLabelsToRemove.Append(aLabIter.Value());
332 for(aLabIter.Initialize(aLabelsToRemove); aLabIter.More(); aLabIter.Next()) {
333 ObjectPtr anObj = aDoc->objects()->object(aLabIter.Value());
335 myRef->Remove(aLabIter.Value());
336 REMOVE_BACK_REF(anObj);
339 if (!aLabelsToRemove.IsEmpty()) {
340 owner()->data()->sendAttributeUpdated(this);
345 Model_AttributeRefList::Model_AttributeRefList(TDF_Label& theLabel)
351 void Model_AttributeRefList::reinit()
353 myIsInitialized = myLab.FindAttribute(TDataStd_ReferenceList::GetID(), myRef) == Standard_True;
354 if (!myIsInitialized) {
355 myRef = TDataStd_ReferenceList::Set(myLab);
357 if (!myLab.FindAttribute(TDataStd_ExtStringList::GetID(), myExtDocRef)) {
358 myExtDocRef = TDataStd_ExtStringList::Set(myLab);