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) { // empty list is not initialized list: sketch will be not valid after add/undo
135 return ModelAPI_AttributeRefList::isInitialized();
138 ObjectPtr Model_AttributeRefList::iteratedObject(TDF_ListIteratorOfLabelList& theLIter,
139 TDataStd_ListIteratorOfListOfExtendedString& theExtIter,
140 std::shared_ptr<Model_Document> theDoc) const
143 if (!theLIter.Value().IsNull() && !theLIter.Value().IsRoot()) {
144 if (theLIter.Value() == myRef->Label()) { // external document object
145 int anID = atoi(TCollection_AsciiString(theExtIter.Value()).ToCString());
147 DocumentPtr aRefDoc = Model_Application::getApplication()->document(anID);
149 std::shared_ptr<Model_Document> aDR = std::dynamic_pointer_cast<Model_Document>(aRefDoc);
151 TDF_Tool::Label(aDR->objects()->featuresLabel().Data(),
152 TCollection_AsciiString(theExtIter.Value()).ToCString(), aRefLab);
153 if (!aRefLab.IsNull()) {
154 anObj = aDR->objects()->object(aRefLab);
158 } else { // internal document object
159 anObj = theDoc->objects()->object(theLIter.Value());
165 list<ObjectPtr> Model_AttributeRefList::list()
167 std::list<ObjectPtr> aResult;
168 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
169 owner()->document());
171 const TDF_LabelList& aList = myRef->List();
172 TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
173 for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
174 aResult.push_back(iteratedObject(aLIter, anExtIter, aDoc));
180 bool Model_AttributeRefList::isInList(const ObjectPtr& theObj)
185 if (theObj->document() == owner()->document()) { // this document object
186 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
187 owner()->document());
189 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
190 if (aData.get() && aData->isValid()) {
191 TDF_Label anObjLab = aData->label().Father();
192 const TDF_LabelList& aList = myRef->List();
193 for (TDF_ListIteratorOfLabelList aLIter(aList); aLIter.More(); aLIter.Next()) {
194 if (aLIter.Value().IsEqual(anObjLab)) {
200 } else { // external document object
201 // create new lists because for the current moment remove one of the duplicated elements
202 // from the list is buggy
203 std::ostringstream anIdString; // string with document Id
204 anIdString<<theObj->document()->id();
205 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObj->data());
206 TCollection_AsciiString anEntry;
207 TDF_Tool::Entry(aData->label().Father(), anEntry);
209 TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
210 for (; anExtIter.More(); anExtIter.Next()) {
211 if (anExtIter.Value() == anIdString.str().c_str()) {
213 if (anExtIter.Value() == anEntry) { // fully maches
224 ObjectPtr Model_AttributeRefList::object(const int theIndex, const bool theWithEmpty) const
226 std::shared_ptr<Model_Document> aDoc =
227 std::dynamic_pointer_cast<Model_Document>(owner()->document());
230 TDataStd_ListIteratorOfListOfExtendedString anExtIter(myExtDocRef->List());
231 for (TDF_ListIteratorOfLabelList aLIter(myRef->List()); aLIter.More(); aLIter.Next()) {
232 if (theWithEmpty || (!aLIter.Value().IsNull() && !aLIter.Value().IsRoot()))
234 if (anIndex == theIndex) {
235 return iteratedObject(aLIter, anExtIter, aDoc);
237 if (aLIter.Value() == myRef->Label()) {
246 void Model_AttributeRefList::substitute(const ObjectPtr& theCurrent, const ObjectPtr& theNew)
248 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
249 owner()->document());
251 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theCurrent->data());
252 if (aData.get() && aData->isValid()) {
253 TDF_Label aCurrentLab = aData->label().Father();
255 if (theNew.get() && theNew->data()->isValid()) { // the new may be null
256 std::shared_ptr<Model_Data> aNewData =
257 std::dynamic_pointer_cast<Model_Data>(theNew->data());
258 aNewLab = aNewData->label().Father();
260 aNewLab = aCurrentLab.Root(); // root means null object
262 // do the substitution
263 ADD_BACK_REF(theNew);
264 if (myRef->InsertAfter(aNewLab, aCurrentLab)) {
265 myRef->Remove(aCurrentLab);
266 REMOVE_BACK_REF(theCurrent);
268 owner()->data()->sendAttributeUpdated(this);
273 void Model_AttributeRefList::exchange(const ObjectPtr& theObject1, const ObjectPtr& theObject2)
275 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
276 owner()->document());
278 std::shared_ptr<Model_Data> aData1 = std::dynamic_pointer_cast<Model_Data>(theObject1->data());
279 if (aData1.get() && aData1->isValid()) {
280 TDF_Label aLab1 = aData1->label().Father();
281 if (theObject2.get() && theObject2->data()->isValid()) { // the new may be null
282 std::shared_ptr<Model_Data> aData2 =
283 std::dynamic_pointer_cast<Model_Data>(theObject2->data());
284 if (aData2.get() && aData2->isValid()) {
285 TDF_Label aLab2 = aData2->label().Father();
286 // do the substitution: use the temporary label, as usually in exchange
287 TDF_Label aTmpLab = aLab1.Root();
288 if (myRef->InsertAfter(aTmpLab, aLab1)) {
289 myRef->Remove(aLab1);
291 if (myRef->InsertAfter(aLab1, aLab2)) {
292 myRef->Remove(aLab2);
294 if (myRef->InsertAfter(aLab2, aTmpLab)) {
295 myRef->Remove(aTmpLab);
297 owner()->data()->sendAttributeUpdated(this);
304 void Model_AttributeRefList::removeLast()
306 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
307 owner()->document());
308 if (aDoc && !myRef->IsEmpty()) {
309 ObjectPtr anObj = aDoc->objects()->object(myRef->Last());
311 myRef->Remove(myRef->Last());
312 REMOVE_BACK_REF(anObj);
313 owner()->data()->sendAttributeUpdated(this);
318 void Model_AttributeRefList::remove(const std::set<int>& theIndices)
320 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(
321 owner()->document());
322 if (aDoc && !myRef->IsEmpty()) {
323 // collet labels that will be removed
324 TDF_LabelList aLabelsToRemove;
325 TDF_ListIteratorOfLabelList aLabIter(myRef->List());
326 for(int aCurrent = 0; aLabIter.More(); aLabIter.Next(), aCurrent++) {
327 if (theIndices.find(aCurrent) != theIndices.end())
328 aLabelsToRemove.Append(aLabIter.Value());
331 for(aLabIter.Initialize(aLabelsToRemove); aLabIter.More(); aLabIter.Next()) {
332 ObjectPtr anObj = aDoc->objects()->object(aLabIter.Value());
334 myRef->Remove(aLabIter.Value());
335 REMOVE_BACK_REF(anObj);
338 if (!aLabelsToRemove.IsEmpty()) {
339 owner()->data()->sendAttributeUpdated(this);
344 Model_AttributeRefList::Model_AttributeRefList(TDF_Label& theLabel)
346 myIsInitialized = theLabel.FindAttribute(TDataStd_ReferenceList::GetID(), myRef) == Standard_True;
347 if (!myIsInitialized) {
348 myRef = TDataStd_ReferenceList::Set(theLabel);
350 if (!theLabel.FindAttribute(TDataStd_ExtStringList::GetID(), myExtDocRef)) {
351 myExtDocRef = TDataStd_ExtStringList::Set(theLabel);