Salome HOME
eb2b6bbc7dd0c82ed90391fe41cce9ffff6d72da
[modules/shaper.git] / src / XGUI / XGUI_Displayer.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_Displayer.h"
22 #include "XGUI_Workshop.h"
23 #include "XGUI_ViewerProxy.h"
24 #include "XGUI_SelectionMgr.h"
25 #include "XGUI_Selection.h"
26 #include "XGUI_CustomPrs.h"
27
28 #ifndef HAVE_SALOME
29 #include <AppElements_Viewer.h>
30 #endif
31
32 #include <ModelAPI_Document.h>
33 #include <ModelAPI_Data.h>
34 #include <ModelAPI_Object.h>
35 #include <ModelAPI_Tools.h>
36 #include <ModelAPI_AttributeIntArray.h>
37 #include <ModelAPI_ResultCompSolid.h>
38
39 #include <ModuleBase_ResultPrs.h>
40 #include <ModuleBase_Tools.h>
41 #include <ModuleBase_IModule.h>
42 #include <ModuleBase_ViewerPrs.h>
43 #include <ModuleBase_Preferences.h>
44
45 #include <GeomAPI_Shape.h>
46 #include <GeomAPI_IPresentable.h>
47 #include <GeomAPI_ICustomPrs.h>
48
49 #include <SUIT_ResourceMgr.h>
50
51 #include <AIS_InteractiveContext.hxx>
52 #include <AIS_ListOfInteractive.hxx>
53 #include <AIS_ListIteratorOfListOfInteractive.hxx>
54 #include <AIS_DimensionSelectionMode.hxx>
55 #include <AIS_Shape.hxx>
56 #include <AIS_Dimension.hxx>
57 #include <AIS_Trihedron.hxx>
58 #ifdef BEFORE_TRIHEDRON_PATCH
59 #include <AIS_Axis.hxx>
60 #include <AIS_Plane.hxx>
61 #include <AIS_Point.hxx>
62 #endif
63 #include <AIS_Selection.hxx>
64 #include <TColStd_ListIteratorOfListOfInteger.hxx>
65 #include <SelectMgr_ListOfFilter.hxx>
66 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
67 #include <Prs3d_Drawer.hxx>
68 #include <Prs3d_IsoAspect.hxx>
69 #include <SelectMgr_SelectionManager.hxx>
70
71 #include <StdSelect_ViewerSelector3d.hxx>
72
73 #include <TColStd_MapOfTransient.hxx>
74 #include <TColStd_MapIteratorOfMapOfTransient.hxx>
75
76 #ifdef TINSPECTOR
77 #include <VInspectorAPI_CallBack.hxx>
78 #endif
79
80 #include <Events_Loop.h>
81 #include <ModelAPI_Events.h>
82
83 #include <set>
84
85 /// defines the local context mouse selection sensitivity
86 const int MOUSE_SENSITIVITY_IN_PIXEL = 10;
87
88 //#define DEBUG_ACTIVATE_OBJECTS
89 //#define DEBUG_DEACTIVATE
90 //#define DEBUG_ACTIVATE_AIS
91 //#define DEBUG_DEACTIVATE_AIS
92
93 //#define DEBUG_DISPLAY
94 //#define DEBUG_FEATURE_REDISPLAY
95 //#define DEBUG_SELECTION_FILTERS
96
97 //#define DEBUG_COMPOSILID_DISPLAY
98
99 //#define DEBUG_OCCT_SHAPE_SELECTION
100
101 #define CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
102
103 void displayedObjects(const Handle(AIS_InteractiveContext)& theAIS, AIS_ListOfInteractive& theList)
104 {
105   // Get from null point
106   theAIS->DisplayedObjects(theList, true);
107 }
108
109 QString qIntListInfo(const QIntList& theValues, const QString& theSeparator = QString(", "))
110 {
111   QStringList anInfo;
112   QIntList::const_iterator anIt = theValues.begin(), aLast = theValues.end();
113   for (; anIt != aLast; anIt++) {
114     anInfo.append(QString::number(*anIt));
115   }
116   return anInfo.join(theSeparator);
117 }
118
119 void deselectPresentation(const Handle(AIS_InteractiveObject) theObject,
120                           const Handle(AIS_InteractiveContext)& theContext)
121 {
122   NCollection_List<Handle(SelectBasics_EntityOwner)> aResultOwners;
123
124   for (theContext->InitSelected(); theContext->MoreSelected(); theContext->NextSelected()) {
125     Handle(SelectMgr_EntityOwner) anOwner = theContext->SelectedOwner();
126     if (anOwner.IsNull()) // TODO: check why it is possible
127       continue;
128     if (anOwner->Selectable() == theObject && anOwner->IsSelected())
129       aResultOwners.Append(anOwner);
130   }
131   NCollection_List<Handle(SelectBasics_EntityOwner)>::Iterator anOwnersIt (aResultOwners);
132   Handle(SelectMgr_EntityOwner) anOwner;
133   for (; anOwnersIt.More(); anOwnersIt.Next()) {
134     anOwner = Handle(SelectMgr_EntityOwner)::DownCast(anOwnersIt.Value());
135     if (!anOwner.IsNull())
136       theContext->AddOrRemoveSelected(anOwner, false);
137   }
138 }
139
140 XGUI_Displayer::XGUI_Displayer(XGUI_Workshop* theWorkshop)
141   : myWorkshop(theWorkshop), myNeedUpdate(false),
142   myIsTrihedronActive(true), myViewerBlockedRecursiveCount(0),
143   myIsFirstAISContextUse(true)
144 {
145   myCustomPrs = std::shared_ptr<GeomAPI_ICustomPrs>(new XGUI_CustomPrs(theWorkshop));
146 }
147
148 XGUI_Displayer::~XGUI_Displayer()
149 {
150 }
151
152 bool XGUI_Displayer::isVisible(ObjectPtr theObject) const
153 {
154   return myResult2AISObjectMap.contains(theObject);
155 }
156
157 bool XGUI_Displayer::display(ObjectPtr theObject, bool theUpdateViewer)
158 {
159   bool aDisplayed = false;
160   if (isVisible(theObject)) {
161 #ifdef DEBUG_COMPOSILID_DISPLAY
162     ResultCompSolidPtr aCompsolidResult =
163       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObject);
164     if (aCompsolidResult.get()) {
165       for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
166         ResultPtr aSubResult = aCompsolidResult->subResult(i);
167         if (aSubResult.get())
168           redisplay(aSubResult, false);
169       }
170       if (theUpdateViewer)
171         updateViewer();
172     }
173     else
174 #endif
175     aDisplayed = redisplay(theObject, theUpdateViewer);
176   } else {
177     AISObjectPtr anAIS;
178     GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
179     bool isShading = false;
180     if (aPrs.get() != NULL) {
181       anAIS = aPrs->getAISObject(anAIS);
182       if (anAIS.get()) {
183         // correct deviation coefficient for
184         /*Handle(AIS_InteractiveObject) anAISPrs = anAIS->impl<Handle(AIS_InteractiveObject)>();
185         if (!anAISPrs.IsNull()) {
186           Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(anAISPrs);
187           if (!aShapePrs.IsNull()) {
188             TopoDS_Shape aShape = aShapePrs->Shape();
189             if (!aShape.IsNull())
190               //ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, anAISPrs->Attributes());
191           }
192         }*/
193       }
194     } else {
195       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
196       if (aResult.get() != NULL) {
197 #ifdef DEBUG_COMPOSILID_DISPLAY
198         ResultCompSolidPtr aCompsolidResult =
199           std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObject);
200         if (aCompsolidResult.get()) {
201           for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
202             ResultPtr aSubResult = aCompsolidResult->subResult(i);
203             if (aSubResult.get())
204               display(aSubResult, false);
205           }
206           if (theUpdateViewer)
207             updateViewer();
208         }
209         else {
210 #endif
211         std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
212         if (aShapePtr.get() != NULL) {
213           anAIS = AISObjectPtr(new GeomAPI_AISObject());
214           Handle(AIS_InteractiveObject) anAISPrs =
215             myWorkshop->module()->createPresentation(aResult);
216           if (anAISPrs.IsNull())
217             anAISPrs = new ModuleBase_ResultPrs(aResult);
218           else {
219             Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(anAISPrs);
220             if (!aShapePrs.IsNull())
221               ModuleBase_Tools::setPointBallHighlighting((AIS_Shape*) aShapePrs.get());
222           }
223           anAIS->setImpl(new Handle(AIS_InteractiveObject)(anAISPrs));
224           //anAIS->createShape(aShapePtr);
225           isShading = true;
226         }
227 #ifdef DEBUG_COMPOSILID_DISPLAY
228         } // close else
229 #endif
230       }
231     }
232     if (anAIS)
233       aDisplayed = display(theObject, anAIS, isShading, theUpdateViewer);
234   }
235   return aDisplayed;
236 }
237
238 bool canBeShaded(Handle(AIS_InteractiveObject) theAIS, ModuleBase_IModule* theModule)
239 {
240   Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(theAIS);
241   if (!aShapePrs.IsNull()) {
242     TopoDS_Shape aShape = aShapePrs->Shape();
243     if (aShape.IsNull())
244       return false;
245     TopAbs_ShapeEnum aType = aShape.ShapeType();
246     if ((aType == TopAbs_VERTEX) || (aType == TopAbs_EDGE) || (aType == TopAbs_WIRE))
247       return false;
248     else {
249       // Check that the presentation is not a sketch
250       return theModule->canBeShaded(theAIS);
251     }
252   }
253   return false;
254 }
255
256 bool XGUI_Displayer::display(ObjectPtr theObject, AISObjectPtr theAIS,
257                              bool isShading, bool theUpdateViewer)
258 {
259   bool aDisplayed = false;
260
261   Handle(AIS_InteractiveContext) aContext = AISContext();
262   if (aContext.IsNull())
263     return aDisplayed;
264
265   Handle(AIS_InteractiveObject) anAISIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
266   if (!anAISIO.IsNull()) {
267     appendResultObject(theObject, theAIS);
268
269     bool isCustomized = customizeObject(theObject);
270
271     int aDispMode = isShading? Shading : Wireframe;
272     if (isShading)
273       anAISIO->Attributes()->SetFaceBoundaryDraw( Standard_True );
274     anAISIO->SetDisplayMode(aDispMode);
275     aContext->Display(anAISIO, aDispMode, 0, false, true, AIS_DS_Displayed);
276     #ifdef TINSPECTOR
277     if (getCallBack()) getCallBack()->Display(anAISIO);
278     #endif
279     aDisplayed = true;
280
281     emit objectDisplayed(theObject, theAIS);
282     activate(anAISIO, myActiveSelectionModes, theUpdateViewer);
283   }
284   if (theUpdateViewer)
285     updateViewer();
286
287   return aDisplayed;
288 }
289
290 bool XGUI_Displayer::erase(ObjectPtr theObject, const bool theUpdateViewer)
291 {
292   bool aErased = false;
293   if (!isVisible(theObject))
294     return aErased;
295
296   Handle(AIS_InteractiveContext) aContext = AISContext();
297   if (aContext.IsNull())
298     return aErased;
299
300   AISObjectPtr anObject = myResult2AISObjectMap[theObject];
301   if (anObject) {
302     Handle(AIS_InteractiveObject) anAIS = anObject->impl<Handle(AIS_InteractiveObject)>();
303     if (!anAIS.IsNull()) {
304       emit beforeObjectErase(theObject, anObject);
305       aContext->Remove(anAIS, false/*update viewer*/);
306       #ifdef TINSPECTOR
307       if (getCallBack()) getCallBack()->Remove(anAIS);
308       #endif
309       aErased = true;
310     }
311   }
312   myResult2AISObjectMap.remove(theObject);
313
314 #ifdef DEBUG_DISPLAY
315   std::ostringstream aPtrStr;
316   aPtrStr << theObject.get();
317   qDebug(QString("erase object: %1").arg(aPtrStr.str().c_str()).toStdString().c_str());
318   qDebug(getResult2AISObjectMapInfo().c_str());
319 #endif
320
321   if (theUpdateViewer)
322     updateViewer();
323
324   return aErased;
325 }
326
327 bool XGUI_Displayer::redisplay(ObjectPtr theObject, bool theUpdateViewer)
328 {
329   bool aRedisplayed = false;
330   if (!isVisible(theObject))
331     return aRedisplayed;
332
333   AISObjectPtr aAISObj = getAISObject(theObject);
334   Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
335
336   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
337   if (aPrs) {
338     AISObjectPtr aAIS_Obj = aPrs->getAISObject(aAISObj);
339     if (!aAIS_Obj) {
340       aRedisplayed = erase(theObject, theUpdateViewer);
341       return aRedisplayed;
342     }
343     if (aAIS_Obj != aAISObj) {
344       appendResultObject(theObject, aAIS_Obj);
345     }
346     aAISIO = aAIS_Obj->impl<Handle(AIS_InteractiveObject)>();
347   }
348
349   Handle(AIS_InteractiveContext) aContext = AISContext();
350   if (!aContext.IsNull() && !aAISIO.IsNull()) {
351     // Check that the visualized shape is the same and the redisplay is not necessary
352     // Redisplay of AIS object leads to this object selection compute and the selection
353     // in the browser is lost
354     // this check is not necessary anymore because the selection store/restore is realized
355     // before and after the values modification.
356     // Moreother, this check avoids customize and redisplay presentation if the presentable
357     // parameter is changed.
358     bool isEqualShapes = false;
359     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
360     if (aResult.get() != NULL) {
361       Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(aAISIO);
362       if (!aShapePrs.IsNull()) {
363         std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
364         if (aShapePtr.get()) {
365           const TopoDS_Shape& aOldShape = aShapePrs->Shape();
366           if (!aOldShape.IsNull())
367             isEqualShapes = aOldShape.IsEqual(aShapePtr->impl<TopoDS_Shape>());
368         }
369       }
370     }
371     // Customization of presentation
372     bool isCustomized = customizeObject(theObject);
373     #ifdef DEBUG_FEATURE_REDISPLAY
374       qDebug(QString("Redisplay: %1, isEqualShapes=%2, isCustomized=%3").
375         arg(!isEqualShapes || isCustomized).arg(isEqualShapes)
376         .arg(isCustomized).toStdString().c_str());
377     #endif
378     if (!isEqualShapes || isCustomized) {
379       /// if shapes are equal and presentation are customized, selection should be restored
380       bool aNeedToRestoreSelection = isEqualShapes && isCustomized;
381       if (aNeedToRestoreSelection)
382         myWorkshop->module()->storeSelection();
383
384 #ifdef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
385       deselectPresentation(aAISIO, aContext);
386 #endif
387       aContext->Redisplay(aAISIO, false);
388
389       #ifdef TINSPECTOR
390       if (getCallBack()) getCallBack()->Redisplay(aAISIO);
391       #endif
392
393       if (aNeedToRestoreSelection)
394         myWorkshop->module()->restoreSelection();
395
396       aRedisplayed = true;
397       #ifdef DEBUG_FEATURE_REDISPLAY
398         qDebug("  Redisplay happens");
399       #endif
400       if (theUpdateViewer)
401         updateViewer();
402     }
403   }
404   return aRedisplayed;
405 }
406
407 void XGUI_Displayer::redisplayObjects()
408 {
409   // redisplay objects visualized in the viewer
410   static Events_ID EVENT_DISP = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
411   static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
412   QObjectPtrList aDisplayed = myWorkshop->displayer()->displayedObjects();
413   QObjectPtrList::const_iterator anIt = aDisplayed.begin(), aLast = aDisplayed.end();
414   for (; anIt != aLast; anIt++) {
415     aECreator->sendUpdated(*anIt, EVENT_DISP);
416   }
417   Events_Loop::loop()->flush(EVENT_DISP);
418 }
419
420 void XGUI_Displayer::deactivate(ObjectPtr theObject, const bool theUpdateViewer)
421 {
422 #ifdef DEBUG_DEACTIVATE
423   QString anInfoStr = ModuleBase_Tools::objectInfo(theObject);
424   qDebug(QString("deactivate: myActiveSelectionModes[%1]: %2, objects = ").
425     arg(myActiveSelectionModes.size()).arg(qIntListInfo(myActiveSelectionModes)).
426     arg(anInfoStr).
427     toStdString().c_str());
428 #endif
429   Handle(AIS_InteractiveContext) aContext = AISContext();
430   if (!aContext.IsNull() && isVisible(theObject)) {
431     AISObjectPtr anObj = myResult2AISObjectMap[theObject];
432     Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
433
434     deactivateAIS(anAIS);
435     // the selection from the previous activation modes should be cleared manually (#26172)
436 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
437     deselectPresentation(anAIS, aContext);
438 #endif
439     if (theUpdateViewer)
440       updateViewer();
441   }
442 }
443
444 void XGUI_Displayer::deactivateObjects(const QObjectPtrList& theObjList,
445                                        const bool theUpdateViewer)
446 {
447   //Handle(AIS_InteractiveObject) aTrihedron = getTrihedron();
448   //if (!aTrihedron.IsNull())
449   //  deactivateAIS(aTrihedron);
450
451   QObjectPtrList::const_iterator anIt = theObjList.begin(), aLast = theObjList.end();
452   for (; anIt != aLast; anIt++) {
453     deactivate(*anIt, false);
454   }
455   //VSV It seems that there is no necessity to update viewer on deactivation
456   //if (theUpdateViewer)
457   //  updateViewer();
458 }
459
460 void XGUI_Displayer::getModesOfActivation(ObjectPtr theObject, QIntList& theModes)
461 {
462   Handle(AIS_InteractiveContext) aContext = AISContext();
463   if (aContext.IsNull() || !isVisible(theObject))
464     return;
465
466   AISObjectPtr aAISObj = getAISObject(theObject);
467
468   if (aAISObj.get() != NULL) {
469     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
470     TColStd_ListOfInteger aTColModes;
471     aContext->ActivatedModes(anAISIO, aTColModes);
472     TColStd_ListIteratorOfListOfInteger itr( aTColModes );
473     for (; itr.More(); itr.Next() ) {
474       theModes.append(itr.Value());
475     }
476   }
477 }
478
479 int XGUI_Displayer::getSelectionMode(int theShapeType)
480 {
481   return (theShapeType > TopAbs_SHAPE) ? theShapeType :
482                                          AIS_Shape::SelectionMode((TopAbs_ShapeEnum)theShapeType);
483 }
484
485 bool XGUI_Displayer::isVisible(XGUI_Displayer* theDisplayer, const ObjectPtr& theObject)
486 {
487   bool aVisible = false;
488   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
489   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
490   if (aPrs.get() || aResult.get()) {
491     aVisible = theDisplayer->isVisible(theObject);
492     // compsolid is not visualized in the viewer,
493     // but should have presentation when all sub solids are
494     // visible. It is useful for highlight presentation where compsolid shape is selectable
495     if (!aVisible && aResult.get() && aResult->groupName() == ModelAPI_ResultCompSolid::group()) {
496       ResultCompSolidPtr aCompsolidResult =
497         std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResult);
498       if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids
499         bool anAllSubsVisible = aCompsolidResult->numberOfSubs() > 0;
500         for(int i = 0; i < aCompsolidResult->numberOfSubs() && anAllSubsVisible; i++) {
501           anAllSubsVisible = theDisplayer->isVisible(aCompsolidResult->subResult(i));
502         }
503         aVisible = anAllSubsVisible;
504       }
505     }
506   }
507   // it is possible that feature is presentable and has results, so we should check visibility
508   // of results if presentation is not shown (e.g. Sketch Circle/Arc features)
509   if (!aVisible) {
510     // check if all results of the feature are visible
511     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
512     std::list<ResultPtr> aResults;
513     ModelAPI_Tools::allResults(aFeature, aResults);
514     std::list<ResultPtr>::const_iterator aIt;
515     aVisible = !aResults.empty();
516     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
517       aVisible = aVisible && theDisplayer->isVisible(*aIt);
518     }
519   }
520   return aVisible;
521 }
522
523 #ifdef DEBUG_ACTIVATE_OBJECTS
524 QString getModeInfo(const int theMode)
525 {
526   QString anInfo = "Undefined";
527   switch(theMode) {
528     case 0: anInfo = "SHAPE(0)"; break;
529     case 1: anInfo = "VERTEX(1)"; break;
530     case 2: anInfo = "EDGE(2)"; break;
531     case 3: anInfo = "WIRE(3)"; break;
532     case 4: anInfo = "FACE(4)"; break;
533     case 5: anInfo = "SHELL(5)"; break;
534     case 6: anInfo = "SOLID(6)"; break;
535     case 7: anInfo = "COMPSOLID(7)"; break;
536     case 8: anInfo = "COMPOUND(8)"; break;
537     case 100: anInfo = "Sel_Mode_First(100)"; break; //SketcherPrs_Tools
538     case 101: anInfo = "Sel_Constraint(101)"; break;
539     case 102: anInfo = "Sel_Dimension_All(102)"; break;
540     case 103: anInfo = "Sel_Dimension_Line(103)"; break;
541     case 104: anInfo = "Sel_Dimension_Text(104)"; break;
542     default: break;
543   }
544   return anInfo;
545 }
546
547 QString getModesInfo(const QIntList& theModes)
548 {
549   QStringList aModesInfo;
550   for (int i = 0, aSize = theModes.size(); i < aSize; i++)
551     aModesInfo.append(getModeInfo(theModes[i]));
552   return QString("[%1] = %2").arg(aModesInfo.size()).arg(aModesInfo.join(", "));
553 }
554 #endif
555
556 void XGUI_Displayer::activateObjects(const QIntList& theModes, const QObjectPtrList& theObjList,
557                                      const bool theUpdateViewer)
558 {
559   // Convert shape types to selection types
560   QIntList aModes;
561   foreach(int aType, theModes) {
562     aModes.append(getSelectionMode(aType));
563   }
564
565 #ifdef DEBUG_ACTIVATE_OBJECTS
566   QStringList anInfo;
567   QObjectPtrList::const_iterator anIt = theObjList.begin(), aLast = theObjList.end();
568   for (; anIt != aLast; ++anIt) {
569     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
570   }
571   QString anInfoStr = anInfo.join(", ");
572
573   qDebug(QString("activateObjects: new modes%1, active modes%2, objects[%3] = %4").
574     arg(getModesInfo(aModes)).
575     arg(getModesInfo(myActiveSelectionModes)).
576     arg(theObjList.size()).
577     arg(anInfoStr).
578     toStdString().c_str());
579 #endif
580   // In order to avoid doblications of selection modes
581   QIntList aNewModes;
582   foreach (int aMode, aModes) {
583     if (!aNewModes.contains(aMode))
584       aNewModes.append(aMode);
585   }
586   myActiveSelectionModes = aNewModes;
587   Handle(AIS_InteractiveContext) aContext = AISContext();
588   // Open local context if there is no one
589   if (aContext.IsNull())
590     return;
591
592   //aContext->UseDisplayedObjects();
593   //myUseExternalObjects = true;
594
595   Handle(AIS_InteractiveObject) anAISIO;
596   AIS_ListOfInteractive aPrsList;
597   //if (aObjList.isEmpty())
598   //  return;
599   //else {
600   foreach(ObjectPtr aObj, theObjList) {
601     if (myResult2AISObjectMap.contains(aObj))
602       aPrsList.Append(myResult2AISObjectMap[aObj]->impl<Handle(AIS_InteractiveObject)>());
603   }
604   //}
605
606   // Add trihedron because it has to partisipate in selection
607   Handle(AIS_InteractiveObject) aTrihedron;
608   if (isTrihedronActive()) {
609     aTrihedron = getTrihedron();
610     if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron))
611       aPrsList.Append(aTrihedron);
612   }
613   if (aPrsList.Extent() == 0)
614     return;
615
616   AIS_ListIteratorOfListOfInteractive aLIt(aPrsList);
617   bool isActivationChanged = false;
618   for(aLIt.Initialize(aPrsList); aLIt.More(); aLIt.Next()){
619     anAISIO = aLIt.Value();
620     if (activate(anAISIO, myActiveSelectionModes, false))
621       isActivationChanged = true;
622   }
623 }
624
625 bool XGUI_Displayer::isActive(ObjectPtr theObject) const
626 {
627   Handle(AIS_InteractiveContext) aContext = AISContext();
628   if (aContext.IsNull() || !isVisible(theObject))
629     return false;
630
631   AISObjectPtr anObj = myResult2AISObjectMap[theObject];
632   Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
633
634   TColStd_ListOfInteger aModes;
635   aContext->ActivatedModes(anAIS, aModes);
636   #ifdef TINSPECTOR
637   if (getCallBack()) getCallBack()->ActivatedModes(anAIS, aModes);
638   #endif
639
640   return aModes.Extent() > 0;
641 }
642
643
644 void XGUI_Displayer::setSelected(const  QList<ModuleBase_ViewerPrsPtr>& theValues,
645                                  bool theUpdateViewer)
646 {
647   Handle(AIS_InteractiveContext) aContext = AISContext();
648   if (aContext.IsNull())
649     return;
650   aContext->UnhilightSelected(false);
651   aContext->ClearSelected(false);
652   #ifdef TINSPECTOR
653   if (getCallBack()) getCallBack()->ClearSelected();
654   #endif
655   NCollection_DataMap<TopoDS_Shape, NCollection_Map<Handle(AIS_InteractiveObject)>>
656     aShapesToBeSelected;
657
658   foreach (ModuleBase_ViewerPrsPtr aPrs, theValues) {
659     const GeomShapePtr& aGeomShape = aPrs->shape();
660     if (aGeomShape.get() && !aGeomShape->isNull()) {
661       const TopoDS_Shape& aShape = aGeomShape->impl<TopoDS_Shape>();
662 #ifdef DEBUG_OCCT_SHAPE_SELECTION
663       // problem 1: performance
664       // problem 2: IO is not specified, so the first found owner is selected, as a result
665       // it might belong to another result
666       aContext->AddOrRemoveSelected(aShape, false);
667       #ifdef TINSPECTOR
668       if (getCallBack()) getCallBack()->AddOrRemoveSelected(aShape);
669       #endif
670 #else
671       NCollection_Map<Handle(AIS_InteractiveObject)> aPresentations;
672       if (aShapesToBeSelected.IsBound(aShape))
673         aPresentations = aShapesToBeSelected.Find(aShape);
674       ObjectPtr anObject = aPrs->object();
675       getPresentations(anObject, aPresentations);
676
677       aShapesToBeSelected.Bind(aShape, aPresentations);
678 #endif
679     } else {
680       ObjectPtr anObject = aPrs->object();
681       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
682       if (aResult.get() && isVisible(aResult)) {
683         AISObjectPtr anObj = myResult2AISObjectMap[aResult];
684         Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
685         if (!anAIS.IsNull()) {
686           // The methods are replaced in order to provide multi-selection, e.g. restore selection
687           // by activating multi selector widget. It also gives an advantage that the multi
688           // selection in OB gives multi-selection in the viewer
689           //aContext->SetSelected(anAIS, false);
690           // The selection in the context was cleared, so the method sets the objects are selected
691           aContext->AddOrRemoveSelected(anAIS, false);
692           #ifdef TINSPECTOR
693           if (getCallBack()) getCallBack()->AddOrRemoveSelected(anAIS);
694           #endif
695         }
696       }
697     }
698   }
699   if (!aShapesToBeSelected.IsEmpty())
700     XGUI_Displayer::AddOrRemoveSelectedShapes(aContext, aShapesToBeSelected);
701
702   if (theUpdateViewer)
703     updateViewer();
704 }
705
706 void XGUI_Displayer::clearSelected(const bool theUpdateViewer)
707 {
708   Handle(AIS_InteractiveContext) aContext = AISContext();
709   if (!aContext.IsNull()) {
710     aContext->UnhilightSelected(false);//UnhilightCurrents(false);
711     aContext->ClearSelected(theUpdateViewer);
712     #ifdef TINSPECTOR
713     if (getCallBack()) getCallBack()->ClearSelected();
714     #endif
715   }
716 }
717
718 bool XGUI_Displayer::eraseAll(const bool theUpdateViewer)
719 {
720   bool aErased = false;
721   Handle(AIS_InteractiveContext) aContext = AISContext();
722   if (!aContext.IsNull()) {
723     foreach (ObjectPtr aObj, myResult2AISObjectMap.keys()) {
724       AISObjectPtr aAISObj = myResult2AISObjectMap[aObj];
725       // erase an object
726       Handle(AIS_InteractiveObject) anIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
727       if (!anIO.IsNull()) {
728         emit beforeObjectErase(aObj, aAISObj);
729         aContext->Remove(anIO, false/*update viewer*/);
730         #ifdef TINSPECTOR
731         if (getCallBack()) getCallBack()->Remove(anIO);
732         #endif
733         aErased = true;
734       }
735     }
736     if (theUpdateViewer)
737       updateViewer();
738   }
739   myResult2AISObjectMap.clear();
740 #ifdef DEBUG_DISPLAY
741   qDebug("eraseAll");
742   qDebug(getResult2AISObjectMapInfo().c_str());
743 #endif
744   return aErased;
745 }
746
747 void deactivateObject(Handle(AIS_InteractiveContext) theContext,
748                       Handle(AIS_InteractiveObject) theObject
749 #ifdef TINSPECTOR
750                       , Handle(VInspectorAPI_CallBack) theCallBack
751 #endif
752                       )
753 {
754   if (!theObject.IsNull()) {
755     theContext->Deactivate(theObject);
756     #ifdef TINSPECTOR
757     if (theCallBack) theCallBack->Deactivate(theObject);
758     #endif
759   }
760 }
761
762 void XGUI_Displayer::deactivateTrihedron(const bool theUpdateViewer) const
763 {
764   Handle(AIS_InteractiveObject) aTrihedron = getTrihedron();
765   Handle(AIS_InteractiveContext) aContext = AISContext();
766   if (!aTrihedron.IsNull() && aContext->IsDisplayed(aTrihedron)) {
767     Handle(AIS_Trihedron) aTrie = Handle(AIS_Trihedron)::DownCast(aTrihedron);
768     deactivateObject(aContext, aTrie
769     #ifdef TINSPECTOR
770       , getCallBack()
771     #endif
772       );
773
774     /// #1136 hidden axis are selected in sketch
775 #ifdef BEFORE_TRIHEDRON_PATCH
776     deactivateObject(aContext, aTrie->XAxis()
777     #ifdef TINSPECTOR
778       , getCallBack()
779     #endif
780     );
781     deactivateObject(aContext, aTrie->YAxis()
782     #ifdef TINSPECTOR
783       , getCallBack()
784     #endif
785     );
786     deactivateObject(aContext, aTrie->Axis()
787     #ifdef TINSPECTOR
788       , getCallBack()
789     #endif
790     );
791     deactivateObject(aContext, aTrie->Position()
792     #ifdef TINSPECTOR
793       , getCallBack()
794     #endif
795     );
796
797     deactivateObject(aContext, aTrie->XYPlane()
798     #ifdef TINSPECTOR
799       , getCallBack()
800     #endif
801     );
802     deactivateObject(aContext, aTrie->XZPlane()
803     #ifdef TINSPECTOR
804       , getCallBack()
805     #endif
806     );
807     deactivateObject(aContext, aTrie->YZPlane()
808     #ifdef TINSPECTOR
809       , getCallBack()
810     #endif
811     );
812 #endif
813     if (theUpdateViewer)
814       updateViewer();
815   }
816 }
817
818 Handle(AIS_InteractiveObject) XGUI_Displayer::getTrihedron() const
819 {
820   return myWorkshop->viewer()->trihedron();
821 }
822
823 /*void XGUI_Displayer::openLocalContext()
824 {
825   Handle(AIS_InteractiveContext) aContext = AISContext();
826   // Open local context if there is no one
827   if (!aContext.IsNull() && !aContext->HasOpenedContext()) {
828     // Preserve selected objects
829     //AIS_ListOfInteractive aAisList;
830     //for (aContext->InitCurrent(); aContext->MoreCurrent(); aContext->NextCurrent())
831     //  aAisList.Append(aContext->Current());
832
833     // get the filters from the global context and append them to the local context
834     // a list of filters in the global context is not cleared and should be cleared here
835     SelectMgr_ListOfFilter aFilters;
836     aFilters.Assign(aContext->Filters());
837     // it is important to remove the filters in the global context, because there is a code
838     // in the closeLocalContex, which restore the global context filters
839     aContext->RemoveFilters();
840
841     //aContext->ClearCurrents();
842     aContext->OpenLocalContext();
843     //deactivateTrihedron();
844     //aContext->NotUseDisplayedObjects();
845
846     //myUseExternalObjects = false;
847
848     SelectMgr_ListIteratorOfListOfFilter aIt(aFilters);
849     for (;aIt.More(); aIt.Next()) {
850       aContext->AddFilter(aIt.Value());
851     }
852     // Restore selection
853     //AIS_ListIteratorOfListOfInteractive aIt2(aAisList);
854     //for(; aIt2.More(); aIt2.Next()) {
855     //  aContext->SetSelected(aIt2.Value(), false);
856     //}
857   }
858 }*/
859
860 /*void XGUI_Displayer::closeLocalContexts(const bool theUpdateViewer)
861 {
862   Handle(AIS_InteractiveContext) aContext = AISContext();
863   if (!aContext.IsNull() && aContext->HasOpenedContext()) {
864     // Preserve selected objects
865     //AIS_ListOfInteractive aAisList;
866     //for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
867     //  aAisList.Append(aContext->SelectedInteractive());
868
869     // get the filters from the local context and append them to the global context
870     // a list of filters in the local context is cleared
871     SelectMgr_ListOfFilter aFilters;
872     aFilters.Assign(aContext->Filters());
873
874     //aContext->ClearSelected();
875     aContext->CloseAllContexts(false);
876
877     // From the moment when the AIS_DS_Displayed flag is used in the Display of AIS object,
878     // this code is obsolete. It is temporaty commented and should be removed after
879     // the test campaign.
880     // Redisplay all object if they were displayed in localContext
881     /*Handle(AIS_InteractiveObject) aAISIO;
882     foreach (AISObjectPtr aAIS, myResult2AISObjectMap) {
883       aAISIO = aAIS->impl<Handle(AIS_InteractiveObject)>();
884       if (aContext->DisplayStatus(aAISIO) != AIS_DS_Displayed) {
885         aContext->Display(aAISIO, false);
886         aContext->SetDisplayMode(aAISIO, Shading, false);
887       }
888     }*+/
889
890     // Append the filters from the local selection in the global selection context
891     SelectMgr_ListIteratorOfListOfFilter aIt(aFilters);
892     for (;aIt.More(); aIt.Next()) {
893       Handle(SelectMgr_Filter) aFilter = aIt.Value();
894       aContext->AddFilter(aFilter);
895     }
896
897     if (theUpdateViewer)
898       updateViewer();
899     //myUseExternalObjects = false;
900
901     // Restore selection
902     //AIS_ListIteratorOfListOfInteractive aIt2(aAisList);
903     //for(; aIt2.More(); aIt2.Next()) {
904     //  if (aContext->IsDisplayed(aIt2.Value()))
905     //    aContext->SetCurrentObject(aIt2.Value(), false);
906     //}
907   }
908 }*/
909
910 AISObjectPtr XGUI_Displayer::getAISObject(ObjectPtr theObject) const
911 {
912   AISObjectPtr anIO;
913   if (myResult2AISObjectMap.contains(theObject))
914     anIO = myResult2AISObjectMap[theObject];
915   return anIO;
916 }
917
918 ObjectPtr XGUI_Displayer::getObject(const AISObjectPtr& theIO) const
919 {
920   Handle(AIS_InteractiveObject) aRefAIS = theIO->impl<Handle(AIS_InteractiveObject)>();
921   return getObject(aRefAIS);
922 }
923
924 ObjectPtr XGUI_Displayer::getObject(const Handle(AIS_InteractiveObject)& theIO) const
925 {
926   ObjectPtr anObject;
927   foreach (ObjectPtr anObj, myResult2AISObjectMap.keys()) {
928     AISObjectPtr aAIS = myResult2AISObjectMap[anObj];
929     Handle(AIS_InteractiveObject) anAIS = aAIS->impl<Handle(AIS_InteractiveObject)>();
930     if (anAIS == theIO)
931       anObject = anObj;
932     if (anObject.get())
933       break;
934   }
935   if (!anObject.get()) {
936     std::shared_ptr<GeomAPI_AISObject> anAISObj = AISObjectPtr(new GeomAPI_AISObject());
937     if (!theIO.IsNull()) {
938       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(theIO));
939     }
940     anObject = myWorkshop->module()->findPresentedObject(anAISObj);
941   }
942   return anObject;
943 }
944
945 bool XGUI_Displayer::enableUpdateViewer(const bool isEnabled)
946 {
947   bool aWasEnabled = isUpdateEnabled();
948   if (isEnabled)
949     myViewerBlockedRecursiveCount--;
950   else
951     myViewerBlockedRecursiveCount++;
952
953   if (myNeedUpdate && isUpdateEnabled()) {
954     updateViewer();
955     myNeedUpdate = false;
956   }
957   return aWasEnabled;
958 }
959
960 bool XGUI_Displayer::isUpdateEnabled() const
961 {
962   return myViewerBlockedRecursiveCount == 0;
963 }
964
965 void XGUI_Displayer::updateViewer() const
966 {
967   Handle(AIS_InteractiveContext) aContext = AISContext();
968   if (!aContext.IsNull() && isUpdateEnabled()) {
969     //myWorkshop->viewer()->Zfitall();
970     aContext->UpdateCurrentViewer();
971   } else {
972     myNeedUpdate = true;
973   }
974 }
975
976 void XGUI_Displayer::activateAIS(const Handle(AIS_InteractiveObject)& theIO,
977                                  const int theMode, const bool theUpdateViewer) const
978 {
979   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
980   if (!theIO.IsNull() && theIO == getTrihedron()) {
981     if (theMode != AIS_Shape::SelectionType(TopAbs_EDGE) &&
982         theMode != AIS_Shape::SelectionType(TopAbs_VERTEX))
983       return;
984   }
985   if (!aContext.IsNull()) {
986     if (myWorkshop->module()) {
987       int aMode = (theMode > 8)? theMode : AIS_Shape::SelectionType(theMode);
988       aContext->Activate(theIO, theMode, false);
989     } else
990       aContext->Activate(theIO, theMode, false);
991     #ifdef TINSPECTOR
992     if (getCallBack()) getCallBack()->Activate(theIO, theMode);
993     #endif
994
995     // the fix from VPA for more suitable selection of sketcher lines
996     if (theIO->Width() > 1) {
997       double aPrecision = theIO->Width() + 2;
998       if (theMode == getSelectionMode(TopAbs_VERTEX))
999         aPrecision = ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
1000                                                                     "point-selection-sensitivity",
1001                                                                         12);
1002       else if ((theMode == getSelectionMode(TopAbs_EDGE)) ||
1003                (theMode == getSelectionMode(TopAbs_WIRE)))
1004         aPrecision = theIO->Width() +
1005            ModuleBase_Preferences::resourceMgr()->doubleValue("Viewer",
1006                                                               "edge-selection-sensitivity", 2);
1007       aContext->SetSelectionSensitivity(theIO, theMode, aPrecision);
1008     }
1009
1010 #ifdef DEBUG_ACTIVATE_AIS
1011     ObjectPtr anObject = getObject(theIO);
1012     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
1013     qDebug(QString("activateAIS: theMode = %1, object = %2").arg(theMode)
1014       .arg(anInfo).toStdString().c_str());
1015 #endif
1016     if (theUpdateViewer)
1017       updateViewer();
1018   }
1019 }
1020
1021 void XGUI_Displayer::deactivateAIS(const Handle(AIS_InteractiveObject)& theIO,
1022                                    const int theMode) const
1023 {
1024   Handle(AIS_InteractiveContext) aContext = AISContext();
1025   if (!aContext.IsNull()) {
1026     if (theMode == -1) {
1027       aContext->Deactivate(theIO);
1028       #ifdef TINSPECTOR
1029       if (getCallBack()) getCallBack()->Deactivate(theIO);
1030       #endif
1031     }
1032     else {
1033       aContext->Deactivate(theIO, theMode);
1034       #ifdef TINSPECTOR
1035       if (getCallBack()) getCallBack()->Deactivate(theIO, theMode);
1036       #endif
1037     }
1038
1039 #ifdef DEBUG_DEACTIVATE_AIS
1040     ObjectPtr anObject = getObject(theIO);
1041     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
1042     qDebug(QString("deactivateAIS: theMode = %1, object = %2").arg(theMode)
1043       .arg(anInfo).toStdString().c_str());
1044 #endif
1045   }
1046 }
1047
1048 Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const
1049 {
1050   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
1051   if (!aContext.IsNull() && myIsFirstAISContextUse/*&& !aContext->HasOpenedContext()*/) {
1052     XGUI_Displayer* aDisplayer = (XGUI_Displayer*)this;
1053     aDisplayer->myIsFirstAISContextUse = false;
1054     //aContext->OpenLocalContext();
1055     if (!isTrihedronActive())
1056       deactivateTrihedron(true);
1057     aContext->DefaultDrawer()->VIsoAspect()->SetNumber(0);
1058     aContext->DefaultDrawer()->UIsoAspect()->SetNumber(0);
1059   }
1060   return aContext;
1061 }
1062
1063 Handle(SelectMgr_AndFilter) XGUI_Displayer::GetFilter()
1064 {
1065   Handle(AIS_InteractiveContext) aContext = AISContext();
1066   if (!aContext.IsNull() && myAndFilter.IsNull()) {
1067     myAndFilter = new SelectMgr_AndFilter();
1068     aContext->AddFilter(myAndFilter);
1069   }
1070   return myAndFilter;
1071 }
1072
1073 bool XGUI_Displayer::displayAIS(AISObjectPtr theAIS, const bool toActivateInSelectionModes,
1074                                 const Standard_Integer theDisplayMode, bool theUpdateViewer)
1075 {
1076   bool aDisplayed = false;
1077   Handle(AIS_InteractiveContext) aContext = AISContext();
1078   Handle(AIS_InteractiveObject) anAISIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
1079   if (!aContext.IsNull() && !anAISIO.IsNull()) {
1080     aContext->Display(anAISIO, theDisplayMode, 0, false/*update viewer*/, true, AIS_DS_Displayed);
1081     #ifdef TINSPECTOR
1082     if (getCallBack()) getCallBack()->Display(anAISIO);
1083     #endif
1084     aDisplayed = true;
1085     aContext->Deactivate(anAISIO);
1086     #ifdef TINSPECTOR
1087     if (getCallBack()) getCallBack()->Deactivate(anAISIO);
1088     #endif
1089     aContext->Load(anAISIO);
1090     #ifdef TINSPECTOR
1091     if (getCallBack()) getCallBack()->Load(anAISIO);
1092     #endif
1093     if (toActivateInSelectionModes) {
1094       if (myActiveSelectionModes.size() == 0)
1095         activateAIS(anAISIO, 0, theUpdateViewer);
1096       else {
1097         foreach(int aMode, myActiveSelectionModes) {
1098           activateAIS(anAISIO, aMode, theUpdateViewer);
1099         }
1100       }
1101     }
1102     if (theUpdateViewer)
1103       updateViewer();
1104   }
1105   return aDisplayed;
1106 }
1107
1108 bool XGUI_Displayer::eraseAIS(AISObjectPtr theAIS, const bool theUpdateViewer)
1109 {
1110   bool aErased = false;
1111   Handle(AIS_InteractiveContext) aContext = AISContext();
1112   if (!aContext.IsNull()) {
1113     Handle(AIS_InteractiveObject) anAISIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
1114     if (!anAISIO.IsNull() && aContext->IsDisplayed(anAISIO)) {
1115       aContext->Remove(anAISIO, false/*update viewer*/);
1116       #ifdef TINSPECTOR
1117       if (getCallBack()) getCallBack()->Remove(anAISIO);
1118       #endif
1119       aErased = true;
1120     }
1121   }
1122   if (aErased && theUpdateViewer)
1123     updateViewer();
1124   return aErased;
1125 }
1126
1127
1128 void XGUI_Displayer::setDisplayMode(ObjectPtr theObject, DisplayMode theMode, bool theUpdateViewer)
1129 {
1130   if (theMode == NoMode)
1131     return;
1132
1133   Handle(AIS_InteractiveContext) aContext = AISContext();
1134   if (aContext.IsNull())
1135     return;
1136
1137   AISObjectPtr aAISObj = getAISObject(theObject);
1138   if (!aAISObj)
1139     return;
1140
1141   Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1142   aContext->SetDisplayMode(aAISIO, theMode, false);
1143   // Redisplay in order to update new mode because it could be not computed before
1144   if (theUpdateViewer)
1145     updateViewer();
1146 }
1147
1148 XGUI_Displayer::DisplayMode XGUI_Displayer::displayMode(ObjectPtr theObject) const
1149 {
1150   Handle(AIS_InteractiveContext) aContext = AISContext();
1151   if (aContext.IsNull())
1152     return NoMode;
1153
1154   AISObjectPtr aAISObj = getAISObject(theObject);
1155   if (!aAISObj)
1156     return NoMode;
1157
1158   Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1159   return (XGUI_Displayer::DisplayMode) aAISIO->DisplayMode();
1160 }
1161
1162 void XGUI_Displayer::deactivateSelectionFilters()
1163 {
1164   Handle(AIS_InteractiveContext) aContext = AISContext();
1165   if (!myAndFilter.IsNull()) {
1166     bool aFound = false;
1167     if (!aContext.IsNull()) {
1168       const SelectMgr_ListOfFilter& aFilters = aContext->Filters();
1169       SelectMgr_ListIteratorOfListOfFilter anIt(aFilters);
1170       for (; anIt.More() && !aFound; anIt.Next()) {
1171         Handle(SelectMgr_Filter) aFilter = anIt.Value();
1172         aFound = aFilter == myAndFilter;
1173       }
1174       if (aFound)
1175         aContext->RemoveFilter(myAndFilter);
1176     }
1177     myAndFilter.Nullify();
1178   }
1179 }
1180
1181 void XGUI_Displayer::addSelectionFilter(const Handle(SelectMgr_Filter)& theFilter)
1182 {
1183   Handle(AIS_InteractiveContext) aContext = AISContext();
1184   if (aContext.IsNull() || hasSelectionFilter(theFilter))
1185     return;
1186
1187   Handle(SelectMgr_CompositionFilter) aCompositeFilter = GetFilter();
1188   if (!aCompositeFilter.IsNull()) {
1189     aCompositeFilter->Add(theFilter);
1190 #ifdef DEBUG_SELECTION_FILTERS
1191     int aCount = aCompositeFilter->StoredFilters().Extent();
1192     qDebug(QString("addSelectionFilter: filters.count() = %1").arg(aCount).toStdString().c_str());
1193 #endif
1194   }
1195 }
1196
1197 void XGUI_Displayer::removeSelectionFilter(const Handle(SelectMgr_Filter)& theFilter)
1198 {
1199   Handle(AIS_InteractiveContext) aContext = AISContext();
1200   if (aContext.IsNull())
1201     return;
1202
1203   Handle(SelectMgr_AndFilter) aCompositeFilter = GetFilter();
1204   if (!aCompositeFilter.IsNull() && aCompositeFilter->IsIn(theFilter)) {
1205     aCompositeFilter->Remove(theFilter);
1206 #ifdef DEBUG_SELECTION_FILTERS
1207     int aCount = aCompositeFilter->StoredFilters().Extent();
1208     qDebug(QString("removeSelectionFilter: filters.count() = %1")
1209       .arg(aCount).toStdString().c_str());
1210 #endif
1211   }
1212 }
1213
1214 bool XGUI_Displayer::hasSelectionFilter(const Handle(SelectMgr_Filter)& theFilter)
1215 {
1216   bool aFilterFound = false;
1217
1218   Handle(AIS_InteractiveContext) aContext = AISContext();
1219   if (aContext.IsNull())
1220     return aFilterFound;
1221   const SelectMgr_ListOfFilter& aFilters = aContext->Filters();
1222   SelectMgr_ListIteratorOfListOfFilter aIt(aFilters);
1223   for (; aIt.More() && !aFilterFound; aIt.Next()) {
1224     if (theFilter.get() == aIt.Value().get())
1225       aFilterFound = true;
1226   }
1227   Handle(SelectMgr_CompositionFilter) aCompositeFilter = GetFilter();
1228   if (!aCompositeFilter.IsNull()) {
1229     const SelectMgr_ListOfFilter& aStoredFilters = aCompositeFilter->StoredFilters();
1230     for (aIt.Initialize(aStoredFilters); aIt.More() && !aFilterFound; aIt.Next()) {
1231       if (theFilter.get() == aIt.Value().get())
1232         aFilterFound = true;
1233     }
1234   }
1235   return aFilterFound;
1236 }
1237
1238 void XGUI_Displayer::removeFilters()
1239 {
1240   Handle(AIS_InteractiveContext) aContext = AISContext();
1241   if (aContext.IsNull())
1242     return;
1243
1244   Handle(SelectMgr_CompositionFilter) aCompositeFilter = GetFilter();
1245   if (!aCompositeFilter.IsNull())
1246     aCompositeFilter->Clear();
1247 }
1248
1249 void XGUI_Displayer::showOnly(const QObjectPtrList& theList)
1250 {
1251   QObjectPtrList aDispList = myResult2AISObjectMap.keys();
1252   foreach(ObjectPtr aObj, aDispList) {
1253     if (!theList.contains(aObj))
1254       erase(aObj, false);
1255   }
1256   foreach(ObjectPtr aObj, theList) {
1257     if (!isVisible(aObj))
1258       display(aObj, false);
1259   }
1260   updateViewer();
1261 }
1262
1263 bool XGUI_Displayer::canBeShaded(ObjectPtr theObject) const
1264 {
1265   if (!isVisible(theObject))
1266     return false;
1267
1268   AISObjectPtr aAISObj = getAISObject(theObject);
1269   if (aAISObj.get() == NULL)
1270     return false;
1271
1272   Handle(AIS_InteractiveObject) anAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1273   return ::canBeShaded(anAIS, myWorkshop->module());
1274 }
1275
1276 bool XGUI_Displayer::activate(const Handle(AIS_InteractiveObject)& theIO,
1277                               const QIntList& theModes,
1278                               const bool theUpdateViewer) const
1279 {
1280   Handle(AIS_InteractiveContext) aContext = AISContext();
1281   if (aContext.IsNull() || theIO.IsNull())
1282     return false;
1283
1284   bool isActivationChanged = false;
1285   // deactivate object in all modes, which are not in the list of activation
1286   // It seems that after the IO deactivation the selected state of the IO's owners
1287   // is modified in OCC(version: 6.8.0) and the selection of the object later is lost.
1288   // By this reason, the number of the IO deactivate is decreased and the object is deactivated
1289   // only if there is a difference in the current modes and the parameters modes.
1290   // If the selection problem happens again, it is possible to write a test scenario and create
1291   // a bug. The bug steps are the following:
1292   // Create two IO, activate them in 5 modes, select the first IO, deactivate 3 modes for both,
1293   // with clicked SHIFT select the second object.
1294   // The result is the selection of the first IO is lost.
1295   TColStd_ListOfInteger aTColModes;
1296   aContext->ActivatedModes(theIO, aTColModes);
1297   #ifdef TINSPECTOR
1298   if (getCallBack()) getCallBack()->ActivatedModes(theIO, aTColModes);
1299   #endif
1300   TColStd_ListIteratorOfListOfInteger itr( aTColModes );
1301   QIntList aModesActivatedForIO;
1302   bool isDeactivated = false;
1303   bool aHasValidMode = false;
1304   for (; itr.More(); itr.Next() ) {
1305     Standard_Integer aMode = itr.Value();
1306     aHasValidMode = aHasValidMode || aMode != -1;
1307     int aShapeMode = (aMode > 8)? aMode : AIS_Shape::SelectionType(aMode);
1308     if (!theModes.contains(aMode)) {
1309       deactivateAIS(theIO, aMode);
1310       isDeactivated = true;
1311     }
1312     else {
1313       aModesActivatedForIO.append(aMode);
1314     }
1315   }
1316   if (isDeactivated) {
1317     // the selection from the previous activation modes should be cleared manually (#26172)
1318     //theIO->ClearSelected();
1319     //#ifdef TINSPECTOR
1320     //if (getCallBack()) getCallBack()->ClearSelected(theIO);
1321     //#endif
1322 #ifndef CLEAR_OUTDATED_SELECTION_BEFORE_REDISPLAY
1323     deselectPresentation(theIO, aContext);
1324 #endif
1325     // For performance issues
1326     //if (theUpdateViewer)
1327     //  updateViewer();
1328     isActivationChanged = true;
1329   }
1330
1331   // loading the interactive object allowing the decomposition
1332   if (aTColModes.IsEmpty() || !aHasValidMode) {
1333     aContext->Load(theIO, -1, true);
1334     Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
1335     if (!aTrihedron.IsNull()) {
1336       // Workaround for Trihedron. It should be loaded using the next Load method to
1337       // add this object to myGlobal map of selection manager
1338       // it is important to activate trihedron in two selection modes: edges and vertices
1339       aContext->SelectionManager()->Load(theIO);
1340     }
1341
1342     #ifdef TINSPECTOR
1343     if (getCallBack()) getCallBack()->Load(theIO);
1344     #endif
1345   }
1346
1347   // trihedron AIS check should be after the AIS loading.
1348   // If it is not loaded, it is steel selectable in the viewer.
1349   Handle(AIS_Trihedron) aTrihedron;
1350   if (!isTrihedronActive())
1351     aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
1352   if (aTrihedron.IsNull()) {
1353       // In order to clear active modes list
1354     if (theModes.size() == 0) {
1355       activateAIS(theIO, 0, theUpdateViewer);
1356     } else {
1357       foreach(int aMode, theModes) {
1358         if (!aModesActivatedForIO.contains(aMode)) {
1359           activateAIS(theIO, aMode, theUpdateViewer);
1360           isActivationChanged = true;
1361         }
1362       }
1363     }
1364   }
1365   return isActivationChanged;
1366 }
1367
1368 bool XGUI_Displayer::customizeObject(ObjectPtr theObject)
1369 {
1370   AISObjectPtr anAISObj = getAISObject(theObject);
1371   // correct the result's color it it has the attribute
1372   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
1373
1374   // Customization of presentation
1375   GeomCustomPrsPtr aCustomPrs;
1376   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1377   if (aFeature.get() != NULL) {
1378     GeomCustomPrsPtr aCustPrs = std::dynamic_pointer_cast<GeomAPI_ICustomPrs>(aFeature);
1379     if (aCustPrs.get() != NULL)
1380       aCustomPrs = aCustPrs;
1381   }
1382   if (aCustomPrs.get() == NULL) {
1383     GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
1384     // we ignore presentable not customized objects
1385     if (aPrs.get() == NULL)
1386       aCustomPrs = myCustomPrs;
1387   }
1388   bool isCustomized = aCustomPrs.get() &&
1389                       aCustomPrs->customisePresentation(aResult, anAISObj, myCustomPrs);
1390   isCustomized = myWorkshop->module()->afterCustomisePresentation(aResult, anAISObj, myCustomPrs)
1391                  || isCustomized;
1392   return isCustomized;
1393 }
1394
1395
1396 QColor XGUI_Displayer::setObjectColor(ObjectPtr theObject,
1397                                       const QColor& theColor,
1398                                       bool theUpdateViewer)
1399 {
1400   if (!isVisible(theObject))
1401     return Qt::black;
1402
1403   AISObjectPtr anAISObj = getAISObject(theObject);
1404   int aR, aG, aB;
1405   anAISObj->getColor(aR, aG, aB);
1406   anAISObj->setColor(theColor.red(), theColor.green(), theColor.blue());
1407   if (theUpdateViewer)
1408     updateViewer();
1409   return QColor(aR, aG, aB);
1410 }
1411
1412 void XGUI_Displayer::appendResultObject(ObjectPtr theObject, AISObjectPtr theAIS)
1413 {
1414   myResult2AISObjectMap[theObject] = theAIS;
1415
1416 #ifdef DEBUG_DISPLAY
1417   std::ostringstream aPtrStr;
1418   aPtrStr << theObject.get();
1419   qDebug(QString("display object: %1").arg(aPtrStr.str().c_str()).toStdString().c_str());
1420   qDebug(getResult2AISObjectMapInfo().c_str());
1421 #endif
1422 }
1423
1424 #ifdef _DEBUG
1425 std::string XGUI_Displayer::getResult2AISObjectMapInfo() const
1426 {
1427   QStringList aContent;
1428   foreach (ObjectPtr aObj, myResult2AISObjectMap.keys()) {
1429     AISObjectPtr aAISObj = myResult2AISObjectMap[aObj];
1430     std::ostringstream aPtrStr;
1431     aPtrStr << "aObj = " << aObj.get() << ":";
1432     aPtrStr << "anAIS = " << aAISObj.get() << ":";
1433     aPtrStr << "[" << ModuleBase_Tools::objectInfo(aObj).toStdString().c_str() << "]";
1434
1435     aContent.append(aPtrStr.str().c_str());
1436   }
1437   return QString("myResult2AISObjectMap: size = %1\n%2\n").arg(myResult2AISObjectMap.size()).
1438                                             arg(aContent.join("\n")).toStdString().c_str();
1439 }
1440 #endif
1441
1442 void XGUI_Displayer::getPresentations(const ObjectPtr& theObject,
1443                                   NCollection_Map<Handle(AIS_InteractiveObject)>& thePresentations)
1444 {
1445   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
1446   if (aResult.get()) {
1447     AISObjectPtr aAISObj = getAISObject(aResult);
1448     if (aAISObj.get() == NULL) {
1449       // if result is a result of a composite feature, it is visualized by visualization of
1450       // composite children, so we should get one of this presentations
1451       ResultCompSolidPtr aCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResult);
1452       if (aCompSolid.get() && aCompSolid->numberOfSubs() > 0) {
1453         aAISObj = getAISObject(aCompSolid->subResult(0));
1454       }
1455     }
1456     if (aAISObj.get() != NULL) {
1457       Handle(AIS_InteractiveObject) anAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1458       if (!anAIS.IsNull() && !thePresentations.Contains(anAIS))
1459         thePresentations.Add(anAIS);
1460     }
1461   }
1462   else {
1463     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
1464     // find presentation of the feature
1465     AISObjectPtr aAISObj = getAISObject(aFeature);
1466     if (aAISObj.get() != NULL) {
1467       Handle(AIS_InteractiveObject) anAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1468       if (!anAIS.IsNull() && !thePresentations.Contains(anAIS))
1469         thePresentations.Add(anAIS);
1470     }
1471     // find presentations of the feature results
1472     std::list<ResultPtr> aResults;
1473     ModelAPI_Tools::allResults(aFeature, aResults);
1474     std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
1475     for (; anIt != aLast; ++anIt) {
1476       AISObjectPtr aAISObj = getAISObject(*anIt);
1477       if (aAISObj.get() != NULL) {
1478         Handle(AIS_InteractiveObject) anAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1479         if (!anAIS.IsNull() && !thePresentations.Contains(anAIS))
1480           thePresentations.Add(anAIS);
1481       }
1482     }
1483   }
1484 }
1485
1486 void XGUI_Displayer::activateTrihedron(bool theIsActive)
1487 {
1488   myIsTrihedronActive = theIsActive;
1489   if (!myIsTrihedronActive) {
1490     deactivateTrihedron(true);
1491   }
1492 }
1493
1494 void XGUI_Displayer::displayTrihedron(bool theToDisplay) const
1495 {
1496   Handle(AIS_InteractiveContext) aContext = AISContext();
1497   if (aContext.IsNull())
1498     return;
1499
1500   Handle(AIS_Trihedron) aTrihedron = myWorkshop->viewer()->trihedron();
1501
1502   if (theToDisplay) {
1503     if (!aContext->IsDisplayed(aTrihedron))
1504       aContext->Display(aTrihedron,
1505                         0 /*wireframe*/,
1506                         -1 /* selection mode */,
1507                         Standard_True /* update viewer*/,
1508                         Standard_False /* allow decomposition */,
1509                         AIS_DS_Displayed /* xdisplay status */);
1510     #ifdef TINSPECTOR
1511     if (getCallBack()) getCallBack()->Display(aTrihedron);
1512     #endif
1513
1514     if (!isTrihedronActive())
1515       deactivateTrihedron(false);
1516     else
1517       activate(aTrihedron, myActiveSelectionModes, false);
1518   } else {
1519     deactivateTrihedron(false);
1520
1521     aContext->Erase(aTrihedron, Standard_True);
1522     #ifdef TINSPECTOR
1523     if (getCallBack()) getCallBack()->Remove(aTrihedron);
1524     #endif
1525   }
1526
1527   updateViewer();
1528 }
1529
1530 QIntList XGUI_Displayer::activeSelectionModes() const
1531 {
1532   QIntList aModes;
1533   foreach (int aMode, myActiveSelectionModes) {
1534     // aMode < 9 is a Shape Enum values
1535     aModes << ((aMode < 9)? AIS_Shape::SelectionType(aMode) : aMode);
1536   }
1537   return aModes;
1538 }
1539
1540 void XGUI_Displayer::AddOrRemoveSelectedShapes(Handle(AIS_InteractiveContext) theContext,
1541                            const NCollection_DataMap<TopoDS_Shape,
1542                            NCollection_Map<Handle(AIS_InteractiveObject)>>& theShapesToBeSelected)
1543 {
1544   NCollection_Map<Handle(AIS_InteractiveObject)> aCompsolidPresentations;
1545   NCollection_Map<Handle(AIS_InteractiveObject)> aSelectedPresentations;
1546
1547   NCollection_List<Handle(SelectBasics_EntityOwner)> anActiveOwners;
1548   theContext->MainSelector()->ActiveOwners(anActiveOwners);
1549   NCollection_List<Handle(SelectBasics_EntityOwner)>::Iterator anOwnersIt (anActiveOwners);
1550   Handle(SelectMgr_EntityOwner) anOwner;
1551
1552   /// It is very important to check that the owner is processed only once and has a map of
1553   /// processed owners because SetSelected works as a switch.
1554   /// If count of calls setSelectec is even, the object stays in the previous state
1555   /// (selected, deselected)
1556   /// OCCT: to write about the problem that active owners method returns one owner several times
1557   QList<long> aSelectedIds; // Remember of selected address in order to avoid duplicates
1558   for (; anOwnersIt.More(); anOwnersIt.Next()) {
1559     anOwner = Handle(SelectMgr_EntityOwner)::DownCast (anOwnersIt.Value());
1560     if (aSelectedIds.contains((long)anOwner.get()))
1561       continue;
1562     aSelectedIds.append((long)anOwner.get());
1563
1564     Handle(StdSelect_BRepOwner) BROwnr = Handle(StdSelect_BRepOwner)::DownCast(anOwner);
1565     if (!BROwnr.IsNull() && BROwnr->HasShape()) {
1566       const TopoDS_Shape& aShape = BROwnr->Shape();
1567       if (aShape.IsNull())
1568         continue;
1569
1570       Handle(ModuleBase_BRepOwner) aCustomOwner = Handle(ModuleBase_BRepOwner)::DownCast(anOwner);
1571
1572       NCollection_DataMap<TopoDS_Shape, NCollection_Map<Handle(AIS_InteractiveObject)> >
1573                                              ::Iterator aShapeIt(theShapesToBeSelected);
1574       for (; aShapeIt.More(); aShapeIt.Next()) {
1575         const TopoDS_Shape& aParameterShape = aShapeIt.Key();
1576         // isSame should be used here as it does not check orientation of shapes
1577         // despite on isEqual of shapes or IsBound for shape in QMap. Orientation is
1578         // different for Edges shapes in model shape and owner even if this is the same shape
1579         if (aParameterShape.IsSame(aShape)) {
1580           Handle(AIS_InteractiveObject) anOwnerPresentation =
1581                             Handle(AIS_InteractiveObject)::DownCast(anOwner->Selectable());
1582           NCollection_Map<Handle(AIS_InteractiveObject)> aPresentations =
1583                                       theShapesToBeSelected.Find(aParameterShape);
1584           if (aPresentations.Contains(anOwnerPresentation)) {
1585             theContext->AddOrRemoveSelected(anOwner, Standard_False);
1586             anOwner->SetSelected (Standard_True);
1587             // collect selected presentations to do not select them if compsolid is selected
1588             if (!aSelectedPresentations.Contains(anOwnerPresentation))
1589               aSelectedPresentations.Add(anOwnerPresentation);
1590           }
1591         }
1592         else if (!aCustomOwner.IsNull()) { // CompSolid processing #2219
1593           // shape of owner is compound, but shape to be selected is compsolid, so
1594           // we need to compare shape to AIS presentation of owner(rule of the owner creation)
1595           Handle(AIS_Shape) anOwnerPresentation =
1596                             Handle(AIS_Shape)::DownCast(anOwner->Selectable());
1597           const TopoDS_Shape& aPresentationShape = anOwnerPresentation->Shape();
1598           if (aParameterShape.IsSame(anOwnerPresentation->Shape()) &&
1599               !aCompsolidPresentations.Contains(anOwnerPresentation))
1600             aCompsolidPresentations.Add(anOwnerPresentation);
1601         }
1602       }
1603     }
1604   }
1605   // select CompSolid presentations if their owners was not selected yet
1606   NCollection_Map<Handle(AIS_InteractiveObject)>::Iterator anIt (aCompsolidPresentations);
1607   for (; anIt.More(); anIt.Next()) {
1608     if (aSelectedPresentations.Contains(anIt.Value()))
1609       continue;
1610     theContext->AddOrRemoveSelected(anIt.Value(), Standard_False);
1611   }
1612 }