Salome HOME
Merge tag 'V_1.3.1' into HEAD
[modules/shaper.git] / src / XGUI / XGUI_Displayer.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        XGUI_Displayer.cpp
4 // Created:     20 Apr 2014
5 // Author:      Natalia ERMOLAEVA
6
7 #include "XGUI_Displayer.h"
8 #include "XGUI_Workshop.h"
9 #include "XGUI_ViewerProxy.h"
10 #include "XGUI_SelectionMgr.h"
11 #include "XGUI_Selection.h"
12 #include "XGUI_CustomPrs.h"
13
14 #include <AppElements_Viewer.h>
15
16 #include <ModelAPI_Document.h>
17 #include <ModelAPI_Data.h>
18 #include <ModelAPI_Object.h>
19 #include <ModelAPI_Tools.h>
20 #include <ModelAPI_AttributeIntArray.h>
21 #include <ModelAPI_ResultCompSolid.h>
22
23 #include <ModuleBase_ResultPrs.h>
24 #include <ModuleBase_Tools.h>
25 #include <ModuleBase_IModule.h>
26
27 #include <GeomAPI_Shape.h>
28 #include <GeomAPI_IPresentable.h>
29 #include <GeomAPI_ICustomPrs.h>
30
31 #include <AIS_InteractiveContext.hxx>
32 #include <AIS_LocalContext.hxx>
33 #include <AIS_ListOfInteractive.hxx>
34 #include <AIS_ListIteratorOfListOfInteractive.hxx>
35 #include <AIS_DimensionSelectionMode.hxx>
36 #include <AIS_Shape.hxx>
37 #include <AIS_Dimension.hxx>
38 #include <TColStd_ListIteratorOfListOfInteger.hxx>
39 #include <SelectMgr_ListOfFilter.hxx>
40 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
41 #include <Prs3d_Drawer.hxx>
42 #include <Prs3d_IsoAspect.hxx>
43
44 #include <StdSelect_ViewerSelector3d.hxx>
45
46 #include <TColStd_MapOfTransient.hxx>
47 #include <TColStd_MapIteratorOfMapOfTransient.hxx>
48
49 #include <set>
50
51 const int MOUSE_SENSITIVITY_IN_PIXEL = 10;  ///< defines the local context mouse selection sensitivity
52
53 //#define DEBUG_ACTIVATE_OBJECTS
54 //#define DEBUG_DEACTIVATE
55 //#define DEBUG_ACTIVATE_AIS
56 //#define DEBUG_DEACTIVATE_AIS
57
58 //#define DEBUG_DISPLAY
59 //#define DEBUG_FEATURE_REDISPLAY
60 //#define DEBUG_SELECTION_FILTERS
61
62 //#define DEBUG_COMPOSILID_DISPLAY
63 // Workaround for bug #25637
64 void displayedObjects(const Handle(AIS_InteractiveContext)& theAIS, AIS_ListOfInteractive& theList)
65 {
66   // Get from null point
67   theAIS->DisplayedObjects(theList, true);
68   if (theAIS->HasOpenedContext()) {
69     // get from local context
70     const Handle(AIS_LocalContext)& aLC = theAIS->LocalContext();
71     TColStd_MapOfTransient aMap;
72     int NbDisp = aLC->DisplayedObjects(aMap);
73     TColStd_MapIteratorOfMapOfTransient aIt(aMap);
74
75     Handle(AIS_InteractiveObject) curIO;
76     Handle(Standard_Transient) Tr;
77     for(; aIt.More(); aIt.Next()){
78       Tr = aIt.Key();
79       curIO = *((Handle(AIS_InteractiveObject)*) &Tr);
80       theList.Append(curIO);
81     }
82   }
83 }
84
85 QString qIntListInfo(const QIntList& theValues, const QString& theSeparator = QString(", "))
86 {
87   QStringList anInfo;
88   QIntList::const_iterator anIt = theValues.begin(), aLast = theValues.end();
89   for (; anIt != aLast; anIt++) {
90     anInfo.append(QString::number(*anIt));
91   }
92   return anInfo.join(theSeparator);
93 }
94
95 XGUI_Displayer::XGUI_Displayer(XGUI_Workshop* theWorkshop)
96   : myWorkshop(theWorkshop)
97 {
98   enableUpdateViewer(true);
99   myCustomPrs = std::shared_ptr<GeomAPI_ICustomPrs>(new XGUI_CustomPrs());
100 }
101
102 XGUI_Displayer::~XGUI_Displayer()
103 {
104 }
105
106 bool XGUI_Displayer::isVisible(ObjectPtr theObject) const
107 {
108   return myResult2AISObjectMap.contains(theObject);
109 }
110
111 void XGUI_Displayer::display(ObjectPtr theObject, bool theUpdateViewer)
112 {
113   if (isVisible(theObject)) {
114 #ifdef DEBUG_COMPOSILID_DISPLAY
115     ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObject);
116     if (aCompsolidResult.get()) {
117       for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
118         ResultPtr aSubResult = aCompsolidResult->subResult(i);
119         if (aSubResult.get())
120           redisplay(aSubResult, false);
121       }
122       if (theUpdateViewer)
123         updateViewer();
124     }
125     else
126 #endif
127       redisplay(theObject, theUpdateViewer);
128   } else {
129     AISObjectPtr anAIS;
130
131     GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
132     bool isShading = false;
133     if (aPrs.get() != NULL) {
134       anAIS = aPrs->getAISObject(anAIS);
135     } else {
136       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
137       if (aResult.get() != NULL) {
138 #ifdef DEBUG_COMPOSILID_DISPLAY
139         ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObject);
140         if (aCompsolidResult.get()) {
141           for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
142             ResultPtr aSubResult = aCompsolidResult->subResult(i);
143             if (aSubResult.get())
144               display(aSubResult, false);
145           }
146           if (theUpdateViewer)
147             updateViewer();
148         }
149         else {
150 #endif
151         std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
152         if (aShapePtr.get() != NULL) {
153           anAIS = AISObjectPtr(new GeomAPI_AISObject());
154           anAIS->setImpl(new Handle(AIS_InteractiveObject)(new ModuleBase_ResultPrs(aResult)));
155           //anAIS->createShape(aShapePtr);
156           isShading = true;
157         }
158 #ifdef DEBUG_COMPOSILID_DISPLAY
159         } // close else
160 #endif
161       }
162     }
163     if (anAIS)
164       display(theObject, anAIS, isShading, theUpdateViewer);
165   }
166 }
167
168 bool canBeShaded(Handle(AIS_InteractiveObject) theAIS)
169 {
170   Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(theAIS);
171   if (!aShapePrs.IsNull()) {
172     TopoDS_Shape aShape = aShapePrs->Shape();
173     TopAbs_ShapeEnum aType = aShape.ShapeType();
174     if ((aType == TopAbs_VERTEX) || (aType == TopAbs_EDGE) || (aType == TopAbs_WIRE))
175       return false;
176     else {
177       // Check that the presentation is not a sketch
178       Handle(ModuleBase_ResultPrs) aPrs = Handle(ModuleBase_ResultPrs)::DownCast(theAIS);
179       if (!aPrs.IsNull()) 
180         return !aPrs->isSketchMode();
181       return true;
182     }
183   }
184   return false;
185 }
186
187 void XGUI_Displayer::display(ObjectPtr theObject, AISObjectPtr theAIS, 
188                              bool isShading, bool theUpdateViewer)
189 {
190   Handle(AIS_InteractiveContext) aContext = AISContext();
191   if (aContext.IsNull())
192     return;
193
194   Handle(AIS_InteractiveObject) anAISIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
195   if (!anAISIO.IsNull()) {
196     appendResultObject(theObject, theAIS);
197
198     bool isCustomized = customizeObject(theObject);
199
200     int aDispMode = isShading? Shading : Wireframe;
201     if (isShading)
202       anAISIO->Attributes()->SetFaceBoundaryDraw( Standard_True );
203     anAISIO->SetDisplayMode(aDispMode);
204     aContext->Display(anAISIO, aDispMode, 0, false, true, AIS_DS_Displayed); 
205
206     emit objectDisplayed(theObject, theAIS);
207     activate(anAISIO, myActiveSelectionModes, theUpdateViewer);
208  } 
209   if (theUpdateViewer)
210     updateViewer();
211 }
212
213 void XGUI_Displayer::erase(ObjectPtr theObject, const bool theUpdateViewer)
214 {
215   if (!isVisible(theObject))
216     return;
217
218   Handle(AIS_InteractiveContext) aContext = AISContext();
219   if (aContext.IsNull())
220     return;
221   AISObjectPtr anObject = myResult2AISObjectMap[theObject];
222   if (anObject) {
223     Handle(AIS_InteractiveObject) anAIS = anObject->impl<Handle(AIS_InteractiveObject)>();
224     if (!anAIS.IsNull()) {
225       emit beforeObjectErase(theObject, anObject);
226       aContext->Remove(anAIS, theUpdateViewer);
227     }
228   }
229   myResult2AISObjectMap.remove(theObject);
230 }
231
232 void XGUI_Displayer::redisplay(ObjectPtr theObject, bool theUpdateViewer)
233 {
234   if (!isVisible(theObject))
235     return;
236
237   AISObjectPtr aAISObj = getAISObject(theObject);
238   Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
239
240   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
241   if (aPrs) {
242     AISObjectPtr aAIS_Obj = aPrs->getAISObject(aAISObj);
243     if (!aAIS_Obj) {
244       erase(theObject, theUpdateViewer);
245       return;
246     }
247     if (aAIS_Obj != aAISObj) {
248       appendResultObject(theObject, aAIS_Obj);
249     }
250     aAISIO = aAIS_Obj->impl<Handle(AIS_InteractiveObject)>();
251   }
252
253   if (!aAISIO.IsNull()) {
254     Handle(AIS_InteractiveContext) aContext = AISContext();
255     if (aContext.IsNull())
256       return;
257     // Check that the visualized shape is the same and the redisplay is not necessary
258     // Redisplay of AIS object leads to this object selection compute and the selection 
259     // in the browser is lost
260
261     // this check is not necessary anymore because the selection store/restore is realized
262     // before and after the values modification.
263     // Moreother, this check avoids customize and redisplay presentation if the presentable
264     // parameter is changed.
265     bool isEqualShapes = false;
266     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
267     if (aResult.get() != NULL) {
268       Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(aAISIO);
269       if (!aShapePrs.IsNull()) {
270         std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
271         if (aShapePtr.get()) {
272           const TopoDS_Shape& aOldShape = aShapePrs->Shape();
273           isEqualShapes = aOldShape.IsEqual(aShapePtr->impl<TopoDS_Shape>());
274         }
275       }
276     }
277     // Customization of presentation
278     bool isCustomized = customizeObject(theObject);
279     #ifdef DEBUG_FEATURE_REDISPLAY
280       qDebug(QString("Redisplay: %1, isEqualShapes=%2, isCustomized=%3").
281         arg(!isEqualShapes || isCustomized).arg(isEqualShapes).arg(isCustomized).toStdString().c_str());
282     #endif
283     if (!isEqualShapes || isCustomized) {
284       aContext->Redisplay(aAISIO, false);
285       #ifdef DEBUG_FEATURE_REDISPLAY
286         qDebug("  Redisplay happens");
287       #endif
288       if (theUpdateViewer)
289         updateViewer();
290     }
291   }
292 }
293
294 void XGUI_Displayer::deactivate(ObjectPtr theObject, const bool theUpdateViewer)
295 {
296 #ifdef DEBUG_DEACTIVATE
297   QString anInfoStr = ModuleBase_Tools::objectInfo(theObject);
298   qDebug(QString("deactivate: myActiveSelectionModes[%1]: %2, objects = ").
299     arg(myActiveSelectionModes.size()).arg(qIntListInfo(myActiveSelectionModes)).
300     arg(anInfoStr).
301     toStdString().c_str());
302 #endif
303   if (isVisible(theObject)) {
304     Handle(AIS_InteractiveContext) aContext = AISContext();
305     if (aContext.IsNull())
306       return;
307
308     AISObjectPtr anObj = myResult2AISObjectMap[theObject];
309     Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
310
311     deactivateAIS(anAIS);
312     // the selection from the previous activation modes should be cleared manually (#26172)
313     aContext->LocalContext()->ClearOutdatedSelection(anAIS, true);
314     if (theUpdateViewer)
315       updateViewer();
316   }
317 }
318
319 void XGUI_Displayer::getModesOfActivation(ObjectPtr theObject, QIntList& theModes)
320 {
321   if (!isVisible(theObject))
322     return;
323
324   Handle(AIS_InteractiveContext) aContext = AISContext();
325   if (aContext.IsNull())
326     return;
327
328   AISObjectPtr aAISObj = getAISObject(theObject);
329
330   if (aAISObj.get() != NULL) {
331     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
332     TColStd_ListOfInteger aTColModes;
333     aContext->ActivatedModes(anAISIO, aTColModes);
334     TColStd_ListIteratorOfListOfInteger itr( aTColModes );
335     for (; itr.More(); itr.Next() ) {
336       theModes.append(itr.Value());
337     }
338   }
339 }
340
341 void XGUI_Displayer::activateObjects(const QIntList& theModes, const QObjectPtrList& theObjList,
342                                      const bool theUpdateViewer)
343 {
344   // Convert shape types to selection types
345   QIntList aModes;
346   foreach(int aType, theModes) {
347     if (aType > TopAbs_SHAPE) 
348       aModes.append(aType);
349     else
350       aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum)aType));
351   }
352
353 #ifdef DEBUG_ACTIVATE_OBJECTS
354   QStringList anInfo;
355   QObjectPtrList::const_iterator anIt = theObjList.begin(), aLast = theObjList.end();
356   for (; anIt != aLast; ++anIt) {
357     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
358   }
359   QString anInfoStr = anInfo.join(", ");
360
361   qDebug(QString("activateObjects: aModes[%1] = %2, myActiveSelectionModes[%3] = %4, objects = %5").
362     arg(aModes.size()).arg(qIntListInfo(aModes)).
363     arg(myActiveSelectionModes.size()).arg(qIntListInfo(myActiveSelectionModes)).
364     arg(anInfoStr).
365     toStdString().c_str());
366 #endif
367   // In order to avoid doblications of selection modes
368   QIntList aNewModes;
369   foreach (int aMode, aModes) {
370     if (!aNewModes.contains(aMode))
371       aNewModes.append(aMode);
372   }
373   myActiveSelectionModes = aNewModes;
374   Handle(AIS_InteractiveContext) aContext = AISContext();
375   if (aContext.IsNull())
376     return;
377   // Open local context if there is no one
378   if (!aContext->HasOpenedContext()) 
379     return;
380
381   //aContext->UseDisplayedObjects();
382   //myUseExternalObjects = true;
383
384   Handle(AIS_InteractiveObject) anAISIO;
385   AIS_ListOfInteractive aPrsList;
386   if (theObjList.isEmpty())
387     return;
388   else {
389     foreach(ObjectPtr aObj, theObjList) {
390       if (myResult2AISObjectMap.contains(aObj))
391         aPrsList.Append(myResult2AISObjectMap[aObj]->impl<Handle(AIS_InteractiveObject)>());
392     }
393   }
394
395   AIS_ListIteratorOfListOfInteractive aLIt(aPrsList);
396   for(aLIt.Initialize(aPrsList); aLIt.More(); aLIt.Next()){
397     anAISIO = aLIt.Value();
398     activate(anAISIO, myActiveSelectionModes, false);
399   }
400   if (theUpdateViewer)
401     updateViewer();
402 }
403
404 bool XGUI_Displayer::isActive(ObjectPtr theObject) const
405 {
406   Handle(AIS_InteractiveContext) aContext = AISContext();
407   if (aContext.IsNull())
408     return false;
409   if (!isVisible(theObject))
410     return false;
411     
412   AISObjectPtr anObj = myResult2AISObjectMap[theObject];
413   Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
414
415   TColStd_ListOfInteger aModes;
416   aContext->ActivatedModes(anAIS, aModes);
417   return aModes.Extent() > 0;
418 }
419 void XGUI_Displayer::setSelected(const  QList<ModuleBase_ViewerPrs>& theValues, bool theUpdateViewer)
420 {
421   Handle(AIS_InteractiveContext) aContext = AISContext();
422   if (aContext.IsNull())
423     return;
424   if (aContext->HasOpenedContext()) {
425     aContext->UnhilightSelected();
426     aContext->ClearSelected();
427     foreach (ModuleBase_ViewerPrs aPrs, theValues) {
428       const TopoDS_Shape& aShape = aPrs.shape();
429       if (!aShape.IsNull()) {
430         aContext->AddOrRemoveSelected(aShape, false);
431       } else {
432         ObjectPtr anObject = aPrs.object();
433         ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
434         if (aResult.get() && isVisible(aResult)) {
435           AISObjectPtr anObj = myResult2AISObjectMap[aResult];
436           Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
437           if (!anAIS.IsNull()) {
438             // The methods are replaced in order to provide multi-selection, e.g. restore selection
439             // by activating multi selector widget. It also gives an advantage that the multi
440             // selection in OB gives multi-selection in the viewer
441             //aContext->SetSelected(anAIS, false);
442             // The selection in the context was cleared, so the method sets the objects are selected
443             aContext->AddOrRemoveSelected(anAIS, false);
444           }
445         }
446       }
447     }
448   } else {
449     aContext->UnhilightCurrents();
450     aContext->ClearCurrents();
451     foreach (ModuleBase_ViewerPrs aPrs, theValues) {
452       ObjectPtr anObject = aPrs.object();
453       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
454       if (aResult.get() && isVisible(aResult)) {
455         AISObjectPtr anObj = myResult2AISObjectMap[aResult];
456         Handle(AIS_InteractiveObject) anAIS = anObj->impl<Handle(AIS_InteractiveObject)>();
457         if (!anAIS.IsNull())
458           aContext->SetCurrentObject(anAIS, false);
459       }
460     }
461   }
462   if (theUpdateViewer)
463     updateViewer();
464 }
465
466 void XGUI_Displayer::clearSelected()
467 {
468   Handle(AIS_InteractiveContext) aContext = AISContext();
469   if (aContext) {
470     aContext->UnhilightCurrents(false);
471     aContext->ClearSelected();
472   }
473 }
474
475 void XGUI_Displayer::eraseAll(const bool theUpdateViewer)
476 {
477   Handle(AIS_InteractiveContext) aContext = AISContext();
478   if (!aContext.IsNull()) {
479     foreach (ObjectPtr aObj, myResult2AISObjectMap.keys()) {
480       AISObjectPtr aAISObj = myResult2AISObjectMap[aObj];
481       // erase an object
482       Handle(AIS_InteractiveObject) anIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
483       if (!anIO.IsNull()) {
484         emit beforeObjectErase(aObj, aAISObj);
485         aContext->Remove(anIO, false);
486       }
487     }
488     if (theUpdateViewer)
489       updateViewer();
490   }
491   myResult2AISObjectMap.clear();
492 }
493
494 void XGUI_Displayer::deactivateTrihedron() const
495 {
496   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
497
498   AIS_ListOfInteractive aList;
499   aContext->DisplayedObjects(aList, true);
500   AIS_ListIteratorOfListOfInteractive aIt;
501   for (aIt.Initialize(aList); aIt.More(); aIt.Next()) {
502     Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(aIt.Value());
503     if (!aTrihedron.IsNull()) {
504       aContext->Deactivate(aTrihedron);
505     }
506   }
507 }
508
509 void XGUI_Displayer::openLocalContext()
510 {
511   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
512   if (aContext.IsNull())
513     return;
514   // Open local context if there is no one
515   if (!aContext->HasOpenedContext()) {
516     // Preserve selected objects
517     //AIS_ListOfInteractive aAisList;
518     //for (aContext->InitCurrent(); aContext->MoreCurrent(); aContext->NextCurrent())
519     //  aAisList.Append(aContext->Current());
520
521     // get the filters from the global context and append them to the local context
522     // a list of filters in the global context is not cleared and should be cleared here
523     SelectMgr_ListOfFilter aFilters;
524     aFilters.Assign(aContext->Filters());
525     // it is important to remove the filters in the global context, because there is a code
526     // in the closeLocalContex, which restore the global context filters
527     aContext->RemoveFilters();
528
529     //aContext->ClearCurrents();
530     aContext->OpenLocalContext();
531     deactivateTrihedron();
532     //aContext->NotUseDisplayedObjects();
533
534     //myUseExternalObjects = false;
535
536     SelectMgr_ListIteratorOfListOfFilter aIt(aFilters);
537     for (;aIt.More(); aIt.Next()) {
538       aContext->AddFilter(aIt.Value());
539     }
540     // Restore selection
541     //AIS_ListIteratorOfListOfInteractive aIt2(aAisList);
542     //for(; aIt2.More(); aIt2.Next()) {
543     //  aContext->SetSelected(aIt2.Value(), false);
544     //}
545   }
546 }
547
548 void XGUI_Displayer::closeLocalContexts(const bool theUpdateViewer)
549 {
550   Handle(AIS_InteractiveContext) aContext = AISContext();
551   if ( (!aContext.IsNull()) && (aContext->HasOpenedContext()) ) {
552     // Preserve selected objects
553     //AIS_ListOfInteractive aAisList;
554     //for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
555     //  aAisList.Append(aContext->SelectedInteractive());
556
557     // get the filters from the local context and append them to the global context
558     // a list of filters in the local context is cleared
559     SelectMgr_ListOfFilter aFilters;
560     aFilters.Assign(aContext->Filters());
561
562     //aContext->ClearSelected();
563     aContext->CloseAllContexts(false);
564
565     // Redisplay all object if they were displayed in localContext
566     Handle(AIS_InteractiveObject) aAISIO;
567     foreach (AISObjectPtr aAIS, myResult2AISObjectMap) {
568       aAISIO = aAIS->impl<Handle(AIS_InteractiveObject)>();
569       if (aContext->DisplayStatus(aAISIO) != AIS_DS_Displayed) {
570         aContext->Display(aAISIO, false);
571         aContext->SetDisplayMode(aAISIO, Shading, false);
572       }
573     }
574
575     // Append the filters from the local selection in the global selection context
576     SelectMgr_ListIteratorOfListOfFilter aIt(aFilters);
577     for (;aIt.More(); aIt.Next()) {
578       Handle(SelectMgr_Filter) aFilter = aIt.Value();
579       aContext->AddFilter(aFilter);
580     }
581
582     if (theUpdateViewer)
583       updateViewer();
584     //myUseExternalObjects = false;
585
586     // Restore selection
587     //AIS_ListIteratorOfListOfInteractive aIt2(aAisList);
588     //for(; aIt2.More(); aIt2.Next()) {
589     //  if (aContext->IsDisplayed(aIt2.Value()))
590     //    aContext->SetCurrentObject(aIt2.Value(), false);
591     //}
592   }
593 }
594
595 AISObjectPtr XGUI_Displayer::getAISObject(ObjectPtr theObject) const
596 {
597   AISObjectPtr anIO;
598   if (myResult2AISObjectMap.contains(theObject))
599     anIO = myResult2AISObjectMap[theObject];
600   return anIO;
601 }
602
603 ObjectPtr XGUI_Displayer::getObject(const AISObjectPtr& theIO) const
604 {
605   Handle(AIS_InteractiveObject) aRefAIS = theIO->impl<Handle(AIS_InteractiveObject)>();
606   return getObject(aRefAIS);
607 }
608
609 ObjectPtr XGUI_Displayer::getObject(const Handle(AIS_InteractiveObject)& theIO) const
610 {
611   ObjectPtr anObject;
612   foreach (ObjectPtr anObj, myResult2AISObjectMap.keys()) {
613     AISObjectPtr aAIS = myResult2AISObjectMap[anObj];
614     Handle(AIS_InteractiveObject) anAIS = aAIS->impl<Handle(AIS_InteractiveObject)>();
615     if (anAIS == theIO)
616       anObject = anObj;
617     if (anObject.get())
618       break;
619   }
620   if (!anObject.get()) {
621     std::shared_ptr<GeomAPI_AISObject> anAISObj = AISObjectPtr(new GeomAPI_AISObject());
622     if (!theIO.IsNull()) {
623       anAISObj->setImpl(new Handle(AIS_InteractiveObject)(theIO));
624     }
625     anObject = myWorkshop->module()->findPresentedObject(anAISObj);
626   }
627   return anObject;
628 }
629
630 bool XGUI_Displayer::enableUpdateViewer(const bool isEnabled)
631 {
632   bool aWasEnabled = myEnableUpdateViewer;
633
634   myEnableUpdateViewer = isEnabled;
635
636   return aWasEnabled;
637 }
638
639 void XGUI_Displayer::updateViewer() const
640 {
641   Handle(AIS_InteractiveContext) aContext = AISContext();
642   if (!aContext.IsNull() && myEnableUpdateViewer) {
643     myWorkshop->viewer()->Zfitall();
644     aContext->UpdateCurrentViewer();
645   }
646 }
647
648 void XGUI_Displayer::activateAIS(const Handle(AIS_InteractiveObject)& theIO,
649                                  const int theMode, const bool theUpdateViewer) const
650 {
651   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
652   aContext->Activate(theIO, theMode, theUpdateViewer);
653
654 #ifdef DEBUG_ACTIVATE_AIS
655   ObjectPtr anObject = getObject(theIO);
656   anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
657   qDebug(QString("activateAIS: theMode = %1, object = %2").arg(theMode).arg(anInfo).toStdString().c_str());
658 #endif
659 }
660
661 void XGUI_Displayer::deactivateAIS(const Handle(AIS_InteractiveObject)& theIO, const int theMode) const
662 {
663   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
664   if (theMode == -1)
665     aContext->Deactivate(theIO);
666   else
667     aContext->Deactivate(theIO, theMode);
668
669 #ifdef DEBUG_DEACTIVATE_AIS
670   ObjectPtr anObject = getObject(theIO);
671   anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
672   qDebug(QString("deactivateAIS: theMode = %1, object = %2").arg(theMode).arg(anInfo).toStdString().c_str());
673 #endif
674 }
675
676 Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const
677 {
678   Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
679   if ((!aContext.IsNull()) && (!aContext->HasOpenedContext())) {
680     aContext->OpenLocalContext();
681     deactivateTrihedron();
682     aContext->DefaultDrawer()->VIsoAspect()->SetNumber(0);
683     aContext->DefaultDrawer()->UIsoAspect()->SetNumber(0);
684   }
685   return aContext;
686 }
687
688 Handle(SelectMgr_AndFilter) XGUI_Displayer::GetFilter()
689 {
690   Handle(AIS_InteractiveContext) aContext = AISContext();
691   if (myAndFilter.IsNull() && !aContext.IsNull()) {
692     myAndFilter = new SelectMgr_AndFilter();
693     aContext->AddFilter(myAndFilter);
694   }
695   return myAndFilter;
696 }
697
698 void XGUI_Displayer::displayAIS(AISObjectPtr theAIS, bool theUpdateViewer)
699 {
700   Handle(AIS_InteractiveContext) aContext = AISContext();
701   if (aContext.IsNull())
702     return;
703   Handle(AIS_InteractiveObject) anAISIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
704   if (!anAISIO.IsNull()) {
705     aContext->Display(anAISIO, theUpdateViewer);
706     if (aContext->HasOpenedContext()) {
707       if (myActiveSelectionModes.size() == 0)
708         activateAIS(anAISIO, 0, theUpdateViewer);
709       else {
710         foreach(int aMode, myActiveSelectionModes) {
711           activateAIS(anAISIO, aMode, theUpdateViewer);
712         }
713       }
714     }
715   }
716 }
717
718 void XGUI_Displayer::eraseAIS(AISObjectPtr theAIS, const bool theUpdateViewer)
719 {
720   Handle(AIS_InteractiveContext) aContext = AISContext();
721   if (aContext.IsNull())
722     return;
723   Handle(AIS_InteractiveObject) anAISIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
724   if (!anAISIO.IsNull()) {
725     aContext->Remove(anAISIO, theUpdateViewer);
726   }
727 }
728
729
730 void XGUI_Displayer::setDisplayMode(ObjectPtr theObject, DisplayMode theMode, bool theUpdateViewer)
731 {
732   if (theMode == NoMode)
733     return;
734
735   Handle(AIS_InteractiveContext) aContext = AISContext();
736   if (aContext.IsNull())
737     return;
738
739   AISObjectPtr aAISObj = getAISObject(theObject);
740   if (!aAISObj)
741     return;
742
743   Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
744   aContext->SetDisplayMode(aAISIO, theMode, false);
745   // Redisplay in order to update new mode because it could be not computed before
746   if (theUpdateViewer)
747     updateViewer();
748 }
749
750 XGUI_Displayer::DisplayMode XGUI_Displayer::displayMode(ObjectPtr theObject) const
751 {
752   Handle(AIS_InteractiveContext) aContext = AISContext();
753   if (aContext.IsNull())
754     return NoMode;
755
756   AISObjectPtr aAISObj = getAISObject(theObject);
757   if (!aAISObj)
758     return NoMode;
759
760   Handle(AIS_InteractiveObject) aAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
761   return (XGUI_Displayer::DisplayMode) aAISIO->DisplayMode();
762 }
763
764 void XGUI_Displayer::addSelectionFilter(const Handle(SelectMgr_Filter)& theFilter)
765 {
766   Handle(AIS_InteractiveContext) aContext = AISContext();
767   if (aContext.IsNull() || hasSelectionFilter(theFilter))
768     return;
769
770   Handle(SelectMgr_CompositionFilter) aCompFilter = GetFilter();
771   aCompFilter->Add(theFilter);
772 #ifdef DEBUG_SELECTION_FILTERS
773   int aCount = GetFilter()->StoredFilters().Extent();
774   qDebug(QString("addSelectionFilter: filters.count() = %1").arg(aCount).toStdString().c_str());
775 #endif
776 }
777
778 void XGUI_Displayer::removeSelectionFilter(const Handle(SelectMgr_Filter)& theFilter)
779 {
780   Handle(AIS_InteractiveContext) aContext = AISContext();
781   if (aContext.IsNull())
782     return;
783   Handle(SelectMgr_AndFilter) aCompositeFilter = GetFilter();
784   if (aCompositeFilter->IsIn(theFilter))
785     aCompositeFilter->Remove(theFilter);
786 #ifdef DEBUG_SELECTION_FILTERS
787   int aCount = GetFilter()->StoredFilters().Extent();
788   qDebug(QString("removeSelectionFilter: filters.count() = %1").arg(aCount).toStdString().c_str());
789 #endif
790 }
791
792 bool XGUI_Displayer::hasSelectionFilter(const Handle(SelectMgr_Filter)& theFilter)
793 {
794   bool aFilterFound = false;
795
796   Handle(AIS_InteractiveContext) aContext = AISContext();
797   if (aContext.IsNull())
798     return aFilterFound;
799   const SelectMgr_ListOfFilter& aFilters = aContext->Filters();
800   SelectMgr_ListIteratorOfListOfFilter aIt(aFilters);
801   for (; aIt.More() && !aFilterFound; aIt.Next()) {
802     if (theFilter.Access() == aIt.Value().Access())
803       aFilterFound = true;
804   }
805   Handle(SelectMgr_CompositionFilter) aCompFilter = GetFilter();
806   const SelectMgr_ListOfFilter& aStoredFilters = aCompFilter->StoredFilters();
807   for (aIt.Initialize(aStoredFilters); aIt.More() && !aFilterFound; aIt.Next()) {
808     if (theFilter.Access() == aIt.Value().Access())
809       aFilterFound = true;
810   }
811   return aFilterFound;
812 }
813
814 void XGUI_Displayer::removeFilters()
815 {
816   Handle(AIS_InteractiveContext) aContext = AISContext();
817   if (aContext.IsNull())
818     return;
819   GetFilter()->Clear();
820 }
821
822 void XGUI_Displayer::showOnly(const QObjectPtrList& theList)
823 {
824   QObjectPtrList aDispList = myResult2AISObjectMap.keys();
825   foreach(ObjectPtr aObj, aDispList) {
826     if (!theList.contains(aObj))
827       erase(aObj, false);
828   }
829   foreach(ObjectPtr aObj, theList) {
830     if (!isVisible(aObj))
831       display(aObj, false);
832   }
833   updateViewer();
834 }
835
836 bool XGUI_Displayer::canBeShaded(ObjectPtr theObject) const
837
838   if (!isVisible(theObject))
839     return false;
840
841   AISObjectPtr aAISObj = getAISObject(theObject);
842   if (aAISObj.get() == NULL)
843     return false;
844
845   Handle(AIS_InteractiveObject) anAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
846   return ::canBeShaded(anAIS);
847 }
848
849 void XGUI_Displayer::activate(const Handle(AIS_InteractiveObject)& theIO,
850                               const QIntList& theModes,
851                               const bool theUpdateViewer) const
852 {
853   Handle(AIS_InteractiveContext) aContext = AISContext();
854   if (aContext.IsNull() || theIO.IsNull())
855     return;
856
857   // deactivate object in all modes, which are not in the list of activation
858   // It seems that after the IO deactivation the selected state of the IO's owners
859   // is modified in OCC(version: 6.8.0) and the selection of the object later is lost.
860   // By this reason, the number of the IO deactivate is decreased and the object is deactivated
861   // only if there is a difference in the current modes and the parameters modes.
862   // If the selection problem happens again, it is possible to write a test scenario and create
863   // a bug. The bug steps are the following:
864   // Create two IO, activate them in 5 modes, select the first IO, deactivate 3 modes for both,
865   // with clicked SHIFT select the second object. The result is the selection of the first IO is lost.
866   TColStd_ListOfInteger aTColModes;
867   aContext->ActivatedModes(theIO, aTColModes);
868   TColStd_ListIteratorOfListOfInteger itr( aTColModes );
869   QIntList aModesActivatedForIO;
870   bool isDeactivated = false;
871   for (; itr.More(); itr.Next() ) {
872     Standard_Integer aMode = itr.Value();
873     if (!theModes.contains(aMode)) {
874       deactivateAIS(theIO, aMode);
875       isDeactivated = true;
876     }
877     else {
878       aModesActivatedForIO.append(aMode);
879     }
880   }
881   if (isDeactivated) {
882     // the selection from the previous activation modes should be cleared manually (#26172)
883     aContext->LocalContext()->ClearOutdatedSelection(theIO, true);
884     if (theUpdateViewer)
885       updateViewer();
886   }
887
888   // loading the interactive object allowing the decomposition
889   if (aTColModes.IsEmpty()) {
890     aContext->Load(theIO, -1, true);
891   }
892
893   // trihedron AIS check should be after the AIS loading.
894   // If it is not loaded, it is steel selectable in the viewer.
895   Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(theIO);
896   if (aTrihedron.IsNull()) {
897       //aContext->Load(anAISIO, -1, true);
898       // In order to clear active modes list
899     if (theModes.size() == 0) {
900       //aContext->Load(anAISIO, 0, true);
901       activateAIS(theIO, 0, theUpdateViewer);
902     } else {
903       foreach(int aMode, theModes) {
904         //aContext->Load(anAISIO, aMode, true);
905         if (!aModesActivatedForIO.contains(aMode)) {
906           activateAIS(theIO, aMode, theUpdateViewer);
907         }
908       }
909     }
910   }
911 }
912
913 bool XGUI_Displayer::customizeObject(ObjectPtr theObject)
914 {
915   AISObjectPtr anAISObj = getAISObject(theObject);
916   // correct the result's color it it has the attribute
917   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
918
919   // Customization of presentation
920   GeomCustomPrsPtr aCustomPrs;
921   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
922   if (aFeature.get() != NULL) {
923     GeomCustomPrsPtr aCustPrs = std::dynamic_pointer_cast<GeomAPI_ICustomPrs>(aFeature);
924     if (aCustPrs.get() != NULL)
925       aCustomPrs = aCustPrs;
926   }
927   if (aCustomPrs.get() == NULL) {
928     GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
929     // we ignore presentable not customized objects
930     if (aPrs.get() == NULL)
931       aCustomPrs = myCustomPrs;
932   }
933   bool isCustomized = aCustomPrs.get() &&
934                       aCustomPrs->customisePresentation(aResult, anAISObj, myCustomPrs);
935   myWorkshop->module()->customizeObject(theObject);
936   return isCustomized;
937 }
938
939
940 QColor XGUI_Displayer::setObjectColor(ObjectPtr theObject, const QColor& theColor, bool theUpdateViewer)
941 {
942   if (!isVisible(theObject))
943     return Qt::black;
944
945   AISObjectPtr anAISObj = getAISObject(theObject);
946   int aR, aG, aB;
947   anAISObj->getColor(aR, aG, aB);
948   anAISObj->setColor(theColor.red(), theColor.green(), theColor.blue());
949   if (theUpdateViewer)
950     updateViewer();
951   return QColor(aR, aG, aB);
952 }
953
954 void XGUI_Displayer::appendResultObject(ObjectPtr theObject, AISObjectPtr theAIS)
955 {
956   myResult2AISObjectMap[theObject] = theAIS;
957
958 #ifdef DEBUG_DISPLAY
959   std::ostringstream aPtrStr;
960   aPtrStr << theObject.get();
961   qDebug(QString("display object: %1").arg(aPtrStr.str().c_str()).toStdString().c_str());
962   qDebug(getResult2AISObjectMapInfo().c_str());
963 #endif
964 }
965
966 std::string XGUI_Displayer::getResult2AISObjectMapInfo() const
967 {
968   QStringList aContent;
969   foreach (ObjectPtr aObj, myResult2AISObjectMap.keys()) {
970     AISObjectPtr aAISObj = myResult2AISObjectMap[aObj];
971     std::ostringstream aPtrStr;
972     aPtrStr << "aObj = " << aObj.get() << ":";
973     aPtrStr << "anAIS = " << aAISObj.get() << ":";
974     aPtrStr << "[" << ModuleBase_Tools::objectInfo(aObj).toStdString().c_str() << "]";
975     
976     aContent.append(aPtrStr.str().c_str());
977   }
978   return QString("myResult2AISObjectMap: size = %1\n%2").arg(myResult2AISObjectMap.size()).
979                                             arg(aContent.join("\n")).toStdString().c_str();
980 }