Salome HOME
b95786c36a8bc0f131faa6b752663a545ee25e8e
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_SketcherMgr.cpp
4 // Created:     19 Dec 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_SketcherMgr.h"
8 #include "PartSet_SketcherReetntrantMgr.h"
9 #include "PartSet_Module.h"
10 #include "PartSet_WidgetPoint2d.h"
11 #include "PartSet_WidgetPoint2dDistance.h"
12 #include "PartSet_Tools.h"
13 #include "PartSet_WidgetSketchLabel.h"
14 #include "PartSet_WidgetEditor.h"
15 #include "PartSet_ResultSketchPrs.h"
16
17 #include <XGUI_ModuleConnector.h>
18 #include <XGUI_Displayer.h>
19 #include <XGUI_Workshop.h>
20 #include <XGUI_ContextMenuMgr.h>
21 #include <XGUI_Selection.h>
22 #include <XGUI_SelectionMgr.h>
23 #include <XGUI_ModuleConnector.h>
24 #include <XGUI_PropertyPanel.h>
25 #include <XGUI_ViewerProxy.h>
26 #include <XGUI_OperationMgr.h>
27 #include <XGUI_Tools.h>
28
29 #include <ModuleBase_IPropertyPanel.h>
30 #include <ModuleBase_ISelection.h>
31 #include <ModuleBase_IViewer.h>
32 #include <ModuleBase_IWorkshop.h>
33 #include <ModuleBase_IViewWindow.h>
34 #include <ModuleBase_ModelWidget.h>
35 #include <ModuleBase_Operation.h>
36 #include <ModuleBase_OperationFeature.h>
37 #include <ModuleBase_Operation.h>
38 #include <ModuleBase_WidgetEditor.h>
39 #include <ModuleBase_ViewerPrs.h>
40 #include <ModuleBase_Tools.h>
41 #include <ModuleBase_ResultPrs.h>
42
43 #include <GeomDataAPI_Point2D.h>
44
45 #include <Events_Loop.h>
46
47 #include <SketchPlugin_Line.h>
48 #include <SketchPlugin_Sketch.h>
49 #include <SketchPlugin_Point.h>
50 #include <SketchPlugin_Arc.h>
51 #include <SketchPlugin_Circle.h>
52 #include <SketchPlugin_ConstraintLength.h>
53 #include <SketchPlugin_ConstraintDistance.h>
54 #include <SketchPlugin_ConstraintParallel.h>
55 #include <SketchPlugin_ConstraintPerpendicular.h>
56 #include <SketchPlugin_ConstraintRadius.h>
57 #include <SketchPlugin_ConstraintRigid.h>
58 #include <SketchPlugin_ConstraintHorizontal.h>
59 #include <SketchPlugin_ConstraintVertical.h>
60 #include <SketchPlugin_ConstraintEqual.h>
61 #include <SketchPlugin_ConstraintTangent.h>
62 #include <SketchPlugin_ConstraintCoincidence.h>
63 #include <SketchPlugin_ConstraintFillet.h>
64 #include <SketchPlugin_ConstraintMirror.h>
65 #include <SketchPlugin_ConstraintAngle.h>
66 #include <SketchPlugin_ConstraintCollinear.h>
67 #include <SketchPlugin_ConstraintMiddle.h>
68 #include <SketchPlugin_MultiRotation.h>
69 #include <SketchPlugin_MultiTranslation.h>
70 #include <SketchPlugin_IntersectionPoint.h>
71
72 #include <SketcherPrs_Tools.h>
73
74 #include <SelectMgr_IndexedMapOfOwner.hxx>
75 #include <StdSelect_BRepOwner.hxx>
76
77 //#include <AIS_DimensionSelectionMode.hxx>
78 #include <AIS_Shape.hxx>
79 #include <AIS_Dimension.hxx>
80
81 #include <ModelAPI_Events.h>
82 #include <ModelAPI_Session.h>
83 #include <ModelAPI_AttributeString.h>
84
85 #include <QMouseEvent>
86 #include <QApplication>
87 #include <QCursor>
88 #include <QMessageBox>
89
90 //#define DEBUG_DO_NOT_BY_ENTER
91
92 //#define DEBUG_CURSOR
93
94 /// Returns list of unique objects by sum of objects from List1 and List2
95 /*QList<ModuleBase_ViewerPrsPtr> getSumList(const QList<ModuleBase_ViewerPrsPtr>& theList1,
96                                        const QList<ModuleBase_ViewerPrsPtr>& theList2)
97 {
98   QList<ModuleBase_ViewerPrsPtr> aRes;
99   foreach (ModuleBase_ViewerPrsPtr aPrs, theList1) {
100     if (!aRes.contains(aPrs))
101       aRes.append(aPrs);
102   }
103   foreach (ModuleBase_ViewerPrsPtr aPrs, theList2) {
104     if (!aRes.contains(aPrs))
105       aRes.append(aPrs);
106   }
107   return aRes;
108 }*/
109
110 // Fills the list of features the list of selected presentations.
111 // \param theList a list of selected presentations
112 // \param theSketch a sketch to project a vertex shape of a presentation to the plane
113 // and find the corresponded attribute
114 // \param theFeatureList  an output list of features
115 void fillFeatureList(const QList<ModuleBase_ViewerPrsPtr>& theList,
116                      const FeaturePtr theSketch,
117                      QList<FeaturePtr>& theFeatureList)
118 {
119   QList<ModuleBase_ViewerPrsPtr> aRes;
120
121   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = theList.begin(),
122                                               aLast = theList.end();
123   for (; anIt != aLast; anIt++)
124   {
125     ModuleBase_ViewerPrsPtr aPrs = *anIt;
126     FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs->object());
127     if (aFeature.get()  && !theFeatureList.contains(aFeature))
128       theFeatureList.append(aFeature);
129   }
130 }
131
132 /// Fills attribute and result lists by the selected owner. In case if the attribute is found,
133 /// by the owner shape, it is put to the list. Otherwise if type of owner shape is edge, put the function
134 /// result as is to the list of results.
135 /// \param theOwner a viewer selected owner
136 /// \param theFeature a feature, where the attribute is searched
137 /// \param theSketch a current sketch
138 /// \param theSelectedAttribute an output list of attributes
139 /// \param theSelectedResults an output list of edge results
140 void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,
141                             const FeaturePtr& theFeature, const FeaturePtr& theSketch,
142                             const ResultPtr& theResult,
143                             std::set<AttributePtr>& aSelectedAttributes,
144                             std::set<ResultPtr>& aSelectedResults)
145 {
146   Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(theOwner);
147   if (aBRepOwner.IsNull())
148     return;
149   Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast(
150                                                                     aBRepOwner->Selectable());
151   if (aBRepOwner->HasShape()) {
152     const TopoDS_Shape& aShape = aBRepOwner->Shape();
153     TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
154     if (aShapeType == TopAbs_VERTEX) {
155       AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,
156                                                                     aShape, theSketch);
157       if (aPntAttr.get() != NULL)
158         aSelectedAttributes.insert(aPntAttr);
159     }
160     else if (aShapeType == TopAbs_EDGE &&
161              aSelectedResults.find(theResult) == aSelectedResults.end()) {
162       aSelectedResults.insert(theResult);
163     }
164   }
165 }
166
167 PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
168   : QObject(theModule), myModule(theModule), myIsDragging(false), myDragDone(false),
169     myIsMouseOverWindow(false),
170     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),
171     myIsPopupMenuActive(false)
172 {
173   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
174   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
175
176   myPreviousDrawModeEnabled = true;//aViewer->isSelectionEnabled();
177
178   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),
179           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));
180
181   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),
182           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));
183
184   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
185           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));
186
187   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),
188           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));
189
190   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
191   XGUI_Workshop* aWorkshop = aConnector->workshop();
192   connect(aWorkshop, SIGNAL(applicationStarted()), this, SLOT(onApplicationStarted()));
193
194   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
195   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
196   myIsConstraintsShown[PartSet_Tools::Expressions] = false;
197 }
198
199 PartSet_SketcherMgr::~PartSet_SketcherMgr()
200 {
201   if (!myPlaneFilter.IsNull())
202     myPlaneFilter.Nullify();
203 }
204
205 void PartSet_SketcherMgr::onEnterViewPort()
206 {
207   // 1. if the mouse over window, update the next flag. Do not perform update visibility of
208   // created feature because it should be done in onMouseMove(). Some widgets watch
209   // the mouse move and use the cursor position to update own values. If the presentaion is
210   // redisplayed before this update, the feature presentation jumps from reset value to current.
211   myIsMouseOverWindow = true;
212
213   #ifdef DEBUG_DO_NOT_BY_ENTER
214   return;
215   #endif
216
217   if (canChangeCursor(getCurrentOperation())) {
218     QCursor* aCurrentCursor = QApplication::overrideCursor();
219     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
220       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
221 #ifdef DEBUG_CURSOR
222       qDebug("onEnterViewPort() : Qt::CrossCursor");
223 #endif
224     }
225   }
226
227   if (!isNestedCreateOperation(getCurrentOperation()))
228     return;
229
230   operationMgr()->onValidateOperation();
231
232   // we need change displayed state of the current operation feature
233   // if the feature is presentable, e.g. distance construction. It has no results, so workshop does
234   // not accept a signal about the result created. Nothing is shown until mouse is moved out/in view
235   // port. If the isDisplayed flag is true, the presentable feature is displayed as soon as the
236   // presentation becomes valid and redisplay happens
237   //ModuleBase_Operation* aOperation = getCurrentOperation();
238   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
239                                                                            (getCurrentOperation());
240   if (aFOperation) {
241     FeaturePtr aFeature = aFOperation->feature();
242     if (aFeature.get() && aFeature->data()->isValid()) {
243       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature), false);
244     }
245   }
246 }
247
248 void PartSet_SketcherMgr::onLeaveViewPort()
249 {
250   myIsMouseOverViewProcessed = false;
251   myIsMouseOverWindow = false;
252
253   #ifdef DEBUG_DO_NOT_BY_ENTER
254   return;
255   #endif
256
257   if (canChangeCursor(getCurrentOperation())) {
258     QApplication::restoreOverrideCursor();
259 #ifdef DEBUG_CURSOR
260     qDebug("onLeaveViewPort() : None");
261 #endif
262   }
263
264   if (!isNestedCreateOperation(getCurrentOperation()))
265     return;
266
267   // the method should be performed if the popup menu is called,
268   // the reset of the current widget should not happen
269   if (myIsPopupMenuActive)
270     return;
271
272   // it is important to validate operation here only if sketch entity create operation is active
273   // because at this operation we reacts to the mouse leave/enter view port
274   operationMgr()->onValidateOperation();
275
276   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation
277   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
278   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
279   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
280   // disable the viewer update in order to avoid visualization of redisplayed feature in viewer
281   // obtained after reset value
282   bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
283   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
284   if (anActiveWidget)
285     anActiveWidget->reset();
286
287   // hides the presentation of the current operation feature
288   // the feature is to be erased here, but it is correct to call canDisplayObject because
289   // there can be additional check (e.g. editor widget in distance constraint)
290   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
291                                                                            (getCurrentOperation());
292   if (aFOperation) {
293     FeaturePtr aFeature = aFOperation->feature();
294     visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
295   }
296   // we should update viewer after the presentation are hidden in the viewer
297   // otherwise the reset presentation(line) appears in the viewer(by quick move from viewer to PP)
298   aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
299 }
300
301 void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()
302 {
303   if (!isNestedEditOperation(getCurrentOperation()) ||
304       myModule->sketchReentranceMgr()->isInternalEditActive())
305     return;
306   // it is necessary to save current selection in order to restore it after the values are modifed
307   storeSelection();
308
309   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
310   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
311   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
312   myPreviousUpdateViewerEnabled = aDisplayer->enableUpdateViewer(false);
313 }
314
315 void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()
316 {
317   if (!isNestedEditOperation(getCurrentOperation()) ||
318       myModule->sketchReentranceMgr()->isInternalEditActive()) {
319     myModule->sketchReentranceMgr()->updateInternalEditActiveState();
320     return;
321   }
322   // it is necessary to restore current selection in order to restore it after the values are modified
323   restoreSelection();
324   myCurrentSelection.clear();
325
326   // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
327   // viewer happens by deselect/select the modified objects. The flag should be restored after
328   // the selection processing. The update viewer should be also called.
329   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
330   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
331   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
332   aDisplayer->enableUpdateViewer(myPreviousUpdateViewerEnabled);
333   aDisplayer->updateViewer();
334
335
336 }
337
338 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
339 {
340   if (myModule->sketchReentranceMgr()->processMousePressed(theWnd, theEvent))
341     return;
342
343   //get2dPoint(theWnd, theEvent, myClickedPoint);
344
345   if (!(theEvent->buttons() & Qt::LeftButton))
346     return;
347
348   // Clear dragging mode
349   myIsDragging = false;
350
351   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
352   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
353   if (!aViewer->canDragByMouse())
354     return;
355
356   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
357                                                                (getCurrentOperation());
358   if (!aFOperation)
359     return;
360
361   if (aFOperation->isEditOperation()) {
362     // If the current widget is a selector, do nothing, it processes the mouse press
363     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
364     if(anActiveWidget && anActiveWidget->isViewerSelector()) {
365       return;
366     }
367   }
368
369   // Use only for sketch operations
370   if (myCurrentSketch) {
371     if (!PartSet_Tools::sketchPlane(myCurrentSketch))
372       return;
373
374     bool isSketcher = isSketchOperation(aFOperation);
375     bool isSketchOpe = isNestedSketchOperation(aFOperation);
376
377     // Avoid non-sketch operations
378     if ((!isSketchOpe) && (!isSketcher))
379       return;
380
381     bool isEditing = aFOperation->isEditOperation();
382
383     // Ignore creation sketch operation
384     if ((!isSketcher) && (!isEditing))
385       return;
386
387     Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
388     // Remember highlighted objects for editing
389     ModuleBase_ISelection* aSelect = aWorkshop->selection();
390
391     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
392     storeSelection(!aHasShift);
393
394     if (myCurrentSelection.empty()) {
395       if (isSketchOpe && (!isSketcher))
396         // commit previous operation
397         if (!aFOperation->commit())
398           aFOperation->abort();
399       return;
400     }
401     // Init flyout point for radius rotation
402     FeaturePtr aFeature = myCurrentSelection.begin().key();
403
404     if (isSketcher) {
405       myIsDragging = true;
406       get2dPoint(theWnd, theEvent, myCurrentPoint);
407       myDragDone = false;
408
409       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
410       launchEditing();
411       if (aFeature.get() != NULL) {
412         std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
413                   std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
414       if (aSPFeature.get() && aSPFeature->getKind() == SketchPlugin_ConstraintRadius::ID()) {
415           DataPtr aData = aSPFeature->data();
416           AttributePtr aAttr = aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
417           std::shared_ptr<GeomDataAPI_Point2D> aFPAttr = 
418             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aAttr);
419           aFPAttr->setValue(myCurrentPoint.myCurX, myCurrentPoint.myCurY);
420         }
421       }
422     } else if (isSketchOpe && isEditing) {
423       // If selected another object commit current result
424       aFOperation->commit();
425
426       myIsDragging = true;
427       get2dPoint(theWnd, theEvent, myCurrentPoint);
428       myDragDone = false;
429
430       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
431
432       launchEditing();
433       restoreSelection();
434     }
435   }
436 }
437
438 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
439 {
440   if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))
441     return;
442
443   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
444   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
445   if (!aViewer->canDragByMouse())
446     return;
447   ModuleBase_Operation* aOp = getCurrentOperation();
448   if (aOp) {
449     if (isNestedSketchOperation(aOp)) {
450       //get2dPoint(theWnd, theEvent, myClickedPoint);
451
452       // Only for sketcher operations
453       if (myIsDragging) {
454         if (myDragDone) {
455           //aOp->commit();
456           myCurrentSelection.clear();
457           /*Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
458           if (!aContext.IsNull()) {
459           // Reselect edited object
460           aContext->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
461           if (theEvent->modifiers() & Qt::ShiftModifier)
462             aContext->ShiftSelect();
463           else
464             aContext->Select();
465           */
466         }
467       }
468     }
469   }
470
471   aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
472   myIsDragging = false;
473 }
474
475 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
476 {
477   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
478     return;
479
480   if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
481     myIsMouseOverViewProcessed = true;
482     // 1. perform the widget mouse move functionality and display the presentation
483     // the mouse move should be processed in the widget, if it can in order to visualize correct
484     // presentation. These widgets correct the feature attribute according to the mouse position
485     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
486     PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWidget);
487     if (aPoint2DWdg) {
488       aPoint2DWdg->onMouseMove(theWnd, theEvent);
489     }
490     PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast<PartSet_WidgetPoint2dDistance*>
491                                                                 (anActiveWidget);
492     if (aDistanceWdg) {
493       aDistanceWdg->onMouseMove(theWnd, theEvent);
494     }
495     // the feature is to be erased here, but it is correct to call canDisplayObject because
496     // there can be additional check (e.g. editor widget in distance constraint)
497     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
498                                                                              (getCurrentOperation());
499     if (aFOperation) {
500       FeaturePtr aFeature = aFOperation->feature();
501       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
502     }
503   }
504
505   //myClickedPoint.clear();
506
507   if (myIsDragging) {
508     // 1. the current selection is saved in the mouse press method in order to restore it after moving
509     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
510     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
511     // deselected). This flag should be restored in the slot, processed the mouse release signal.
512
513     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
514     if (!aCurrentOperation)
515       return;
516     if (isSketchOperation(aCurrentOperation))
517       return; // No edit operation activated
518
519     Handle(V3d_View) aView = theWnd->v3dView();
520     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
521     double aX, aY;
522     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);
523     double dX =  aX - myCurrentPoint.myCurX;
524     double dY =  aY - myCurrentPoint.myCurY;
525
526     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
527     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
528     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
529     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
530     // viewer happens by deselect/select the modified objects. The flag should be restored after
531     // the selection processing. The update viewer should be also called.
532     bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
533
534     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
535     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
536     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
537                                           aLast = myCurrentSelection.end();
538     // 4. the features and attributes modification(move)
539     bool isModified = false;
540     for (; anIt != aLast; anIt++) {
541       FeaturePtr aFeature = anIt.key();
542
543       std::set<AttributePtr> anAttributes = anIt.value().first;
544       // Process selection by attribute: the priority to the attribute
545       if (!anAttributes.empty()) {
546         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
547                                                anAttLast = anAttributes.end();
548         for (; anAttIt != anAttLast; anAttIt++) {
549           AttributePtr anAttr = *anAttIt;
550           if (anAttr.get() == NULL)
551             continue;
552           std::string aAttrId = anAttr->id();
553           DataPtr aData = aFeature->data();
554           if (aData->isValid()) {
555             std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
556               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
557             if (aPoint.get() != NULL) {
558               bool isImmutable = aPoint->setImmutable(true);
559               aPoint->move(dX, dY);
560               isModified = true;
561               ModelAPI_EventCreator::get()->sendUpdated(aFeature, aMoveEvent);
562               aPoint->setImmutable(isImmutable);
563             }
564           }
565         }
566       } else {
567         // Process selection by feature
568         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
569           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
570         if (aSketchFeature) {
571           aSketchFeature->move(dX, dY);
572           isModified = true;
573           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, aMoveEvent);
574         }
575       }
576     }
577     // the modified state of the current operation should be updated if there are features, which
578     // were changed here
579     if (isModified) {
580       aCurrentOperation->onValuesChanged();
581     }
582     Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
583     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations
584
585     // 5. it is necessary to save current selection in order to restore it after the features moving
586     restoreSelection();
587     // 6. restore the update viewer flag and call this update
588     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
589     aDisplayer->updateViewer();
590
591     myDragDone = true;
592     myCurrentPoint.setValue(aX, aY);
593   }
594 }
595
596 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
597 {
598   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
599                                                                (getCurrentOperation());
600   if (aFOperation && aFOperation->isEditOperation()) {
601     std::string aId = aFOperation->id().toStdString();
602     if (isDistanceOperation(aFOperation))
603     {
604       // Activate dimension value editing on double click
605       ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
606       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
607       // Find corresponded widget to activate value editing
608       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
609         if (aWgt->attributeID() == SketchPlugin_Constraint::VALUE() ||
610             aWgt->attributeID() == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) {
611           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
612           if (anEditor)
613             anEditor->showPopupEditor();
614           return;
615         }
616       }
617     }
618   }
619 }
620
621 void PartSet_SketcherMgr::onApplicationStarted()
622 {
623   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
624   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
625   XGUI_Workshop* aWorkshop = aConnector->workshop();
626   PartSet_SketcherReetntrantMgr* aReentranceMgr = myModule->sketchReentranceMgr();
627
628   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
629   if (aPropertyPanel) {
630     //connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),
631     //        this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));
632
633     connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),
634             aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));
635     connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
636             aReentranceMgr, SLOT(onWidgetActivated()));
637   }
638
639   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
640   connect(aViewerProxy, SIGNAL(enterViewPort()), this, SLOT(onEnterViewPort()));
641   connect(aViewerProxy, SIGNAL(leaveViewPort()), this, SLOT(onLeaveViewPort()));
642
643   XGUI_ContextMenuMgr* aContextMenuMgr = aWorkshop->contextMenuMgr();
644   connect(aContextMenuMgr, SIGNAL(beforeContextMenu()), this, SLOT(onBeforeContextMenu()));
645   connect(aContextMenuMgr, SIGNAL(afterContextMenu()), this, SLOT(onAfterContextMenu()));
646 }
647
648 //void PartSet_SketcherMgr::onBeforeWidgetActivated(ModuleBase_ModelWidget* theWidget)
649 //{
650   //if (!myClickedPoint.myIsInitialized)
651   //  return;
652
653   //ModuleBase_Operation* aOperation = getCurrentOperation();
654   // the distance constraint feature should not use the clickedd point
655   // this is workaround in order to don't throw down the flyout point value,
656   // set by execute() method of these type of features
657   //if (isDistanceOperation(aOperation))
658   //  return;
659
660   //PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(theWidget);
661   //if (aPnt2dWgt) {
662   //  aPnt2dWgt->setPoint(myClickedPoint.myCurX, myClickedPoint.myCurY);
663   //}
664 //}
665
666 void PartSet_SketcherMgr::onBeforeContextMenu()
667 {
668   myIsPopupMenuActive = true;
669 }
670
671 void PartSet_SketcherMgr::onAfterContextMenu()
672 {
673   myIsPopupMenuActive = false;
674 }
675
676 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, 
677                                      Point& thePoint)
678 {
679   Handle(V3d_View) aView = theWnd->v3dView();
680   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
681   double aX, anY;
682   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, anY);
683   thePoint.setValue(aX, anY);
684 }
685
686 void PartSet_SketcherMgr::launchEditing()
687 {
688   if (!myCurrentSelection.empty()) {
689     FeaturePtr aFeature = myCurrentSelection.begin().key();
690     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
691               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
692     if (aSPFeature && (!aSPFeature->isExternal())) {
693       myModule->editFeature(aSPFeature);
694     }
695   }
696 }
697
698 bool PartSet_SketcherMgr::sketchSolverError()
699 {
700   bool anError = false;
701   CompositeFeaturePtr aSketch = activeSketch();
702   if (aSketch.get()) {
703     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
704     anError = !aAttributeString->value().empty();
705   }
706   return anError;
707 }
708
709 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
710 {
711   std::string anError = "";
712   if (!theFeature.get() || !theFeature->data()->isValid())
713     return anError.c_str();
714
715   CompositeFeaturePtr aSketch = activeSketch();
716   if (aSketch.get() && aSketch == theFeature) {
717     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
718     anError = aAttributeString->value();
719     ModuleBase_Tools::translate(aSketch->getKind(), anError);
720   }
721   return anError.c_str();
722 }
723
724 void PartSet_SketcherMgr::clearClickedFlags()
725 {
726   //myClickedPoint.clear();
727   myCurrentPoint.clear();
728 }
729
730 const QStringList& PartSet_SketcherMgr::sketchOperationIdList()
731 {
732   static QStringList aIds;
733   if (aIds.size() == 0) {
734     aIds << SketchPlugin_Line::ID().c_str();
735     aIds << SketchPlugin_Point::ID().c_str();
736     aIds << SketchPlugin_Arc::ID().c_str();
737     aIds << SketchPlugin_Circle::ID().c_str();
738     aIds << SketchPlugin_ConstraintFillet::ID().c_str();
739     aIds << SketchPlugin_IntersectionPoint::ID().c_str();
740     // TODO
741     // SketchRectangle is a python feature, so its ID is passed just as a string
742     aIds << "SketchRectangle";
743     aIds.append(replicationsIdList());
744     aIds.append(constraintsIdList());
745   }
746   return aIds;
747 }
748
749 const QStringList& PartSet_SketcherMgr::replicationsIdList()
750 {
751   static QStringList aReplicationIds;
752   if (aReplicationIds.size() == 0) {
753     aReplicationIds << SketchPlugin_ConstraintMirror::ID().c_str();
754     aReplicationIds << SketchPlugin_MultiRotation::ID().c_str();
755     aReplicationIds << SketchPlugin_MultiTranslation::ID().c_str();
756   }
757   return aReplicationIds;
758 }
759
760 const QStringList& PartSet_SketcherMgr::constraintsIdList()
761 {
762   static QStringList aConstraintIds;
763   if (aConstraintIds.size() == 0) {
764     aConstraintIds << SketchPlugin_ConstraintLength::ID().c_str();
765     aConstraintIds << SketchPlugin_ConstraintDistance::ID().c_str();
766     aConstraintIds << SketchPlugin_ConstraintRigid::ID().c_str();
767     aConstraintIds << SketchPlugin_ConstraintRadius::ID().c_str();
768     aConstraintIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
769     aConstraintIds << SketchPlugin_ConstraintParallel::ID().c_str();
770     aConstraintIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
771     aConstraintIds << SketchPlugin_ConstraintVertical::ID().c_str();
772     aConstraintIds << SketchPlugin_ConstraintEqual::ID().c_str();
773     aConstraintIds << SketchPlugin_ConstraintTangent::ID().c_str();
774     aConstraintIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
775     aConstraintIds << SketchPlugin_ConstraintAngle::ID().c_str();
776     aConstraintIds << SketchPlugin_ConstraintCollinear::ID().c_str();
777     aConstraintIds << SketchPlugin_ConstraintMiddle::ID().c_str();
778   }
779   return aConstraintIds;
780 }
781
782 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
783 {
784   theModes.clear();
785
786   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
787   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
788   theModes.append(SketcherPrs_Tools::Sel_Constraint);
789   theModes.append(TopAbs_VERTEX);
790   theModes.append(TopAbs_EDGE);
791 }
792
793 Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ResultPtr& theResult)
794 {
795   Handle(AIS_InteractiveObject) aPrs;
796
797   FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
798   if (aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID()) {
799     aPrs = new PartSet_ResultSketchPrs(theResult);
800   }
801   return aPrs;
802 }
803
804 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
805 {
806   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
807 }
808
809 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation)
810 {
811   return theOperation &&
812          PartSet_SketcherMgr::sketchOperationIdList().contains(theOperation->id());
813 }
814
815 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation)
816 {
817   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
818                                                                (theOperation);
819   return aFOperation && !aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
820 }
821
822 bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation)
823 {
824   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
825                                                                (theOperation);
826   return aFOperation && aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
827 }
828
829 bool PartSet_SketcherMgr::isEntity(const std::string& theId)
830 {
831   return (theId == SketchPlugin_Line::ID()) ||
832          (theId == SketchPlugin_Point::ID()) ||
833          (theId == SketchPlugin_Arc::ID()) ||
834          (theId == SketchPlugin_Circle::ID());
835 }
836
837 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)
838 {
839   std::string anId = theOperation ? theOperation->id().toStdString() : "";
840
841   return isDistanceKind(anId);
842 }
843
844 bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)
845 {
846   return (theKind == SketchPlugin_ConstraintLength::ID()) ||
847          (theKind == SketchPlugin_ConstraintDistance::ID()) ||
848          (theKind == SketchPlugin_ConstraintRadius::ID()) ||
849          (theKind == SketchPlugin_ConstraintAngle::ID());
850 }
851
852 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
853 {
854   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
855                                                                (getCurrentOperation());
856   if (!aFOperation)
857     return;
858
859   myModule->onViewTransformed();
860
861   // Display all sketcher sub-Objects
862   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
863   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
864
865   // Hide sketcher result
866   std::list<ResultPtr> aResults = myCurrentSketch->results();
867   std::list<ResultPtr>::const_iterator aIt;
868   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
869     (*aIt)->setDisplayed(false);
870   }
871   myCurrentSketch->setDisplayed(false);
872
873   // Display sketcher objects
874   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
875     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
876     std::list<ResultPtr> aResults = aFeature->results();
877     std::list<ResultPtr>::const_iterator aIt;
878     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
879       (*aIt)->setDisplayed(true);
880     }
881     aFeature->setDisplayed(true);
882   }
883
884   if(myCirclePointFilter.IsNull()) {
885     myCirclePointFilter = new PartSet_CirclePointFilter(myModule->workshop());
886   }
887
888   myModule->workshop()->viewer()->addSelectionFilter(myCirclePointFilter);
889
890   if (myPlaneFilter.IsNull()) 
891     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
892
893   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
894   bool aHasPlane = false;
895   std::shared_ptr<GeomAPI_Pln> aPln;
896   aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
897   myPlaneFilter->setPlane(aPln);
898
899   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
900   // all displayed objects should be activated in current selection modes according to switched
901   // plane filter
902   if (aPln.get())
903     aConnector->activateModuleSelectionModes();
904 }
905
906 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
907 {
908   myIsMouseOverWindow = false;
909   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
910   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
911   myIsConstraintsShown[PartSet_Tools::Expressions] = false;
912
913   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
914
915   DataPtr aData = myCurrentSketch->data();
916   if (!aData->isValid()) {
917     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
918     // The sketch was aborted
919     myCurrentSketch = CompositeFeaturePtr();
920     // TODO: move this outside of if-else
921     myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);
922     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
923
924     // Erase all sketcher objects
925     QStringList aSketchIds = sketchOperationIdList();
926     QObjectPtrList aObjects = aDisplayer->displayedObjects();
927     foreach (ObjectPtr aObj, aObjects) {
928       DataPtr aObjData = aObj->data();
929       if (!aObjData->isValid())
930         aObj->setDisplayed(false);
931     }
932   }
933   else {
934     // Hide all sketcher sub-Objects
935     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
936       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
937       std::list<ResultPtr> aResults = aFeature->results();
938       std::list<ResultPtr>::const_iterator aIt;
939       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
940         (*aIt)->setDisplayed(false);
941       }
942       aFeature->setDisplayed(false);
943     }
944     // Display sketcher result
945     std::list<ResultPtr> aResults = myCurrentSketch->results();
946     std::list<ResultPtr>::const_iterator aIt;
947     Events_Loop* aLoop = Events_Loop::loop();
948     static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
949
950     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
951                                                                            (theOperation);
952     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
953       if (!aFOperation->isDisplayedOnStart(*aIt)) {
954         (*aIt)->setDisplayed(true);
955         // this display event is needed because sketch already may have "displayed" state,
956         // but not displayed while it is still active (issue 613, abort of existing sketch)
957         ModelAPI_EventCreator::get()->sendUpdated(*aIt, aDispEvent);
958       }
959     }
960     if (!aFOperation->isDisplayedOnStart(myCurrentSketch))
961       myCurrentSketch->setDisplayed(true);
962     
963     myCurrentSketch = CompositeFeaturePtr();
964
965     myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);
966     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
967
968     Events_Loop::loop()->flush(aDispEvent);
969   }
970   // restore the module selection modes, which were changed on startSketch
971   aConnector->activateModuleSelectionModes();
972 }
973
974 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
975 {
976   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
977     QCursor* aCurrentCursor = QApplication::overrideCursor();
978     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
979       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
980 #ifdef DEBUG_CURSOR
981       qDebug("startNestedSketch() : Qt::CrossCursor");
982 #endif
983     }
984   }
985 }
986
987 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
988 {
989   myIsMouseOverViewProcessed = true;
990   operationMgr()->onValidateOperation();
991   if (canChangeCursor(theOperation)) {
992     QApplication::restoreOverrideCursor();
993 #ifdef DEBUG_CURSOR
994     qDebug("stopNestedSketch() : None");
995 #endif
996   }
997   /// improvement to deselect automatically all eventual selected objects, when
998   // returning to the neutral point of the Sketcher
999   workshop()->selector()->clearSelection();
1000 }
1001
1002 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
1003 {
1004   if (isNestedCreateOperation(theOperation)) {
1005     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1006                                                                              (theOperation);
1007     if (aFOperation) {
1008       FeaturePtr aFeature = aFOperation->feature();
1009       // it is necessary to check the the feature data validity because
1010       // some kind of features are removed by an operation commit(the macro state of a feature)
1011       if (aFeature.get() && aFeature->data()->isValid()) {
1012         visualizeFeature(aFeature, aFOperation->isEditOperation(), true);
1013       }
1014     }
1015   }
1016 }
1017
1018 void PartSet_SketcherMgr::activatePlaneFilter(const bool& toActivate)
1019 {
1020   if (toActivate)
1021     myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
1022   else
1023     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
1024 }
1025
1026 bool PartSet_SketcherMgr::operationActivatedByPreselection()
1027 {
1028   bool isOperationStopped = false;
1029   ModuleBase_Operation* anOperation = getCurrentOperation();
1030   if(anOperation && PartSet_SketcherMgr::isNestedSketchOperation(anOperation)) {
1031     // Set final definitions if they are necessary
1032     //propertyPanelDefined(aOperation);
1033     /// Commit sketcher operations automatically
1034     /// distance operation are able to show popup editor to modify the distance value
1035     /// after entering the value, the operation should be committed/aborted(by Esc key)
1036     bool aCanCommitOperation = true;
1037     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1038                                                                             (anOperation);
1039     if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {
1040       bool aValueAccepted = setDistanceValueByPreselection(anOperation, myModule->workshop(),
1041                                                            aCanCommitOperation);
1042       if (!aValueAccepted)
1043         return isOperationStopped;
1044     }
1045
1046     if (aCanCommitOperation)
1047       isOperationStopped = anOperation->commit();
1048     else {
1049       anOperation->abort();
1050       isOperationStopped = true;
1051     }
1052   }
1053   return isOperationStopped;
1054 }
1055
1056 bool PartSet_SketcherMgr::canUndo() const
1057 {
1058   return isNestedCreateOperation(getCurrentOperation());
1059 }
1060
1061 bool PartSet_SketcherMgr::canRedo() const
1062 {
1063   return isNestedCreateOperation(getCurrentOperation());
1064 }
1065
1066 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const
1067 {
1068   bool aCanErase = true;
1069   // when the sketch operation is active, results of sketch sub-feature can not be hidden
1070   if (myCurrentSketch.get()) {
1071     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
1072     if (aResult.get()) {
1073       // Display sketcher objects
1074       for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {
1075
1076         FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1077         std::list<ResultPtr> aResults = aFeature->results();
1078         std::list<ResultPtr>::const_iterator anIt;
1079         for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {
1080           aCanErase = *anIt != aResult;
1081         }
1082       }
1083     }
1084   }
1085   return aCanErase;
1086 }
1087
1088 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
1089 {
1090   bool aCanDisplay = true;
1091
1092   bool aHasActiveSketch = activeSketch().get() != NULL;
1093   if (aHasActiveSketch) {
1094     // 1. the sketch feature should not be displayed during the sketch active operation
1095     // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch 
1096     // nested features can be visualized
1097     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1098     if (aFeature.get() != NULL && aFeature == activeSketch()) {
1099       aCanDisplay = false;
1100     }
1101     std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1102                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1103     /// some sketch entities should be never shown, e.g. projection feature
1104     if (aSketchFeature.get())
1105       aCanDisplay = aSketchFeature->canBeDisplayed();
1106   }
1107   else { // there are no an active sketch
1108     // 2. sketch sub-features should not be visualized if the sketch operation is not active
1109     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1110     if (aFeature.get() != NULL) {
1111       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1112                               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1113       if (aSketchFeature.get()) {
1114         aCanDisplay = false;
1115       }
1116     }
1117   }
1118
1119   // 3. the method should not filter the objects, which are not related to the current operation.
1120   // The object is filtered just if it is a current operation feature or this feature result
1121   if (aCanDisplay) {
1122     bool isObjectFound = false;
1123     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1124                                                                  (getCurrentOperation());
1125     if (aFOperation) {
1126       FeaturePtr aFeature = aFOperation->feature();
1127       if (aFeature.get()) {
1128         std::list<ResultPtr> aResults = aFeature->results();
1129         if (theObject == aFeature)
1130           isObjectFound = true;
1131         else {
1132           std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
1133           for (; anIt != aLast && !isObjectFound; anIt++) {
1134             isObjectFound = *anIt == theObject;
1135           }
1136         }
1137       }
1138     }
1139     if (isObjectFound) {
1140       // 4. For created nested feature operation do not display the created feature if
1141       // the mouse curstor leaves the OCC window.
1142       // The correction cases, which ignores this condition:
1143       // a. the property panel values modification
1144       // b. the popup menu activated
1145       // c. widget editor control
1146       #ifndef DEBUG_DO_NOT_BY_ENTER
1147       if (isNestedCreateOperation(getCurrentOperation())) {
1148         ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1149         ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
1150         // the active widget editor should not influence here. The presentation should be visible always
1151         // when this widget is active.
1152         if (!anEditorWdg && !myIsPopupMenuActive) {
1153           // during a nested create operation, the feature is redisplayed only if the mouse over view
1154           // of there was a value modified in the property panel after the mouse left the view
1155           aCanDisplay = canDisplayCurrentCreatedFeature();
1156         }
1157       }
1158       #endif
1159     }
1160   }
1161
1162   // checks the sketcher constraints visibility according to active sketch check box states
1163   if (aCanDisplay) {
1164     bool aProcessed = false;
1165     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1166     if (aFeature.get()) {
1167       bool aConstraintDisplayed = canDisplayConstraint(aFeature, PartSet_Tools::Any, aProcessed);
1168       if (aProcessed)
1169         aCanDisplay = aConstraintDisplayed;
1170     }
1171   }
1172
1173   return aCanDisplay;
1174 }
1175
1176 bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,
1177                                              const PartSet_Tools::ConstraintVisibleState& theState,
1178                                              bool& isProcessed) const
1179 {
1180   bool aSwitchedOn = true;
1181
1182   const QStringList& aConstrIds = constraintsIdList();
1183
1184   std::string aKind = theFeature->getKind();
1185   if (aConstrIds.contains(QString(aKind.c_str()))) {
1186     bool isTypedConstraint = false;
1187
1188     switch (theState) {
1189       case PartSet_Tools::Dimensional: {
1190         bool isDistance = isDistanceKind(aKind);
1191         if (isDistance) {
1192           isProcessed = true;
1193           aSwitchedOn = myIsConstraintsShown[theState];
1194         }
1195       }
1196       break;
1197       case PartSet_Tools::Geometrical: {
1198         bool isGeometrical = !isDistanceKind(aKind);
1199         if (isGeometrical) {
1200           isProcessed = true;
1201           aSwitchedOn = myIsConstraintsShown[theState];
1202         }
1203       }
1204       break;
1205       case PartSet_Tools::Any: {
1206         isProcessed = true;
1207         bool isDistance = isDistanceKind(aKind);
1208         if (isDistance)
1209           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Dimensional];
1210         else
1211           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Geometrical];
1212       }
1213       break;
1214     default:
1215       break;
1216     }
1217   }
1218   return aSwitchedOn;
1219 }
1220
1221 /*void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)
1222 {
1223   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1224                                                                            (getCurrentOperation());
1225   if (aFOperation && myCurrentSketch.get()) {
1226     // find results of the current operation
1227     // these results should not be proposed to be deleted
1228     FeaturePtr anOperationFeature = aFOperation->feature();
1229     std::list<ResultPtr> anOperationResultList = anOperationFeature->results();
1230     std::set<ResultPtr> anOperationResults;
1231     std::list<ResultPtr>::const_iterator aRIt = anOperationResultList.begin(),
1232                                         aRLast = anOperationResultList.end();
1233     for (; aRIt != aRLast; aRIt++)
1234       anOperationResults.insert(*aRIt);
1235
1236     std::set<FeaturePtr> anObjectsToBeDeleted;
1237     QStringList anObjectsToBeDeletedNames;
1238     std::list<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();
1239     for (; anIt != aLast; anIt++) {
1240       ObjectPtr anObject = *anIt;
1241       bool aCanErase = true;
1242       // when the sketch operation is active, results of sketch sub-feature can not be hidden
1243       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1244       // the result is found between current feature results
1245       if (anOperationResults.find(aResult) != anOperationResults.end())
1246         continue;
1247
1248       if (aResult.get()) {
1249         // Display sketcher objects
1250         for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {
1251           FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1252           std::list<ResultPtr> aResults = aFeature->results();
1253           std::list<ResultPtr>::const_iterator anIt;
1254           for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {
1255             aCanErase = *anIt != aResult;
1256           }
1257         }
1258       }
1259       if (!aCanErase) {
1260         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1261         if (aFeature.get() && anObjectsToBeDeleted.find(aFeature) == anObjectsToBeDeleted.end()) {
1262           anObjectsToBeDeleted.insert(aFeature);
1263           anObjectsToBeDeletedNames.append(aFeature->name().c_str());
1264         }
1265       }
1266     }
1267     if (!anObjectsToBeDeleted.empty()) {
1268       QString aFeatureNames = anObjectsToBeDeletedNames.join(", ");
1269       QString aMessage = tr("The following features have incorrect presentation and \
1270 will be hidden: %1. Would you like to delete them?")
1271                          .arg(aFeatureNames);
1272       int anAnswer = QMessageBox::question(qApp->activeWindow(), tr("Features hide"),
1273                                            aMessage, QMessageBox::Ok | QMessageBox::Cancel,
1274                                            QMessageBox::Cancel);
1275       if (anAnswer == QMessageBox::Ok) {
1276         QObjectPtrList anObjects;
1277         std::set<FeaturePtr>::const_iterator anIt = anObjectsToBeDeleted.begin(),
1278                                              aLast = anObjectsToBeDeleted.end();
1279         for (; anIt != aLast; anIt++)
1280           anObjects.append(*anIt);
1281         SessionPtr aMgr = ModelAPI_Session::get();
1282         DocumentPtr aDoc = aMgr->activeDocument();
1283         bool aIsOp = aMgr->isOperation();
1284         if (!aIsOp)
1285           aMgr->startOperation();
1286         workshop()->deleteFeatures(anObjects);
1287         //static Events_ID aDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
1288         //static Events_ID aRedispEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
1289         //Events_Loop::loop()->flush(aDeletedEvent);
1290         //Events_Loop::loop()->flush(aRedispEvent);
1291
1292         if (!aIsOp)
1293           aMgr->finishOperation();
1294       }
1295     }
1296   }
1297 }*/
1298
1299 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
1300 {
1301   bool aCanDisplay = myIsMouseOverWindow;
1302   if (!aCanDisplay) {
1303     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1304     if (anActiveWidget)
1305       aCanDisplay = anActiveWidget->getValueState() == ModuleBase_ModelWidget::Stored;
1306   }
1307   return aCanDisplay;
1308 }
1309
1310 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const
1311 {
1312   return isNestedCreateOperation(theOperation) ||
1313          myModule->sketchReentranceMgr()->isInternalEditActive();
1314 }
1315
1316 const QMap<PartSet_Tools::ConstraintVisibleState, bool>& PartSet_SketcherMgr::showConstraintStates()
1317 {
1318   return myIsConstraintsShown;
1319 }
1320
1321 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
1322 {
1323   bool isFoundObject = false;
1324
1325   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
1326   if (anObjectFeature.get()) {
1327     int aSize = myCurrentSketch->numberOfSubs();
1328     for (int i = 0; i < myCurrentSketch->numberOfSubs() && !isFoundObject; i++) {
1329       FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);
1330       isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;
1331     }
1332   }
1333   return isFoundObject;
1334 }
1335
1336 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
1337 {
1338   if (myPlaneFilter.IsNull()) 
1339    myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
1340
1341   myPlaneFilter->setPlane(thePln);
1342 }
1343
1344 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,
1345                                                          ModuleBase_IWorkshop* theWorkshop,
1346                                                          bool& theCanCommitOperation)
1347 {
1348   bool isValueAccepted = false;
1349   theCanCommitOperation = false;
1350
1351   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1352                                                                               (theOperation);
1353   FeaturePtr aFeature = aFOperation->feature();
1354   // editor is shown only if all attribute references are filled by preseletion
1355   bool anAllRefAttrInitialized = true;
1356
1357   std::list<AttributePtr> aRefAttrs = aFeature->data()->attributes(
1358                                               ModelAPI_AttributeRefAttr::typeId());
1359   std::list<AttributePtr>::const_iterator anIt = aRefAttrs.begin(), aLast = aRefAttrs.end();
1360   for (; anIt != aLast && anAllRefAttrInitialized; anIt++) {
1361     anAllRefAttrInitialized = (*anIt)->isInitialized();
1362   }
1363   if (anAllRefAttrInitialized) {
1364     // Activate dimension value editing on double click
1365     ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
1366     QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
1367     // Find corresponded widget to activate value editing
1368     foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
1369       if (aWgt->attributeID() == "ConstraintValue") {
1370         // the featue should be displayed in order to find the AIS text position,
1371         // the place where the editor will be shown
1372         aFeature->setDisplayed(true);
1373         /// the execute is necessary to perform in the feature compute for flyout position
1374         aFeature->execute();
1375
1376         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
1377         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1378
1379         PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
1380         if (anEditor) {
1381           int aX = 0, anY = 0;
1382
1383           XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);
1384           XGUI_Displayer* aDisplayer = aWorkshop->displayer();
1385           AISObjectPtr anAIS = aDisplayer->getAISObject(aFeature);
1386           Handle(AIS_InteractiveObject) anAISIO;
1387           if (anAIS.get() != NULL) {
1388             anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1389           }
1390           if (anAIS.get() != NULL) {
1391             Handle(AIS_InteractiveObject) anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1392
1393             if (!anAISIO.IsNull()) {
1394               Handle(AIS_Dimension) aDim = Handle(AIS_Dimension)::DownCast(anAISIO);
1395               if (!aDim.IsNull()) {
1396                 gp_Pnt aPosition = aDim->GetTextPosition();
1397
1398                 ModuleBase_IViewer* aViewer = aWorkshop->viewer();
1399                 Handle(V3d_View) aView = aViewer->activeView();
1400                 int aCX, aCY;
1401                 aView->Convert(aPosition.X(), aPosition.Y(), aPosition.Z(), aCX, aCY);
1402
1403                 QWidget* aViewPort = aViewer->activeViewPort();
1404                 QPoint aGlPoint = aViewPort->mapToGlobal(QPoint(aCX, aCY));
1405                 aX = aGlPoint.x();
1406                 anY = aGlPoint.y();
1407               }
1408             }
1409             anEditor->setCursorPosition(aX, anY);
1410             isValueAccepted = anEditor->showPopupEditor(false);
1411             theCanCommitOperation = true;
1412           }
1413         }
1414       }
1415     }
1416   }
1417   return isValueAccepted;
1418 }
1419
1420 void PartSet_SketcherMgr::getCurrentSelection(const FeaturePtr& theFeature,
1421                                               const FeaturePtr& theSketch,
1422                                               ModuleBase_IWorkshop* theWorkshop,
1423                                               FeatureToSelectionMap& theSelection)
1424 {
1425   if (theFeature.get() == NULL)
1426     return;
1427
1428   std::set<AttributePtr> aSelectedAttributes;
1429   std::set<ResultPtr> aSelectedResults;
1430
1431   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1432   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
1433   if (!aContext.IsNull()) {
1434     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1435     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1436
1437     std::list<ResultPtr> aResults = theFeature->results();
1438     std::list<ResultPtr>::const_iterator aIt;
1439     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
1440     {
1441       ResultPtr aResult = *aIt;
1442       AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1443       if (aAISObj.get() == NULL)
1444         continue;
1445       Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1446       for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
1447       {
1448         Handle(SelectMgr_EntityOwner) anOwner = aContext->SelectedOwner();
1449         if (anOwner->Selectable() != anAISIO)
1450           continue;
1451         getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
1452                                aSelectedAttributes, aSelectedResults);
1453       }
1454       for (aContext->InitDetected(); aContext->MoreDetected(); aContext->NextDetected()) {
1455         Handle(SelectMgr_EntityOwner) anOwner = aContext->DetectedOwner();
1456         if (anOwner.IsNull())
1457           continue;
1458         if (anOwner->Selectable() != anAISIO)
1459           continue;
1460         getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
1461                                aSelectedAttributes, aSelectedResults);
1462       }
1463     }
1464   }
1465   theSelection[theFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);
1466 }
1467
1468 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,
1469                                              const FeaturePtr& theSketch,
1470                                              ModuleBase_IWorkshop* theWorkshop,
1471                                              const FeatureToSelectionMap& theSelection,
1472                                              SelectMgr_IndexedMapOfOwner& theOwnersToSelect)
1473 {
1474   if (theFeature.get() == NULL)
1475     return;
1476
1477   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
1478   std::set<AttributePtr> aSelectedAttributes = anIt.value().first;
1479   std::set<ResultPtr> aSelectedResults = anIt.value().second;
1480
1481   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1482
1483   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1484   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1485
1486   // 1. found the feature's owners. Check the AIS objects of the constructions
1487   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);
1488   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {
1489     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1490
1491     SelectMgr_IndexedMapOfOwner aSelectedOwners;
1492     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1493     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
1494       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
1495       if (!anOwner.IsNull())
1496         theOwnersToSelect.Add(anOwner);
1497     }
1498   }
1499
1500   // 2. found the feature results's owners
1501   std::list<ResultPtr> aResults = theFeature->results();
1502   std::list<ResultPtr>::const_iterator aIt;
1503   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
1504   {
1505     ResultPtr aResult = *aIt;
1506     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1507     if (aAISObj.get() == NULL)
1508       continue; 
1509     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1510
1511     SelectMgr_IndexedMapOfOwner aSelectedOwners;  
1512     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1513     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
1514       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
1515       if ( anOwner.IsNull() || !anOwner->HasShape() )
1516         continue;
1517       const TopoDS_Shape& aShape = anOwner->Shape();
1518       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
1519       if (aShapeType == TopAbs_VERTEX) {
1520         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
1521         if (aPntAttr.get() != NULL &&
1522             aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end()) {
1523           theOwnersToSelect.Add(anOwner);
1524         }
1525       }
1526       else if (aShapeType == TopAbs_EDGE) {
1527         bool aFound = aSelectedResults.find(aResult) != aSelectedResults.end();
1528         if (aSelectedResults.find(aResult) != aSelectedResults.end() &&
1529             theOwnersToSelect.FindIndex(anOwner) <= 0)
1530           theOwnersToSelect.Add(anOwner);
1531       }
1532     }
1533   }
1534 }
1535
1536 void PartSet_SketcherMgr::connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect)
1537 {
1538   if (isToConnect) {
1539     connect(theWidget, SIGNAL(beforeValuesChanged()),
1540             this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1541     connect(theWidget, SIGNAL(afterValuesChanged()),
1542             this, SLOT(onAfterValuesChangedInPropertyPanel()));
1543   }
1544   else {
1545     disconnect(theWidget, SIGNAL(beforeValuesChanged()),
1546                 this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1547     disconnect(theWidget, SIGNAL(afterValuesChanged()),
1548                 this, SLOT(onAfterValuesChangedInPropertyPanel()));
1549   }
1550 }
1551
1552 void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
1553 {
1554   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1555                                                                            (getCurrentOperation());
1556   if (aFOperation) {
1557     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
1558         PartSet_SketcherMgr::isNestedSketchOperation(aFOperation) &&
1559         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {
1560       FeaturePtr aFeature = aFOperation->feature();
1561       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
1562     }
1563   }
1564 }
1565
1566 void PartSet_SketcherMgr::customizePresentation(const ObjectPtr& theObject)
1567 {
1568   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1569                                                                            (getCurrentOperation());
1570   if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
1571                       PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)))
1572     SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
1573
1574   // update entities selection priorities
1575   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1576   if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
1577     // update priority for feature
1578     updateSelectionPriority(aFeature, aFeature);
1579     // update priority for results of the feature
1580     std::list<ResultPtr> aResults = aFeature->results();
1581     std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();
1582     for (; anIt != aLastIt; anIt++)
1583       updateSelectionPriority(*anIt, aFeature);
1584   }
1585 }
1586
1587 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
1588 {
1589   return myModule->workshop()->currentOperation();
1590 }
1591
1592 //**************************************************************
1593 ModuleBase_ModelWidget* PartSet_SketcherMgr::getActiveWidget() const
1594 {
1595   ModuleBase_ModelWidget* aWidget = 0;
1596   ModuleBase_Operation* anOperation = getCurrentOperation();
1597   if (anOperation) {
1598     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
1599     if (aPanel)
1600       aWidget = aPanel->activeWidget();
1601   }
1602   return aWidget;
1603 }
1604
1605 void PartSet_SketcherMgr::visualizeFeature(const FeaturePtr& theFeature,
1606                                            const bool isEditOperation,
1607                                            const bool isToDisplay,
1608                                            const bool isFlushRedisplay)
1609 {
1610   #ifdef DEBUG_DO_NOT_BY_ENTER
1611   return;
1612   #endif
1613
1614   if (isEditOperation || !theFeature.get())
1615     return;
1616
1617   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1618   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1619
1620   // 1. change visibility of the object itself, here the presentable object is processed,
1621   // e.g. constraints features
1622   //FeaturePtr aFeature = aFOperation->feature();
1623   std::list<ResultPtr> aResults = theFeature->results();
1624   if (isToDisplay)
1625     theFeature->setDisplayed(true);
1626   else
1627     theFeature->setDisplayed(false);
1628
1629   // change visibility of the object results, e.g. non-constraint features
1630   std::list<ResultPtr>::const_iterator aIt;
1631   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1632     if (isToDisplay) {
1633       (*aIt)->setDisplayed(true);
1634     }
1635     else {
1636       (*aIt)->setDisplayed(false);
1637     }
1638   }
1639   if (isFlushRedisplay)
1640     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1641 }
1642
1643 void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
1644 {
1645   if (!myCurrentSketch.get())
1646     return;
1647
1648   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1649   ModuleBase_ISelection* aSelect = aWorkshop->selection();
1650   QList<ModuleBase_ViewerPrsPtr> aHighlighted = aSelect->getHighlighted();
1651
1652   QList<FeaturePtr> aFeatureList;
1653   if (theHighlightedOnly) {
1654     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
1655   }
1656   else {
1657     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
1658
1659     QList<ModuleBase_ViewerPrsPtr> aSelected = aSelect->getSelected(ModuleBase_ISelection::AllControls);
1660     fillFeatureList(aSelected, myCurrentSketch, aFeatureList);
1661   }
1662
1663   // 1. it is necessary to save current selection in order to restore it after the features moving
1664   myCurrentSelection.clear();
1665   QList<FeaturePtr>::const_iterator anIt = aFeatureList.begin(), aLast = aFeatureList.end();
1666   for (; anIt != aLast; anIt++) {
1667     getCurrentSelection(*anIt, myCurrentSketch, aWorkshop, myCurrentSelection);
1668   }
1669   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1670 }
1671
1672 void PartSet_SketcherMgr::restoreSelection()
1673 {
1674   if (!myCurrentSketch.get())
1675     return;
1676
1677   //qDebug(QString("restoreSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1678   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1679   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1680   FeatureToSelectionMap::const_iterator aSIt = myCurrentSelection.begin(),
1681                                         aSLast = myCurrentSelection.end();
1682   SelectMgr_IndexedMapOfOwner anOwnersToSelect;
1683   for (; aSIt != aSLast; aSIt++) {
1684     anOwnersToSelect.Clear();
1685     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, myCurrentSelection,
1686                         anOwnersToSelect);
1687     aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);
1688   }
1689 }
1690
1691 void PartSet_SketcherMgr::onShowConstraintsToggle(int theType, bool theState)
1692 {
1693   PartSet_Tools::ConstraintVisibleState aType = (PartSet_Tools::ConstraintVisibleState)theType;
1694
1695   updateBySketchParameters(aType, theState);
1696 }
1697
1698 void PartSet_SketcherMgr::updateBySketchParameters(
1699                                    const PartSet_Tools::ConstraintVisibleState& theType,
1700                                    bool theState)
1701 {
1702   if (myCurrentSketch.get() == NULL)
1703     return;
1704
1705   bool aPrevState = myIsConstraintsShown[theType];
1706   myIsConstraintsShown[theType] = theState;
1707
1708   switch (theType) {
1709     case PartSet_Tools::Geometrical:
1710     case PartSet_Tools::Dimensional: {
1711       if (aPrevState != theState) {
1712         ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1713         XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1714         for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
1715           FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
1716           bool aProcessed = false;
1717           bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, theType, aProcessed);
1718           if (aProcessed)
1719             aSubFeature->setDisplayed(aConstraintDisplayed);
1720         }
1721         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1722       }
1723     }
1724     break;
1725     case PartSet_Tools::Expressions: {
1726       if (aPrevState != theState) {
1727         /// call all sketch features redisplay, the expression state will be corrected in customize
1728         /// of distance presentation
1729         Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1730         PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
1731       }
1732     }
1733     break;
1734   }
1735 }
1736
1737 void PartSet_SketcherMgr::updateSelectionPriority(ObjectPtr theObject,
1738                                                   FeaturePtr theFeature)
1739 {
1740   if (!theObject.get() || !theFeature.get())
1741     return;
1742
1743   AISObjectPtr anAIS = workshop()->displayer()->getAISObject(theObject);
1744   Handle(AIS_InteractiveObject) anAISIO;
1745   if (anAIS.get() != NULL) {
1746     anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1747   }
1748
1749   if (!anAISIO.IsNull()) { // the presentation for the object is visualized
1750     int anAdditionalPriority = 0;
1751     // current feature
1752     std::shared_ptr<SketchPlugin_Feature> aSPFeature =
1753             std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
1754     if (aSPFeature.get() != NULL) {
1755       // 1. Vertices
1756       // 2. Simple segments
1757       // 3. External objects (violet color)
1758       // 4. Auxiliary segments (dotted)
1759       // StdSelect_BRepSelectionTool::Load uses priority calculating:
1760       // Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;
1761       // Priority of Vertex is 8, edge(segment) is 7.
1762       // It might be not corrected as provides the condition above.
1763       bool isExternal = aSPFeature->isExternal();
1764       bool isAuxiliary = PartSet_Tools::isAuxiliarySketchEntity(aSPFeature);
1765       // current feature
1766       if (!isExternal && !isAuxiliary)
1767         anAdditionalPriority = 30;
1768       // external feature
1769       if (isExternal)
1770         anAdditionalPriority = 20;
1771       // auxiliary feature
1772       if (isAuxiliary) {
1773         anAdditionalPriority = 10; /// auxiliary objects should have less priority that
1774         // edges/vertices of local selection on not-sketch objects
1775       }
1776       Handle(ModuleBase_ResultPrs) aResult = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);
1777       if (!aResult.IsNull()) {
1778         aResult->setAdditionalSelectionPriority(anAdditionalPriority);
1779       }
1780     }
1781   }
1782 }
1783
1784 XGUI_Workshop* PartSet_SketcherMgr::workshop() const
1785 {
1786   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
1787   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
1788   return aConnector->workshop();
1789 }
1790
1791 XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const
1792 {
1793   return workshop()->operationMgr();
1794 }
1795