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