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