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