1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
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 "XGUI_SelectionActivate.h"
22 #include "ModelAPI_Object.h"
24 #include "ModuleBase_IModule.h"
25 #include "ModuleBase_IViewer.h"
26 #include "ModuleBase_ModelWidget.h"
27 #include "ModuleBase_Preferences.h"
29 #include "XGUI_ActiveControlMgr.h"
30 #include "XGUI_ActiveControlSelector.h"
31 #include "XGUI_Displayer.h"
32 #include "XGUI_FacesPanel.h"
33 #include "XGUI_FacesPanelSelector.h"
34 #include "XGUI_SelectionMgr.h"
35 #include "XGUI_Tools.h"
36 #include "XGUI_Workshop.h"
38 #include <SUIT_ResourceMgr.h>
40 #include <AIS_InteractiveContext.hxx>
41 #include <AIS_Shape.hxx>
42 #include <AIS_Trihedron.hxx>
44 #include <SelectMgr_SelectionManager.hxx>
46 //#define DEBUG_ACTIVATE_OBJECTS
47 //#define DEBUG_DEACTIVATE
48 //#define DEBUG_ACTIVATE_AIS
49 //#define DEBUG_DEACTIVATE_AIS
52 #include <inspector/VInspectorAPI_CallBack.hxx>
55 #define CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
57 //**************************************************************
58 XGUI_SelectionActivate::XGUI_SelectionActivate(ModuleBase_IWorkshop* theWorkshop)
59 : ModuleBase_ISelectionActivate(theWorkshop), myIsTrihedronActive(true)
63 //**************************************************************
64 XGUI_SelectionActivate::SelectionPlace XGUI_SelectionActivate::activeSelectionPlace() const
66 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
67 XGUI_ActiveControlSelector* anActiveSelector = aWorkshop->activeControlMgr()->activeSelector();
68 if (!anActiveSelector)
71 if (anActiveSelector->getType() == XGUI_FacesPanelSelector::Type())
77 //**************************************************************
78 void XGUI_SelectionActivate::updateSelectionModes()
81 switch (activeSelectionPlace()) {
83 myWorkshop->module()->activeSelectionModes(aModes);
86 ModuleBase_ModelWidget* anActiveWidget = myWorkshop->module()->activeWidget();
88 getSelectionModes(anActiveWidget, aModes);
90 myWorkshop->module()->activeSelectionModes(aModes); //using module modes
94 XGUI_Tools::workshop(myWorkshop)->facesPanel()->selectionModes(aModes);
95 myWorkshop->module()->moduleSelectionModes(-1/*all modes*/, aModes);
100 activateObjects(aModes, getDisplayer()->displayedObjects(), true);
103 //**************************************************************
104 void XGUI_SelectionActivate::updateSelectionFilters()
106 SelectMgr_ListOfFilter aSelectionFilters;
107 switch (activeSelectionPlace()) {
109 QIntList aModuleSelectionFilters = myWorkshop->module()->selectionFilters();
110 myWorkshop->module()->moduleSelectionFilters(aModuleSelectionFilters, aSelectionFilters);
113 case PropertyPanel: {
114 QIntList aModuleSelectionFilters = myWorkshop->module()->selectionFilters();
116 ModuleBase_ModelWidget* anActiveWidget = myWorkshop->module()->activeWidget();
118 anActiveWidget->selectionFilters(aModuleSelectionFilters, aSelectionFilters);
119 myWorkshop->module()->moduleSelectionFilters(aModuleSelectionFilters, aSelectionFilters);
123 XGUI_Tools::workshop(myWorkshop)->facesPanel()->selectionFilters(aSelectionFilters);
124 //QIntList aModuleSelectionFilters = myWorkshop->module()->selectionFilters();
125 //myWorkshop->module()->moduleSelectionFilters(aModuleSelectionFilters, aSelectionFilters);
130 activateSelectionFilters(aSelectionFilters);
133 //**************************************************************
134 void XGUI_SelectionActivate::activateSelectionFilters
135 (const SelectMgr_ListOfFilter& theSelectionFilters)
137 XGUI_Displayer* aDisplayer = getDisplayer();
138 aDisplayer->deactivateSelectionFilters(false);
140 SelectMgr_ListIteratorOfListOfFilter aIt(theSelectionFilters);
141 for (; aIt.More(); aIt.Next()) {
142 Handle(SelectMgr_Filter) aFilter = aIt.Value();
143 if (aFilter.IsNull())
145 aDisplayer->addSelectionFilter(aFilter);
149 //**************************************************************
150 void XGUI_SelectionActivate::getSelectionModes(ModuleBase_ModelWidget* theWidget,
156 int aModuleSelectionModes = -1;
157 theWidget->selectionModes(aModuleSelectionModes, theModes);
158 myWorkshop->module()->moduleSelectionModes(aModuleSelectionModes, theModes);
161 //**************************************************************
162 QIntList XGUI_SelectionActivate::activeSelectionModes() const
165 foreach (int aMode, myActiveSelectionModes) {
166 // aMode < 9 is a Shape Enum values
167 aModes << ((aMode < 9)? AIS_Shape::SelectionType(aMode) : aMode);
172 //**************************************************************
173 bool XGUI_SelectionActivate::isActive(ObjectPtr theObject) const
175 Handle(AIS_InteractiveContext) aContext = AISContext();
176 if (aContext.IsNull() || !getDisplayer()->isVisible(theObject))
179 AISObjectPtr anObj = getDisplayedAISObject(theObject);
180 Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
182 TColStd_ListOfInteger aModes;
183 aContext->ActivatedModes(anAIS, aModes);
185 return aModes.Extent() > 0;
188 //**************************************************************
189 void XGUI_SelectionActivate::activateObjects(const QIntList& theModes,
190 const QObjectPtrList& theObjList, const bool theUpdateViewer)
192 setSelectionModes(theModes);
194 Handle(AIS_InteractiveContext) aContext = AISContext();
195 // Open local context if there is no one
196 if (aContext.IsNull())
199 //aContext->UseDisplayedObjects();
200 //myUseExternalObjects = true;
202 Handle(AIS_InteractiveObject) anAISIO;
203 AIS_ListOfInteractive aPrsList;
204 AIS_ListOfInteractive aPrsListToBeDeactivated;
205 //if (aObjList.isEmpty())
208 foreach(ObjectPtr anObject, theObjList) {
209 AISObjectPtr anAISObject = getDisplayedAISObject(anObject);
210 if (!anAISObject.get())
213 Handle(AIS_InteractiveObject) aPrs = anAISObject->impl<Handle(AIS_InteractiveObject)>();
214 if (myWorkshop->module()->canActivateSelection(anObject))
215 aPrsList.Append(aPrs);
217 aPrsListToBeDeactivated.Append(aPrs);
221 // Add trihedron because it has to partisipate in selection
222 Handle(AIS_InteractiveObject) aTrihedron;
223 if (isTrihedronActive()) {
224 aTrihedron = getTrihedron();
225 if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron))
226 aPrsList.Append(aTrihedron);
228 if (aPrsList.Extent() == 0 && aPrsListToBeDeactivated.Extent() == 0)
231 AIS_ListIteratorOfListOfInteractive aLIt;
232 bool isActivationChanged = false;
233 for(aLIt.Initialize(aPrsList); aLIt.More(); aLIt.Next()) {
234 anAISIO = aLIt.Value();
235 if (activate(anAISIO, false))
236 isActivationChanged = true;
239 for(aLIt.Initialize(aPrsListToBeDeactivated); aLIt.More(); aLIt.Next()) {
240 anAISIO = aLIt.Value();
241 deactivateAIS(anAISIO);
242 isActivationChanged = true;
246 #ifdef DEBUG_ACTIVATE_OBJECTS
247 //**************************************************************
248 QString getModeInfo(const int theMode)
250 QString anInfo = "Undefined";
252 case 0: anInfo = "SHAPE(0)"; break;
253 case 1: anInfo = "VERTEX(1)"; break;
254 case 2: anInfo = "EDGE(2)"; break;
255 case 3: anInfo = "WIRE(3)"; break;
256 case 4: anInfo = "FACE(4)"; break;
257 case 5: anInfo = "SHELL(5)"; break;
258 case 6: anInfo = "SOLID(6)"; break;
259 case 7: anInfo = "COMPSOLID(7)"; break;
260 case 8: anInfo = "COMPOUND(8)"; break;
261 case 100: anInfo = "Sel_Mode_First(100)"; break; //SketcherPrs_Tools
262 case 101: anInfo = "Sel_Constraint(101)"; break;
263 case 102: anInfo = "Sel_Dimension_All(102)"; break;
264 case 103: anInfo = "Sel_Dimension_Line(103)"; break;
265 case 104: anInfo = "Sel_Dimension_Text(104)"; break;
271 //**************************************************************
272 QString getModesInfo(const QIntList& theModes)
274 QStringList aModesInfo;
275 for (int i = 0, aSize = theModes.size(); i < aSize; i++)
276 aModesInfo.append(getModeInfo(theModes[i]));
277 return QString("[%1] = %2").arg(aModesInfo.size()).arg(aModesInfo.join(", "));
281 //**************************************************************
282 void XGUI_SelectionActivate::setSelectionModes(const QIntList& theModes)
284 // Convert shape types to selection types
286 foreach(int aType, theModes) {
287 aModes.append(getSelectionMode(aType));
290 #ifdef DEBUG_ACTIVATE_OBJECTS
292 QObjectPtrList::const_iterator anIt = theObjList.begin(), aLast = theObjList.end();
293 for (; anIt != aLast; ++anIt) {
294 anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
296 QString anInfoStr = anInfo.join(", ");
298 qDebug(QString("activateObjects: new modes%1, active modes%2, objects[%3] = %4").
299 arg(getModesInfo(aModes)).
300 arg(getModesInfo(myActiveSelectionModes)).
301 arg(theObjList.size()).
303 toStdString().c_str());
305 // In order to avoid doblications of selection modes
307 foreach (int aMode, aModes) {
308 if (!aNewModes.contains(aMode))
309 aNewModes.append(aMode);
311 myActiveSelectionModes = aNewModes;
314 //**************************************************************
315 void XGUI_SelectionActivate::activateOnDisplay(const Handle(AIS_InteractiveObject)& theIO,
316 const bool theUpdateViewer)
318 if (myActiveSelectionModes.size() == 0)
319 activateAIS(theIO, 0, theUpdateViewer);
321 foreach(int aMode, myActiveSelectionModes) {
322 activateAIS(theIO, aMode, theUpdateViewer);
327 //**************************************************************
328 void XGUI_SelectionActivate::activateAIS(const Handle(AIS_InteractiveObject)& theIO,
329 const int theMode, const bool theUpdateViewer) const
331 Handle(AIS_InteractiveContext) aContext = AISContext();
332 if (!theIO.IsNull() && theIO == getTrihedron()) {
333 if (theMode != AIS_Shape::SelectionType(TopAbs_EDGE) &&
334 theMode != AIS_Shape::SelectionType(TopAbs_VERTEX))
337 if (!aContext.IsNull()) {
338 if (myWorkshop->module()) {
339 // the code is obsolete, used in additional check before activate, it was removed
340 //int aMode = (theMode > 8)? theMode : AIS_Shape::SelectionType(theMode);
341 aContext->Activate(theIO, theMode, false);
343 if (getDisplayer()->getCallBack()) getDisplayer()->getCallBack()->Activate(theIO, theMode);
347 aContext->Activate(theIO, theMode, false);
349 if (getDisplayer()->getCallBack()) getDisplayer()->getCallBack()->Activate(theIO, theMode);
352 // the fix from VPA for more suitable selection of sketcher lines
353 if (theIO->Width() > 1) {
354 double aPrecision = theIO->Width() + 2;
355 if (theMode == getSelectionMode(TopAbs_VERTEX))
356 aPrecision = ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
357 "point-selection-sensitivity", 12);
358 else if ((theMode == getSelectionMode(TopAbs_EDGE)) ||
359 (theMode == getSelectionMode(TopAbs_WIRE)))
360 aPrecision = theIO->Width() + ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
361 "edge-selection-sensitivity", 2);
362 aContext->SetSelectionSensitivity(theIO, theMode, aPrecision);
365 #ifdef DEBUG_ACTIVATE_AIS
366 ObjectPtr anObject = getObject(theIO);
367 anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
368 qDebug(QString("activateAIS: theMode = %1, object = %2").arg(theMode)
369 .arg(anInfo).toStdString().c_str());
372 getDisplayer()->updateViewer();
376 //**************************************************************
377 void XGUI_SelectionActivate::deactivateAIS(const Handle(AIS_InteractiveObject)& theIO,
378 const int theMode) const
380 Handle(AIS_InteractiveContext) aContext = AISContext();
381 if (!aContext.IsNull()) {
383 aContext->Deactivate(theIO);
385 aContext->Deactivate(theIO, theMode);
387 #ifdef DEBUG_DEACTIVATE_AIS
388 ObjectPtr anObject = getObject(theIO);
389 anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
390 qDebug(QString("deactivateAIS: theMode = %1, object = %2").arg(theMode)
391 .arg(anInfo).toStdString().c_str());
396 //**************************************************************
397 bool XGUI_SelectionActivate::activate(const Handle(AIS_InteractiveObject)& theIO,
398 const bool theUpdateViewer) const
400 Handle(AIS_InteractiveContext) aContext = AISContext();
401 if (aContext.IsNull() || theIO.IsNull())
404 bool isActivationChanged = false;
405 // deactivate object in all modes, which are not in the list of activation
406 // It seems that after the IO deactivation the selected state of the IO's owners
407 // is modified in OCC(version: 6.8.0) and the selection of the object later is lost.
408 // By this reason, the number of the IO deactivate is decreased and the object is deactivated
409 // only if there is a difference in the current modes and the parameters modes.
410 // If the selection problem happens again, it is possible to write a test scenario and create
411 // a bug. The bug steps are the following:
412 // Create two IO, activate them in 5 modes, select the first IO, deactivate 3 modes for both,
413 // with clicked SHIFT select the second object.
414 // The result is the selection of the first IO is lost.
415 TColStd_ListOfInteger aTColModes;
416 aContext->ActivatedModes(theIO, aTColModes);
417 TColStd_ListIteratorOfListOfInteger itr( aTColModes );
418 QIntList aModesActivatedForIO;
419 bool isDeactivated = false;
420 bool aHasValidMode = false;
421 for (; itr.More(); itr.Next() ) {
422 Standard_Integer aMode = itr.Value();
423 aHasValidMode = aHasValidMode || aMode != -1;
424 int aShapeMode = (aMode > 8)? aMode : AIS_Shape::SelectionType(aMode);
425 if (!myActiveSelectionModes.contains(aMode)) {
426 deactivateAIS(theIO, aMode);
427 isDeactivated = true;
430 aModesActivatedForIO.append(aMode);
434 // the selection from the previous activation modes should be cleared manually (#26172)
435 //theIO->ClearSelected();
436 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
437 XGUI_Tools::workshop(myWorkshop)->selector()->deselectPresentation(theIO);
439 // For performance issues
440 //if (theUpdateViewer)
441 // getDisplayer()->updateViewer();
442 isActivationChanged = true;
445 // loading the interactive object allowing the decomposition
446 if (aTColModes.IsEmpty() || !aHasValidMode) {
447 aContext->Load(theIO, -1, true);
448 Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
449 if (!aTrihedron.IsNull()) {
450 // Workaround for Trihedron. It should be loaded using the next Load method to
451 // add this object to myGlobal map of selection manager
452 // it is important to activate trihedron in two selection modes: edges and vertices
453 aContext->SelectionManager()->Load(theIO);
457 // trihedron AIS check should be after the AIS loading.
458 // If it is not loaded, it is steel selectable in the viewer.
459 Handle(AIS_Trihedron) aTrihedron;
460 if (!isTrihedronActive())
461 aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
462 if (aTrihedron.IsNull()) {
463 // In order to clear active modes list
464 if (myActiveSelectionModes.size() == 0) {
465 activateAIS(theIO, 0, theUpdateViewer);
467 foreach(int aMode, myActiveSelectionModes) {
468 if (!aModesActivatedForIO.contains(aMode)) {
469 activateAIS(theIO, aMode, theUpdateViewer);
470 isActivationChanged = true;
475 return isActivationChanged;
478 //**************************************************************
479 void XGUI_SelectionActivate::deactivate(const ObjectPtr& theObject, const bool theUpdateViewer)
481 #ifdef DEBUG_DEACTIVATE
482 QString anInfoStr = ModuleBase_Tools::objectInfo(theObject);
483 qDebug(QString("deactivate: myActiveSelectionModes[%1]: %2, objects = ").
484 arg(myActiveSelectionModes.size()).arg(qIntListInfo(myActiveSelectionModes)).
486 toStdString().c_str());
488 Handle(AIS_InteractiveContext) aContext = AISContext();
489 if (!aContext.IsNull() && getDisplayer()->isVisible(theObject)) {
490 AISObjectPtr anObj = getDisplayedAISObject(theObject);
491 Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
493 deactivateAIS(anAIS);
494 // the selection from the previous activation modes should be cleared manually (#26172)
495 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
496 XGUI_Tools::workshop(myWorkshop)->selector()->deselectPresentation(anAIS);
499 getDisplayer()->updateViewer();
503 /// #1136 hidden axis are selected in sketch
504 #ifdef BEFORE_TRIHEDRON_PATCH
505 //**************************************************************
506 void deactivateObject(Handle(AIS_InteractiveContext) theContext,
507 Handle(AIS_InteractiveObject) theObject)
509 if (!theObject.IsNull())
510 theContext->Deactivate(theObject);
514 //**************************************************************
515 void XGUI_SelectionActivate::activateTrihedron(bool theIsActive)
517 myIsTrihedronActive = theIsActive;
518 if (!myIsTrihedronActive)
519 deactivateTrihedron(true);
522 //**************************************************************
523 void XGUI_SelectionActivate::deactivateTrihedron(const bool theUpdateViewer) const
525 Handle(AIS_InteractiveObject) aTrihedron = getTrihedron();
526 Handle(AIS_InteractiveContext) aContext = AISContext();
527 if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron)) {
528 Handle(AIS_Trihedron) aTrie = Handle(AIS_Trihedron)::DownCast(aTrihedron);
530 aContext->Deactivate(aTrie);
532 /// #1136 hidden axis are selected in sketch
533 #ifdef BEFORE_TRIHEDRON_PATCH
534 deactivateObject(aContext, aTrie->XAxis());
535 deactivateObject(aContext, aTrie->YAxis());
536 deactivateObject(aContext, aTrie->Axis());
537 deactivateObject(aContext, aTrie->Position());
539 deactivateObject(aContext, aTrie->XYPlane());
540 deactivateObject(aContext, aTrie->XZPlane());
541 deactivateObject(aContext, aTrie->YZPlane());
544 getDisplayer()->updateViewer();
548 //**************************************************************
549 void XGUI_SelectionActivate::deactivateTrihedronInSelectionModes()
551 Handle(AIS_InteractiveContext) aContext = AISContext();
552 if (!aContext.IsNull()) {
553 Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(getTrihedron());
554 /// deactivate trihedron in selection modes
555 TColStd_ListOfInteger aTColModes;
556 aContext->ActivatedModes(aTrihedron, aTColModes);
557 TColStd_ListIteratorOfListOfInteger itr(aTColModes);
558 for (; itr.More(); itr.Next()) {
559 Standard_Integer aMode = itr.Value();
560 aContext->Deactivate(aTrihedron, aMode);
565 //**************************************************************
566 Handle(AIS_InteractiveContext) XGUI_SelectionActivate::AISContext() const
568 return myWorkshop->viewer()->AISContext();
571 //**************************************************************
572 XGUI_Displayer* XGUI_SelectionActivate::getDisplayer() const
574 return XGUI_Tools::workshop(myWorkshop)->displayer();
577 //**************************************************************
578 Handle(AIS_InteractiveObject) XGUI_SelectionActivate::getTrihedron() const
580 return myWorkshop->viewer()->trihedron();
583 //**************************************************************
584 AISObjectPtr XGUI_SelectionActivate::getDisplayedAISObject(ObjectPtr theObject) const
586 return getDisplayer()->getAISObject(theObject);
589 //**************************************************************
590 int XGUI_SelectionActivate::getSelectionMode(int theShapeType)
592 return (theShapeType > TopAbs_SHAPE) ? theShapeType :
593 AIS_Shape::SelectionMode((TopAbs_ShapeEnum)theShapeType);