Salome HOME
Add copyright header according to request of CEA from 06.06.2017
[modules/shaper.git] / src / Model / Model_AttributeRefList.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_AttributeRefList.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 <TDF_Tool.hxx>
28 #include <TDataStd_ListIteratorOfListOfExtendedString.hxx>
29
30 void Model_AttributeRefList::append(ObjectPtr theObject)
31 {
32   if (owner()->document() == theObject->document()) {
33     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
34     myRef->Append(aData->label().Father());  // store label of the object
35   } else if (theObject.get() && theObject->data()->isValid()) { // reference to the other document
36     myRef->Append(myRef->Label());
37     // if these attributes exist, the link is external: keep reference to access the label
38     std::ostringstream anIdString; // string with document Id
39     anIdString<<theObject->document()->id();
40     myExtDocRef->Append(anIdString.str().c_str());
41     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
42     TCollection_AsciiString anEntry;
43     TDF_Tool::Entry(aData->label().Father(), anEntry);
44     myExtDocRef->Append(anEntry);
45   } else return; // something is wrong
46
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(theObject);
50   owner()->data()->sendAttributeUpdated(this);
51 }
52
53 void Model_AttributeRefList::remove(ObjectPtr theObject)
54 {
55   if (theObject.get() != NULL) {
56     if (owner()->document() == theObject->document()) {
57       std::shared_ptr<Model_Data> aData;
58       aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
59       myRef->Remove(aData->label().Father());
60       REMOVE_BACK_REF(theObject);
61       owner()->data()->sendAttributeUpdated(this);
62     } else {
63       // create new lists because for the current moment remove one of the duplicated elements
64       // from the list is buggy
65       TDF_LabelList anOldList = myRef->List();
66       myRef->Clear();
67       TDataStd_ListOfExtendedString anOldExts = myExtDocRef->List();
68       myExtDocRef->Clear();
69
70       std::ostringstream anIdString; // string with document Id
71       anIdString<<theObject->document()->id();
72       std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
73       TCollection_AsciiString anEntry;
74       TDF_Tool::Entry(aData->label().Father(), anEntry);
75       bool aFound = false;
76       TDataStd_ListIteratorOfListOfExtendedString anExtIter(anOldExts);
77       for (TDF_ListIteratorOfLabelList aLIter(anOldList); aLIter.More(); aLIter.Next()) {
78         if (aLIter.Value() == myRef->Label()) {
79           if (anExtIter.Value() == anIdString.str().c_str()) {
80             TDataStd_ListIteratorOfListOfExtendedString anExtIter2 = anExtIter;
81             anExtIter2.Next();
82             if (anExtIter2.Value() == anEntry) { // fully maches, so, remove(don't copy)
83               aFound = true;
84               continue;
85             }
86           }
87           myExtDocRef->Append(anExtIter.Value());
88           anExtIter.Next();
89           myExtDocRef->Append(anExtIter.Value());
90           anExtIter.Next();
91         }
92         myRef->Append(aLIter.Value());
93       }
94       if (aFound) {
95         REMOVE_BACK_REF(theObject);
96         owner()->data()->sendAttributeUpdated(this);
97       }
98     }
99   }
100   else { // in case of empty object remove, the first empty object is removed from the list
101     std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
102         owner()->document());
103     if (aDoc) {
104       const TDF_LabelList& aList = myRef->List();
105       for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
106         ObjectPtr anObj = aDoc->objects()->object(aLIter.Value());
107         if (anObj.get() == NULL) {
108           myRef->Remove(aLIter.Value());
109           REMOVE_BACK_REF(theObject);
110           owner()->data()->sendAttributeUpdated(this);
111           break;
112         }
113       }
114     }
115   }
116 }
117
118 void Model_AttributeRefList::clear()
119 {
120   std::list<ObjectPtr> anOldList = list();
121   myRef->Clear();
122   std::list<ObjectPtr>::iterator anOldIter = anOldList.begin();
123   for(; anOldIter != anOldList.end(); anOldIter++) {
124     REMOVE_BACK_REF((*anOldIter));
125   }
126   myExtDocRef->Clear();
127   owner()->data()->sendAttributeUpdated(this);
128 }
129
130 int Model_AttributeRefList::size(const bool theWithEmpty) const
131 {
132   if (theWithEmpty)
133     return myRef->Extent();
134   int aResult = 0;
135   const TDF_LabelList& aList = myRef->List();
136   for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
137     if (!aLIter.Value().IsNull() && !aLIter.Value().IsRoot()) aResult++;
138   }
139   return aResult;
140 }
141
142 bool Model_AttributeRefList::isInitialized()
143 {
144   if (size(false) == 0) {
145     // empty list is not initialized list: sketch will be not valid after add/undo
146     return false;
147   }
148   return ModelAPI_AttributeRefList::isInitialized();
149 }
150
151 ObjectPtr Model_AttributeRefList::iteratedObject(TDF_ListIteratorOfLabelList& theLIter,
152     TDataStd_ListIteratorOfListOfExtendedString& theExtIter,
153     std::shared_ptr<Model_Document> theDoc) const
154 {
155   ObjectPtr anObj;
156   if (!theLIter.Value().IsNull() && !theLIter.Value().IsRoot()) {
157     if (theLIter.Value() == myRef->Label()) { // external document object
158       int anID = atoi(TCollection_AsciiString(theExtIter.Value()).ToCString());
159       theExtIter.Next();
160       DocumentPtr aRefDoc = Model_Application::getApplication()->document(anID);
161       if (aRefDoc.get()) {
162         std::shared_ptr<Model_Document> aDR = std::dynamic_pointer_cast<Model_Document>(aRefDoc);
163         TDF_Label aRefLab;
164         TDF_Tool::Label(aDR->objects()->featuresLabel().Data(),
165           TCollection_AsciiString(theExtIter.Value()).ToCString(), aRefLab);
166         if (!aRefLab.IsNull()) {
167           anObj = aDR->objects()->object(aRefLab);
168         }
169       }
170       theExtIter.Next();
171     } else { // internal document object
172       anObj = theDoc->objects()->object(theLIter.Value());
173     }
174   }
175   return anObj;
176 }
177
178 std::list<ObjectPtr> Model_AttributeRefList::list()
179 {
180   std::list<ObjectPtr> aResult;
181   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
182       owner()->document());
183   if (aDoc) {
184     const TDF_LabelList& aList = myRef->List();
185     TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
186     for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
187       aResult.push_back(iteratedObject(aLIter, anExtIter, aDoc));
188     }
189   }
190   return aResult;
191 }
192
193 bool Model_AttributeRefList::isInList(const ObjectPtr& theObj)
194 {
195   if(!theObj.get()) {
196     return false;
197   }
198   if (theObj->document() == owner()->document()) { // this document object
199     std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
200         owner()->document());
201     if (aDoc) {
202       std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
203       if (aData.get() && aData->isValid()) {
204         TDF_Label anObjLab = aData->label().Father();
205         const TDF_LabelList& aList = myRef->List();
206         for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
207           if (aLIter.Value().IsEqual(anObjLab)) {
208             return true;
209           }
210         }
211       }
212     }
213   } else { // external document object
214     // create new lists because for the current moment remove one of the duplicated elements
215     // from the list is buggy
216     std::ostringstream anIdString; // string with document Id
217     anIdString<<theObj->document()->id();
218     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
219     TCollection_AsciiString anEntry;
220     TDF_Tool::Entry(aData->label().Father(), anEntry);
221     bool aFound = false;
222     TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
223     for (; anExtIter.More(); anExtIter.Next()) {
224       if (anExtIter.Value() == anIdString.str().c_str()) {
225         anExtIter.Next();
226         if (anExtIter.Value() == anEntry) { // fully maches
227           return true;
228         }
229       } else {
230         anExtIter.Next();
231       }
232     }
233   }
234   return false;
235 }
236
237 ObjectPtr Model_AttributeRefList::object(const int theIndex, const bool theWithEmpty) const
238 {
239   std::shared_ptr<Model_Document> aDoc =
240     std::dynamic_pointer_cast<Model_Document>(owner()->document());
241   if (aDoc) {
242     int anIndex = -1;
243     TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
244     for (TDF_ListIteratorOfLabelList aLIter(myRef->List()); aLIter.More(); aLIter.Next()) {
245       if (theWithEmpty || (!aLIter.Value().IsNull() && !aLIter.Value().IsRoot()))
246         anIndex++;
247       if (anIndex == theIndex) {
248         return iteratedObject(aLIter, anExtIter, aDoc);
249       }
250       if (aLIter.Value() == myRef->Label()) {
251         anExtIter.Next();
252         anExtIter.Next();
253       }
254     }
255   }
256   return ObjectPtr();
257 }
258
259 void Model_AttributeRefList::substitute(const ObjectPtr& theCurrent, const ObjectPtr& theNew)
260 {
261   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
262       owner()->document());
263   if (aDoc) {
264     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theCurrent->data());
265     if (aData.get() && aData->isValid()) {
266       TDF_Label aCurrentLab = aData->label().Father();
267       TDF_Label aNewLab;
268       if (theNew.get() && theNew->data()->isValid()) { // the new may be null
269         std::shared_ptr<Model_Data> aNewData =
270           std::dynamic_pointer_cast<Model_Data>(theNew->data());
271         aNewLab = aNewData->label().Father();
272       } else {
273         aNewLab = aCurrentLab.Root(); // root means null object
274       }
275       // do the substitution
276       ADD_BACK_REF(theNew);
277       if (myRef->InsertAfter(aNewLab, aCurrentLab)) {
278         myRef->Remove(aCurrentLab);
279         REMOVE_BACK_REF(theCurrent);
280       }
281       owner()->data()->sendAttributeUpdated(this);
282     }
283   }
284 }
285
286 void Model_AttributeRefList::exchange(const ObjectPtr& theObject1, const ObjectPtr& theObject2)
287 {
288   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
289       owner()->document());
290   if (aDoc) {
291     std::shared_ptr<Model_Data> aData1 = std::dynamic_pointer_cast<Model_Data>(theObject1->data());
292     if (aData1.get() && aData1->isValid()) {
293       TDF_Label aLab1 = aData1->label().Father();
294       if (theObject2.get() && theObject2->data()->isValid()) { // the new may be null
295         std::shared_ptr<Model_Data> aData2 =
296           std::dynamic_pointer_cast<Model_Data>(theObject2->data());
297         if (aData2.get() && aData2->isValid()) {
298           TDF_Label aLab2 = aData2->label().Father();
299           // do the substitution: use the temporary label, as usually in exchange
300           TDF_Label aTmpLab = aLab1.Root();
301           if (myRef->InsertAfter(aTmpLab, aLab1)) {
302             myRef->Remove(aLab1);
303           }
304           if (myRef->InsertAfter(aLab1, aLab2)) {
305             myRef->Remove(aLab2);
306           }
307           if (myRef->InsertAfter(aLab2, aTmpLab)) {
308             myRef->Remove(aTmpLab);
309           }
310           owner()->data()->sendAttributeUpdated(this);
311         }
312       }
313     }
314   }
315 }
316
317 void Model_AttributeRefList::removeLast()
318 {
319   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
320       owner()->document());
321   if (aDoc && !myRef->IsEmpty()) {
322     ObjectPtr anObj = aDoc->objects()->object(myRef->Last());
323     if (anObj.get()) {
324       myRef->Remove(myRef->Last());
325       REMOVE_BACK_REF(anObj);
326       owner()->data()->sendAttributeUpdated(this);
327     }
328   }
329 }
330
331 void Model_AttributeRefList::remove(const std::set<int>& theIndices)
332 {
333   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
334       owner()->document());
335   if (aDoc && !myRef->IsEmpty()) {
336     // collet labels that will be removed
337     TDF_LabelList aLabelsToRemove;
338     TDF_ListIteratorOfLabelList aLabIter(myRef->List());
339     for(int aCurrent = 0; aLabIter.More(); aLabIter.Next(), aCurrent++) {
340       if (theIndices.find(aCurrent) != theIndices.end())
341         aLabelsToRemove.Append(aLabIter.Value());
342     }
343     // remove labels
344     for(aLabIter.Initialize(aLabelsToRemove); aLabIter.More(); aLabIter.Next()) {
345       ObjectPtr anObj = aDoc->objects()->object(aLabIter.Value());
346       if (anObj.get()) {
347         myRef->Remove(aLabIter.Value());
348         REMOVE_BACK_REF(anObj);
349       }
350     }
351     if (!aLabelsToRemove.IsEmpty()) {
352       owner()->data()->sendAttributeUpdated(this);
353     }
354   }
355 }
356
357 Model_AttributeRefList::Model_AttributeRefList(TDF_Label& theLabel)
358 {
359   myLab = theLabel;
360   reinit();
361 }
362
363 void Model_AttributeRefList::reinit()
364 {
365   myIsInitialized = myLab.FindAttribute(TDataStd_ReferenceList::GetID(), myRef) == Standard_True;
366   if (!myIsInitialized) {
367     myRef = TDataStd_ReferenceList::Set(myLab);
368   }
369   if (!myLab.FindAttribute(TDataStd_ExtStringList::GetID(), myExtDocRef)) {
370     myExtDocRef = TDataStd_ExtStringList::Set(myLab);
371   }
372 }