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