Salome HOME
c308eea3aa9fa022d706757907ce2d8b83c329c8
[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
16 #include <XGUI_ModuleConnector.h>
17 #include <XGUI_Displayer.h>
18 #include <XGUI_Workshop.h>
19 #include <XGUI_ContextMenuMgr.h>
20 #include <XGUI_Selection.h>
21 #include <XGUI_SelectionMgr.h>
22 #include <XGUI_ModuleConnector.h>
23 #include <XGUI_PropertyPanel.h>
24 #include <XGUI_ViewerProxy.h>
25 #include <XGUI_OperationMgr.h>
26
27 #include <ModuleBase_IPropertyPanel.h>
28 #include <ModuleBase_ISelection.h>
29 #include <ModuleBase_IViewer.h>
30 #include <ModuleBase_IWorkshop.h>
31 #include <ModuleBase_IViewWindow.h>
32 #include <ModuleBase_ModelWidget.h>
33 #include <ModuleBase_Operation.h>
34 #include <ModuleBase_OperationFeature.h>
35 #include <ModuleBase_Operation.h>
36 #include <ModuleBase_WidgetEditor.h>
37
38 #include <GeomDataAPI_Point2D.h>
39
40 #include <Events_Loop.h>
41
42 #include <SketchPlugin_Line.h>
43 #include <SketchPlugin_Sketch.h>
44 #include <SketchPlugin_Point.h>
45 #include <SketchPlugin_Arc.h>
46 #include <SketchPlugin_Circle.h>
47 #include <SketchPlugin_ConstraintLength.h>
48 #include <SketchPlugin_ConstraintDistance.h>
49 #include <SketchPlugin_ConstraintParallel.h>
50 #include <SketchPlugin_ConstraintPerpendicular.h>
51 #include <SketchPlugin_ConstraintRadius.h>
52 #include <SketchPlugin_ConstraintRigid.h>
53 #include <SketchPlugin_ConstraintHorizontal.h>
54 #include <SketchPlugin_ConstraintVertical.h>
55 #include <SketchPlugin_ConstraintEqual.h>
56 #include <SketchPlugin_ConstraintTangent.h>
57 #include <SketchPlugin_ConstraintCoincidence.h>
58 #include <SketchPlugin_ConstraintFillet.h>
59 #include <SketchPlugin_ConstraintMirror.h>
60 #include <SketchPlugin_ConstraintAngle.h>
61 #include <SketchPlugin_MultiRotation.h>
62 #include <SketchPlugin_MultiTranslation.h>
63
64 #include <SketcherPrs_Tools.h>
65
66 #include <SelectMgr_IndexedMapOfOwner.hxx>
67 #include <StdSelect_BRepOwner.hxx>
68
69 //#include <AIS_DimensionSelectionMode.hxx>
70 #include <AIS_Shape.hxx>
71
72 #include <ModelAPI_Events.h>
73 #include <ModelAPI_Session.h>
74 #include <ModelAPI_AttributeString.h>
75
76 #include <QMouseEvent>
77 #include <QApplication>
78 #include <QCursor>
79
80 //#define DEBUG_DO_NOT_BY_ENTER
81
82 //#define DEBUG_CURSOR
83
84 /// Returns list of unique objects by sum of objects from List1 and List2
85 /*QList<ModuleBase_ViewerPrs> getSumList(const QList<ModuleBase_ViewerPrs>& theList1,
86                                        const QList<ModuleBase_ViewerPrs>& theList2)
87 {
88   QList<ModuleBase_ViewerPrs> aRes;
89   foreach (ModuleBase_ViewerPrs aPrs, theList1) {
90     if (!aRes.contains(aPrs))
91       aRes.append(aPrs);
92   }
93   foreach (ModuleBase_ViewerPrs aPrs, theList2) {
94     if (!aRes.contains(aPrs))
95       aRes.append(aPrs);
96   }
97   return aRes;
98 }*/
99
100 // Fills the list of features the list of selected presentations.
101 // \param theList a list of selected presentations
102 // \param theSketch a sketch to project a vertex shape of a presentation to the plane
103 // and find the corresponded attribute
104 // \param theFeatureList  an output list of features
105 void fillFeatureList(const QList<ModuleBase_ViewerPrs>& theList,
106                      const FeaturePtr theSketch,
107                      QList<FeaturePtr>& theFeatureList)
108 {
109   QList<ModuleBase_ViewerPrs> aRes;
110
111   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theList.begin(),
112                                               aLast = theList.end();
113   for (; anIt != aLast; anIt++)
114   {
115     ModuleBase_ViewerPrs aPrs = *anIt;
116     FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs.object());
117     if (aFeature.get()  && !theFeatureList.contains(aFeature))
118       theFeatureList.append(aFeature);
119   }
120 }
121
122 /// Fills attribute and result lists by the selected owner. In case if the attribute is found,
123 /// by the owner shape, it is put to the list. Otherwise if type of owner shape is edge, put the function
124 /// result as is to the list of results.
125 /// \param theOwner a viewer selected owner
126 /// \param theFeature a feature, where the attribute is searched
127 /// \param theSketch a current sketch
128 /// \param theSelectedAttribute an output list of attributes
129 /// \param theSelectedResults an output list of edge results
130 void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,
131                             const FeaturePtr& theFeature, const FeaturePtr& theSketch,
132                             const ResultPtr& theResult,
133                             std::set<AttributePtr>& aSelectedAttributes,
134                             std::set<ResultPtr>& aSelectedResults)
135 {
136   Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(theOwner);
137   if (aBRepOwner.IsNull())
138     return;
139   Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast(
140                                                                     aBRepOwner->Selectable());
141   if (aBRepOwner->HasShape()) {
142     const TopoDS_Shape& aShape = aBRepOwner->Shape();
143     TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
144     if (aShapeType == TopAbs_VERTEX) {
145       AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,
146                                                                     aShape, theSketch);
147       if (aPntAttr.get() != NULL)
148         aSelectedAttributes.insert(aPntAttr);
149     }
150     else if (aShapeType == TopAbs_EDGE &&
151              aSelectedResults.find(theResult) == aSelectedResults.end()) {
152       aSelectedResults.insert(theResult);
153     }
154   }
155 }
156
157 PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
158   : QObject(theModule), myModule(theModule), myIsDragging(false), myDragDone(false),
159     myIsMouseOverWindow(false),
160     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),
161     myIsPopupMenuActive(false), myIsConstraintsShown(true)
162 {
163   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
164   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
165
166   myPreviousDrawModeEnabled = true;//aViewer->isSelectionEnabled();
167
168   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),
169           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));
170
171   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),
172           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));
173
174   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
175           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));
176
177   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),
178           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));
179
180   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
181   XGUI_Workshop* aWorkshop = aConnector->workshop();
182   connect(aWorkshop, SIGNAL(applicationStarted()), this, SLOT(onApplicationStarted()));
183 }
184
185 PartSet_SketcherMgr::~PartSet_SketcherMgr()
186 {
187   if (!myPlaneFilter.IsNull())
188     myPlaneFilter.Nullify();
189 }
190
191 void PartSet_SketcherMgr::onEnterViewPort()
192 {
193   // 1. if the mouse over window, update the next flag. Do not perform update visibility of
194   // created feature because it should be done in onMouseMove(). Some widgets watch
195   // the mouse move and use the cursor position to update own values. If the presentaion is
196   // redisplayed before this update, the feature presentation jumps from reset value to current.
197   myIsMouseOverWindow = true;
198
199   #ifdef DEBUG_DO_NOT_BY_ENTER
200   return;
201   #endif
202
203   if (canChangeCursor(getCurrentOperation())) {
204     QCursor* aCurrentCursor = QApplication::overrideCursor();
205     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
206       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
207 #ifdef DEBUG_CURSOR
208       qDebug("onEnterViewPort() : Qt::CrossCursor");
209 #endif
210     }
211   }
212
213   if (!isNestedCreateOperation(getCurrentOperation()))
214     return;
215
216   operationMgr()->onValidateOperation();
217
218   // we need change displayed state of the current operation feature
219   // if the feature is presentable, e.g. distance construction. It has no results, so workshop does
220   // not accept a signal about the result created. Nothing is shown until mouse is moved out/in view
221   // port. If the isDisplayed flag is true, the presentable feature is displayed as soon as the
222   // presentation becomes valid and redisplay happens
223   //ModuleBase_Operation* aOperation = getCurrentOperation();
224   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
225                                                                            (getCurrentOperation());
226   if (aFOperation) {
227     FeaturePtr aFeature = aFOperation->feature();
228     if (aFeature.get() && aFeature->data()->isValid()) {
229       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature), false);
230     }
231   }
232 }
233
234 void PartSet_SketcherMgr::onLeaveViewPort()
235 {
236   myIsMouseOverViewProcessed = false;
237   myIsMouseOverWindow = false;
238   // it is important to validate operation here only if sketch entity create operation is active
239   // because at this operation we reacts to the mouse leave/enter view port
240   //operationMgr()->onValidateOperation();
241
242   #ifdef DEBUG_DO_NOT_BY_ENTER
243   return;
244   #endif
245
246   if (canChangeCursor(getCurrentOperation())) {
247     QApplication::restoreOverrideCursor();
248 #ifdef DEBUG_CURSOR
249     qDebug("onLeaveViewPort() : None");
250 #endif
251   }
252
253   if (!isNestedCreateOperation(getCurrentOperation()))
254     return;
255
256   // the method should be performed if the popup menu is called,
257   // the reset of the current widget should not happen
258   if (myIsPopupMenuActive)
259     return;
260
261   operationMgr()->onValidateOperation();
262
263   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation
264   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
265   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
266   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
267   // disable the viewer update in order to avoid visualization of redisplayed feature in viewer
268   // obtained after reset value
269   bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
270   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
271   if (anActiveWidget)
272     anActiveWidget->reset();
273
274   // hides the presentation of the current operation feature
275   // the feature is to be erased here, but it is correct to call canDisplayObject because
276   // there can be additional check (e.g. editor widget in distance constraint)
277   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
278                                                                            (getCurrentOperation());
279   if (aFOperation) {
280     FeaturePtr aFeature = aFOperation->feature();
281     visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
282   }
283   // we should update viewer after the presentation are hidden in the viewer
284   // otherwise the reset presentation(line) appears in the viewer(by quick move from viewer to PP)
285   aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
286 }
287
288 void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()
289 {
290   if (!isNestedEditOperation(getCurrentOperation()) ||
291       myModule->sketchReentranceMgr()->isInternalEditActive())
292     return;
293   // it is necessary to save current selection in order to restore it after the values are modifed
294   storeSelection();
295
296   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
297   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
298   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
299   myPreviousUpdateViewerEnabled = aDisplayer->enableUpdateViewer(false);
300 }
301
302 void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()
303 {
304   if (!isNestedEditOperation(getCurrentOperation()) ||
305       myModule->sketchReentranceMgr()->isInternalEditActive())
306     return;
307   // it is necessary to restore current selection in order to restore it after the values are modified
308   restoreSelection();
309   myCurrentSelection.clear();
310
311   // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
312   // viewer happens by deselect/select the modified objects. The flag should be restored after
313   // the selection processing. The update viewer should be also called.
314   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
315   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
316   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
317   aDisplayer->enableUpdateViewer(myPreviousUpdateViewerEnabled);
318   aDisplayer->updateViewer();
319 }
320
321 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
322 {
323   if (myModule->sketchReentranceMgr()->processMousePressed(theWnd, theEvent))
324     return;
325
326   //get2dPoint(theWnd, theEvent, myClickedPoint);
327
328   if (!(theEvent->buttons() & Qt::LeftButton))
329     return;
330
331   // Clear dragging mode
332   myIsDragging = false;
333
334   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
335   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
336   if (!aViewer->canDragByMouse())
337     return;
338
339   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
340                                                                (getCurrentOperation());
341   if (!aFOperation)
342     return;
343
344   if (aFOperation->isEditOperation()) {
345     // If the current widget is a selector, do nothing, it processes the mouse press
346     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
347     if(anActiveWidget && anActiveWidget->isViewerSelector()) {
348       return;
349     }
350   }
351
352   // Use only for sketch operations
353   if (myCurrentSketch) {
354     if (!PartSet_Tools::sketchPlane(myCurrentSketch))
355       return;
356
357     bool isSketcher = isSketchOperation(aFOperation);
358     bool isSketchOpe = isNestedSketchOperation(aFOperation);
359
360     // Avoid non-sketch operations
361     if ((!isSketchOpe) && (!isSketcher))
362       return;
363
364     bool isEditing = aFOperation->isEditOperation();
365
366     // Ignore creation sketch operation
367     if ((!isSketcher) && (!isEditing))
368       return;
369
370     Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
371     if (!aContext.IsNull()) {
372       // MoveTo in order to highlight current object
373       aContext->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
374     }
375     // Remember highlighted objects for editing
376     ModuleBase_ISelection* aSelect = aWorkshop->selection();
377
378     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
379     storeSelection(!aHasShift);
380
381     if (myCurrentSelection.empty()) {
382       if (isSketchOpe && (!isSketcher))
383         // commit previous operation
384         if (!aFOperation->commit())
385           aFOperation->abort();
386       return;
387     }
388     // Init flyout point for radius rotation
389     FeaturePtr aFeature = myCurrentSelection.begin().key();
390
391     if (isSketcher) {
392       myIsDragging = true;
393       get2dPoint(theWnd, theEvent, myCurrentPoint);
394       myDragDone = false;
395       // TODO: Has to be uncommented when SALOME patch on draw mode become avialable
396       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
397       launchEditing();
398       if (aFeature.get() != NULL) {
399         std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
400                   std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
401       if (aSPFeature.get() && aSPFeature->getKind() == SketchPlugin_ConstraintRadius::ID()) {
402           DataPtr aData = aSPFeature->data();
403           AttributePtr aAttr = aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
404           std::shared_ptr<GeomDataAPI_Point2D> aFPAttr = 
405             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aAttr);
406           aFPAttr->setValue(myCurrentPoint.myCurX, myCurrentPoint.myCurY);
407         }
408       }
409     } else if (isSketchOpe && isEditing) {
410       // If selected another object commit current result
411       aFOperation->commit();
412
413       myIsDragging = true;
414       get2dPoint(theWnd, theEvent, myCurrentPoint);
415       myDragDone = false;
416       // TODO: Has to be uncommented when SALOME patch on draw mode become avialable
417       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
418
419       // this is temporary commented in order to avoid the following wrong case:
420       // Distance constraint is under edition, double click on the digit -> nothing happens
421       // because QApplication::processEvents() calls onMouseDoubleClick, which try to show editor
422       // but as the prev edit is commited an new one is not started, editor is not shown.
423       // This is necessary in order to finalize previous operation
424       //QApplication::processEvents();
425       launchEditing();
426     }
427   }
428 }
429
430 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
431 {
432   if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))
433     return;
434
435   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
436   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
437   if (!aViewer->canDragByMouse())
438     return;
439   ModuleBase_Operation* aOp = getCurrentOperation();
440   if (aOp) {
441     if (isNestedSketchOperation(aOp)) {
442       //get2dPoint(theWnd, theEvent, myClickedPoint);
443
444       // Only for sketcher operations
445       if (myIsDragging) {
446         if (myDragDone) {
447           //aOp->commit();
448           myCurrentSelection.clear();
449           /*Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
450           if (!aContext.IsNull()) {
451           // Reselect edited object
452           aContext->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
453           if (theEvent->modifiers() & Qt::ShiftModifier)
454             aContext->ShiftSelect();
455           else
456             aContext->Select();
457           */
458         }
459       }
460     }
461   }
462       // TODO: Has to be uncommented when SALOME patch on draw mode become avialable
463   aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
464   //aWorkshop->viewer()->enableSelection(myPreviousDrawModeEnabled);
465   myIsDragging = false;
466 }
467
468 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
469 {
470   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
471     return;
472
473   if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
474     myIsMouseOverViewProcessed = true;
475     // 1. perform the widget mouse move functionality and display the presentation
476     // the mouse move should be processed in the widget, if it can in order to visualize correct
477     // presentation. These widgets correct the feature attribute according to the mouse position
478     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
479     PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWidget);
480     if (aPoint2DWdg) {
481       aPoint2DWdg->onMouseMove(theWnd, theEvent);
482     }
483     PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast<PartSet_WidgetPoint2dDistance*>
484                                                                 (anActiveWidget);
485     if (aDistanceWdg) {
486       aDistanceWdg->onMouseMove(theWnd, theEvent);
487     }
488     // the feature is to be erased here, but it is correct to call canDisplayObject because
489     // there can be additional check (e.g. editor widget in distance constraint)
490     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
491                                                                              (getCurrentOperation());
492     if (aFOperation) {
493       FeaturePtr aFeature = aFOperation->feature();
494       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
495     }
496   }
497
498   //myClickedPoint.clear();
499
500   if (myIsDragging) {
501     // 1. the current selection is saved in the mouse press method in order to restore it after moving
502     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
503     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
504     // deselected). This flag should be restored in the slot, processed the mouse release signal.
505
506     // TODO: Has to be commented out when SALOME patch on draw mode become avialable
507     //ModuleBase_IViewer* aViewer = myModule->workshop()->viewer();
508     //aViewer->enableSelection(false);
509
510     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
511     if (!aCurrentOperation)
512       return;
513     if (isSketchOperation(aCurrentOperation))
514       return; // No edit operation activated
515
516     Handle(V3d_View) aView = theWnd->v3dView();
517     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
518     double aX, aY;
519     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);
520     double dX =  aX - myCurrentPoint.myCurX;
521     double dY =  aY - myCurrentPoint.myCurY;
522
523     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
524     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
525     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
526     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
527     // viewer happens by deselect/select the modified objects. The flag should be restored after
528     // the selection processing. The update viewer should be also called.
529     bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
530
531     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
532     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
533     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
534                                           aLast = myCurrentSelection.end();
535     // 4. the features and attributes modification(move)
536     bool isModified = false;
537     for (; anIt != aLast; anIt++) {
538       FeaturePtr aFeature = anIt.key();
539
540       std::set<AttributePtr> anAttributes = anIt.value().first;
541       // Process selection by attribute: the priority to the attribute
542       if (!anAttributes.empty()) {
543         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
544                                                anAttLast = anAttributes.end();
545         for (; anAttIt != anAttLast; anAttIt++) {
546           AttributePtr anAttr = *anAttIt;
547           if (anAttr.get() == NULL)
548             continue;
549           std::string aAttrId = anAttr->id();
550           DataPtr aData = aFeature->data();
551           if (aData->isValid()) {
552             std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
553               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
554             if (aPoint.get() != NULL) {
555               bool isImmutable = aPoint->setImmutable(true);
556               aPoint->move(dX, dY);
557               isModified = true;
558               ModelAPI_EventCreator::get()->sendUpdated(aFeature, aMoveEvent);
559               aPoint->setImmutable(isImmutable);
560             }
561           }
562         }
563       } else {
564         // Process selection by feature
565         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
566           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
567         if (aSketchFeature) {
568           aSketchFeature->move(dX, dY);
569           isModified = true;
570           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, aMoveEvent);
571         }
572       }
573     }
574     // the modified state of the current operation should be updated if there are features, which
575     // were changed here
576     if (isModified) {
577       aCurrentOperation->onValuesChanged();
578     }
579     Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
580     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations
581
582     // 5. it is necessary to save current selection in order to restore it after the features moving
583     restoreSelection();
584     // 6. restore the update viewer flag and call this update
585     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
586     aDisplayer->updateViewer();
587
588     myDragDone = true;
589     myCurrentPoint.setValue(aX, aY);
590   }
591 }
592
593 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
594 {
595   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
596                                                                (getCurrentOperation());
597   if (aFOperation && aFOperation->isEditOperation()) {
598     std::string aId = aFOperation->id().toStdString();
599     if (isDistanceOperation(aFOperation))
600     {
601       // Activate dimension value editing on double click
602       ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
603       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
604       // Find corresponded widget to activate value editing
605       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
606         if (aWgt->attributeID() == "ConstraintValue") {
607           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
608           if (anEditor)
609             anEditor->showPopupEditor();
610           return;
611         }
612       }
613     }
614   }
615 }
616
617 void PartSet_SketcherMgr::onApplicationStarted()
618 {
619   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
620   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
621   XGUI_Workshop* aWorkshop = aConnector->workshop();
622   PartSet_SketcherReetntrantMgr* aReentranceMgr = myModule->sketchReentranceMgr();
623
624   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
625   if (aPropertyPanel) {
626     //connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),
627     //        this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));
628
629     connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),
630             aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));
631     connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
632             aReentranceMgr, SLOT(onWidgetActivated()));
633   }
634
635   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
636   connect(aViewerProxy, SIGNAL(enterViewPort()), this, SLOT(onEnterViewPort()));
637   connect(aViewerProxy, SIGNAL(leaveViewPort()), this, SLOT(onLeaveViewPort()));
638
639   XGUI_ContextMenuMgr* aContextMenuMgr = aWorkshop->contextMenuMgr();
640   connect(aContextMenuMgr, SIGNAL(beforeContextMenu()), this, SLOT(onBeforeContextMenu()));
641   connect(aContextMenuMgr, SIGNAL(afterContextMenu()), this, SLOT(onAfterContextMenu()));
642 }
643
644 //void PartSet_SketcherMgr::onBeforeWidgetActivated(ModuleBase_ModelWidget* theWidget)
645 //{
646   //if (!myClickedPoint.myIsInitialized)
647   //  return;
648
649   //ModuleBase_Operation* aOperation = getCurrentOperation();
650   // the distance constraint feature should not use the clickedd point
651   // this is workaround in order to don't throw down the flyout point value,
652   // set by execute() method of these type of features
653   //if (isDistanceOperation(aOperation))
654   //  return;
655
656   //PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(theWidget);
657   //if (aPnt2dWgt) {
658   //  aPnt2dWgt->setPoint(myClickedPoint.myCurX, myClickedPoint.myCurY);
659   //}
660 //}
661
662 void PartSet_SketcherMgr::onBeforeContextMenu()
663 {
664   myIsPopupMenuActive = true;
665 }
666
667 void PartSet_SketcherMgr::onAfterContextMenu()
668 {
669   myIsPopupMenuActive = false;
670 }
671
672 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, 
673                                      Point& thePoint)
674 {
675   Handle(V3d_View) aView = theWnd->v3dView();
676   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
677   double aX, anY;
678   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, anY);
679   thePoint.setValue(aX, anY);
680 }
681
682 void PartSet_SketcherMgr::launchEditing()
683 {
684   if (!myCurrentSelection.empty()) {
685     FeaturePtr aFeature = myCurrentSelection.begin().key();
686     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
687               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
688     if (aSPFeature) {
689       myModule->editFeature(aSPFeature);
690     }
691   }
692 }
693
694 bool PartSet_SketcherMgr::sketchSolverError()
695 {
696   bool anError = false;
697   CompositeFeaturePtr aSketch = activeSketch();
698   if (aSketch.get()) {
699     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
700     anError = !aAttributeString->value().empty();
701   }
702   return anError;
703 }
704
705 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
706 {
707   QString anError = "";
708   if (!theFeature.get() || !theFeature->data()->isValid())
709     return anError;
710
711   CompositeFeaturePtr aSketch = activeSketch();
712   if (aSketch.get() && aSketch == theFeature) {
713     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
714     anError = aAttributeString->value().c_str();
715   }
716   return anError;
717 }
718
719 void PartSet_SketcherMgr::clearClickedFlags()
720 {
721   //myClickedPoint.clear();
722   myCurrentPoint.clear();
723 }
724
725 const QStringList& PartSet_SketcherMgr::sketchOperationIdList()
726 {
727   static QStringList aIds;
728   if (aIds.size() == 0) {
729     aIds << SketchPlugin_Line::ID().c_str();
730     aIds << SketchPlugin_Point::ID().c_str();
731     aIds << SketchPlugin_Arc::ID().c_str();
732     aIds << SketchPlugin_Circle::ID().c_str();
733     aIds << SketchPlugin_ConstraintFillet::ID().c_str();
734     aIds.append(constraintsIdList());
735   }
736   return aIds;
737 }
738
739 const QStringList& PartSet_SketcherMgr::constraintsIdList()
740 {
741   static QStringList aIds;
742   if (aIds.size() == 0) {
743     aIds << SketchPlugin_ConstraintLength::ID().c_str();
744     aIds << SketchPlugin_ConstraintDistance::ID().c_str();
745     aIds << SketchPlugin_ConstraintRigid::ID().c_str();
746     aIds << SketchPlugin_ConstraintRadius::ID().c_str();
747     aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
748     aIds << SketchPlugin_ConstraintParallel::ID().c_str();
749     aIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
750     aIds << SketchPlugin_ConstraintVertical::ID().c_str();
751     aIds << SketchPlugin_ConstraintEqual::ID().c_str();
752     aIds << SketchPlugin_ConstraintTangent::ID().c_str();
753     aIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
754     aIds << SketchPlugin_ConstraintMirror::ID().c_str();
755     aIds << SketchPlugin_ConstraintAngle::ID().c_str();
756     aIds << SketchPlugin_MultiRotation::ID().c_str();
757     aIds << SketchPlugin_MultiTranslation::ID().c_str();
758   }
759   return aIds;
760 }
761
762 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
763 {
764   theModes.clear();
765
766   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
767   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
768   theModes.append(SketcherPrs_Tools::Sel_Constraint);
769   theModes.append(TopAbs_VERTEX);
770   theModes.append(TopAbs_EDGE);
771 }
772
773 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
774 {
775   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
776 }
777
778 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation)
779 {
780   return theOperation &&
781          PartSet_SketcherMgr::sketchOperationIdList().contains(theOperation->id());
782 }
783
784 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation)
785 {
786   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
787                                                                (theOperation);
788   return aFOperation && !aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
789 }
790
791 bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation)
792 {
793   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
794                                                                (theOperation);
795   return aFOperation && aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
796 }
797
798 bool PartSet_SketcherMgr::isEntity(const std::string& theId)
799 {
800   return (theId == SketchPlugin_Line::ID()) ||
801          (theId == SketchPlugin_Point::ID()) ||
802          (theId == SketchPlugin_Arc::ID()) ||
803          (theId == SketchPlugin_Circle::ID());
804 }
805
806 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)
807 {
808   std::string aId = theOperation ? theOperation->id().toStdString() : "";
809
810   return (aId == SketchPlugin_ConstraintLength::ID()) ||
811          (aId == SketchPlugin_ConstraintDistance::ID()) ||
812          (aId == SketchPlugin_ConstraintRadius::ID()) ||
813          (aId == SketchPlugin_ConstraintAngle::ID());
814 }
815
816 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
817 {
818   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
819                                                                (getCurrentOperation());
820   if (!aFOperation)
821     return;
822
823   myModule->onViewTransformed();
824
825   // Display all sketcher sub-Objects
826   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
827   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
828   aConnector->workshop()->displayer()->activateTrihedron(true);
829
830   // Hide sketcher result
831   std::list<ResultPtr> aResults = myCurrentSketch->results();
832   std::list<ResultPtr>::const_iterator aIt;
833   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
834     (*aIt)->setDisplayed(false);
835   }
836   myCurrentSketch->setDisplayed(false);
837
838   // Display sketcher objects
839   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
840     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
841     std::list<ResultPtr> aResults = aFeature->results();
842     std::list<ResultPtr>::const_iterator aIt;
843     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
844       (*aIt)->setDisplayed(true);
845     }
846     aFeature->setDisplayed(true);
847   }
848
849   if (myPlaneFilter.IsNull()) 
850     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
851
852   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
853
854   bool aHasPlane = false;
855   std::shared_ptr<GeomAPI_Pln> aPln;
856   if (aFOperation->isEditOperation()) {
857     // If it is editing of sketch then it means that plane is already defined
858     aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
859     if (aPln.get())
860       aHasPlane = true;
861   }
862   myPlaneFilter->setPlane(aPln);
863
864   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
865   // all sketch objects should be activated in the sketch selection modes by edit operation start
866   // in case of creation operation, there is an active widget, which activates own selection mode
867   if (aFOperation->isEditOperation() && aHasPlane)
868     aConnector->activateModuleSelectionModes();
869 }
870
871 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
872 {
873   myIsMouseOverWindow = false;
874   myIsConstraintsShown = true;
875
876   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
877
878   DataPtr aData = myCurrentSketch->data();
879   if (!aData->isValid()) {
880     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
881     // The sketch was aborted
882     myCurrentSketch = CompositeFeaturePtr();
883     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
884
885     // Erase all sketcher objects
886     QStringList aSketchIds = sketchOperationIdList();
887     QObjectPtrList aObjects = aDisplayer->displayedObjects();
888     foreach (ObjectPtr aObj, aObjects) {
889       DataPtr aObjData = aObj->data();
890       if (!aObjData->isValid())
891         aObj->setDisplayed(false);
892     }
893   }
894   else {
895     // Hide all sketcher sub-Objects
896     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
897       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
898       std::list<ResultPtr> aResults = aFeature->results();
899       std::list<ResultPtr>::const_iterator aIt;
900       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
901         (*aIt)->setDisplayed(false);
902       }
903       aFeature->setDisplayed(false);
904     }
905     // Display sketcher result
906     std::list<ResultPtr> aResults = myCurrentSketch->results();
907     std::list<ResultPtr>::const_iterator aIt;
908     Events_Loop* aLoop = Events_Loop::loop();
909     static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
910
911     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
912                                                                            (theOperation);
913     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
914       if (!aFOperation->isDisplayedOnStart(*aIt)) {
915         (*aIt)->setDisplayed(true);
916         // this display event is needed because sketch already may have "displayed" state,
917         // but not displayed while it is still active (issue 613, abort of existing sketch)
918         ModelAPI_EventCreator::get()->sendUpdated(*aIt, aDispEvent);
919       }
920     }
921     if (!aFOperation->isDisplayedOnStart(myCurrentSketch))
922       myCurrentSketch->setDisplayed(true);
923     
924     myCurrentSketch = CompositeFeaturePtr();
925     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
926
927     Events_Loop::loop()->flush(aDispEvent);
928   }
929   // restore the module selection modes, which were changed on startSketch
930   aConnector->activateModuleSelectionModes();
931   aConnector->workshop()->displayer()->activateTrihedron(false);
932 }
933
934 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
935 {
936   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
937     QCursor* aCurrentCursor = QApplication::overrideCursor();
938     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
939       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
940 #ifdef DEBUG_CURSOR
941       qDebug("startNestedSketch() : Qt::CrossCursor");
942 #endif
943     }
944   }
945 }
946
947 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
948 {
949   myIsMouseOverViewProcessed = true;
950   operationMgr()->onValidateOperation();
951   if (canChangeCursor(theOperation)) {
952     QApplication::restoreOverrideCursor();
953 #ifdef DEBUG_CURSOR
954     qDebug("stopNestedSketch() : None");
955 #endif
956   }
957 }
958
959 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
960 {
961   if (isNestedCreateOperation(theOperation)) {
962     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
963                                                                              (theOperation);
964     if (aFOperation) {
965       FeaturePtr aFeature = aFOperation->feature();
966       // it is necessary to check the the feature data validity because
967       // some kind of features are removed by an operation commit(the macro state of a feature)
968       if (aFeature.get() && aFeature->data()->isValid()) {
969         visualizeFeature(aFeature, aFOperation->isEditOperation(), true);
970       }
971     }
972   }
973 }
974
975 bool PartSet_SketcherMgr::canUndo() const
976 {
977   return isNestedCreateOperation(getCurrentOperation());
978 }
979
980 bool PartSet_SketcherMgr::canRedo() const
981 {
982   return isNestedCreateOperation(getCurrentOperation());
983 }
984
985 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const
986 {
987   bool aCanErase = true;
988   // when the sketch operation is active, results of sketch sub-feature can not be hidden
989   if (myCurrentSketch.get()) {
990     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
991     if (aResult.get()) {
992       // Display sketcher objects
993       for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {
994
995         FeaturePtr aFeature = myCurrentSketch->subFeature(i);
996         std::list<ResultPtr> aResults = aFeature->results();
997         std::list<ResultPtr>::const_iterator anIt;
998         for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {
999           aCanErase = *anIt != aResult;
1000         }
1001       }
1002     }
1003   }
1004   return aCanErase;
1005 }
1006
1007 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
1008 {
1009   bool aCanDisplay = true;
1010
1011   bool aHasActiveSketch = activeSketch().get() != NULL;
1012   if (aHasActiveSketch) {
1013     // 1. the sketch feature should not be displayed during the sketch active operation
1014     // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch 
1015     // nested features can be visualized
1016     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1017     if (aFeature.get() != NULL && aFeature == activeSketch()) {
1018       aCanDisplay = false;
1019     }
1020   }
1021   else { // there are no an active sketch
1022     // 2. sketch sub-features should not be visualized if the sketch operation is not active
1023     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1024     if (aFeature.get() != NULL) {
1025       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1026                               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1027       if (aSketchFeature.get()) {
1028         aCanDisplay = false;
1029       }
1030     }
1031   }
1032
1033   // 3. the method should not filter the objects, which are not related to the current operation.
1034   // The object is filtered just if it is a current operation feature or this feature result
1035   bool isObjectFound = false;
1036   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1037                                                                (getCurrentOperation());
1038   if (aFOperation) {
1039     FeaturePtr aFeature = aFOperation->feature();
1040     if (aFeature.get()) {
1041       std::list<ResultPtr> aResults = aFeature->results();
1042       if (theObject == aFeature)
1043         isObjectFound = true;
1044       else {
1045         std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
1046         for (; anIt != aLast && !isObjectFound; anIt++) {
1047           isObjectFound = *anIt == theObject;
1048         }
1049       }
1050     }
1051   }
1052   if (!isObjectFound) 
1053     return aCanDisplay;
1054   
1055   // 4. For created nested feature operation do not display the created feature if
1056   // the mouse curstor leaves the OCC window.
1057   // The correction cases, which ignores this condition:
1058   // a. the property panel values modification
1059   // b. the popup menu activated
1060   // c. widget editor control
1061   #ifndef DEBUG_DO_NOT_BY_ENTER
1062   if (aCanDisplay && isNestedCreateOperation(getCurrentOperation())) {
1063     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1064     ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
1065     // the active widget editor should not influence here. The presentation should be visible always
1066     // when this widget is active.
1067     if (!anEditorWdg && !myIsPopupMenuActive) {
1068       // during a nested create operation, the feature is redisplayed only if the mouse over view
1069       // of there was a value modified in the property panel after the mouse left the view
1070       aCanDisplay = canDisplayCurrentCreatedFeature();
1071     }
1072   }
1073   #endif
1074   return aCanDisplay;
1075 }
1076
1077 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
1078 {
1079   bool aCanDisplay = myIsMouseOverWindow;
1080   if (!aCanDisplay) {
1081     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1082     if (anActiveWidget)
1083       aCanDisplay = anActiveWidget->getValueState() == ModuleBase_ModelWidget::Stored;
1084   }
1085   return aCanDisplay;
1086 }
1087
1088 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const
1089 {
1090   return isNestedCreateOperation(theOperation) ||
1091          myModule->sketchReentranceMgr()->isInternalEditActive();
1092 }
1093
1094 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
1095 {
1096   bool isFoundObject = false;
1097
1098   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
1099   if (anObjectFeature.get()) {
1100     int aSize = myCurrentSketch->numberOfSubs();
1101     for (int i = 0; i < myCurrentSketch->numberOfSubs() && !isFoundObject; i++) {
1102       FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);
1103       isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;
1104     }
1105   }
1106   return isFoundObject;
1107 }
1108
1109 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
1110 {
1111   if (myPlaneFilter.IsNull()) 
1112    myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
1113
1114   myPlaneFilter->setPlane(thePln);
1115 }
1116
1117 void PartSet_SketcherMgr::getCurrentSelection(const FeaturePtr& theFeature,
1118                                               const FeaturePtr& theSketch,
1119                                               ModuleBase_IWorkshop* theWorkshop,
1120                                               FeatureToSelectionMap& theSelection)
1121 {
1122   if (theFeature.get() == NULL)
1123     return;
1124
1125   std::set<AttributePtr> aSelectedAttributes;
1126   std::set<ResultPtr> aSelectedResults;
1127
1128   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1129   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
1130   if (!aContext.IsNull()) {
1131     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1132     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1133
1134     std::list<ResultPtr> aResults = theFeature->results();
1135     std::list<ResultPtr>::const_iterator aIt;
1136     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
1137     {
1138       ResultPtr aResult = *aIt;
1139       AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1140       if (aAISObj.get() == NULL)
1141         continue;
1142       Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1143       for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
1144       {
1145         Handle(SelectMgr_EntityOwner) anOwner = aContext->SelectedOwner();
1146         if (anOwner->Selectable() != anAISIO)
1147           continue;
1148         getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
1149                                aSelectedAttributes, aSelectedResults);
1150       }
1151       for (aContext->InitDetected(); aContext->MoreDetected(); aContext->NextDetected()) {
1152         Handle(SelectMgr_EntityOwner) anOwner = aContext->DetectedOwner();
1153         if (anOwner.IsNull())
1154           continue;
1155         if (anOwner->Selectable() != anAISIO)
1156           continue;
1157         getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
1158                                aSelectedAttributes, aSelectedResults);
1159       }
1160     }
1161   }
1162   theSelection[theFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);
1163 }
1164
1165 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,
1166                                              const FeaturePtr& theSketch,
1167                                              ModuleBase_IWorkshop* theWorkshop,
1168                                              const FeatureToSelectionMap& theSelection,
1169                                              SelectMgr_IndexedMapOfOwner& theOwnersToSelect)
1170 {
1171   if (theFeature.get() == NULL)
1172     return;
1173
1174   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
1175   std::set<AttributePtr> aSelectedAttributes = anIt.value().first;
1176   std::set<ResultPtr> aSelectedResults = anIt.value().second;
1177
1178   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1179
1180   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1181   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1182
1183   // 1. found the feature's owners. Check the AIS objects of the constructions
1184   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);
1185   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {
1186     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1187
1188     SelectMgr_IndexedMapOfOwner aSelectedOwners;
1189     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1190     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
1191       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
1192       if (!anOwner.IsNull())
1193         theOwnersToSelect.Add(anOwner);
1194     }
1195   }
1196
1197   // 2. found the feature results's owners
1198   std::list<ResultPtr> aResults = theFeature->results();
1199   std::list<ResultPtr>::const_iterator aIt;
1200   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
1201   {
1202     ResultPtr aResult = *aIt;
1203     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1204     if (aAISObj.get() == NULL)
1205       continue; 
1206     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1207
1208     SelectMgr_IndexedMapOfOwner aSelectedOwners;  
1209     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1210     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
1211       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
1212       if ( anOwner.IsNull() || !anOwner->HasShape() )
1213         continue;
1214       const TopoDS_Shape& aShape = anOwner->Shape();
1215       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
1216       if (aShapeType == TopAbs_VERTEX) {
1217         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
1218         if (aPntAttr.get() != NULL &&
1219             aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end()) {
1220           theOwnersToSelect.Add(anOwner);
1221         }
1222       }
1223       else if (aShapeType == TopAbs_EDGE) {
1224         bool aFound = aSelectedResults.find(aResult) != aSelectedResults.end();
1225         if (aSelectedResults.find(aResult) != aSelectedResults.end() &&
1226             theOwnersToSelect.FindIndex(anOwner) <= 0)
1227           theOwnersToSelect.Add(anOwner);
1228       }
1229     }
1230   }
1231 }
1232
1233 void PartSet_SketcherMgr::connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect)
1234 {
1235   if (isToConnect) {
1236     connect(theWidget, SIGNAL(beforeValuesChanged()),
1237             this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1238     connect(theWidget, SIGNAL(afterValuesChanged()),
1239             this, SLOT(onAfterValuesChangedInPropertyPanel()));
1240   }
1241   else {
1242     disconnect(theWidget, SIGNAL(beforeValuesChanged()),
1243                 this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1244     disconnect(theWidget, SIGNAL(afterValuesChanged()),
1245                 this, SLOT(onAfterValuesChangedInPropertyPanel()));
1246   }
1247 }
1248
1249 void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
1250 {
1251   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1252                                                                            (getCurrentOperation());
1253   if (aFOperation) {
1254     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
1255         PartSet_SketcherMgr::isNestedSketchOperation(aFOperation) &&
1256         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {
1257       FeaturePtr aFeature = aFOperation->feature();
1258       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
1259     }
1260   }
1261 }
1262
1263 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
1264 {
1265   return myModule->workshop()->currentOperation();
1266 }
1267
1268 //**************************************************************
1269 ModuleBase_ModelWidget* PartSet_SketcherMgr::getActiveWidget() const
1270 {
1271   ModuleBase_ModelWidget* aWidget = 0;
1272   ModuleBase_Operation* anOperation = getCurrentOperation();
1273   if (anOperation) {
1274     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
1275     if (aPanel)
1276       aWidget = aPanel->activeWidget();
1277   }
1278   return aWidget;
1279 }
1280
1281 void PartSet_SketcherMgr::visualizeFeature(const FeaturePtr& theFeature,
1282                                            const bool isEditOperation,
1283                                            const bool isToDisplay,
1284                                            const bool isFlushRedisplay)
1285 {
1286   #ifdef DEBUG_DO_NOT_BY_ENTER
1287   return;
1288   #endif
1289
1290   if (isEditOperation || !theFeature.get())
1291     return;
1292
1293   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1294   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1295
1296   // 1. change visibility of the object itself, here the presentable object is processed,
1297   // e.g. constraints features
1298   //FeaturePtr aFeature = aFOperation->feature();
1299   std::list<ResultPtr> aResults = theFeature->results();
1300   if (isToDisplay)
1301     theFeature->setDisplayed(true);
1302   else
1303     theFeature->setDisplayed(false);
1304
1305   // change visibility of the object results, e.g. non-constraint features
1306   std::list<ResultPtr>::const_iterator aIt;
1307   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1308     if (isToDisplay) {
1309       (*aIt)->setDisplayed(true);
1310     }
1311     else {
1312       (*aIt)->setDisplayed(false);
1313     }
1314   }
1315   if (isFlushRedisplay)
1316     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1317 }
1318
1319 void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
1320 {
1321   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1322   ModuleBase_ISelection* aSelect = aWorkshop->selection();
1323   QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
1324
1325   QList<FeaturePtr> aFeatureList;
1326   if (theHighlightedOnly) {
1327     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
1328   }
1329   else {
1330     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
1331
1332     QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected(ModuleBase_ISelection::AllControls);
1333     fillFeatureList(aSelected, myCurrentSketch, aFeatureList);
1334   }
1335
1336   // 1. it is necessary to save current selection in order to restore it after the features moving
1337   myCurrentSelection.clear();
1338   QList<FeaturePtr>::const_iterator anIt = aFeatureList.begin(), aLast = aFeatureList.end();
1339   for (; anIt != aLast; anIt++) {
1340     getCurrentSelection(*anIt, myCurrentSketch, aWorkshop, myCurrentSelection);
1341   }
1342   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1343 }
1344
1345 void PartSet_SketcherMgr::restoreSelection()
1346 {
1347   //qDebug(QString("restoreSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1348   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1349   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1350   FeatureToSelectionMap::const_iterator aSIt = myCurrentSelection.begin(),
1351                                         aSLast = myCurrentSelection.end();
1352   SelectMgr_IndexedMapOfOwner anOwnersToSelect;
1353   for (; aSIt != aSLast; aSIt++) {
1354     anOwnersToSelect.Clear();
1355     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, myCurrentSelection,
1356                         anOwnersToSelect);
1357     aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);
1358   }
1359 }
1360
1361 void PartSet_SketcherMgr::onShowConstraintsToggle(bool theOn)
1362 {
1363   if (myIsConstraintsShown == theOn)
1364     return;
1365   if (myCurrentSketch.get() == NULL)
1366     return;
1367
1368   myIsConstraintsShown = theOn;
1369
1370   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1371   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1372
1373   const QStringList& aConstrIds = constraintsIdList();
1374   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
1375     FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
1376     if (aConstrIds.contains(QString(aSubFeature->getKind().c_str()))) {
1377       if (myIsConstraintsShown) 
1378         aSubFeature->setDisplayed(true);
1379       else
1380         aSubFeature->setDisplayed(false);
1381     }
1382   }
1383   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1384 }
1385
1386 XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const
1387 {
1388   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
1389   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
1390   XGUI_Workshop* aWorkshop = aConnector->workshop();
1391
1392   return aWorkshop->operationMgr();
1393 }
1394