Salome HOME
40016c3ef6fa67885edd95174ea6353042c4c637
[modules/shaper.git] / src / Model / Model_AttributeRefAttrList.cpp
1 // Copyright (C) 2014-2023  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "Model_AttributeRefAttrList.h"
21 #include "Model_Application.h"
22 #include "Model_Data.h"
23 #include "Model_Objects.h"
24 #include <ModelAPI_Feature.h>
25 #include <TDF_ListIteratorOfLabelList.hxx>
26 #include <TDataStd_ListIteratorOfListOfExtendedString.hxx>
27
28 void Model_AttributeRefAttrList::append(ObjectPtr theObject)
29 {
30   TDF_Label aLabel;
31   if (theObject) {
32     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
33     aLabel = aData->label().Father();
34   }
35
36   myRef->Append(aLabel); // store label of the object
37   myIDs->Append(""); // for the object store an empty string
38   // do it before the transaction finish to make just created/removed objects know dependencies
39   // and reference from composite feature is removed automatically
40   ADD_BACK_REF(theObject);
41
42   owner()->data()->sendAttributeUpdated(this);
43 }
44
45 void Model_AttributeRefAttrList::append(AttributePtr theAttr)
46 {
47   std::shared_ptr<Model_Data> aData =
48     std::dynamic_pointer_cast<Model_Data>(theAttr->owner()->data());
49   myRef->Append(aData->label().Father());  // store label of the object
50   myIDs->Append(theAttr->id().c_str()); // store the ID of the referenced attribute
51   // do it before the transaction finish to make just created/removed objects know dependencies
52   // and reference from composite feature is removed automatically
53   ADD_BACK_REF(theAttr->owner());
54
55   owner()->data()->sendAttributeUpdated(this);
56 }
57
58 void Model_AttributeRefAttrList::remove(ObjectPtr theObject)
59 {
60   TDF_Label aTheObjLab;
61   if (theObject.get() != NULL) {
62     aTheObjLab = std::dynamic_pointer_cast<Model_Data>(theObject->data())->label().Father();
63   }
64   std::shared_ptr<Model_Document> aDoc =
65     std::dynamic_pointer_cast<Model_Document>(owner()->document());
66   // remove from the both lists by clearing the list and then appending one by one
67   // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
68   TDF_LabelList aRefList = myRef->List();
69   myRef->Clear();
70   TDataStd_ListOfExtendedString anIDList = myIDs->List();
71   myIDs->Clear();
72   bool aOneisDeleted = false;
73   TDF_ListIteratorOfLabelList aRefIter(aRefList);
74   TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
75   for (; aRefIter.More(); aRefIter.Next(), anIDIter.Next()) {
76     // append now only not removed
77     if (aOneisDeleted || aRefIter.Value() != aTheObjLab || !anIDIter.Value().IsEmpty() ||
78       (aTheObjLab.IsNull() && aDoc->objects()->object(aRefIter.Value()) != NULL)) {
79       myRef->Append(aRefIter.Value());
80       myIDs->Append(anIDIter.Value());
81     } else if (aTheObjLab.IsNull() && aDoc->objects()->object(aRefIter.Value()) != NULL) {
82       aOneisDeleted = true;
83     }
84   }
85   if (aOneisDeleted) {
86     REMOVE_BACK_REF(theObject);
87     owner()->data()->sendAttributeUpdated(this);
88   }
89 }
90
91 void Model_AttributeRefAttrList::remove(AttributePtr theAttr)
92 {
93   TDF_Label aTheObjLab;
94   if (theAttr->owner().get() != NULL) {
95     aTheObjLab = std::dynamic_pointer_cast<Model_Data>(theAttr->owner()->data())->label().Father();
96   }
97   std::shared_ptr<Model_Document> aDoc =
98     std::dynamic_pointer_cast<Model_Document>(owner()->document());
99   // remove from the both lists by clearing the list and then appending one by one
100   // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
101   TDF_LabelList aRefList = myRef->List();
102   myRef->Clear();
103   TDataStd_ListOfExtendedString anIDList = myIDs->List();
104   myIDs->Clear();
105   bool aOneisDeleted = false;
106   TDF_ListIteratorOfLabelList aRefIter(aRefList);
107   TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
108   for (; aRefIter.More(); aRefIter.Next(), anIDIter.Next()) {
109     if (aOneisDeleted || anIDIter.Value() != theAttr->id().c_str() ||
110         // append now only not removed
111         aRefIter.Value() != aTheObjLab || // append now only not removed
112         (aTheObjLab.IsNull() && aDoc->objects()->object(aRefIter.Value()) != NULL)) {
113       myRef->Append(aRefIter.Value());
114       myIDs->Append(anIDIter.Value());
115     } else {
116       aOneisDeleted = true;
117     }
118   }
119   if (aOneisDeleted) {
120     REMOVE_BACK_REF(theAttr->owner());
121     owner()->data()->sendAttributeUpdated(this);
122   }
123 }
124
125 void Model_AttributeRefAttrList::clear()
126 {
127   std::list<std::pair<ObjectPtr, AttributePtr> > anOldList = list();
128   myRef->Clear();
129   myIDs->Clear();
130   std::list<std::pair<ObjectPtr, AttributePtr> >::iterator anOldIter = anOldList.begin();
131   for(; anOldIter != anOldList.end(); anOldIter++) {
132     REMOVE_BACK_REF((anOldIter->first));
133   }
134   owner()->data()->sendAttributeUpdated(this);
135 }
136
137 int Model_AttributeRefAttrList::size() const
138 {
139   return myRef->Extent();
140 }
141
142 bool Model_AttributeRefAttrList::isInitialized()
143 {
144   if (size() == 0) { // empty list is not initialized list: sketch will be not valid after add/undo
145     return false;
146   }
147   return ModelAPI_AttributeRefAttrList::isInitialized();
148 }
149
150 std::list<std::pair<ObjectPtr, AttributePtr> > Model_AttributeRefAttrList::list()
151 {
152   std::list<std::pair<ObjectPtr, AttributePtr> > aResult;
153   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
154       owner()->document());
155   if (aDoc) {
156     const TDF_LabelList& aList = myRef->List();
157     const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
158     TDF_ListIteratorOfLabelList aLIter(aList);
159     TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
160     for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
161       ObjectPtr anObj;
162       if (!aLIter.Value().IsNull()) {
163         anObj = aDoc->objects()->object(aLIter.Value());
164         aResult.push_back(std::pair<ObjectPtr, AttributePtr>(anObj,
165           anObj->data()->attribute(TCollection_AsciiString(anIDIter.Value()).ToCString())));
166       } else {
167         aResult.push_back(std::pair<ObjectPtr, AttributePtr>(ObjectPtr(), AttributePtr()));
168       }
169     }
170   }
171   return aResult;
172 }
173
174 bool Model_AttributeRefAttrList::isInList(const ObjectPtr& theObj)
175 {
176   if(!theObj.get()) {
177     return false;
178   }
179   std::list<ObjectPtr> aResult;
180   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
181       owner()->document());
182   if (aDoc) {
183     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
184     if (aData.get() && aData->isValid()) {
185       TDF_Label anObjLab = aData->label().Father();
186       const TDF_LabelList& aList = myRef->List();
187       const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
188       TDF_ListIteratorOfLabelList aLIter(aList);
189       TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
190       for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
191         if (anIDIter.Value().IsEmpty() && aLIter.Value().IsEqual(anObjLab)) {
192           return true;
193         }
194       }
195     }
196   }
197   return false;
198 }
199
200 bool Model_AttributeRefAttrList::isInList(const AttributePtr& theAttr)
201 {
202   if (!theAttr->owner().get()) {
203     return false;
204   }
205   std::list<ObjectPtr> aResult;
206   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
207       owner()->document());
208   if (aDoc) {
209     std::shared_ptr<Model_Data> aData =
210       std::dynamic_pointer_cast<Model_Data>(theAttr->owner()->data());
211     if (aData.get() && aData->isValid()) {
212       TDF_Label anObjLab = aData->label().Father();
213       const TDF_LabelList& aList = myRef->List();
214       const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
215       TDF_ListIteratorOfLabelList aLIter(aList);
216       TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
217       for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
218         if (anIDIter.Value() == theAttr->id().c_str() && aLIter.Value().IsEqual(anObjLab)) {
219           return true;
220         }
221       }
222     }
223   }
224   return false;
225 }
226
227 bool Model_AttributeRefAttrList::isAttribute(const int theIndex) const
228 {
229   const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
230   TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
231   int anIndex = -1;
232   for (; anIDIter.More(); anIDIter.Next()) {
233     anIndex++;
234     if (anIndex == theIndex) {
235       return !anIDIter.Value().IsEmpty();
236     }
237   }
238   return false;
239 }
240
241 ObjectPtr Model_AttributeRefAttrList::object(const int theIndex) const
242 {
243   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
244       owner()->document());
245   if (aDoc) {
246     const TDF_LabelList& aList = myRef->List();
247     int anIndex = -1;
248     for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
249       anIndex++;
250       if (anIndex == theIndex) {
251         if (aLIter.Value().IsNull()) { // null label => null sub
252           return ObjectPtr();
253         }
254         return aDoc->objects()->object(aLIter.Value());
255       }
256     }
257   }
258   return ObjectPtr();
259 }
260
261 AttributePtr Model_AttributeRefAttrList::attribute(const int theIndex) const
262 {
263   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
264       owner()->document());
265   if (aDoc) {
266     int anIndex = -1;
267     const TDF_LabelList& aList = myRef->List();
268     const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
269     TDF_ListIteratorOfLabelList aLIter(aList);
270     TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
271     for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
272       anIndex++;
273       if (anIndex == theIndex) {
274         if (aLIter.Value().IsNull()) { // null label => null sub
275           return AttributePtr();
276         }
277         return aDoc->objects()->object(aLIter.Value())->data()->
278           attribute(TCollection_AsciiString(anIDIter.Value().ToExtString()).ToCString());
279       }
280     }
281   }
282   return AttributePtr();
283 }
284
285 void Model_AttributeRefAttrList::removeLast()
286 {
287   // remove from the both lists by clearing the list and then appending one by one
288   // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
289   std::set<int> aLastSet;
290   aLastSet.insert(size() - 1);
291   remove(aLastSet);
292 }
293
294 void Model_AttributeRefAttrList::remove(const std::set<int>& theIndices)
295 {
296   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
297       owner()->document());
298   if (aDoc && !myRef->IsEmpty()) {
299     // remove from the both lists by clearing the list and then appending one by one
300     // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
301     TDF_LabelList aRefList = myRef->List();
302     myRef->Clear();
303     TDataStd_ListOfExtendedString anIDList = myIDs->List();
304     myIDs->Clear();
305     bool aOneisDeleted = false;
306     TDF_ListIteratorOfLabelList aRefIter(aRefList);
307     TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
308     for (int anIndex = 0; aRefIter.More(); aRefIter.Next(), anIDIter.Next(), anIndex++) {
309       if (theIndices.find(anIndex) == theIndices.end()) { // not found
310         myRef->Append(aRefIter.Value());
311         myIDs->Append(anIDIter.Value());
312       } else { // found, so need to update the dependencies
313         aOneisDeleted = true;
314         ObjectPtr anObj;
315         if (!aRefIter.Value().IsNull())
316           anObj = aDoc->objects()->object(aRefIter.Value());
317         if (anObj.get()) {
318           REMOVE_BACK_REF(anObj);
319         }
320       }
321     }
322     if (aOneisDeleted) {
323       owner()->data()->sendAttributeUpdated(this);
324     }
325   }
326 }
327
328 Model_AttributeRefAttrList::Model_AttributeRefAttrList(TDF_Label& theLabel)
329 {
330   myLab = theLabel;
331   reinit();
332 }
333
334 void Model_AttributeRefAttrList::reinit()
335 {
336   myIsInitialized = myLab.FindAttribute(TDataStd_ReferenceList::GetID(), myRef) == Standard_True;
337   if (!myIsInitialized) {
338     myRef = TDataStd_ReferenceList::Set(myLab);
339     myIDs = TDataStd_ExtStringList::Set(myLab);
340   } else {
341     myLab.FindAttribute(TDataStd_ExtStringList::GetID(), myIDs);
342   }
343 }