Salome HOME
Task 5.1.7: To be able to export a part to a file and import it into an existing...
[modules/shaper.git] / src / Model / Model_AttributeRefAttrList.cpp
1 // Copyright (C) 2014-2019  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   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
31   myRef->Append(aData->label().Father());  // store label of the object
32   myIDs->Append(""); // for the object store an empty string
33   // do it before the transaction finish to make just created/removed objects know dependencies
34   // and reference from composite feature is removed automatically
35   ADD_BACK_REF(theObject);
36
37   owner()->data()->sendAttributeUpdated(this);
38 }
39
40 void Model_AttributeRefAttrList::append(AttributePtr theAttr)
41 {
42   std::shared_ptr<Model_Data> aData =
43     std::dynamic_pointer_cast<Model_Data>(theAttr->owner()->data());
44   myRef->Append(aData->label().Father());  // store label of the object
45   myIDs->Append(theAttr->id().c_str()); // store the ID of the referenced attribute
46   // do it before the transaction finish to make just created/removed objects know dependencies
47   // and reference from composite feature is removed automatically
48   ADD_BACK_REF(theAttr->owner());
49
50   owner()->data()->sendAttributeUpdated(this);
51 }
52
53 void Model_AttributeRefAttrList::remove(ObjectPtr theObject)
54 {
55   TDF_Label aTheObjLab;
56   if (theObject.get() != NULL) {
57     aTheObjLab = std::dynamic_pointer_cast<Model_Data>(theObject->data())->label().Father();
58   }
59   std::shared_ptr<Model_Document> aDoc =
60     std::dynamic_pointer_cast<Model_Document>(owner()->document());
61   // remove from the both lists by clearing the list and then appending one by one
62   // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
63   TDF_LabelList aRefList = myRef->List();
64   myRef->Clear();
65   TDataStd_ListOfExtendedString anIDList = myIDs->List();
66   myIDs->Clear();
67   bool aOneisDeleted = false;
68   TDF_ListIteratorOfLabelList aRefIter(aRefList);
69   TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
70   for (; aRefIter.More(); aRefIter.Next(), anIDIter.Next()) {
71     // append now only not removed
72     if (aOneisDeleted || aRefIter.Value() != aTheObjLab || !anIDIter.Value().IsEmpty() ||
73       (aTheObjLab.IsNull() && aDoc->objects()->object(aRefIter.Value()) != NULL)) {
74       myRef->Append(aRefIter.Value());
75       myIDs->Append(anIDIter.Value());
76     } else if (aTheObjLab.IsNull() && aDoc->objects()->object(aRefIter.Value()) != NULL) {
77       aOneisDeleted = true;
78     }
79   }
80   if (aOneisDeleted) {
81     REMOVE_BACK_REF(theObject);
82     owner()->data()->sendAttributeUpdated(this);
83   }
84 }
85
86 void Model_AttributeRefAttrList::remove(AttributePtr theAttr)
87 {
88   TDF_Label aTheObjLab;
89   if (theAttr->owner().get() != NULL) {
90     aTheObjLab = std::dynamic_pointer_cast<Model_Data>(theAttr->owner()->data())->label().Father();
91   }
92   std::shared_ptr<Model_Document> aDoc =
93     std::dynamic_pointer_cast<Model_Document>(owner()->document());
94   // remove from the both lists by clearing the list and then appending one by one
95   // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
96   TDF_LabelList aRefList = myRef->List();
97   myRef->Clear();
98   TDataStd_ListOfExtendedString anIDList = myIDs->List();
99   myIDs->Clear();
100   bool aOneisDeleted = false;
101   TDF_ListIteratorOfLabelList aRefIter(aRefList);
102   TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
103   for (; aRefIter.More(); aRefIter.Next(), anIDIter.Next()) {
104     if (aOneisDeleted || anIDIter.Value() != theAttr->id().c_str() ||
105         // append now only not removed
106         aRefIter.Value() != aTheObjLab || // append now only not removed
107         (aTheObjLab.IsNull() && aDoc->objects()->object(aRefIter.Value()) != NULL)) {
108       myRef->Append(aRefIter.Value());
109       myIDs->Append(anIDIter.Value());
110     } else {
111       aOneisDeleted = true;
112     }
113   }
114   if (aOneisDeleted) {
115     REMOVE_BACK_REF(theAttr->owner());
116     owner()->data()->sendAttributeUpdated(this);
117   }
118 }
119
120 void Model_AttributeRefAttrList::clear()
121 {
122   std::list<std::pair<ObjectPtr, AttributePtr> > anOldList = list();
123   myRef->Clear();
124   myIDs->Clear();
125   std::list<std::pair<ObjectPtr, AttributePtr> >::iterator anOldIter = anOldList.begin();
126   for(; anOldIter != anOldList.end(); anOldIter++) {
127     REMOVE_BACK_REF((anOldIter->first));
128   }
129   owner()->data()->sendAttributeUpdated(this);
130 }
131
132 int Model_AttributeRefAttrList::size() const
133 {
134   return myRef->Extent();
135 }
136
137 bool Model_AttributeRefAttrList::isInitialized()
138 {
139   if (size() == 0) { // empty list is not initialized list: sketch will be not valid after add/undo
140     return false;
141   }
142   return ModelAPI_AttributeRefAttrList::isInitialized();
143 }
144
145 std::list<std::pair<ObjectPtr, AttributePtr> > Model_AttributeRefAttrList::list()
146 {
147   std::list<std::pair<ObjectPtr, AttributePtr> > aResult;
148   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
149       owner()->document());
150   if (aDoc) {
151     const TDF_LabelList& aList = myRef->List();
152     const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
153     TDF_ListIteratorOfLabelList aLIter(aList);
154     TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
155     for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
156       ObjectPtr anObj;
157       if (!aLIter.Value().IsNull()) {
158         anObj = aDoc->objects()->object(aLIter.Value());
159         aResult.push_back(std::pair<ObjectPtr, AttributePtr>(anObj,
160           anObj->data()->attribute(TCollection_AsciiString(anIDIter.Value()).ToCString())));
161       } else {
162         aResult.push_back(std::pair<ObjectPtr, AttributePtr>(ObjectPtr(), AttributePtr()));
163       }
164     }
165   }
166   return aResult;
167 }
168
169 bool Model_AttributeRefAttrList::isInList(const ObjectPtr& theObj)
170 {
171   if(!theObj.get()) {
172     return false;
173   }
174   std::list<ObjectPtr> aResult;
175   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
176       owner()->document());
177   if (aDoc) {
178     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
179     if (aData.get() && aData->isValid()) {
180       TDF_Label anObjLab = aData->label().Father();
181       const TDF_LabelList& aList = myRef->List();
182       const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
183       TDF_ListIteratorOfLabelList aLIter(aList);
184       TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
185       for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
186         if (anIDIter.Value().IsEmpty() && aLIter.Value().IsEqual(anObjLab)) {
187           return true;
188         }
189       }
190     }
191   }
192   return false;
193 }
194
195 bool Model_AttributeRefAttrList::isInList(const AttributePtr& theAttr)
196 {
197   if (!theAttr->owner().get()) {
198     return false;
199   }
200   std::list<ObjectPtr> aResult;
201   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
202       owner()->document());
203   if (aDoc) {
204     std::shared_ptr<Model_Data> aData =
205       std::dynamic_pointer_cast<Model_Data>(theAttr->owner()->data());
206     if (aData.get() && aData->isValid()) {
207       TDF_Label anObjLab = aData->label().Father();
208       const TDF_LabelList& aList = myRef->List();
209       const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
210       TDF_ListIteratorOfLabelList aLIter(aList);
211       TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
212       for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
213         if (anIDIter.Value() == theAttr->id().c_str() && aLIter.Value().IsEqual(anObjLab)) {
214           return true;
215         }
216       }
217     }
218   }
219   return false;
220 }
221
222 bool Model_AttributeRefAttrList::isAttribute(const int theIndex) const
223 {
224   const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
225   TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
226   int anIndex = -1;
227   for (; anIDIter.More(); anIDIter.Next()) {
228     anIndex++;
229     if (anIndex == theIndex) {
230       return !anIDIter.Value().IsEmpty();
231     }
232   }
233   return false;
234 }
235
236 ObjectPtr Model_AttributeRefAttrList::object(const int theIndex) const
237 {
238   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
239       owner()->document());
240   if (aDoc) {
241     const TDF_LabelList& aList = myRef->List();
242     int anIndex = -1;
243     for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
244       anIndex++;
245       if (anIndex == theIndex) {
246         if (aLIter.Value().IsNull()) { // null label => null sub
247           return ObjectPtr();
248         }
249         return aDoc->objects()->object(aLIter.Value());
250       }
251     }
252   }
253   return ObjectPtr();
254 }
255
256 AttributePtr Model_AttributeRefAttrList::attribute(const int theIndex) const
257 {
258   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
259       owner()->document());
260   if (aDoc) {
261     int anIndex = -1;
262     const TDF_LabelList& aList = myRef->List();
263     const TDataStd_ListOfExtendedString& anIDList = myIDs->List();
264     TDF_ListIteratorOfLabelList aLIter(aList);
265     TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
266     for (; aLIter.More(); aLIter.Next(), anIDIter.Next()) {
267       anIndex++;
268       if (anIndex == theIndex) {
269         if (aLIter.Value().IsNull()) { // null label => null sub
270           return AttributePtr();
271         }
272         return aDoc->objects()->object(aLIter.Value())->data()->
273           attribute(TCollection_AsciiString(anIDIter.Value().ToExtString()).ToCString());
274       }
275     }
276   }
277   return AttributePtr();
278 }
279
280 void Model_AttributeRefAttrList::removeLast()
281 {
282   // remove from the both lists by clearing the list and then appending one by one
283   // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
284   std::set<int> aLastSet;
285   aLastSet.insert(size() - 1);
286   remove(aLastSet);
287 }
288
289 void Model_AttributeRefAttrList::remove(const std::set<int>& theIndices)
290 {
291   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
292       owner()->document());
293   if (aDoc && !myRef->IsEmpty()) {
294     // remove from the both lists by clearing the list and then appending one by one
295     // TODO: in OCCT 7.0 there are methods for removing by index, seems will be more optimal
296     TDF_LabelList aRefList = myRef->List();
297     myRef->Clear();
298     TDataStd_ListOfExtendedString anIDList = myIDs->List();
299     myIDs->Clear();
300     bool aOneisDeleted = false;
301     TDF_ListIteratorOfLabelList aRefIter(aRefList);
302     TDataStd_ListIteratorOfListOfExtendedString anIDIter(anIDList);
303     for (int anIndex = 0; aRefIter.More(); aRefIter.Next(), anIDIter.Next(), anIndex++) {
304       if (theIndices.find(anIndex) == theIndices.end()) { // not found
305         myRef->Append(aRefIter.Value());
306         myIDs->Append(anIDIter.Value());
307       } else { // found, so need to update the dependencies
308         aOneisDeleted = true;
309         ObjectPtr anObj = aDoc->objects()->object(aRefIter.Value());
310         if (anObj.get()) {
311           REMOVE_BACK_REF(anObj);
312         }
313       }
314     }
315     if (aOneisDeleted) {
316       owner()->data()->sendAttributeUpdated(this);
317     }
318   }
319 }
320
321 Model_AttributeRefAttrList::Model_AttributeRefAttrList(TDF_Label& theLabel)
322 {
323   myLab = theLabel;
324   reinit();
325 }
326
327 void Model_AttributeRefAttrList::reinit()
328 {
329   myIsInitialized = myLab.FindAttribute(TDataStd_ReferenceList::GetID(), myRef) == Standard_True;
330   if (!myIsInitialized) {
331     myRef = TDataStd_ReferenceList::Set(myLab);
332     myIDs = TDataStd_ExtStringList::Set(myLab);
333   } else {
334     myLab.FindAttribute(TDataStd_ExtStringList::GetID(), myIDs);
335   }
336 }