Salome HOME
Sketch shape in plane selection filter should not be activated while PartSet_WidgetSh...
[modules/shaper.git] / src / XGUI / XGUI_SelectionActivate.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "XGUI_SelectionActivate.h"
22
23 #include "ModelAPI_Object.h"
24
25 #include "ModuleBase_IModule.h"
26 #include "ModuleBase_IViewer.h"
27 #include "ModuleBase_ModelWidget.h"
28 #include "ModuleBase_Preferences.h"
29
30 #include "XGUI_ActiveControlMgr.h"
31 #include "XGUI_ActiveControlSelector.h"
32 #include "XGUI_Displayer.h"
33 #include "XGUI_FacesPanel.h"
34 #include "XGUI_FacesPanelSelector.h"
35 #include "XGUI_SelectionMgr.h"
36 #include "XGUI_Tools.h"
37 #include "XGUI_Workshop.h"
38
39 #include <SUIT_ResourceMgr.h>
40
41 #include <AIS_InteractiveContext.hxx>
42 #include <AIS_Shape.hxx>
43 #include <AIS_Trihedron.hxx>
44
45 #include <SelectMgr_SelectionManager.hxx>
46
47 //#define DEBUG_ACTIVATE_OBJECTS
48 //#define DEBUG_DEACTIVATE
49 //#define DEBUG_ACTIVATE_AIS
50 //#define DEBUG_DEACTIVATE_AIS
51
52 #define CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
53
54 //**************************************************************
55 XGUI_SelectionActivate::XGUI_SelectionActivate(ModuleBase_IWorkshop* theWorkshop)
56  : ModuleBase_ISelectionActivate(theWorkshop), myIsTrihedronActive(true)
57 {
58 }
59
60 //**************************************************************
61 XGUI_SelectionActivate::SelectionPlace XGUI_SelectionActivate::activeSelectionPlace() const
62 {
63   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
64   XGUI_ActiveControlSelector* anActiveSelector = aWorkshop->activeControlMgr()->activeSelector();
65   if (!anActiveSelector)
66     return Workshop;
67
68   if (anActiveSelector->getType() == XGUI_FacesPanelSelector::Type())
69     return FacesPanel;
70   else
71     return PropertyPanel;
72 }
73
74 //**************************************************************
75 void XGUI_SelectionActivate::updateSelectionModes()
76 {
77   QIntList aModes;
78   switch (activeSelectionPlace()) {
79   case Workshop:
80     myWorkshop->module()->activeSelectionModes(aModes);
81     break;
82     case PropertyPanel: {
83       ModuleBase_ModelWidget* anActiveWidget = myWorkshop->module()->activeWidget();
84       if (anActiveWidget)
85         getSelectionModes(anActiveWidget, aModes);
86       else
87         myWorkshop->module()->activeSelectionModes(aModes); //using module modes
88     }
89     break;
90     case FacesPanel: {
91       XGUI_Tools::workshop(myWorkshop)->facesPanel()->selectionModes(aModes);
92       myWorkshop->module()->moduleSelectionModes(-1/*all modes*/, aModes);
93     }
94     break;
95     default: break;
96   }
97   activateObjects(aModes, getDisplayer()->displayedObjects(), true);
98 }
99
100 //**************************************************************
101 void XGUI_SelectionActivate::updateSelectionFilters()
102 {
103   SelectMgr_ListOfFilter aSelectionFilters;
104   switch (activeSelectionPlace()) {
105     case Workshop:
106       myWorkshop->module()->moduleSelectionFilters(myWorkshop->module()->selectionFilters(),
107         aSelectionFilters);
108     break;
109     case PropertyPanel: {
110       ModuleBase_ModelWidget* anActiveWidget = myWorkshop->module()->activeWidget();
111       QIntList aModuleSelectionFilters = myWorkshop->module()->selectionFilters();
112       if (anActiveWidget)
113         anActiveWidget->selectionFilters(aModuleSelectionFilters, aSelectionFilters);
114       myWorkshop->module()->moduleSelectionFilters(aModuleSelectionFilters, aSelectionFilters);
115     }
116     break;
117     case FacesPanel: {
118       XGUI_Tools::workshop(myWorkshop)->facesPanel()->selectionFilters(aSelectionFilters);
119     }
120     break;
121     default: break;
122   }
123   activateSelectionFilters(aSelectionFilters);
124 }
125
126 //**************************************************************
127 void XGUI_SelectionActivate::activateSelectionFilters
128   (const SelectMgr_ListOfFilter& theSelectionFilters)
129 {
130   XGUI_Displayer* aDisplayer = getDisplayer();
131   aDisplayer->deactivateSelectionFilters(false);
132
133   SelectMgr_ListIteratorOfListOfFilter aIt(theSelectionFilters);
134   for (; aIt.More(); aIt.Next()) {
135     Handle(SelectMgr_Filter) aFilter = aIt.Value();
136     if (aFilter.IsNull())
137       continue;
138     aDisplayer->addSelectionFilter(aFilter);
139   }
140 }
141
142 //**************************************************************
143 void XGUI_SelectionActivate::getSelectionModes(ModuleBase_ModelWidget* theWidget,
144                                                QIntList& theModes)
145 {
146   if (!theWidget)
147     return;
148
149   int aModuleSelectionModes = -1;
150   theWidget->selectionModes(aModuleSelectionModes, theModes);
151   myWorkshop->module()->moduleSelectionModes(aModuleSelectionModes, theModes);
152 }
153
154 //**************************************************************
155 QIntList XGUI_SelectionActivate::activeSelectionModes() const
156 {
157   QIntList aModes;
158   foreach (int aMode, myActiveSelectionModes) {
159     // aMode < 9 is a Shape Enum values
160     aModes << ((aMode < 9)? AIS_Shape::SelectionType(aMode) : aMode);
161   }
162   return aModes;
163 }
164
165 //**************************************************************
166 bool XGUI_SelectionActivate::isActive(ObjectPtr theObject) const
167 {
168   Handle(AIS_InteractiveContext) aContext = AISContext();
169   if (aContext.IsNull() || !getDisplayer()->isVisible(theObject))
170     return false;
171
172   AISObjectPtr anObj = getDisplayedAISObject(theObject);
173   Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
174
175   TColStd_ListOfInteger aModes;
176   aContext->ActivatedModes(anAIS, aModes);
177
178   return aModes.Extent() > 0;
179 }
180
181 //**************************************************************
182 void XGUI_SelectionActivate::activateObjects(const QIntList& theModes,
183   const QObjectPtrList& theObjList, const bool theUpdateViewer)
184 {
185   setSelectionModes(theModes);
186
187   Handle(AIS_InteractiveContext) aContext = AISContext();
188   // Open local context if there is no one
189   if (aContext.IsNull())
190     return;
191
192   //aContext->UseDisplayedObjects();
193   //myUseExternalObjects = true;
194
195   Handle(AIS_InteractiveObject) anAISIO;
196   AIS_ListOfInteractive aPrsList;
197   AIS_ListOfInteractive aPrsListToBeDeactivated;
198   //if (aObjList.isEmpty())
199   //  return;
200   //else {
201   foreach(ObjectPtr anObject, theObjList) {
202     AISObjectPtr anAISObject = getDisplayedAISObject(anObject);
203     if (!anAISObject.get())
204       continue;
205
206     Handle(AIS_InteractiveObject) aPrs = anAISObject->impl<Handle(AIS_InteractiveObject)>();
207     if (myWorkshop->module()->canActivateSelection(anObject))
208       aPrsList.Append(aPrs);
209     else
210       aPrsListToBeDeactivated.Append(aPrs);
211   }
212   //}
213
214   // Add trihedron because it has to partisipate in selection
215   Handle(AIS_InteractiveObject) aTrihedron;
216   if (isTrihedronActive()) {
217     aTrihedron = getTrihedron();
218     if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron))
219       aPrsList.Append(aTrihedron);
220   }
221   if (aPrsList.Extent() == 0 && aPrsListToBeDeactivated.Extent() == 0)
222     return;
223
224   AIS_ListIteratorOfListOfInteractive aLIt;
225   bool isActivationChanged = false;
226   for(aLIt.Initialize(aPrsList); aLIt.More(); aLIt.Next()) {
227     anAISIO = aLIt.Value();
228     if (activate(anAISIO, false))
229       isActivationChanged = true;
230   }
231
232   for(aLIt.Initialize(aPrsListToBeDeactivated); aLIt.More(); aLIt.Next()) {
233     anAISIO = aLIt.Value();
234     deactivateAIS(anAISIO);
235     isActivationChanged = true;
236   }
237 }
238
239 #ifdef DEBUG_ACTIVATE_OBJECTS
240 //**************************************************************
241 QString getModeInfo(const int theMode)
242 {
243   QString anInfo = "Undefined";
244   switch(theMode) {
245     case 0: anInfo = "SHAPE(0)"; break;
246     case 1: anInfo = "VERTEX(1)"; break;
247     case 2: anInfo = "EDGE(2)"; break;
248     case 3: anInfo = "WIRE(3)"; break;
249     case 4: anInfo = "FACE(4)"; break;
250     case 5: anInfo = "SHELL(5)"; break;
251     case 6: anInfo = "SOLID(6)"; break;
252     case 7: anInfo = "COMPSOLID(7)"; break;
253     case 8: anInfo = "COMPOUND(8)"; break;
254     case 100: anInfo = "Sel_Mode_First(100)"; break; //SketcherPrs_Tools
255     case 101: anInfo = "Sel_Constraint(101)"; break;
256     case 102: anInfo = "Sel_Dimension_All(102)"; break;
257     case 103: anInfo = "Sel_Dimension_Line(103)"; break;
258     case 104: anInfo = "Sel_Dimension_Text(104)"; break;
259     default: break;
260   }
261   return anInfo;
262 }
263
264 //**************************************************************
265 QString getModesInfo(const QIntList& theModes)
266 {
267   QStringList aModesInfo;
268   for (int i = 0, aSize = theModes.size(); i < aSize; i++)
269     aModesInfo.append(getModeInfo(theModes[i]));
270   return QString("[%1] = %2").arg(aModesInfo.size()).arg(aModesInfo.join(", "));
271 }
272 #endif
273
274 //**************************************************************
275 void XGUI_SelectionActivate::setSelectionModes(const QIntList& theModes)
276 {
277   // Convert shape types to selection types
278   QIntList aModes;
279   foreach(int aType, theModes) {
280     aModes.append(getSelectionMode(aType));
281   }
282
283 #ifdef DEBUG_ACTIVATE_OBJECTS
284   QStringList anInfo;
285   QObjectPtrList::const_iterator anIt = theObjList.begin(), aLast = theObjList.end();
286   for (; anIt != aLast; ++anIt) {
287     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
288   }
289   QString anInfoStr = anInfo.join(", ");
290
291   qDebug(QString("activateObjects: new modes%1, active modes%2, objects[%3] = %4").
292     arg(getModesInfo(aModes)).
293     arg(getModesInfo(myActiveSelectionModes)).
294     arg(theObjList.size()).
295     arg(anInfoStr).
296     toStdString().c_str());
297 #endif
298   // In order to avoid doblications of selection modes
299   QIntList aNewModes;
300   foreach (int aMode, aModes) {
301     if (!aNewModes.contains(aMode))
302       aNewModes.append(aMode);
303   }
304   myActiveSelectionModes = aNewModes;
305 }
306
307 //**************************************************************
308 void XGUI_SelectionActivate::activateOnDisplay(const Handle(AIS_InteractiveObject)& theIO,
309                                                const bool theUpdateViewer)
310 {
311   if (myActiveSelectionModes.size() == 0)
312     activateAIS(theIO, 0, theUpdateViewer);
313   else {
314     foreach(int aMode, myActiveSelectionModes) {
315       activateAIS(theIO, aMode, theUpdateViewer);
316     }
317   }
318 }
319
320 //**************************************************************
321 void XGUI_SelectionActivate::activateAIS(const Handle(AIS_InteractiveObject)& theIO,
322                                          const int theMode, const bool theUpdateViewer) const
323 {
324   Handle(AIS_InteractiveContext) aContext = AISContext();
325   if (!theIO.IsNull() && theIO == getTrihedron()) {
326     if (theMode != AIS_Shape::SelectionType(TopAbs_EDGE) &&
327         theMode != AIS_Shape::SelectionType(TopAbs_VERTEX))
328       return;
329   }
330   if (!aContext.IsNull()) {
331     if (myWorkshop->module()) {
332       int aMode = (theMode > 8)? theMode : AIS_Shape::SelectionType(theMode);
333       aContext->Activate(theIO, theMode, false);
334     } else
335       aContext->Activate(theIO, theMode, false);
336
337     // the fix from VPA for more suitable selection of sketcher lines
338     if (theIO->Width() > 1) {
339       double aPrecision = theIO->Width() + 2;
340       if (theMode == getSelectionMode(TopAbs_VERTEX))
341         aPrecision = ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
342         "point-selection-sensitivity", 12);
343       else if ((theMode == getSelectionMode(TopAbs_EDGE)) ||
344                (theMode == getSelectionMode(TopAbs_WIRE)))
345         aPrecision = theIO->Width() + ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
346            "edge-selection-sensitivity", 2);
347       aContext->SetSelectionSensitivity(theIO, theMode, aPrecision);
348     }
349
350 #ifdef DEBUG_ACTIVATE_AIS
351     ObjectPtr anObject = getObject(theIO);
352     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
353     qDebug(QString("activateAIS: theMode = %1, object = %2").arg(theMode)
354       .arg(anInfo).toStdString().c_str());
355 #endif
356     if (theUpdateViewer)
357       getDisplayer()->updateViewer();
358   }
359 }
360
361 //**************************************************************
362 void XGUI_SelectionActivate::deactivateAIS(const Handle(AIS_InteractiveObject)& theIO,
363                                            const int theMode) const
364 {
365   Handle(AIS_InteractiveContext) aContext = AISContext();
366   if (!aContext.IsNull()) {
367     if (theMode == -1)
368       aContext->Deactivate(theIO);
369     else
370       aContext->Deactivate(theIO, theMode);
371
372 #ifdef DEBUG_DEACTIVATE_AIS
373     ObjectPtr anObject = getObject(theIO);
374     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
375     qDebug(QString("deactivateAIS: theMode = %1, object = %2").arg(theMode)
376       .arg(anInfo).toStdString().c_str());
377 #endif
378   }
379 }
380
381 //**************************************************************
382 bool XGUI_SelectionActivate::activate(const Handle(AIS_InteractiveObject)& theIO,
383                                       const bool theUpdateViewer) const
384 {
385   Handle(AIS_InteractiveContext) aContext = AISContext();
386   if (aContext.IsNull() || theIO.IsNull())
387     return false;
388
389   bool isActivationChanged = false;
390   // deactivate object in all modes, which are not in the list of activation
391   // It seems that after the IO deactivation the selected state of the IO's owners
392   // is modified in OCC(version: 6.8.0) and the selection of the object later is lost.
393   // By this reason, the number of the IO deactivate is decreased and the object is deactivated
394   // only if there is a difference in the current modes and the parameters modes.
395   // If the selection problem happens again, it is possible to write a test scenario and create
396   // a bug. The bug steps are the following:
397   // Create two IO, activate them in 5 modes, select the first IO, deactivate 3 modes for both,
398   // with clicked SHIFT select the second object.
399   // The result is the selection of the first IO is lost.
400   TColStd_ListOfInteger aTColModes;
401   aContext->ActivatedModes(theIO, aTColModes);
402   TColStd_ListIteratorOfListOfInteger itr( aTColModes );
403   QIntList aModesActivatedForIO;
404   bool isDeactivated = false;
405   bool aHasValidMode = false;
406   for (; itr.More(); itr.Next() ) {
407     Standard_Integer aMode = itr.Value();
408     aHasValidMode = aHasValidMode || aMode != -1;
409     int aShapeMode = (aMode > 8)? aMode : AIS_Shape::SelectionType(aMode);
410     if (!myActiveSelectionModes.contains(aMode)) {
411       deactivateAIS(theIO, aMode);
412       isDeactivated = true;
413     }
414     else {
415       aModesActivatedForIO.append(aMode);
416     }
417   }
418   if (isDeactivated) {
419     // the selection from the previous activation modes should be cleared manually (#26172)
420     //theIO->ClearSelected();
421 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
422     XGUI_Tools::workshop(myWorkshop)->selector()->deselectPresentation(theIO);
423 #endif
424     // For performance issues
425     //if (theUpdateViewer)
426     //  getDisplayer()->updateViewer();
427     isActivationChanged = true;
428   }
429
430   // loading the interactive object allowing the decomposition
431   if (aTColModes.IsEmpty() || !aHasValidMode) {
432     aContext->Load(theIO, -1, true);
433     Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
434     if (!aTrihedron.IsNull()) {
435       // Workaround for Trihedron. It should be loaded using the next Load method to
436       // add this object to myGlobal map of selection manager
437       // it is important to activate trihedron in two selection modes: edges and vertices
438       aContext->SelectionManager()->Load(theIO);
439     }
440   }
441
442   // trihedron AIS check should be after the AIS loading.
443   // If it is not loaded, it is steel selectable in the viewer.
444   Handle(AIS_Trihedron) aTrihedron;
445   if (!isTrihedronActive())
446     aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
447   if (aTrihedron.IsNull()) {
448       // In order to clear active modes list
449     if (myActiveSelectionModes.size() == 0) {
450       activateAIS(theIO, 0, theUpdateViewer);
451     } else {
452       foreach(int aMode, myActiveSelectionModes) {
453         if (!aModesActivatedForIO.contains(aMode)) {
454           activateAIS(theIO, aMode, theUpdateViewer);
455           isActivationChanged = true;
456         }
457       }
458     }
459   }
460   return isActivationChanged;
461 }
462
463 //**************************************************************
464 void XGUI_SelectionActivate::deactivate(const ObjectPtr& theObject, const bool theUpdateViewer)
465 {
466 #ifdef DEBUG_DEACTIVATE
467   QString anInfoStr = ModuleBase_Tools::objectInfo(theObject);
468   qDebug(QString("deactivate: myActiveSelectionModes[%1]: %2, objects = ").
469     arg(myActiveSelectionModes.size()).arg(qIntListInfo(myActiveSelectionModes)).
470     arg(anInfoStr).
471     toStdString().c_str());
472 #endif
473   Handle(AIS_InteractiveContext) aContext = AISContext();
474   if (!aContext.IsNull() && getDisplayer()->isVisible(theObject)) {
475     AISObjectPtr anObj = getDisplayedAISObject(theObject);
476     Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
477
478     deactivateAIS(anAIS);
479     // the selection from the previous activation modes should be cleared manually (#26172)
480 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
481     XGUI_Tools::workshop(myWorkshop)->selector()->deselectPresentation(anAIS);
482 #endif
483     if (theUpdateViewer)
484       getDisplayer()->updateViewer();
485   }
486 }
487
488 /// #1136 hidden axis are selected in sketch
489 #ifdef BEFORE_TRIHEDRON_PATCH
490 //**************************************************************
491 void deactivateObject(Handle(AIS_InteractiveContext) theContext,
492                       Handle(AIS_InteractiveObject) theObject)
493 {
494   if (!theObject.IsNull())
495     theContext->Deactivate(theObject);
496 }
497 #endif
498
499 //**************************************************************
500 void XGUI_SelectionActivate::activateTrihedron(bool theIsActive)
501 {
502   myIsTrihedronActive = theIsActive;
503   if (!myIsTrihedronActive)
504     deactivateTrihedron(true);
505 }
506
507 //**************************************************************
508 void XGUI_SelectionActivate::deactivateTrihedron(const bool theUpdateViewer) const
509 {
510   Handle(AIS_InteractiveObject) aTrihedron = getTrihedron();
511   Handle(AIS_InteractiveContext) aContext = AISContext();
512   if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron)) {
513     Handle(AIS_Trihedron) aTrie = Handle(AIS_Trihedron)::DownCast(aTrihedron);
514     if (!aTrie.IsNull())
515       aContext->Deactivate(aTrie);
516
517     /// #1136 hidden axis are selected in sketch
518 #ifdef BEFORE_TRIHEDRON_PATCH
519     deactivateObject(aContext, aTrie->XAxis());
520     deactivateObject(aContext, aTrie->YAxis());
521     deactivateObject(aContext, aTrie->Axis());
522     deactivateObject(aContext, aTrie->Position());
523
524     deactivateObject(aContext, aTrie->XYPlane());
525     deactivateObject(aContext, aTrie->XZPlane());
526     deactivateObject(aContext, aTrie->YZPlane());
527 #endif
528     if (theUpdateViewer)
529       getDisplayer()->updateViewer();
530   }
531 }
532
533 //**************************************************************
534 void XGUI_SelectionActivate::deactivateTrihedronInSelectionModes()
535 {
536   Handle(AIS_InteractiveContext) aContext = AISContext();
537   Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(getTrihedron());
538   /// deactivate trihedron in selection modes
539   TColStd_ListOfInteger aTColModes;
540   aContext->ActivatedModes(aTrihedron, aTColModes);
541   TColStd_ListIteratorOfListOfInteger itr( aTColModes );
542   for (; itr.More(); itr.Next() ) {
543     Standard_Integer aMode = itr.Value();
544     aContext->Deactivate(aTrihedron, aMode);
545   }
546 }
547
548 //**************************************************************
549 Handle(AIS_InteractiveContext) XGUI_SelectionActivate::AISContext() const
550 {
551   return myWorkshop->viewer()->AISContext();
552 }
553
554 //**************************************************************
555 XGUI_Displayer* XGUI_SelectionActivate::getDisplayer() const
556 {
557   return XGUI_Tools::workshop(myWorkshop)->displayer();
558 }
559
560 //**************************************************************
561 Handle(AIS_InteractiveObject) XGUI_SelectionActivate::getTrihedron() const
562 {
563   return myWorkshop->viewer()->trihedron();
564 }
565
566 //**************************************************************
567 AISObjectPtr XGUI_SelectionActivate::getDisplayedAISObject(ObjectPtr theObject) const
568 {
569   return getDisplayer()->getAISObject(theObject);
570 }
571
572 //**************************************************************
573 int XGUI_SelectionActivate::getSelectionMode(int theShapeType)
574 {
575   return (theShapeType > TopAbs_SHAPE) ? theShapeType :
576                                          AIS_Shape::SelectionMode((TopAbs_ShapeEnum)theShapeType);
577 }