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