1 // Copyright (C) 2014-2023 CEA, EDF
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <ModuleBase_WidgetSelector.h>
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>
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>
40 #include <Config_WidgetAPI.h>
42 #include <TopoDS_Iterator.hxx>
44 // Get object from group
45 // Return true if find object
46 static bool getObjectFromGroup(ObjectPtr& theObject, GeomShapePtr& theShape);
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)
54 QString aFiltering = QString::fromStdString(theData->getProperty("filter_points"));
55 if (aFiltering.toLower() == "false")
56 myIsPointsFiltering = false;
59 //********************************************************************
60 ModuleBase_WidgetSelector::~ModuleBase_WidgetSelector()
64 //********************************************************************
65 void ModuleBase_WidgetSelector::getGeomSelection(const ModuleBase_ViewerPrsPtr& thePrs,
67 GeomShapePtr& theShape)
69 ModuleBase_ISelection* aSelection = myWorkshop->selection();
70 theObject = aSelection->getResult(thePrs);
72 theObject = thePrs->object();
73 theShape = aSelection->getShape(thePrs);
75 FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
76 while (aFeature.get() &&
77 aFeature->lastResult().get() &&
78 aFeature->lastResult()->groupName() == ModelAPI_ResultGroup::group()) {
79 if (!getObjectFromGroup(theObject, theShape))
81 aFeature = ModelAPI_Feature::feature(theObject);
83 thePrs->setObject(theObject);
87 //********************************************************************
88 bool ModuleBase_WidgetSelector::processSelection()
90 QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
91 // equal vertices should not be used here
92 if (myIsPointsFiltering)
93 ModuleBase_ISelection::filterSelectionOnEqualPoints(aSelected);
95 bool isDone = setSelection(aSelected, true/*false*/);
96 updateOnSelectionChanged(isDone);
101 //********************************************************************
102 void ModuleBase_WidgetSelector::updateOnSelectionChanged(const bool theDone)
104 // "false" flag should be used here, it connects to the #26658 OCC bug, when the user click in
105 // the same place repeatedly without mouse moved. In the case validation by filters is not
106 // perfromed, so an invalid object is selected. E.g. distance constraint, selection of a point.
107 // the 3rd click in the same point allow using this point.
108 emit valuesChanged();
109 // the updateObject method should be called to flush the updated sigal. The workshop listens it,
110 // calls validators for the feature and, as a result, updates the Apply button state.
111 updateObject(myFeature);
113 // we need to forget about previous validation result as the current selection can influence on it
114 clearValidatedCash();
120 //********************************************************************
121 QIntList ModuleBase_WidgetSelector::getShapeTypes() const
123 QIntList aShapeTypes = shapeTypes();
124 // this type should be mentioned in XML, poor selection otherwise
125 if (/*aShapeTypes.contains(TopAbs_SOLID) ||*/
126 aShapeTypes.contains(ModuleBase_ResultPrs::Sel_Result/*TopAbs_SHAPE*/)) {
127 // it should be selectable for both, "solids" and "objects" types
128 aShapeTypes.append(TopAbs_COMPSOLID);
133 //********************************************************************
134 QList<ModuleBase_ViewerPrsPtr> ModuleBase_WidgetSelector::getAttributeSelection() const
136 return QList<ModuleBase_ViewerPrsPtr>();
139 //********************************************************************
140 bool ModuleBase_WidgetSelector::acceptSubShape(const GeomShapePtr& theShape,
141 const ResultPtr& theResult) const
145 GeomShapePtr aShape = theShape;
147 QIntList aShapeTypes = getShapeTypes();
148 if (aShapeTypes.empty()) {
152 // when the SHAPE type is provided by XML as Object, the whole result shape should be selected.
153 //if (!aShape.get() && aShapeTypes.contains(ModuleBase_ResultPrs::Sel_Result)) {
154 // In case of selection of a feature aShape could be not NULL, but result has to be selected
155 if (aShapeTypes.contains(ModuleBase_ResultPrs::Sel_Result)) {
160 if (!aShape.get() && theResult.get()) {
162 aShape = theResult->shape();
164 TopAbs_ShapeEnum aShapeType = TopAbs_SHAPE;
166 // Check that the selection corresponds to selection type
167 TopoDS_Shape aTopoShape = aShape->impl<TopoDS_Shape>();
168 if (!aTopoShape.IsNull()) {
169 aShapeType = aTopoShape.ShapeType();
170 // for compounds check sub-shapes: it may be compound of needed type:
171 // Booleans may produce compounds of Solids
172 if (aShapeType == TopAbs_COMPOUND) {
173 aShapeType = ModuleBase_Tools::getCompoundSubType(aTopoShape);
178 QIntList::const_iterator anIt = aShapeTypes.begin(), aLast = aShapeTypes.end();
179 for (; anIt != aLast && !aValid; anIt++) {
180 TopAbs_ShapeEnum aCurrentShapeType = (TopAbs_ShapeEnum)*anIt;
181 if (aShapeType == aCurrentShapeType)
183 else if (aCurrentShapeType == TopAbs_FACE) {
184 // try to process the construction shape only if there is no a selected shape in the viewer
185 if (!theShape.get() && theResult.get()) {
186 ResultConstructionPtr aCResult =
187 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theResult);
188 aValid = aCResult.get() && aCResult->facesNum() > 0;
195 //********************************************************************
196 void ModuleBase_WidgetSelector::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
198 theModuleSelectionModes = -1;
199 theModes.append(getShapeTypes());
202 //********************************************************************
203 void ModuleBase_WidgetSelector::updateSelectionModesAndFilters(bool toActivate)
205 updateSelectionName();
207 myWorkshop->selectionActivate()->updateSelectionFilters();
208 myWorkshop->selectionActivate()->updateSelectionModes();
211 clearValidatedCash();
214 //********************************************************************
215 void ModuleBase_WidgetSelector::activateCustom()
217 // Restore selection in the viewer by the attribute selection list
218 // it should be postponed to have current widget as active to validate restored selection
219 static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION);
220 ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
223 //********************************************************************
224 bool ModuleBase_WidgetSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
226 GeomShapePtr aShape = myWorkshop->selection()->getShape(thePrs);
227 ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
228 bool aValid = aResult.get();
229 if (!isWholeResultAllowed())
230 aValid = acceptSubShape(aShape, aResult);
233 // In order to avoid selection of the same object
234 aResult = myWorkshop->selection()->getResult(thePrs);
235 FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aResult);
236 aValid = aSelectedFeature != myFeature;
241 //********************************************************************
242 bool ModuleBase_WidgetSelector::setSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
246 getGeomSelection(thePrs, anObject, aShape);
248 // the last flag is to be depending on hasObject is called before. To be corrected later
249 return ModuleBase_Tools::setObject(attribute(), anObject, aShape,
250 myWorkshop, myIsInValidate, true);
253 //********************************************************************
254 void ModuleBase_WidgetSelector::deactivate()
256 ModuleBase_WidgetValidated::deactivate();
257 /// clear temporary cash
258 AttributePtr anAttribute = attribute();
259 if (!anAttribute.get())
261 std::string aType = anAttribute->attributeType();
262 if (anAttribute->attributeType() == ModelAPI_AttributeSelection::typeId()) {
263 AttributeSelectionPtr aSelectAttr =
264 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(anAttribute);
265 aSelectAttr->removeTemporaryValues();
267 else if (anAttribute->attributeType() == ModelAPI_AttributeSelectionList::typeId()) {
268 AttributeSelectionListPtr aSelectAttr =
269 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(anAttribute);
270 aSelectAttr->removeTemporaryValues();
274 //********************************************************************
275 bool ModuleBase_WidgetSelector::isWholeResultAllowed() const
277 AttributePtr anAttribute = attribute();
278 if (anAttribute.get()) {
279 AttributeSelectionListPtr aSelAttr =
280 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(anAttribute);
282 return aSelAttr->isWholeResultAllowed();
287 bool getObjectFromGroup(ObjectPtr& theObject, GeomShapePtr& theShape)
289 FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
291 AttributeSelectionListPtr anAttrList = aFeature->selectionList("group_list");
293 for (int anIndex = 0; anIndex < anAttrList->size(); ++anIndex) {
294 AttributeSelectionPtr aSelect = anAttrList->value(anIndex);
295 if (aSelect->context()->shape()->isSubShape(theShape) ||
296 aSelect->context()->shape()->isEqual(theShape)) {
297 theObject = aSelect->contextObject();