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