Salome HOME
TODO cleanup
[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
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
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
467   aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
468   myIsDragging = false;
469 }
470
471 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
472 {
473   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
474     return;
475
476   if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
477     myIsMouseOverViewProcessed = true;
478     // 1. perform the widget mouse move functionality and display the presentation
479     // the mouse move should be processed in the widget, if it can in order to visualize correct
480     // presentation. These widgets correct the feature attribute according to the mouse position
481     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
482     PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWidget);
483     if (aPoint2DWdg) {
484       aPoint2DWdg->onMouseMove(theWnd, theEvent);
485     }
486     PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast<PartSet_WidgetPoint2dDistance*>
487                                                                 (anActiveWidget);
488     if (aDistanceWdg) {
489       aDistanceWdg->onMouseMove(theWnd, theEvent);
490     }
491     // the feature is to be erased here, but it is correct to call canDisplayObject because
492     // there can be additional check (e.g. editor widget in distance constraint)
493     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
494                                                                              (getCurrentOperation());
495     if (aFOperation) {
496       FeaturePtr aFeature = aFOperation->feature();
497       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
498     }
499   }
500
501   //myClickedPoint.clear();
502
503   if (myIsDragging) {
504     // 1. the current selection is saved in the mouse press method in order to restore it after moving
505     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
506     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
507     // deselected). This flag should be restored in the slot, processed the mouse release signal.
508
509     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
510     if (!aCurrentOperation)
511       return;
512     if (isSketchOperation(aCurrentOperation))
513       return; // No edit operation activated
514
515     Handle(V3d_View) aView = theWnd->v3dView();
516     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
517     double aX, aY;
518     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);
519     double dX =  aX - myCurrentPoint.myCurX;
520     double dY =  aY - myCurrentPoint.myCurY;
521
522     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
523     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
524     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
525     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
526     // viewer happens by deselect/select the modified objects. The flag should be restored after
527     // the selection processing. The update viewer should be also called.
528     bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
529
530     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
531     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
532     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
533                                           aLast = myCurrentSelection.end();
534     // 4. the features and attributes modification(move)
535     bool isModified = false;
536     for (; anIt != aLast; anIt++) {
537       FeaturePtr aFeature = anIt.key();
538
539       std::set<AttributePtr> anAttributes = anIt.value().first;
540       // Process selection by attribute: the priority to the attribute
541       if (!anAttributes.empty()) {
542         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
543                                                anAttLast = anAttributes.end();
544         for (; anAttIt != anAttLast; anAttIt++) {
545           AttributePtr anAttr = *anAttIt;
546           if (anAttr.get() == NULL)
547             continue;
548           std::string aAttrId = anAttr->id();
549           DataPtr aData = aFeature->data();
550           if (aData->isValid()) {
551             std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
552               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
553             if (aPoint.get() != NULL) {
554               bool isImmutable = aPoint->setImmutable(true);
555               aPoint->move(dX, dY);
556               isModified = true;
557               ModelAPI_EventCreator::get()->sendUpdated(aFeature, aMoveEvent);
558               aPoint->setImmutable(isImmutable);
559             }
560           }
561         }
562       } else {
563         // Process selection by feature
564         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
565           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
566         if (aSketchFeature) {
567           aSketchFeature->move(dX, dY);
568           isModified = true;
569           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, aMoveEvent);
570         }
571       }
572     }
573     // the modified state of the current operation should be updated if there are features, which
574     // were changed here
575     if (isModified) {
576       aCurrentOperation->onValuesChanged();
577     }
578     Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
579     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations
580
581     // 5. it is necessary to save current selection in order to restore it after the features moving
582     restoreSelection();
583     // 6. restore the update viewer flag and call this update
584     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
585     aDisplayer->updateViewer();
586
587     myDragDone = true;
588     myCurrentPoint.setValue(aX, aY);
589   }
590 }
591
592 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
593 {
594   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
595                                                                (getCurrentOperation());
596   if (aFOperation && aFOperation->isEditOperation()) {
597     std::string aId = aFOperation->id().toStdString();
598     if (isDistanceOperation(aFOperation))
599     {
600       // Activate dimension value editing on double click
601       ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
602       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
603       // Find corresponded widget to activate value editing
604       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
605         if (aWgt->attributeID() == "ConstraintValue") {
606           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
607           if (anEditor)
608             anEditor->showPopupEditor();
609           return;
610         }
611       }
612     }
613   }
614 }
615
616 void PartSet_SketcherMgr::onApplicationStarted()
617 {
618   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
619   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
620   XGUI_Workshop* aWorkshop = aConnector->workshop();
621   PartSet_SketcherReetntrantMgr* aReentranceMgr = myModule->sketchReentranceMgr();
622
623   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
624   if (aPropertyPanel) {
625     //connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),
626     //        this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));
627
628     connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),
629             aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));
630     connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
631             aReentranceMgr, SLOT(onWidgetActivated()));
632   }
633
634   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
635   connect(aViewerProxy, SIGNAL(enterViewPort()), this, SLOT(onEnterViewPort()));
636   connect(aViewerProxy, SIGNAL(leaveViewPort()), this, SLOT(onLeaveViewPort()));
637
638   XGUI_ContextMenuMgr* aContextMenuMgr = aWorkshop->contextMenuMgr();
639   connect(aContextMenuMgr, SIGNAL(beforeContextMenu()), this, SLOT(onBeforeContextMenu()));
640   connect(aContextMenuMgr, SIGNAL(afterContextMenu()), this, SLOT(onAfterContextMenu()));
641 }
642
643 //void PartSet_SketcherMgr::onBeforeWidgetActivated(ModuleBase_ModelWidget* theWidget)
644 //{
645   //if (!myClickedPoint.myIsInitialized)
646   //  return;
647
648   //ModuleBase_Operation* aOperation = getCurrentOperation();
649   // the distance constraint feature should not use the clickedd point
650   // this is workaround in order to don't throw down the flyout point value,
651   // set by execute() method of these type of features
652   //if (isDistanceOperation(aOperation))
653   //  return;
654
655   //PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(theWidget);
656   //if (aPnt2dWgt) {
657   //  aPnt2dWgt->setPoint(myClickedPoint.myCurX, myClickedPoint.myCurY);
658   //}
659 //}
660
661 void PartSet_SketcherMgr::onBeforeContextMenu()
662 {
663   myIsPopupMenuActive = true;
664 }
665
666 void PartSet_SketcherMgr::onAfterContextMenu()
667 {
668   myIsPopupMenuActive = false;
669 }
670
671 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, 
672                                      Point& thePoint)
673 {
674   Handle(V3d_View) aView = theWnd->v3dView();
675   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
676   double aX, anY;
677   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, anY);
678   thePoint.setValue(aX, anY);
679 }
680
681 void PartSet_SketcherMgr::launchEditing()
682 {
683   if (!myCurrentSelection.empty()) {
684     FeaturePtr aFeature = myCurrentSelection.begin().key();
685     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
686               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
687     if (aSPFeature) {
688       myModule->editFeature(aSPFeature);
689     }
690   }
691 }
692
693 bool PartSet_SketcherMgr::sketchSolverError()
694 {
695   bool anError = false;
696   CompositeFeaturePtr aSketch = activeSketch();
697   if (aSketch.get()) {
698     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
699     anError = !aAttributeString->value().empty();
700   }
701   return anError;
702 }
703
704 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
705 {
706   QString anError = "";
707   if (!theFeature.get() || !theFeature->data()->isValid())
708     return anError;
709
710   CompositeFeaturePtr aSketch = activeSketch();
711   if (aSketch.get() && aSketch == theFeature) {
712     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
713     anError = aAttributeString->value().c_str();
714   }
715   return anError;
716 }
717
718 void PartSet_SketcherMgr::clearClickedFlags()
719 {
720   //myClickedPoint.clear();
721   myCurrentPoint.clear();
722 }
723
724 const QStringList& PartSet_SketcherMgr::sketchOperationIdList()
725 {
726   static QStringList aIds;
727   if (aIds.size() == 0) {
728     aIds << SketchPlugin_Line::ID().c_str();
729     aIds << SketchPlugin_Point::ID().c_str();
730     aIds << SketchPlugin_Arc::ID().c_str();
731     aIds << SketchPlugin_Circle::ID().c_str();
732     aIds << SketchPlugin_ConstraintFillet::ID().c_str();
733     aIds.append(constraintsIdList());
734   }
735   return aIds;
736 }
737
738 const QStringList& PartSet_SketcherMgr::constraintsIdList()
739 {
740   static QStringList aIds;
741   if (aIds.size() == 0) {
742     aIds << SketchPlugin_ConstraintLength::ID().c_str();
743     aIds << SketchPlugin_ConstraintDistance::ID().c_str();
744     aIds << SketchPlugin_ConstraintRigid::ID().c_str();
745     aIds << SketchPlugin_ConstraintRadius::ID().c_str();
746     aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
747     aIds << SketchPlugin_ConstraintParallel::ID().c_str();
748     aIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
749     aIds << SketchPlugin_ConstraintVertical::ID().c_str();
750     aIds << SketchPlugin_ConstraintEqual::ID().c_str();
751     aIds << SketchPlugin_ConstraintTangent::ID().c_str();
752     aIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
753     aIds << SketchPlugin_ConstraintMirror::ID().c_str();
754     aIds << SketchPlugin_ConstraintAngle::ID().c_str();
755     aIds << SketchPlugin_MultiRotation::ID().c_str();
756     aIds << SketchPlugin_MultiTranslation::ID().c_str();
757   }
758   return aIds;
759 }
760
761 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
762 {
763   theModes.clear();
764
765   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
766   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
767   theModes.append(SketcherPrs_Tools::Sel_Constraint);
768   theModes.append(TopAbs_VERTEX);
769   theModes.append(TopAbs_EDGE);
770 }
771
772 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
773 {
774   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
775 }
776
777 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation)
778 {
779   return theOperation &&
780          PartSet_SketcherMgr::sketchOperationIdList().contains(theOperation->id());
781 }
782
783 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation)
784 {
785   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
786                                                                (theOperation);
787   return aFOperation && !aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
788 }
789
790 bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation)
791 {
792   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
793                                                                (theOperation);
794   return aFOperation && aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
795 }
796
797 bool PartSet_SketcherMgr::isEntity(const std::string& theId)
798 {
799   return (theId == SketchPlugin_Line::ID()) ||
800          (theId == SketchPlugin_Point::ID()) ||
801          (theId == SketchPlugin_Arc::ID()) ||
802          (theId == SketchPlugin_Circle::ID());
803 }
804
805 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)
806 {
807   std::string anId = theOperation ? theOperation->id().toStdString() : "";
808
809   return isDistanceKind(anId);
810 }
811
812 bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)
813 {
814   return (theKind == SketchPlugin_ConstraintLength::ID()) ||
815          (theKind == SketchPlugin_ConstraintDistance::ID()) ||
816          (theKind == SketchPlugin_ConstraintRadius::ID()) ||
817          (theKind == SketchPlugin_ConstraintAngle::ID());
818 }
819
820 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
821 {
822   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
823                                                                (getCurrentOperation());
824   if (!aFOperation)
825     return;
826
827   myModule->onViewTransformed();
828
829   // Display all sketcher sub-Objects
830   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
831   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
832   aConnector->workshop()->displayer()->activateTrihedron(true);
833
834   // Hide sketcher result
835   std::list<ResultPtr> aResults = myCurrentSketch->results();
836   std::list<ResultPtr>::const_iterator aIt;
837   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
838     (*aIt)->setDisplayed(false);
839   }
840   myCurrentSketch->setDisplayed(false);
841
842   // Display sketcher objects
843   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
844     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
845     std::list<ResultPtr> aResults = aFeature->results();
846     std::list<ResultPtr>::const_iterator aIt;
847     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
848       (*aIt)->setDisplayed(true);
849     }
850     aFeature->setDisplayed(true);
851   }
852
853   if (myPlaneFilter.IsNull()) 
854     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
855
856   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
857
858   bool aHasPlane = false;
859   std::shared_ptr<GeomAPI_Pln> aPln;
860   if (aFOperation->isEditOperation()) {
861     // If it is editing of sketch then it means that plane is already defined
862     aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
863     if (aPln.get())
864       aHasPlane = true;
865   }
866   myPlaneFilter->setPlane(aPln);
867
868   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
869   // all sketch objects should be activated in the sketch selection modes by edit operation start
870   // in case of creation operation, there is an active widget, which activates own selection mode
871   if (aFOperation->isEditOperation() && aHasPlane)
872     aConnector->activateModuleSelectionModes();
873 }
874
875 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
876 {
877   myIsMouseOverWindow = false;
878   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
879   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
880
881   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
882
883   DataPtr aData = myCurrentSketch->data();
884   if (!aData->isValid()) {
885     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
886     // The sketch was aborted
887     myCurrentSketch = CompositeFeaturePtr();
888     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
889
890     // Erase all sketcher objects
891     QStringList aSketchIds = sketchOperationIdList();
892     QObjectPtrList aObjects = aDisplayer->displayedObjects();
893     foreach (ObjectPtr aObj, aObjects) {
894       DataPtr aObjData = aObj->data();
895       if (!aObjData->isValid())
896         aObj->setDisplayed(false);
897     }
898   }
899   else {
900     // Hide all sketcher sub-Objects
901     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
902       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
903       std::list<ResultPtr> aResults = aFeature->results();
904       std::list<ResultPtr>::const_iterator aIt;
905       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
906         (*aIt)->setDisplayed(false);
907       }
908       aFeature->setDisplayed(false);
909     }
910     // Display sketcher result
911     std::list<ResultPtr> aResults = myCurrentSketch->results();
912     std::list<ResultPtr>::const_iterator aIt;
913     Events_Loop* aLoop = Events_Loop::loop();
914     static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
915
916     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
917                                                                            (theOperation);
918     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
919       if (!aFOperation->isDisplayedOnStart(*aIt)) {
920         (*aIt)->setDisplayed(true);
921         // this display event is needed because sketch already may have "displayed" state,
922         // but not displayed while it is still active (issue 613, abort of existing sketch)
923         ModelAPI_EventCreator::get()->sendUpdated(*aIt, aDispEvent);
924       }
925     }
926     if (!aFOperation->isDisplayedOnStart(myCurrentSketch))
927       myCurrentSketch->setDisplayed(true);
928     
929     myCurrentSketch = CompositeFeaturePtr();
930     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
931
932     Events_Loop::loop()->flush(aDispEvent);
933   }
934   // restore the module selection modes, which were changed on startSketch
935   aConnector->activateModuleSelectionModes();
936   aConnector->workshop()->displayer()->activateTrihedron(false);
937 }
938
939 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
940 {
941   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
942     QCursor* aCurrentCursor = QApplication::overrideCursor();
943     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
944       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
945 #ifdef DEBUG_CURSOR
946       qDebug("startNestedSketch() : Qt::CrossCursor");
947 #endif
948     }
949   }
950 }
951
952 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
953 {
954   myIsMouseOverViewProcessed = true;
955   operationMgr()->onValidateOperation();
956   if (canChangeCursor(theOperation)) {
957     QApplication::restoreOverrideCursor();
958 #ifdef DEBUG_CURSOR
959     qDebug("stopNestedSketch() : None");
960 #endif
961   }
962 }
963
964 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
965 {
966   if (isNestedCreateOperation(theOperation)) {
967     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
968                                                                              (theOperation);
969     if (aFOperation) {
970       FeaturePtr aFeature = aFOperation->feature();
971       // it is necessary to check the the feature data validity because
972       // some kind of features are removed by an operation commit(the macro state of a feature)
973       if (aFeature.get() && aFeature->data()->isValid()) {
974         visualizeFeature(aFeature, aFOperation->isEditOperation(), true);
975       }
976     }
977   }
978 }
979
980 void PartSet_SketcherMgr::operationActivatedByPreselection()
981 {
982   ModuleBase_Operation* anOperation = getCurrentOperation();
983   if(anOperation && PartSet_SketcherMgr::isNestedSketchOperation(anOperation)) {
984     // Set final definitions if they are necessary
985     //propertyPanelDefined(aOperation);
986     /// Commit sketcher operations automatically
987     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
988                                                                             (anOperation);
989     if (aFOperation) {
990       if (PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {
991         FeaturePtr aFeature = aFOperation->feature();
992         // editor is shown only if all attribute references are filled by preseletion
993         bool anAllRefAttrInitialized = true;
994
995         std::list<AttributePtr> aRefAttrs = aFeature->data()->attributes(
996                                                     ModelAPI_AttributeRefAttr::typeId());
997         std::list<AttributePtr>::const_iterator anIt = aRefAttrs.begin(), aLast = aRefAttrs.end();
998         for (; anIt != aLast && anAllRefAttrInitialized; anIt++) {
999           anAllRefAttrInitialized = (*anIt)->isInitialized();
1000         }
1001         if (anAllRefAttrInitialized) {
1002           // Activate dimension value editing on double click
1003           ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
1004           QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
1005           // Find corresponded widget to activate value editing
1006           foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
1007             if (aWgt->attributeID() == "ConstraintValue") {
1008               // the featue should be displayed in order to find the AIS text position,
1009               // the place where the editor will be shown
1010               aFeature->setDisplayed(true);
1011               /// the execute is necessary to perform in the feature compute for flyout position
1012               aFeature->execute();
1013
1014               Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
1015               Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1016
1017               PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
1018               if (anEditor) {
1019                 int aX = 0, anY = 0;
1020
1021                 ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1022                 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1023                 XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1024                 AISObjectPtr anAIS = aDisplayer->getAISObject(aFeature);
1025                 Handle(AIS_InteractiveObject) anAISIO;
1026                 if (anAIS.get() != NULL) {
1027                   anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1028                 }
1029                 if (anAIS.get() != NULL) {
1030                   Handle(AIS_InteractiveObject) anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1031
1032                   if (!anAISIO.IsNull()) {
1033                     Handle(AIS_Dimension) aDim = Handle(AIS_Dimension)::DownCast(anAISIO);
1034                     if (!aDim.IsNull()) {
1035                       gp_Pnt aPosition = aDim->GetTextPosition();
1036
1037                       ModuleBase_IViewer* aViewer = aWorkshop->viewer();
1038                       Handle(V3d_View) aView = aViewer->activeView();
1039                       int aCX, aCY;
1040                       aView->Convert(aPosition.X(), aPosition.Y(), aPosition.Z(), aCX, aCY);
1041
1042                       QWidget* aViewPort = aViewer->activeViewPort();
1043                       QPoint aGlPoint = aViewPort->mapToGlobal(QPoint(aCX, aCY));
1044                       aX = aGlPoint.x();
1045                       anY = aGlPoint.y();
1046                     }
1047                   }
1048                   anEditor->setCursorPosition(aX, anY);
1049                   anEditor->showPopupEditor(false);
1050                 }
1051               }
1052             }
1053           }
1054         }
1055       }
1056     }
1057     anOperation->commit();
1058   }
1059 }
1060
1061 bool PartSet_SketcherMgr::canUndo() const
1062 {
1063   return isNestedCreateOperation(getCurrentOperation());
1064 }
1065
1066 bool PartSet_SketcherMgr::canRedo() const
1067 {
1068   return isNestedCreateOperation(getCurrentOperation());
1069 }
1070
1071 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const
1072 {
1073   bool aCanErase = true;
1074   // when the sketch operation is active, results of sketch sub-feature can not be hidden
1075   if (myCurrentSketch.get()) {
1076     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
1077     if (aResult.get()) {
1078       // Display sketcher objects
1079       for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {
1080
1081         FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1082         std::list<ResultPtr> aResults = aFeature->results();
1083         std::list<ResultPtr>::const_iterator anIt;
1084         for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {
1085           aCanErase = *anIt != aResult;
1086         }
1087       }
1088     }
1089   }
1090   return aCanErase;
1091 }
1092
1093 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
1094 {
1095   bool aCanDisplay = true;
1096
1097   bool aHasActiveSketch = activeSketch().get() != NULL;
1098   if (aHasActiveSketch) {
1099     // 1. the sketch feature should not be displayed during the sketch active operation
1100     // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch 
1101     // nested features can be visualized
1102     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1103     if (aFeature.get() != NULL && aFeature == activeSketch()) {
1104       aCanDisplay = false;
1105     }
1106   }
1107   else { // there are no an active sketch
1108     // 2. sketch sub-features should not be visualized if the sketch operation is not active
1109     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1110     if (aFeature.get() != NULL) {
1111       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1112                               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1113       if (aSketchFeature.get()) {
1114         aCanDisplay = false;
1115       }
1116     }
1117   }
1118
1119   // 3. the method should not filter the objects, which are not related to the current operation.
1120   // The object is filtered just if it is a current operation feature or this feature result
1121   bool isObjectFound = false;
1122   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1123                                                                (getCurrentOperation());
1124   if (aFOperation) {
1125     FeaturePtr aFeature = aFOperation->feature();
1126     if (aFeature.get()) {
1127       std::list<ResultPtr> aResults = aFeature->results();
1128       if (theObject == aFeature)
1129         isObjectFound = true;
1130       else {
1131         std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
1132         for (; anIt != aLast && !isObjectFound; anIt++) {
1133           isObjectFound = *anIt == theObject;
1134         }
1135       }
1136     }
1137   }
1138   if (!isObjectFound) 
1139     return aCanDisplay;
1140   
1141   // 4. For created nested feature operation do not display the created feature if
1142   // the mouse curstor leaves the OCC window.
1143   // The correction cases, which ignores this condition:
1144   // a. the property panel values modification
1145   // b. the popup menu activated
1146   // c. widget editor control
1147   #ifndef DEBUG_DO_NOT_BY_ENTER
1148   if (aCanDisplay && isNestedCreateOperation(getCurrentOperation())) {
1149     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1150     ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
1151     // the active widget editor should not influence here. The presentation should be visible always
1152     // when this widget is active.
1153     if (!anEditorWdg && !myIsPopupMenuActive) {
1154       // during a nested create operation, the feature is redisplayed only if the mouse over view
1155       // of there was a value modified in the property panel after the mouse left the view
1156       aCanDisplay = canDisplayCurrentCreatedFeature();
1157     }
1158   }
1159   #endif
1160   return aCanDisplay;
1161 }
1162
1163 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
1164 {
1165   bool aCanDisplay = myIsMouseOverWindow;
1166   if (!aCanDisplay) {
1167     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1168     if (anActiveWidget)
1169       aCanDisplay = anActiveWidget->getValueState() == ModuleBase_ModelWidget::Stored;
1170   }
1171   return aCanDisplay;
1172 }
1173
1174 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const
1175 {
1176   return isNestedCreateOperation(theOperation) ||
1177          myModule->sketchReentranceMgr()->isInternalEditActive();
1178 }
1179
1180 const QMap<PartSet_Tools::ConstraintVisibleState, bool>& PartSet_SketcherMgr::showConstraintStates()
1181 {
1182   return myIsConstraintsShown;
1183 }
1184
1185 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
1186 {
1187   bool isFoundObject = false;
1188
1189   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
1190   if (anObjectFeature.get()) {
1191     int aSize = myCurrentSketch->numberOfSubs();
1192     for (int i = 0; i < myCurrentSketch->numberOfSubs() && !isFoundObject; i++) {
1193       FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);
1194       isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;
1195     }
1196   }
1197   return isFoundObject;
1198 }
1199
1200 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
1201 {
1202   if (myPlaneFilter.IsNull()) 
1203    myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
1204
1205   myPlaneFilter->setPlane(thePln);
1206 }
1207
1208 void PartSet_SketcherMgr::getCurrentSelection(const FeaturePtr& theFeature,
1209                                               const FeaturePtr& theSketch,
1210                                               ModuleBase_IWorkshop* theWorkshop,
1211                                               FeatureToSelectionMap& theSelection)
1212 {
1213   if (theFeature.get() == NULL)
1214     return;
1215
1216   std::set<AttributePtr> aSelectedAttributes;
1217   std::set<ResultPtr> aSelectedResults;
1218
1219   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1220   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
1221   if (!aContext.IsNull()) {
1222     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1223     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1224
1225     std::list<ResultPtr> aResults = theFeature->results();
1226     std::list<ResultPtr>::const_iterator aIt;
1227     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
1228     {
1229       ResultPtr aResult = *aIt;
1230       AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1231       if (aAISObj.get() == NULL)
1232         continue;
1233       Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1234       for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
1235       {
1236         Handle(SelectMgr_EntityOwner) anOwner = aContext->SelectedOwner();
1237         if (anOwner->Selectable() != anAISIO)
1238           continue;
1239         getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
1240                                aSelectedAttributes, aSelectedResults);
1241       }
1242       for (aContext->InitDetected(); aContext->MoreDetected(); aContext->NextDetected()) {
1243         Handle(SelectMgr_EntityOwner) anOwner = aContext->DetectedOwner();
1244         if (anOwner.IsNull())
1245           continue;
1246         if (anOwner->Selectable() != anAISIO)
1247           continue;
1248         getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
1249                                aSelectedAttributes, aSelectedResults);
1250       }
1251     }
1252   }
1253   theSelection[theFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);
1254 }
1255
1256 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,
1257                                              const FeaturePtr& theSketch,
1258                                              ModuleBase_IWorkshop* theWorkshop,
1259                                              const FeatureToSelectionMap& theSelection,
1260                                              SelectMgr_IndexedMapOfOwner& theOwnersToSelect)
1261 {
1262   if (theFeature.get() == NULL)
1263     return;
1264
1265   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
1266   std::set<AttributePtr> aSelectedAttributes = anIt.value().first;
1267   std::set<ResultPtr> aSelectedResults = anIt.value().second;
1268
1269   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1270
1271   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1272   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1273
1274   // 1. found the feature's owners. Check the AIS objects of the constructions
1275   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);
1276   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {
1277     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1278
1279     SelectMgr_IndexedMapOfOwner aSelectedOwners;
1280     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1281     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
1282       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
1283       if (!anOwner.IsNull())
1284         theOwnersToSelect.Add(anOwner);
1285     }
1286   }
1287
1288   // 2. found the feature results's owners
1289   std::list<ResultPtr> aResults = theFeature->results();
1290   std::list<ResultPtr>::const_iterator aIt;
1291   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
1292   {
1293     ResultPtr aResult = *aIt;
1294     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1295     if (aAISObj.get() == NULL)
1296       continue; 
1297     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1298
1299     SelectMgr_IndexedMapOfOwner aSelectedOwners;  
1300     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1301     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
1302       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
1303       if ( anOwner.IsNull() || !anOwner->HasShape() )
1304         continue;
1305       const TopoDS_Shape& aShape = anOwner->Shape();
1306       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
1307       if (aShapeType == TopAbs_VERTEX) {
1308         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
1309         if (aPntAttr.get() != NULL &&
1310             aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end()) {
1311           theOwnersToSelect.Add(anOwner);
1312         }
1313       }
1314       else if (aShapeType == TopAbs_EDGE) {
1315         bool aFound = aSelectedResults.find(aResult) != aSelectedResults.end();
1316         if (aSelectedResults.find(aResult) != aSelectedResults.end() &&
1317             theOwnersToSelect.FindIndex(anOwner) <= 0)
1318           theOwnersToSelect.Add(anOwner);
1319       }
1320     }
1321   }
1322 }
1323
1324 void PartSet_SketcherMgr::connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect)
1325 {
1326   if (isToConnect) {
1327     connect(theWidget, SIGNAL(beforeValuesChanged()),
1328             this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1329     connect(theWidget, SIGNAL(afterValuesChanged()),
1330             this, SLOT(onAfterValuesChangedInPropertyPanel()));
1331   }
1332   else {
1333     disconnect(theWidget, SIGNAL(beforeValuesChanged()),
1334                 this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1335     disconnect(theWidget, SIGNAL(afterValuesChanged()),
1336                 this, SLOT(onAfterValuesChangedInPropertyPanel()));
1337   }
1338 }
1339
1340 void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
1341 {
1342   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1343                                                                            (getCurrentOperation());
1344   if (aFOperation) {
1345     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
1346         PartSet_SketcherMgr::isNestedSketchOperation(aFOperation) &&
1347         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {
1348       FeaturePtr aFeature = aFOperation->feature();
1349       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
1350     }
1351   }
1352 }
1353
1354 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
1355 {
1356   return myModule->workshop()->currentOperation();
1357 }
1358
1359 //**************************************************************
1360 ModuleBase_ModelWidget* PartSet_SketcherMgr::getActiveWidget() const
1361 {
1362   ModuleBase_ModelWidget* aWidget = 0;
1363   ModuleBase_Operation* anOperation = getCurrentOperation();
1364   if (anOperation) {
1365     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
1366     if (aPanel)
1367       aWidget = aPanel->activeWidget();
1368   }
1369   return aWidget;
1370 }
1371
1372 void PartSet_SketcherMgr::visualizeFeature(const FeaturePtr& theFeature,
1373                                            const bool isEditOperation,
1374                                            const bool isToDisplay,
1375                                            const bool isFlushRedisplay)
1376 {
1377   #ifdef DEBUG_DO_NOT_BY_ENTER
1378   return;
1379   #endif
1380
1381   if (isEditOperation || !theFeature.get())
1382     return;
1383
1384   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1385   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1386
1387   // 1. change visibility of the object itself, here the presentable object is processed,
1388   // e.g. constraints features
1389   //FeaturePtr aFeature = aFOperation->feature();
1390   std::list<ResultPtr> aResults = theFeature->results();
1391   if (isToDisplay)
1392     theFeature->setDisplayed(true);
1393   else
1394     theFeature->setDisplayed(false);
1395
1396   // change visibility of the object results, e.g. non-constraint features
1397   std::list<ResultPtr>::const_iterator aIt;
1398   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1399     if (isToDisplay) {
1400       (*aIt)->setDisplayed(true);
1401     }
1402     else {
1403       (*aIt)->setDisplayed(false);
1404     }
1405   }
1406   if (isFlushRedisplay)
1407     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1408 }
1409
1410 void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
1411 {
1412   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1413   ModuleBase_ISelection* aSelect = aWorkshop->selection();
1414   QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
1415
1416   QList<FeaturePtr> aFeatureList;
1417   if (theHighlightedOnly) {
1418     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
1419   }
1420   else {
1421     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
1422
1423     QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected(ModuleBase_ISelection::AllControls);
1424     fillFeatureList(aSelected, myCurrentSketch, aFeatureList);
1425   }
1426
1427   // 1. it is necessary to save current selection in order to restore it after the features moving
1428   myCurrentSelection.clear();
1429   QList<FeaturePtr>::const_iterator anIt = aFeatureList.begin(), aLast = aFeatureList.end();
1430   for (; anIt != aLast; anIt++) {
1431     getCurrentSelection(*anIt, myCurrentSketch, aWorkshop, myCurrentSelection);
1432   }
1433   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1434 }
1435
1436 void PartSet_SketcherMgr::restoreSelection()
1437 {
1438   //qDebug(QString("restoreSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1439   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1440   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1441   FeatureToSelectionMap::const_iterator aSIt = myCurrentSelection.begin(),
1442                                         aSLast = myCurrentSelection.end();
1443   SelectMgr_IndexedMapOfOwner anOwnersToSelect;
1444   for (; aSIt != aSLast; aSIt++) {
1445     anOwnersToSelect.Clear();
1446     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, myCurrentSelection,
1447                         anOwnersToSelect);
1448     aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);
1449   }
1450 }
1451
1452 void PartSet_SketcherMgr::onShowConstraintsToggle(bool theState, int theType)
1453 {
1454   PartSet_Tools::ConstraintVisibleState aType = (PartSet_Tools::ConstraintVisibleState)theType;
1455   if (myIsConstraintsShown.contains(aType) && myIsConstraintsShown[aType] == theState)
1456     return;
1457   if (myCurrentSketch.get() == NULL)
1458     return;
1459
1460   myIsConstraintsShown[aType] = theState;
1461
1462   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1463   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1464
1465   const QStringList& aConstrIds = constraintsIdList();
1466   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
1467     FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
1468     std::string aKind = aSubFeature->getKind();
1469     if (aConstrIds.contains(QString(aKind.c_str()))) {
1470       bool isTypedConstraint = false;
1471       if (aType == PartSet_Tools::Dimensional) {
1472         isTypedConstraint = isDistanceKind(aKind);
1473       }
1474       else
1475         isTypedConstraint = !isDistanceKind(aKind);
1476
1477       if (isTypedConstraint) {
1478         if (theState)
1479           aSubFeature->setDisplayed(true);
1480         else
1481           aSubFeature->setDisplayed(false);
1482       }
1483     }
1484   }
1485   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1486 }
1487
1488 XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const
1489 {
1490   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
1491   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
1492   XGUI_Workshop* aWorkshop = aConnector->workshop();
1493
1494   return aWorkshop->operationMgr();
1495 }
1496