1 // Copyright (C) 2014-2017 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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include "XGUI_SelectionActivate.h"
23 #include "ModelAPI_Object.h"
25 #include "ModuleBase_IModule.h"
26 #include "ModuleBase_IViewer.h"
27 #include "ModuleBase_ModelWidget.h"
28 #include "ModuleBase_Preferences.h"
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"
39 #include <SUIT_ResourceMgr.h>
41 #include <AIS_InteractiveContext.hxx>
42 #include <AIS_Shape.hxx>
43 #include <AIS_Trihedron.hxx>
45 #include <SelectMgr_SelectionManager.hxx>
47 //#define DEBUG_ACTIVATE_OBJECTS
48 //#define DEBUG_DEACTIVATE
49 //#define DEBUG_ACTIVATE_AIS
50 //#define DEBUG_DEACTIVATE_AIS
52 #define CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
54 //**************************************************************
55 XGUI_SelectionActivate::XGUI_SelectionActivate(ModuleBase_IWorkshop* theWorkshop)
56 : ModuleBase_ISelectionActivate(theWorkshop), myIsTrihedronActive(true)
60 //**************************************************************
61 XGUI_SelectionActivate::SelectionPlace XGUI_SelectionActivate::activeSelectionPlace() const
63 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop);
64 XGUI_ActiveControlSelector* anActiveSelector = aWorkshop->activeControlMgr()->activeSelector();
65 if (!anActiveSelector)
68 if (anActiveSelector->getType() == XGUI_FacesPanelSelector::Type())
74 //**************************************************************
75 void XGUI_SelectionActivate::updateSelectionModes()
78 switch (activeSelectionPlace()) {
80 myWorkshop->module()->activeSelectionModes(aModes);
83 ModuleBase_ModelWidget* anActiveWidget = myWorkshop->module()->activeWidget();
85 getSelectionModes(anActiveWidget, aModes);
87 myWorkshop->module()->activeSelectionModes(aModes); //using module modes
91 XGUI_Tools::workshop(myWorkshop)->facesPanel()->selectionModes(aModes);
92 myWorkshop->module()->customSubShapesSelectionModes(aModes); // avoid wire selection
97 activateObjects(aModes, getDisplayer()->displayedObjects(), true);
100 //**************************************************************
101 void XGUI_SelectionActivate::updateSelectionFilters()
103 SelectMgr_ListOfFilter aSelectionFilters;
104 switch (activeSelectionPlace()) {
106 XGUI_Tools::workshop(myWorkshop)->selectionFilters(aSelectionFilters);
108 case PropertyPanel: {
109 ModuleBase_ModelWidget* anActiveWidget = myWorkshop->module()->activeWidget();
110 getSelectionFilters(anActiveWidget, aSelectionFilters);
114 //XGUI_Tools::workshop(myWorkshop)->selectionFilters(aSelectionFilters);
115 XGUI_Tools::workshop(myWorkshop)->facesPanel()->selectionFilters(aSelectionFilters);
120 activateSelectionFilters(aSelectionFilters);
123 //**************************************************************
124 void XGUI_SelectionActivate::activateSelectionAndFilters(ModuleBase_ModelWidget* theWidget)
126 // activate selection modes
128 getSelectionModes(theWidget, aModes);
129 activateObjects(aModes, getDisplayer()->displayedObjects(), true);
131 // activate selection filters
132 SelectMgr_ListOfFilter aSelectionFilters;
133 getSelectionFilters(theWidget, aSelectionFilters);
134 activateSelectionFilters(aSelectionFilters);
137 //**************************************************************
138 void XGUI_SelectionActivate::activateSelectionFilters
139 (const SelectMgr_ListOfFilter& theSelectionFilters)
141 XGUI_Displayer* aDisplayer = getDisplayer();
142 aDisplayer->deactivateSelectionFilters(false);
144 SelectMgr_ListIteratorOfListOfFilter aIt(theSelectionFilters);
145 for (; aIt.More(); aIt.Next()) {
146 Handle(SelectMgr_Filter) aFilter = aIt.Value();
147 if (aFilter.IsNull())
149 aDisplayer->addSelectionFilter(aFilter);
153 //**************************************************************
154 void XGUI_SelectionActivate::getSelectionModes(ModuleBase_ModelWidget* theWidget,
160 bool isAdditional = false;
161 theWidget->selectionModes(theModes, isAdditional);
163 myWorkshop->module()->customSubShapesSelectionModes(theModes);
164 //theModes.append(XGUI_Tools::workshop(myWorkshop)->viewerSelectionModes());
165 //myWorkshop->module()->activeSelectionModes(theModes);
169 //**************************************************************
170 void XGUI_SelectionActivate::getSelectionFilters(ModuleBase_ModelWidget* theWidget,
171 SelectMgr_ListOfFilter& theSelectionFilters)
173 XGUI_Tools::workshop(myWorkshop)->selectionFilters(theSelectionFilters);
176 theWidget->selectionFilters(theSelectionFilters);
179 //**************************************************************
180 QIntList XGUI_SelectionActivate::activeSelectionModes() const
183 foreach (int aMode, myActiveSelectionModes) {
184 // aMode < 9 is a Shape Enum values
185 aModes << ((aMode < 9)? AIS_Shape::SelectionType(aMode) : aMode);
190 //**************************************************************
191 bool XGUI_SelectionActivate::isActive(ObjectPtr theObject) const
193 Handle(AIS_InteractiveContext) aContext = AISContext();
194 if (aContext.IsNull() || !getDisplayer()->isVisible(theObject))
197 AISObjectPtr anObj = getDisplayedAISObject(theObject);
198 Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
200 TColStd_ListOfInteger aModes;
201 aContext->ActivatedModes(anAIS, aModes);
203 return aModes.Extent() > 0;
206 //**************************************************************
207 void XGUI_SelectionActivate::activateObjects(const QIntList& theModes,
208 const QObjectPtrList& theObjList, const bool theUpdateViewer)
210 setSelectionModes(theModes);
212 Handle(AIS_InteractiveContext) aContext = AISContext();
213 // Open local context if there is no one
214 if (aContext.IsNull())
217 //aContext->UseDisplayedObjects();
218 //myUseExternalObjects = true;
220 Handle(AIS_InteractiveObject) anAISIO;
221 AIS_ListOfInteractive aPrsList;
222 AIS_ListOfInteractive aPrsListToBeDeactivated;
223 //if (aObjList.isEmpty())
226 foreach(ObjectPtr anObject, theObjList) {
227 AISObjectPtr anAISObject = getDisplayedAISObject(anObject);
228 if (!anAISObject.get())
231 Handle(AIS_InteractiveObject) aPrs = anAISObject->impl<Handle(AIS_InteractiveObject)>();
232 if (myWorkshop->module()->canActivateSelection(anObject))
233 aPrsList.Append(aPrs);
235 aPrsListToBeDeactivated.Append(aPrs);
239 // Add trihedron because it has to partisipate in selection
240 Handle(AIS_InteractiveObject) aTrihedron;
241 if (isTrihedronActive()) {
242 aTrihedron = getTrihedron();
243 if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron))
244 aPrsList.Append(aTrihedron);
246 if (aPrsList.Extent() == 0 && aPrsListToBeDeactivated.Extent() == 0)
249 AIS_ListIteratorOfListOfInteractive aLIt;
250 bool isActivationChanged = false;
251 for(aLIt.Initialize(aPrsList); aLIt.More(); aLIt.Next()) {
252 anAISIO = aLIt.Value();
253 if (activate(anAISIO, false))
254 isActivationChanged = true;
257 for(aLIt.Initialize(aPrsListToBeDeactivated); aLIt.More(); aLIt.Next()) {
258 anAISIO = aLIt.Value();
259 deactivateAIS(anAISIO);
260 isActivationChanged = true;
264 #ifdef DEBUG_ACTIVATE_OBJECTS
265 //**************************************************************
266 QString getModeInfo(const int theMode)
268 QString anInfo = "Undefined";
270 case 0: anInfo = "SHAPE(0)"; break;
271 case 1: anInfo = "VERTEX(1)"; break;
272 case 2: anInfo = "EDGE(2)"; break;
273 case 3: anInfo = "WIRE(3)"; break;
274 case 4: anInfo = "FACE(4)"; break;
275 case 5: anInfo = "SHELL(5)"; break;
276 case 6: anInfo = "SOLID(6)"; break;
277 case 7: anInfo = "COMPSOLID(7)"; break;
278 case 8: anInfo = "COMPOUND(8)"; break;
279 case 100: anInfo = "Sel_Mode_First(100)"; break; //SketcherPrs_Tools
280 case 101: anInfo = "Sel_Constraint(101)"; break;
281 case 102: anInfo = "Sel_Dimension_All(102)"; break;
282 case 103: anInfo = "Sel_Dimension_Line(103)"; break;
283 case 104: anInfo = "Sel_Dimension_Text(104)"; break;
289 //**************************************************************
290 QString getModesInfo(const QIntList& theModes)
292 QStringList aModesInfo;
293 for (int i = 0, aSize = theModes.size(); i < aSize; i++)
294 aModesInfo.append(getModeInfo(theModes[i]));
295 return QString("[%1] = %2").arg(aModesInfo.size()).arg(aModesInfo.join(", "));
299 //**************************************************************
300 void XGUI_SelectionActivate::setSelectionModes(const QIntList& theModes)
302 // Convert shape types to selection types
304 foreach(int aType, theModes) {
305 aModes.append(getSelectionMode(aType));
308 #ifdef DEBUG_ACTIVATE_OBJECTS
310 QObjectPtrList::const_iterator anIt = theObjList.begin(), aLast = theObjList.end();
311 for (; anIt != aLast; ++anIt) {
312 anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
314 QString anInfoStr = anInfo.join(", ");
316 qDebug(QString("activateObjects: new modes%1, active modes%2, objects[%3] = %4").
317 arg(getModesInfo(aModes)).
318 arg(getModesInfo(myActiveSelectionModes)).
319 arg(theObjList.size()).
321 toStdString().c_str());
323 // In order to avoid doblications of selection modes
325 foreach (int aMode, aModes) {
326 if (!aNewModes.contains(aMode))
327 aNewModes.append(aMode);
329 myActiveSelectionModes = aNewModes;
332 //**************************************************************
333 void XGUI_SelectionActivate::activateOnDisplay(const Handle(AIS_InteractiveObject)& theIO,
334 const bool theUpdateViewer)
336 if (myActiveSelectionModes.size() == 0)
337 activateAIS(theIO, 0, theUpdateViewer);
339 foreach(int aMode, myActiveSelectionModes) {
340 activateAIS(theIO, aMode, theUpdateViewer);
345 //**************************************************************
346 void XGUI_SelectionActivate::activateAIS(const Handle(AIS_InteractiveObject)& theIO,
347 const int theMode, const bool theUpdateViewer) const
349 Handle(AIS_InteractiveContext) aContext = AISContext();
350 if (!theIO.IsNull() && theIO == getTrihedron()) {
351 if (theMode != AIS_Shape::SelectionType(TopAbs_EDGE) &&
352 theMode != AIS_Shape::SelectionType(TopAbs_VERTEX))
355 if (!aContext.IsNull()) {
356 if (myWorkshop->module()) {
357 int aMode = (theMode > 8)? theMode : AIS_Shape::SelectionType(theMode);
358 aContext->Activate(theIO, theMode, false);
360 aContext->Activate(theIO, theMode, false);
362 // the fix from VPA for more suitable selection of sketcher lines
363 if (theIO->Width() > 1) {
364 double aPrecision = theIO->Width() + 2;
365 if (theMode == getSelectionMode(TopAbs_VERTEX))
366 aPrecision = ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
367 "point-selection-sensitivity", 12);
368 else if ((theMode == getSelectionMode(TopAbs_EDGE)) ||
369 (theMode == getSelectionMode(TopAbs_WIRE)))
370 aPrecision = theIO->Width() + ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
371 "edge-selection-sensitivity", 2);
372 aContext->SetSelectionSensitivity(theIO, theMode, aPrecision);
375 #ifdef DEBUG_ACTIVATE_AIS
376 ObjectPtr anObject = getObject(theIO);
377 anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
378 qDebug(QString("activateAIS: theMode = %1, object = %2").arg(theMode)
379 .arg(anInfo).toStdString().c_str());
382 getDisplayer()->updateViewer();
386 //**************************************************************
387 void XGUI_SelectionActivate::deactivateAIS(const Handle(AIS_InteractiveObject)& theIO,
388 const int theMode) const
390 Handle(AIS_InteractiveContext) aContext = AISContext();
391 if (!aContext.IsNull()) {
393 aContext->Deactivate(theIO);
395 aContext->Deactivate(theIO, theMode);
397 #ifdef DEBUG_DEACTIVATE_AIS
398 ObjectPtr anObject = getObject(theIO);
399 anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
400 qDebug(QString("deactivateAIS: theMode = %1, object = %2").arg(theMode)
401 .arg(anInfo).toStdString().c_str());
406 //**************************************************************
407 bool XGUI_SelectionActivate::activate(const Handle(AIS_InteractiveObject)& theIO,
408 const bool theUpdateViewer) const
410 Handle(AIS_InteractiveContext) aContext = AISContext();
411 if (aContext.IsNull() || theIO.IsNull())
414 bool isActivationChanged = false;
415 // deactivate object in all modes, which are not in the list of activation
416 // It seems that after the IO deactivation the selected state of the IO's owners
417 // is modified in OCC(version: 6.8.0) and the selection of the object later is lost.
418 // By this reason, the number of the IO deactivate is decreased and the object is deactivated
419 // only if there is a difference in the current modes and the parameters modes.
420 // If the selection problem happens again, it is possible to write a test scenario and create
421 // a bug. The bug steps are the following:
422 // Create two IO, activate them in 5 modes, select the first IO, deactivate 3 modes for both,
423 // with clicked SHIFT select the second object.
424 // The result is the selection of the first IO is lost.
425 TColStd_ListOfInteger aTColModes;
426 aContext->ActivatedModes(theIO, aTColModes);
427 TColStd_ListIteratorOfListOfInteger itr( aTColModes );
428 QIntList aModesActivatedForIO;
429 bool isDeactivated = false;
430 bool aHasValidMode = false;
431 for (; itr.More(); itr.Next() ) {
432 Standard_Integer aMode = itr.Value();
433 aHasValidMode = aHasValidMode || aMode != -1;
434 int aShapeMode = (aMode > 8)? aMode : AIS_Shape::SelectionType(aMode);
435 if (!myActiveSelectionModes.contains(aMode)) {
436 deactivateAIS(theIO, aMode);
437 isDeactivated = true;
440 aModesActivatedForIO.append(aMode);
444 // the selection from the previous activation modes should be cleared manually (#26172)
445 //theIO->ClearSelected();
446 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
447 XGUI_Tools::workshop(myWorkshop)->selector()->deselectPresentation(theIO);
449 // For performance issues
450 //if (theUpdateViewer)
451 // getDisplayer()->updateViewer();
452 isActivationChanged = true;
455 // loading the interactive object allowing the decomposition
456 if (aTColModes.IsEmpty() || !aHasValidMode) {
457 aContext->Load(theIO, -1, true);
458 Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
459 if (!aTrihedron.IsNull()) {
460 // Workaround for Trihedron. It should be loaded using the next Load method to
461 // add this object to myGlobal map of selection manager
462 // it is important to activate trihedron in two selection modes: edges and vertices
463 aContext->SelectionManager()->Load(theIO);
467 // trihedron AIS check should be after the AIS loading.
468 // If it is not loaded, it is steel selectable in the viewer.
469 Handle(AIS_Trihedron) aTrihedron;
470 if (!isTrihedronActive())
471 aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
472 if (aTrihedron.IsNull()) {
473 // In order to clear active modes list
474 if (myActiveSelectionModes.size() == 0) {
475 activateAIS(theIO, 0, theUpdateViewer);
477 foreach(int aMode, myActiveSelectionModes) {
478 if (!aModesActivatedForIO.contains(aMode)) {
479 activateAIS(theIO, aMode, theUpdateViewer);
480 isActivationChanged = true;
485 return isActivationChanged;
488 //**************************************************************
489 void XGUI_SelectionActivate::deactivate(const ObjectPtr& theObject, const bool theUpdateViewer)
491 #ifdef DEBUG_DEACTIVATE
492 QString anInfoStr = ModuleBase_Tools::objectInfo(theObject);
493 qDebug(QString("deactivate: myActiveSelectionModes[%1]: %2, objects = ").
494 arg(myActiveSelectionModes.size()).arg(qIntListInfo(myActiveSelectionModes)).
496 toStdString().c_str());
498 Handle(AIS_InteractiveContext) aContext = AISContext();
499 if (!aContext.IsNull() && getDisplayer()->isVisible(theObject)) {
500 AISObjectPtr anObj = getDisplayedAISObject(theObject);
501 Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
503 deactivateAIS(anAIS);
504 // the selection from the previous activation modes should be cleared manually (#26172)
505 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
506 XGUI_Tools::workshop(myWorkshop)->selector()->deselectPresentation(anAIS);
509 getDisplayer()->updateViewer();
513 /// #1136 hidden axis are selected in sketch
514 #ifdef BEFORE_TRIHEDRON_PATCH
515 //**************************************************************
516 void deactivateObject(Handle(AIS_InteractiveContext) theContext,
517 Handle(AIS_InteractiveObject) theObject)
519 if (!theObject.IsNull())
520 theContext->Deactivate(theObject);
524 //**************************************************************
525 void XGUI_SelectionActivate::activateTrihedron(bool theIsActive)
527 myIsTrihedronActive = theIsActive;
528 if (!myIsTrihedronActive)
529 deactivateTrihedron(true);
532 //**************************************************************
533 void XGUI_SelectionActivate::deactivateTrihedron(const bool theUpdateViewer) const
535 Handle(AIS_InteractiveObject) aTrihedron = getTrihedron();
536 Handle(AIS_InteractiveContext) aContext = AISContext();
537 if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron)) {
538 Handle(AIS_Trihedron) aTrie = Handle(AIS_Trihedron)::DownCast(aTrihedron);
540 aContext->Deactivate(aTrie);
542 /// #1136 hidden axis are selected in sketch
543 #ifdef BEFORE_TRIHEDRON_PATCH
544 deactivateObject(aContext, aTrie->XAxis());
545 deactivateObject(aContext, aTrie->YAxis());
546 deactivateObject(aContext, aTrie->Axis());
547 deactivateObject(aContext, aTrie->Position());
549 deactivateObject(aContext, aTrie->XYPlane());
550 deactivateObject(aContext, aTrie->XZPlane());
551 deactivateObject(aContext, aTrie->YZPlane());
554 getDisplayer()->updateViewer();
558 //**************************************************************
559 void XGUI_SelectionActivate::deactivateTrihedronInSelectionModes()
561 Handle(AIS_InteractiveContext) aContext = AISContext();
562 Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(getTrihedron());
563 /// deactivate trihedron in selection modes
564 TColStd_ListOfInteger aTColModes;
565 aContext->ActivatedModes(aTrihedron, aTColModes);
566 TColStd_ListIteratorOfListOfInteger itr( aTColModes );
567 for (; itr.More(); itr.Next() ) {
568 Standard_Integer aMode = itr.Value();
569 aContext->Deactivate(aTrihedron, aMode);
573 //**************************************************************
574 Handle(AIS_InteractiveContext) XGUI_SelectionActivate::AISContext() const
576 return myWorkshop->viewer()->AISContext();
579 //**************************************************************
580 XGUI_Displayer* XGUI_SelectionActivate::getDisplayer() const
582 return XGUI_Tools::workshop(myWorkshop)->displayer();
585 //**************************************************************
586 Handle(AIS_InteractiveObject) XGUI_SelectionActivate::getTrihedron() const
588 return myWorkshop->viewer()->trihedron();
591 //**************************************************************
592 AISObjectPtr XGUI_SelectionActivate::getDisplayedAISObject(ObjectPtr theObject) const
594 return getDisplayer()->getAISObject(theObject);
597 //**************************************************************
598 int XGUI_SelectionActivate::getSelectionMode(int theShapeType)
600 return (theShapeType > TopAbs_SHAPE) ? theShapeType :
601 AIS_Shape::SelectionMode((TopAbs_ShapeEnum)theShapeType);