Salome HOME
Split circle. Remain coincidence with newly created arc (issue #1725)
[modules/shaper.git] / src / Model / Model_AttributeSelectionList.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_AttributeSelectionList.cpp
4 // Created:     22 Oct 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include "Model_AttributeSelectionList.h"
8 #include "Model_AttributeSelection.h"
9 #include "Model_Application.h"
10 #include "Model_Events.h"
11 #include "Model_Data.h"
12
13 #include <TDF_AttributeIterator.hxx>
14 #include <TDF_ChildIterator.hxx>
15 #include <TDF_RelocationTable.hxx>
16 #include <TopAbs_ShapeEnum.hxx>
17 #include <TopoDS.hxx>
18 #include <TopoDS_Shape.hxx>
19 #include <TopoDS_Edge.hxx>
20 #include <BRep_Tool.hxx>
21 #include <TNaming_Builder.hxx>
22 #include <TNaming_Iterator.hxx>
23
24 using namespace std;
25
26 void Model_AttributeSelectionList::append(
27     const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
28     const bool theTemporarily)
29 {
30   // do not use the degenerated edge as a shape, a list is not incremented in this case
31   if (theSubShape.get() && !theSubShape->isNull() && theSubShape->isEdge()) {
32     const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
33     if (aSubShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aSubShape))) {
34       return;
35     }
36   }
37
38   if (myIsCashed && !theTemporarily) {
39     myCash[theContext].push_back(theSubShape);
40   }
41
42   int aNewTag = mySize->Get() + 1;
43   TDF_Label aNewLab = mySize->Label().FindChild(aNewTag);
44
45   std::shared_ptr<Model_AttributeSelection> aNewAttr = 
46     std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aNewLab));
47   if (owner()) {
48     aNewAttr->setObject(owner());
49   }
50   aNewAttr->setID(id());
51   mySize->Set(aNewTag);
52   aNewAttr->setValue(theContext, theSubShape, theTemporarily);
53   if (theTemporarily)
54     myTmpAttr = aNewAttr;
55   else 
56     myTmpAttr.reset();
57   owner()->data()->sendAttributeUpdated(this);
58 }
59
60 void Model_AttributeSelectionList::append(
61   const std::string theNamingName, const std::string& theType)
62 {
63   int aNewTag = mySize->Get() + 1;
64   TDF_Label aNewLab = mySize->Label().FindChild(aNewTag);
65
66   std::shared_ptr<Model_AttributeSelection> aNewAttr = 
67     std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aNewLab));
68   if (owner()) {
69     aNewAttr->setObject(owner());
70   }
71   aNewAttr->setID(id());
72   mySize->Set(aNewTag);
73   aNewAttr->selectSubShape(theType.empty() ? selectionType() : theType, theNamingName);
74   owner()->data()->sendAttributeUpdated(this);
75 }
76
77 void Model_AttributeSelectionList::removeLast() 
78 {
79   int anOldSize = mySize->Get();
80   if (anOldSize != 0) {
81     mySize->Set(anOldSize - 1);
82     TDF_Label aLab = mySize->Label().FindChild(anOldSize);
83     std::shared_ptr<Model_AttributeSelection> aOldAttr = 
84       std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aLab));
85     aOldAttr->setObject(owner());
86     REMOVE_BACK_REF(aOldAttr->context());
87     aLab.ForgetAllAttributes(Standard_True);
88     myTmpAttr.reset();
89     owner()->data()->sendAttributeUpdated(this);
90   }
91 }
92
93 // copies named shapes: we need the implementation of this 
94 static void CopyNS(const Handle(TNaming_NamedShape)& theFrom,
95   const Handle(TDF_Attribute)& theTo)
96
97   TDF_Label aLab = theTo->Label();
98   TNaming_Builder B(aLab);
99
100   TNaming_Iterator It (theFrom);
101   for ( ;It.More() ; It.Next()) {
102     const TopoDS_Shape& OS     = It.OldShape();
103     const TopoDS_Shape& NS     = It.NewShape();
104     TNaming_Evolution   Status = It.Evolution();
105
106     switch (Status) {
107     case TNaming_PRIMITIVE :
108       B.Generated(NS);
109       break;
110     case TNaming_GENERATED :
111       B.Generated(OS, NS);
112       break;
113     case TNaming_MODIFY : 
114       B.Modify(OS, NS);
115       break;
116     case TNaming_DELETE : 
117       B.Delete (OS);
118       break;
119     case TNaming_SELECTED :
120       B.Select(NS, OS);
121       break;
122     default:
123       break;
124     }
125   }
126 }
127
128 /// makes copy of all attributes on the given label and all sub-labels
129 static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
130   TDF_AttributeIterator anAttrIter(theSource);
131   for(; anAttrIter.More(); anAttrIter.Next()) {
132     Handle(TDF_Attribute) aTargetAttr;
133     if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
134       // create a new attribute if not yet exists in the destination
135             aTargetAttr = anAttrIter.Value()->NewEmpty();
136       theDestination.AddAttribute(aTargetAttr);
137     }
138     // for named shape copy exact shapes (in NamedShape Paste method the CopyTool is used)
139     Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(anAttrIter.Value());
140     if (aNS.IsNull()) {
141       Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(); // no relocation, empty map
142       anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
143     } else {
144       CopyNS(aNS, aTargetAttr);
145     }
146   }
147   // copy the sub-labels content
148   TDF_ChildIterator aSubLabsIter(theSource);
149   for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
150     copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()));
151   }
152 }
153
154 void Model_AttributeSelectionList::remove(const std::set<int>& theIndices)
155 {
156   int anOldSize = mySize->Get();
157   int aRemoved = 0;
158   // iterate one by one and shifting the removed indicies
159   for(int aCurrent = 0; aCurrent < anOldSize; aCurrent++) {
160     if (theIndices.find(aCurrent) == theIndices.end()) { // not removed
161       if (aRemoved) { // but must be shifted to the removed position
162         TDF_Label aSource = mySize->Label().FindChild(aCurrent + 1);
163         TDF_Label aDest = mySize->Label().FindChild(aCurrent + 1 - aRemoved);
164         copyAttrs(aSource, aDest);
165         // remove the moved source
166         aSource.ForgetAllAttributes(Standard_True);
167       }
168     } else { // this is removed, so remove everything from this label
169       TDF_Label aLab = mySize->Label().FindChild(aCurrent + 1);
170       std::shared_ptr<Model_AttributeSelection> aOldAttr = 
171         std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aLab));
172       aOldAttr->setObject(owner());
173       REMOVE_BACK_REF(aOldAttr->context());
174       aLab.ForgetAllAttributes(Standard_True);
175       myTmpAttr.reset();
176       aRemoved++;
177     }
178   }
179   if (aRemoved) { // remove was performed, so, update the size and this attribute
180     mySize->Set(anOldSize - aRemoved);
181     owner()->data()->sendAttributeUpdated(this);
182   }
183 }
184
185 int Model_AttributeSelectionList::size()
186 {
187   return mySize->Get();
188 }
189
190 bool Model_AttributeSelectionList::isInList(const ResultPtr& theContext,
191                                             const std::shared_ptr<GeomAPI_Shape>& theSubShape,
192                                             const bool theTemporarily)
193 {
194   if (myIsCashed) { // the cashing is active
195     std::map<ResultPtr, std::list<std::shared_ptr<GeomAPI_Shape> > >::iterator aContext =
196       myCash.find(theContext);
197     if (aContext != myCash.end()) {
198       // iterate shapes because "isEqual" method must be called for each shape
199       std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aShapes = aContext->second.begin();
200       for(; aShapes != aContext->second.end(); aShapes++) {
201         if (!theSubShape.get()) {
202           if (!aShapes->get())
203             return true;
204         } else {
205           if (theSubShape->isEqual(*aShapes))
206             return true;
207         }
208       }
209     }
210     return false;
211   }
212   // no-cash method
213   for(int anIndex = size() - 1; anIndex >= 0; anIndex--) {
214     AttributeSelectionPtr anAttr = value(anIndex);
215     if (anAttr.get()) {
216       if (anAttr->context() == theContext) { // contexts are equal, so, check that values are also
217         std::shared_ptr<GeomAPI_Shape> aValue = anAttr->value();
218         if (!aValue.get()) {
219           if (!theSubShape.get()) { // both are null
220             return true;
221           }
222         } else {
223           if (aValue->isEqual(theSubShape)) // shapes are equal
224             return true;
225         }
226       }
227     }
228   }
229   return false;
230 }
231
232 const std::string Model_AttributeSelectionList::selectionType() const
233 {
234   return TCollection_AsciiString(mySelectionType->Get()).ToCString();
235 }
236
237 void Model_AttributeSelectionList::setSelectionType(const std::string& theType)
238 {
239   mySelectionType->Set(theType.c_str());
240 }
241
242 std::shared_ptr<ModelAPI_AttributeSelection> 
243   Model_AttributeSelectionList::value(const int theIndex)
244 {
245   if (myTmpAttr.get() && theIndex == size() - 1) {
246     return myTmpAttr;
247   }
248   TDF_Label aLabel = mySize->Label().FindChild(theIndex + 1);
249   // create a new attribute each time, by demand
250   // supporting of old attributes is too slow (synch each time) and buggy on redo
251   // (if attribute is deleted and created, the abort updates attriute and makes the Attr invalid)
252   std::shared_ptr<Model_AttributeSelection> aNewAttr = 
253     std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aLabel));
254   if (owner()) {
255     aNewAttr->setObject(owner());
256   }
257   return aNewAttr;
258 }
259
260 void Model_AttributeSelectionList::clear()
261 {
262   if (mySize->Get() != 0) {
263     mySize->Set(0);
264     myTmpAttr.reset();
265     TDF_ChildIterator aSubIter(mySize->Label());
266     for(; aSubIter.More(); aSubIter.Next()) {
267       TDF_Label aLab = aSubIter.Value();
268       std::shared_ptr<Model_AttributeSelection> aNewAttr = 
269         std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aLab));
270       if (owner()) {
271         aNewAttr->setObject(owner());
272       }
273       REMOVE_BACK_REF(aNewAttr->context());
274
275       aLab.ForgetAllAttributes(Standard_True);
276     }
277     owner()->data()->sendAttributeUpdated(this);
278   }
279 }
280
281 bool Model_AttributeSelectionList::isInitialized()
282 {
283   if (size() == 0) { // empty list is not initialized list: sketch will be not valid after add/undo
284     return false;
285   }
286   return ModelAPI_AttributeSelectionList::isInitialized();
287 }
288
289 Model_AttributeSelectionList::Model_AttributeSelectionList(TDF_Label& theLabel)
290 {
291   myLab = theLabel;
292   reinit();
293 }
294
295 void Model_AttributeSelectionList::reinit()
296 {
297   myIsInitialized = myLab.FindAttribute(TDataStd_Integer::GetID(), mySize) == Standard_True;
298   if (!myIsInitialized) {
299     mySize = TDataStd_Integer::Set(myLab, 0);
300     mySelectionType = TDataStd_Comment::Set(myLab, "");
301   } else { // recollect mySubs
302     myLab.FindAttribute(TDataStd_Comment::GetID(), mySelectionType);
303   }
304   myIsCashed = false;
305 }
306
307
308 void Model_AttributeSelectionList::cashValues(const bool theEnabled)
309 {
310   myIsCashed = theEnabled;
311   myCash.clear(); // empty list as indicator that cash is not used
312   if (theEnabled) {
313     for(int anIndex = size() - 1; anIndex >= 0; anIndex--) {
314       AttributeSelectionPtr anAttr = value(anIndex);
315       if (anAttr.get()) {
316         myCash[anAttr->context()].push_back(anAttr->value());
317       }
318     }
319   }
320 }