Salome HOME
6876a337fbd189abaf27279d04d8f4dbe6fcc997
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetSelector.cpp
1 // Copyright (C) 2014-2022  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 email : webmaster.salome@opencascade.com
18 //
19
20 #include <ModuleBase_WidgetSelector.h>
21
22 #include <ModuleBase_Events.h>
23 #include <ModuleBase_IModule.h>
24 #include <ModuleBase_ISelection.h>
25 #include <ModuleBase_ISelectionActivate.h>
26 #include <ModuleBase_IWorkshop.h>
27 #include <ModuleBase_Operation.h>
28 #include <ModuleBase_OperationDescription.h>
29 #include <ModuleBase_ResultPrs.h>
30 #include <ModuleBase_Tools.h>
31 #include <ModuleBase_ViewerPrs.h>
32 #include <ModuleBase_WidgetFactory.h>
33
34 #include <ModelAPI_AttributeSelection.h>
35 #include <ModelAPI_AttributeSelectionList.h>
36 #include <ModelAPI_Events.h>
37 #include <ModelAPI_ResultConstruction.h>
38 #include <ModelAPI_ResultGroup.h>
39
40 #include <Config_WidgetAPI.h>
41
42 #include <TopoDS_Iterator.hxx>
43
44 // Get object from group
45 // Return true if find object
46 static bool getObjectFromGroup(ObjectPtr& theObject, GeomShapePtr& theShape);
47
48 ModuleBase_WidgetSelector::ModuleBase_WidgetSelector(QWidget* theParent,
49                                                      ModuleBase_IWorkshop* theWorkshop,
50                                                      const Config_WidgetAPI* theData)
51 : ModuleBase_WidgetValidated(theParent, theWorkshop, theData),
52 myIsPointsFiltering(true)
53 {
54   QString aFiltering = QString::fromStdString(theData->getProperty("filter_points"));
55   if (aFiltering.toLower() == "false")
56     myIsPointsFiltering = false;
57 }
58
59 //********************************************************************
60 ModuleBase_WidgetSelector::~ModuleBase_WidgetSelector()
61 {
62 }
63
64 //********************************************************************
65 void ModuleBase_WidgetSelector::getGeomSelection(const ModuleBase_ViewerPrsPtr& thePrs,
66                                                       ObjectPtr& theObject,
67                                                       GeomShapePtr& theShape)
68 {
69   ModuleBase_ISelection* aSelection = myWorkshop->selection();
70   theObject = aSelection->getResult(thePrs);
71   if (!theObject.get())
72     theObject = thePrs->object();
73   theShape = aSelection->getShape(thePrs);
74
75   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
76   while (aFeature && aFeature->lastResult()->groupName() == ModelAPI_ResultGroup::group()) {
77     if (!getObjectFromGroup(theObject, theShape))
78       break;
79     aFeature = ModelAPI_Feature::feature(theObject);
80
81     thePrs->setObject(theObject);
82   }
83 }
84
85 //********************************************************************
86 bool ModuleBase_WidgetSelector::processSelection()
87 {
88   QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
89   // equal vertices should not be used here
90   if (myIsPointsFiltering)
91     ModuleBase_ISelection::filterSelectionOnEqualPoints(aSelected);
92
93   bool isDone = setSelection(aSelected, true/*false*/);
94   updateOnSelectionChanged(isDone);
95
96   return isDone;
97 }
98
99 //********************************************************************
100 void ModuleBase_WidgetSelector::updateOnSelectionChanged(const bool theDone)
101 {
102   // "false" flag should be used here, it connects to the #26658 OCC bug, when the user click in
103   // the same place repeatedly without mouse moved. In the case validation by filters is not
104   // perfromed, so an invalid object is selected. E.g. distance constraint, selection of a point.
105   // the 3rd click in the same point allow using this point.
106   emit valuesChanged();
107   // the updateObject method should be called to flush the updated sigal. The workshop listens it,
108   // calls validators for the feature and, as a result, updates the Apply button state.
109   updateObject(myFeature);
110
111   // we need to forget about previous validation result as the current selection can influence on it
112   clearValidatedCash();
113
114   if (theDone)
115     updateFocus();
116 }
117
118 //********************************************************************
119 QIntList ModuleBase_WidgetSelector::getShapeTypes() const
120 {
121   QIntList aShapeTypes = shapeTypes();
122   // this type should be mentioned in XML, poor selection otherwise
123   if (/*aShapeTypes.contains(TopAbs_SOLID) ||*/
124       aShapeTypes.contains(ModuleBase_ResultPrs::Sel_Result/*TopAbs_SHAPE*/)) {
125     // it should be selectable for both, "solids" and "objects" types
126     aShapeTypes.append(TopAbs_COMPSOLID);
127   }
128   return aShapeTypes;
129 }
130
131 //********************************************************************
132 QList<ModuleBase_ViewerPrsPtr> ModuleBase_WidgetSelector::getAttributeSelection() const
133 {
134   return QList<ModuleBase_ViewerPrsPtr>();
135 }
136
137 //********************************************************************
138 bool ModuleBase_WidgetSelector::acceptSubShape(const GeomShapePtr& theShape,
139                                                const ResultPtr& theResult) const
140 {
141   bool aValid = false;
142
143   GeomShapePtr aShape = theShape;
144
145   QIntList aShapeTypes = getShapeTypes();
146   if (aShapeTypes.empty()) {
147     aValid = true;
148     return aValid;
149   }
150   // when the SHAPE type is provided by XML as Object, the whole result shape should be selected.
151   //if (!aShape.get() && aShapeTypes.contains(ModuleBase_ResultPrs::Sel_Result)) {
152   // In case of selection of a feature aShape could be not NULL, but result has to be selected
153   if (aShapeTypes.contains(ModuleBase_ResultPrs::Sel_Result)) {
154     aValid = true;
155     return aValid;
156   }
157
158   if (!aShape.get() && theResult.get()) {
159     if (theResult.get())
160       aShape = theResult->shape();
161   }
162   TopAbs_ShapeEnum aShapeType = TopAbs_SHAPE;
163   if (aShape.get()) {
164     // Check that the selection corresponds to selection type
165     TopoDS_Shape aTopoShape = aShape->impl<TopoDS_Shape>();
166     if (!aTopoShape.IsNull()) {
167       aShapeType = aTopoShape.ShapeType();
168       // for compounds check sub-shapes: it may be compound of needed type:
169       // Booleans may produce compounds of Solids
170       if (aShapeType == TopAbs_COMPOUND) {
171         aShapeType = ModuleBase_Tools::getCompoundSubType(aTopoShape);
172       }
173     }
174   }
175
176   QIntList::const_iterator anIt = aShapeTypes.begin(), aLast = aShapeTypes.end();
177   for (; anIt != aLast && !aValid; anIt++) {
178     TopAbs_ShapeEnum aCurrentShapeType = (TopAbs_ShapeEnum)*anIt;
179     if (aShapeType == aCurrentShapeType)
180       aValid = true;
181     else if (aCurrentShapeType == TopAbs_FACE) {
182       // try to process the construction shape only if there is no a selected shape in the viewer
183       if (!theShape.get() && theResult.get()) {
184         ResultConstructionPtr aCResult =
185                                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theResult);
186         aValid = aCResult.get() && aCResult->facesNum() > 0;
187       }
188     }
189   }
190   return aValid;
191 }
192
193 //********************************************************************
194 void ModuleBase_WidgetSelector::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
195 {
196   theModuleSelectionModes = -1;
197   theModes.append(getShapeTypes());
198 }
199
200 //********************************************************************
201 void ModuleBase_WidgetSelector::updateSelectionModesAndFilters(bool toActivate)
202 {
203   updateSelectionName();
204
205   myWorkshop->selectionActivate()->updateSelectionFilters();
206   myWorkshop->selectionActivate()->updateSelectionModes();
207
208   if (!toActivate)
209     clearValidatedCash();
210 }
211
212 //********************************************************************
213 void ModuleBase_WidgetSelector::activateCustom()
214 {
215   // Restore selection in the viewer by the attribute selection list
216   // it should be postponed to have current widget as active to validate restored selection
217   static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION);
218   ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
219 }
220
221 //********************************************************************
222 bool ModuleBase_WidgetSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
223 {
224   GeomShapePtr aShape = myWorkshop->selection()->getShape(thePrs);
225   ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
226   bool aValid = aResult.get();
227   if (!isWholeResultAllowed())
228     aValid = acceptSubShape(aShape, aResult);
229
230   if (aValid) {
231     // In order to avoid selection of the same object
232     aResult = myWorkshop->selection()->getResult(thePrs);
233     FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aResult);
234     aValid = aSelectedFeature != myFeature;
235   }
236   return aValid;
237 }
238
239 //********************************************************************
240 bool ModuleBase_WidgetSelector::setSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
241 {
242   ObjectPtr anObject;
243   GeomShapePtr aShape;
244   getGeomSelection(thePrs, anObject, aShape);
245
246   // the last flag is to be depending on hasObject is called before. To be corrected later
247   return ModuleBase_Tools::setObject(attribute(), anObject, aShape,
248                                      myWorkshop, myIsInValidate, true);
249 }
250
251 //********************************************************************
252 void ModuleBase_WidgetSelector::deactivate()
253 {
254   ModuleBase_WidgetValidated::deactivate();
255   /// clear temporary cash
256   AttributePtr anAttribute = attribute();
257   if (!anAttribute.get())
258     return;
259   std::string aType = anAttribute->attributeType();
260   if (anAttribute->attributeType() == ModelAPI_AttributeSelection::typeId()) {
261     AttributeSelectionPtr aSelectAttr =
262                              std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(anAttribute);
263     aSelectAttr->removeTemporaryValues();
264   }
265   else if (anAttribute->attributeType() == ModelAPI_AttributeSelectionList::typeId()) {
266     AttributeSelectionListPtr aSelectAttr =
267                       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(anAttribute);
268     aSelectAttr->removeTemporaryValues();
269   }
270 }
271
272 //********************************************************************
273 bool ModuleBase_WidgetSelector::isWholeResultAllowed() const
274 {
275   AttributePtr anAttribute = attribute();
276   if (anAttribute.get()) {
277     AttributeSelectionListPtr aSelAttr =
278       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(anAttribute);
279     if (aSelAttr.get())
280       return aSelAttr->isWholeResultAllowed();
281   }
282   return false;
283 }
284
285 bool getObjectFromGroup(ObjectPtr& theObject, GeomShapePtr& theShape)
286 {
287   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
288
289   AttributeSelectionListPtr anAttrList = aFeature->selectionList("group_list");
290
291   for (int anIndex = 0; anIndex < anAttrList->size(); ++anIndex) {
292     AttributeSelectionPtr aSelect = anAttrList->value(anIndex);
293     if (aSelect->context()->shape()->isSubShape(theShape) ||
294         aSelect->context()->shape()->isEqual(theShape)) {
295       theObject = aSelect->contextObject();
296       return true;
297     }
298   }
299   return false;
300 }