Salome HOME
Issue #1305: Make different gray color for selectable and non-selectable items
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetValidated.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include <ModuleBase_WidgetValidated.h>
4 #include <ModuleBase_FilterFactory.h>
5 #include <ModuleBase_IViewer.h>
6 #include <ModuleBase_ISelection.h>
7
8 #include <ModelAPI_Session.h>
9 #include <ModelAPI_Validator.h>
10 #include <ModelAPI_AttributeValidator.h>
11 #include <ModelAPI_Events.h>
12 #include <ModelAPI_ResultCompSolid.h>
13 #include <ModelAPI_Tools.h>
14
15 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
16 #include <SelectMgr_EntityOwner.hxx>
17 #include <StdSelect_BRepOwner.hxx>
18
19 #include <Events_Loop.h>
20
21 #include <QWidget>
22
23 //#define DEBUG_VALID_STATE
24
25 ModuleBase_WidgetValidated::ModuleBase_WidgetValidated(QWidget* theParent,
26                                                        ModuleBase_IWorkshop* theWorkshop,
27                                                        const Config_WidgetAPI* theData)
28 : ModuleBase_ModelWidget(theParent, theData),
29   myWorkshop(theWorkshop), myIsInValidate(false)
30 {
31 }
32
33 ModuleBase_WidgetValidated::~ModuleBase_WidgetValidated()
34 {
35 }
36
37 //********************************************************************
38 bool ModuleBase_WidgetValidated::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
39                                               const bool theToValidate)
40 {
41   if (theValues.empty()) {
42     // In order to make reselection possible, set empty object and shape should be done
43     setSelectionCustom(ModuleBase_ViewerPrs());
44     return false;
45   }
46   // it removes the processed value from the parameters list
47   ModuleBase_ViewerPrs aValue = theValues.takeFirst();
48   bool isDone = false;
49
50   if (!theToValidate || isValidInFilters(aValue)) {
51     isDone = setSelectionCustom(aValue);
52     // updateObject - to update/redisplay feature
53     // it is commented in order to perfom it outside the method
54     //updateObject(myFeature);
55     // to storeValue()
56     //emit valuesChanged();
57   }
58   return isDone;
59 }
60
61 //********************************************************************
62 ObjectPtr ModuleBase_WidgetValidated::findPresentedObject(const AISObjectPtr& theAIS) const
63 {
64   return myPresentedObject;
65 }
66
67 //********************************************************************
68 void ModuleBase_WidgetValidated::clearValidatedCash()
69 {
70   myValidPrs.clear();
71   myInvalidPrs.clear();
72 }
73
74 //********************************************************************
75 void ModuleBase_WidgetValidated::storeAttributeValue()
76 {
77   myIsInValidate = true;
78 }
79
80 //********************************************************************
81 void ModuleBase_WidgetValidated::restoreAttributeValue(const bool theValid)
82 {
83   myIsInValidate = false;
84 }
85
86 //********************************************************************
87 bool ModuleBase_WidgetValidated::isValidInFilters(const ModuleBase_ViewerPrs& thePrs)
88 {
89   bool aValid = true;
90   Handle(SelectMgr_EntityOwner) anOwner = thePrs.owner();
91
92   // if an owner is null, the selection happens in the Object browser.
93   // creates a selection owner on the base of object shape and the object AIS object
94   if (anOwner.IsNull() && thePrs.owner().IsNull() && thePrs.object().get()) {
95     ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
96     if (aResult.get() && aResult->shape().get()) {
97       // some results have no shape, e.g. the parameter one. So, they should not be validated
98       GeomShapePtr aShape = aResult->shape();
99       const TopoDS_Shape aTDShape = aShape->impl<TopoDS_Shape>();
100       Handle(AIS_InteractiveObject) anIO = myWorkshop->selection()->getIO(thePrs);
101       anOwner = new StdSelect_BRepOwner(aTDShape, anIO);
102       myPresentedObject = aResult;
103     }
104     else
105       aValid = false; // only results with a shape can be filtered
106   }
107   // checks the owner by the AIS context activated filters
108   if (!anOwner.IsNull()) {
109     // the widget validator filter should be active, but during check by preselection
110     // it is not yet activated, so we need to activate/deactivate it manually
111     bool isActivated = isFilterActivated();
112     if (!isActivated)
113       activateFilters(true);
114
115     Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
116     if (!aContext.IsNull()) {
117       const SelectMgr_ListOfFilter& aFilters = aContext->Filters();
118       SelectMgr_ListIteratorOfListOfFilter anIt(aFilters);
119       for (; anIt.More() && aValid; anIt.Next()) {
120         Handle(SelectMgr_Filter) aFilter = anIt.Value();
121         aValid = aFilter->IsOk(anOwner);
122       }
123     }
124     if (!isActivated)
125       activateFilters(false);
126   }
127
128   // removes created owner
129   if (!anOwner.IsNull() && anOwner != thePrs.owner()) {
130     anOwner.Nullify();
131     myPresentedObject = ObjectPtr();
132   }
133   return aValid;
134 }
135
136 //********************************************************************
137 bool ModuleBase_WidgetValidated::isValidSelection(const ModuleBase_ViewerPrs& theValue)
138 {
139   bool aValid = false;
140   if (getValidState(theValue, aValid)) {
141     return aValid;
142   }
143
144   aValid = isValidSelectionCustom(theValue);
145   if (!aValid) {
146     storeValidState(theValue, aValid);
147     return aValid;
148   }
149
150   // stores the current values of the widget attribute
151   bool isFlushesActived, isAttributeSetInitializedBlocked;
152   blockAttribute(true, isFlushesActived, isAttributeSetInitializedBlocked);
153
154   storeAttributeValue();
155
156   // saves the owner value to the widget attribute
157   aValid = setSelectionCustom(theValue);
158   if (aValid)
159     // checks the attribute validity
160     aValid = isValidAttribute();
161
162   // restores the current values of the widget attribute
163   restoreAttributeValue(aValid);
164
165   blockAttribute(false, isFlushesActived, isAttributeSetInitializedBlocked);
166   // In particular case the results are deleted and called as redisplayed inside of this
167   // highlight-selection, to they must be flushed as soon as possible.
168   // Example: selection of group-vertices subshapes with shift pressend on body. Without
169   //  these 4 lines below the application crashes because of left presentations on
170   //  removed results still in the viewer.
171   static Events_ID aDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
172   static Events_ID aRedispEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
173   Events_Loop::loop()->flush(aDeletedEvent);
174   Events_Loop::loop()->flush(aRedispEvent);
175
176   storeValidState(theValue, aValid);
177   return aValid;
178 }
179
180 //********************************************************************
181 bool ModuleBase_WidgetValidated::isValidSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
182 {
183   return true;
184 }
185
186 //********************************************************************
187 bool ModuleBase_WidgetValidated::isValidAttribute() const
188 {
189   SessionPtr aMgr = ModelAPI_Session::get();
190   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
191   AttributePtr anAttribute = myFeature->attribute(attributeID());
192   std::string aValidatorID, anError;
193   return aFactory->validate(anAttribute, aValidatorID, anError);
194 }
195
196 bool ModuleBase_WidgetValidated::isFilterActivated() const
197 {
198   bool isActivated = false;
199
200   Handle(SelectMgr_Filter) aSelFilter = myWorkshop->validatorFilter();
201   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
202
203   return aViewer->hasSelectionFilter(aSelFilter);
204 }
205
206 bool ModuleBase_WidgetValidated::activateFilters(const bool toActivate)
207 {
208   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
209
210   Handle(SelectMgr_Filter) aSelFilter = myWorkshop->validatorFilter();
211   bool aHasSelectionFilter = aViewer->hasSelectionFilter(aSelFilter);
212
213   if (toActivate)
214     aViewer->addSelectionFilter(aSelFilter);
215   else {
216     aViewer->removeSelectionFilter(aSelFilter);
217     clearValidState();
218   }
219
220   return aHasSelectionFilter;
221 }
222
223 //********************************************************************
224 void ModuleBase_WidgetValidated::blockAttribute(const bool& theToBlock, bool& isFlushesActived,
225                                                 bool& isAttributeSetInitializedBlocked)
226 {
227   Events_Loop* aLoop = Events_Loop::loop();
228   DataPtr aData = myFeature->data();
229   AttributePtr anAttribute = myFeature->attribute(attributeID());
230   if (theToBlock) {
231     // blocks the flush signals to avoid the temporary objects visualization in the viewer
232     // they should not be shown in order to do not lose highlight by erasing them
233     isFlushesActived = aLoop->activateFlushes(false);
234
235     aData->blockSendAttributeUpdated(true);
236     isAttributeSetInitializedBlocked = anAttribute->blockSetInitialized(true);
237   }
238   else {
239     aData->blockSendAttributeUpdated(false);
240     anAttribute->blockSetInitialized(isAttributeSetInitializedBlocked);
241     aLoop->activateFlushes(isFlushesActived);
242   }
243 }
244
245 //********************************************************************
246 void ModuleBase_WidgetValidated::storeValidState(const ModuleBase_ViewerPrs& theValue, const bool theValid)
247 {
248   bool aValidPrs = myInvalidPrs.contains(theValue);
249   bool anInvalidPrs = myInvalidPrs.contains(theValue);
250
251   if (theValid) {
252     if (!aValidPrs)
253       myValidPrs.append(theValue);
254     // the commented code will be useful when the valid state of the presentation
255     // will be changable between activate/deactivate. Currently it does not happen.
256     //if (anInvalidPrs)
257     //  myInvalidPrs.removeOne(theValue);
258   }
259   else { // !theValid
260     if (!anInvalidPrs)
261       myInvalidPrs.append(theValue);
262     //if (!aValidPrs)
263     //  myValidPrs.removeOne(theValue);
264   }
265 #ifdef DEBUG_VALID_STATE
266   qDebug(QString("storeValidState: myValidPrs.size() = %1, myInvalidPrs.size() = %2").arg(myValidPrs.count())
267                  .arg(myInvalidPrs.count()).toStdString().c_str());
268 #endif
269 }
270
271 //********************************************************************
272 bool ModuleBase_WidgetValidated::getValidState(const ModuleBase_ViewerPrs& theValue, bool& theValid)
273 {
274   bool aValidPrs = myValidPrs.contains(theValue);
275   bool anInvalidPrs = myInvalidPrs.contains(theValue);
276
277   if (aValidPrs)
278     theValid = true;
279   else if (anInvalidPrs)
280     theValid = false;
281
282   return aValidPrs || anInvalidPrs;
283 }
284
285 //********************************************************************
286 void ModuleBase_WidgetValidated::clearValidState()
287 {
288 #ifdef DEBUG_VALID_STATE
289   qDebug("clearValidState");
290 #endif
291   myValidPrs.clear();
292   myInvalidPrs.clear();
293 }
294
295 //********************************************************************
296 QList<ModuleBase_ViewerPrs> ModuleBase_WidgetValidated::getFilteredSelected()
297 {
298   QList<ModuleBase_ViewerPrs> aSelected = myWorkshop->selection()->getSelected(
299                                                        ModuleBase_ISelection::Viewer);
300
301   QList<ModuleBase_ViewerPrs> anOBSelected = myWorkshop->selection()->getSelected(
302                                                        ModuleBase_ISelection::Browser);
303   // filter the OB presentations
304   filterPresentations(anOBSelected);
305   if (!anOBSelected.isEmpty())
306     ModuleBase_ISelection::appendSelected(anOBSelected, aSelected);
307
308   filterCompSolids(aSelected);
309
310   return aSelected;
311 }
312
313 //********************************************************************
314 void ModuleBase_WidgetValidated::filterPresentations(QList<ModuleBase_ViewerPrs>& theValues)
315 {
316   QList<ModuleBase_ViewerPrs> aValidatedValues;
317
318   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
319   bool isDone = false;
320   for (; anIt != aLast; anIt++) {
321     if (isValidInFilters(*anIt))
322       aValidatedValues.append(*anIt);
323   }
324   if (aValidatedValues.size() != theValues.size()) {
325     theValues.clear();
326     theValues = aValidatedValues;
327   }
328 }
329
330 //********************************************************************
331 void ModuleBase_WidgetValidated::filterCompSolids(QList<ModuleBase_ViewerPrs>& theValues)
332 {
333   std::set<ResultCompSolidPtr> aCompSolids;
334   QList<ModuleBase_ViewerPrs> aValidatedValues;
335
336   // Collect compsolids.
337   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
338   for (; anIt != aLast; anIt++) {
339     const ModuleBase_ViewerPrs& aViewerPrs = *anIt;
340     ObjectPtr anObject = aViewerPrs.object();
341     ResultCompSolidPtr aResultCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(anObject);
342     if(aResultCompSolid.get()) {
343       aCompSolids.insert(aResultCompSolid);
344     }
345   }
346
347   // Filter sub-solids of compsolids.
348   anIt = theValues.begin();
349   for (; anIt != aLast; anIt++) {
350     const ModuleBase_ViewerPrs& aViewerPrs = *anIt;
351     ObjectPtr anObject = aViewerPrs.object();
352     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
353     ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aResult);
354     if(aResCompSolidPtr.get() && (aCompSolids.find(aResCompSolidPtr) != aCompSolids.end())) {
355       // Skip sub-solid of compsolid.
356       continue;
357     } else {
358       aValidatedValues.append(*anIt);
359     }
360   }
361
362   if (aValidatedValues.size() != theValues.size()) {
363     theValues.clear();
364     theValues = aValidatedValues;
365   }
366 }