Salome HOME
Feature selector widget for recover feature.
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D\r
2 \r
3 // File:        PartSet_SketcherMgr.cpp\r
4 // Created:     19 Dec 2014\r
5 // Author:      Vitaly SMETANNIKOV\r
6 \r
7 #include "PartSet_SketcherMgr.h"\r
8 #include "PartSet_SketcherReetntrantMgr.h"\r
9 #include "PartSet_Module.h"\r
10 #include "PartSet_MouseProcessor.h"\r
11 #include "PartSet_Tools.h"\r
12 #include "PartSet_WidgetSketchLabel.h"\r
13 #include "PartSet_WidgetEditor.h"\r
14 #include "PartSet_ResultSketchPrs.h"\r
15 \r
16 #include <XGUI_ModuleConnector.h>\r
17 #include <XGUI_Displayer.h>\r
18 #include <XGUI_Workshop.h>\r
19 #include <XGUI_ContextMenuMgr.h>\r
20 #include <XGUI_Selection.h>\r
21 #include <XGUI_SelectionMgr.h>\r
22 #include <XGUI_ModuleConnector.h>\r
23 #include <XGUI_PropertyPanel.h>\r
24 #include <XGUI_ViewerProxy.h>\r
25 #include <XGUI_OperationMgr.h>\r
26 #include <XGUI_ErrorMgr.h>\r
27 #include <XGUI_Tools.h>\r
28 \r
29 #include <ModuleBase_IPropertyPanel.h>\r
30 #include <ModuleBase_ISelection.h>\r
31 #include <ModuleBase_IViewer.h>\r
32 #include <ModuleBase_IWorkshop.h>\r
33 #include <ModuleBase_IViewWindow.h>\r
34 #include <ModuleBase_ModelWidget.h>\r
35 #include <ModuleBase_Operation.h>\r
36 #include <ModuleBase_OperationFeature.h>\r
37 #include <ModuleBase_Operation.h>\r
38 #include <ModuleBase_WidgetEditor.h>\r
39 #include <ModuleBase_ViewerPrs.h>\r
40 #include <ModuleBase_Tools.h>\r
41 #include <ModuleBase_ResultPrs.h>\r
42 \r
43 #include <GeomDataAPI_Point2D.h>\r
44 \r
45 #include <Events_Loop.h>\r
46 \r
47 #include <SketchPlugin_Line.h>\r
48 #include <SketchPlugin_Sketch.h>\r
49 #include <SketchPlugin_Point.h>\r
50 #include <SketchPlugin_Arc.h>\r
51 #include <SketchPlugin_Circle.h>\r
52 #include <SketchPlugin_ConstraintLength.h>\r
53 #include <SketchPlugin_ConstraintDistance.h>\r
54 #include <SketchPlugin_ConstraintParallel.h>\r
55 #include <SketchPlugin_ConstraintPerpendicular.h>\r
56 #include <SketchPlugin_ConstraintRadius.h>\r
57 #include <SketchPlugin_ConstraintRigid.h>\r
58 #include <SketchPlugin_ConstraintHorizontal.h>\r
59 #include <SketchPlugin_ConstraintVertical.h>\r
60 #include <SketchPlugin_ConstraintEqual.h>\r
61 #include <SketchPlugin_ConstraintTangent.h>\r
62 #include <SketchPlugin_ConstraintCoincidence.h>\r
63 #include <SketchPlugin_ConstraintFillet.h>\r
64 #include <SketchPlugin_ConstraintMirror.h>\r
65 #include <SketchPlugin_ConstraintAngle.h>\r
66 #include <SketchPlugin_ConstraintCollinear.h>\r
67 #include <SketchPlugin_ConstraintMiddle.h>\r
68 #include <SketchPlugin_MultiRotation.h>\r
69 #include <SketchPlugin_MultiTranslation.h>\r
70 #include <SketchPlugin_IntersectionPoint.h>\r
71 \r
72 #include <SketcherPrs_Tools.h>\r
73 \r
74 #include <SelectMgr_IndexedMapOfOwner.hxx>\r
75 #include <StdSelect_BRepOwner.hxx>\r
76 \r
77 //#include <AIS_DimensionSelectionMode.hxx>\r
78 #include <AIS_Shape.hxx>\r
79 #include <AIS_Dimension.hxx>\r
80 \r
81 #include <ModelAPI_Events.h>\r
82 #include <ModelAPI_Session.h>\r
83 #include <ModelAPI_AttributeString.h>\r
84 \r
85 #include <ModelAPI_Validator.h>\r
86 #include <ModelAPI_Tools.h>\r
87 \r
88 #include <QMouseEvent>\r
89 #include <QApplication>\r
90 #include <QCursor>\r
91 #include <QMessageBox>\r
92 #include <QMainWindow>\r
93 \r
94 //#define DEBUG_DO_NOT_BY_ENTER\r
95 //#define DEBUG_SKETCHER_ENTITIES\r
96 //#define DEBUG_SKETCH_ENTITIES_ON_MOVE\r
97 \r
98 //#define DEBUG_CURSOR\r
99 \r
100 /// Fills attribute and result lists by the selected owner. In case if the attribute is found,\r
101 /// by the owner shape, it is put to the list. Otherwise if type of owner shape is edge, put the function\r
102 /// result as is to the list of results.\r
103 /// \param theOwner a viewer selected owner\r
104 /// \param theFeature a feature, where the attribute is searched\r
105 /// \param theSketch a current sketch\r
106 /// \param theSelectedAttribute an output list of attributes\r
107 /// \param theSelectedResults an output list of edge results\r
108 void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,\r
109                             const FeaturePtr& theFeature, const FeaturePtr& theSketch,\r
110                             const ResultPtr& theResult,\r
111                             std::set<AttributePtr>& aSelectedAttributes,\r
112                             std::set<ResultPtr>& aSelectedResults)\r
113 {\r
114   Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(theOwner);\r
115   if (aBRepOwner.IsNull())\r
116     return;\r
117   Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast(\r
118                                                                     aBRepOwner->Selectable());\r
119   if (aBRepOwner->HasShape()) {\r
120     const TopoDS_Shape& aShape = aBRepOwner->Shape();\r
121     TopAbs_ShapeEnum aShapeType = aShape.ShapeType();\r
122     if (aShapeType == TopAbs_VERTEX) {\r
123       AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,\r
124                                                                     aShape, theSketch);\r
125       if (aPntAttr.get() != NULL)\r
126         aSelectedAttributes.insert(aPntAttr);\r
127     }\r
128     else if (aShapeType == TopAbs_EDGE &&\r
129              aSelectedResults.find(theResult) == aSelectedResults.end()) {\r
130       aSelectedResults.insert(theResult);\r
131     }\r
132   }\r
133 }\r
134 \r
135 PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)\r
136   : QObject(theModule), myModule(theModule), myIsDragging(false), myDragDone(false),\r
137     myIsMouseOverWindow(false),\r
138     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),\r
139     myIsPopupMenuActive(false)\r
140 {\r
141   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();\r
142   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();\r
143 \r
144   myPreviousDrawModeEnabled = true;//aViewer->isSelectionEnabled();\r
145 \r
146   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),\r
147           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));\r
148 \r
149   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),\r
150           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));\r
151 \r
152   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),\r
153           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));\r
154 \r
155   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),\r
156           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));\r
157 \r
158   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);\r
159   XGUI_Workshop* aWorkshop = aConnector->workshop();\r
160   connect(aWorkshop, SIGNAL(applicationStarted()), this, SLOT(onApplicationStarted()));\r
161 \r
162   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;\r
163   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;\r
164   myIsConstraintsShown[PartSet_Tools::Expressions] = false;\r
165 }\r
166 \r
167 PartSet_SketcherMgr::~PartSet_SketcherMgr()\r
168 {\r
169   if (!myPlaneFilter.IsNull())\r
170     myPlaneFilter.Nullify();\r
171 }\r
172 \r
173 void PartSet_SketcherMgr::onEnterViewPort()\r
174 {\r
175   // 1. if the mouse over window, update the next flag. Do not perform update visibility of\r
176   // created feature because it should be done in onMouseMove(). Some widgets watch\r
177   // the mouse move and use the cursor position to update own values. If the presentaion is\r
178   // redisplayed before this update, the feature presentation jumps from reset value to current.\r
179   myIsMouseOverWindow = true;\r
180 \r
181   #ifdef DEBUG_DO_NOT_BY_ENTER\r
182   return;\r
183   #endif\r
184 \r
185   if (canChangeCursor(getCurrentOperation())) {\r
186     QCursor* aCurrentCursor = QApplication::overrideCursor();\r
187     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {\r
188       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));\r
189 #ifdef DEBUG_CURSOR\r
190       qDebug("onEnterViewPort() : Qt::CrossCursor");\r
191 #endif\r
192     }\r
193   }\r
194 \r
195   if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))\r
196     return;\r
197 \r
198   operationMgr()->onValidateOperation();\r
199 \r
200   // we need change displayed state of the current operation feature\r
201   // if the feature is presentable, e.g. distance construction. It has no results, so workshop does\r
202   // not accept a signal about the result created. Nothing is shown until mouse is moved out/in view\r
203   // port. If the isDisplayed flag is true, the presentable feature is displayed as soon as the\r
204   // presentation becomes valid and redisplay happens\r
205   //ModuleBase_Operation* aOperation = getCurrentOperation();\r
206   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
207                                                                            (getCurrentOperation());\r
208   if (aFOperation) {\r
209     FeaturePtr aFeature = aFOperation->feature();\r
210     if (aFeature.get() && aFeature->data()->isValid()) {\r
211       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature), false);\r
212     }\r
213   }\r
214 }\r
215 \r
216 void PartSet_SketcherMgr::onLeaveViewPort()\r
217 {\r
218   myIsMouseOverViewProcessed = false;\r
219   myIsMouseOverWindow = false;\r
220 \r
221   #ifdef DEBUG_DO_NOT_BY_ENTER\r
222   return;\r
223   #endif\r
224 \r
225   if (canChangeCursor(getCurrentOperation())) {\r
226     QApplication::restoreOverrideCursor();\r
227 #ifdef DEBUG_CURSOR\r
228     qDebug("onLeaveViewPort() : None");\r
229 #endif\r
230   }\r
231 \r
232   if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))\r
233     return;\r
234 \r
235   // the method should be performed if the popup menu is called,\r
236   // the reset of the current widget should not happen\r
237   if (myIsPopupMenuActive)\r
238     return;\r
239 \r
240   // it is important to validate operation here only if sketch entity create operation is active\r
241   // because at this operation we reacts to the mouse leave/enter view port\r
242   operationMgr()->onValidateOperation();\r
243 \r
244   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation\r
245   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
246   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
247   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
248   // disable the viewer update in order to avoid visualization of redisplayed feature in viewer\r
249   // obtained after reset value\r
250   bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);\r
251   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
252   if (anActiveWidget)\r
253     anActiveWidget->reset();\r
254 \r
255   // hides the presentation of the current operation feature\r
256   // the feature is to be erased here, but it is correct to call canDisplayObject because\r
257   // there can be additional check (e.g. editor widget in distance constraint)\r
258   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
259                                                                            (getCurrentOperation());\r
260   if (aFOperation) {\r
261     FeaturePtr aFeature = aFOperation->feature();\r
262     visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));\r
263   }\r
264   // we should update viewer after the presentation are hidden in the viewer\r
265   // otherwise the reset presentation(line) appears in the viewer(by quick move from viewer to PP)\r
266   aDisplayer->enableUpdateViewer(isEnableUpdateViewer);\r
267 }\r
268 \r
269 void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()\r
270 {\r
271   if (!isNestedEditOperation(getCurrentOperation(), myModule->sketchMgr()->activeSketch()) ||\r
272       myModule->sketchReentranceMgr()->isInternalEditActive())\r
273     return;\r
274   // it is necessary to save current selection in order to restore it after the values are modifed\r
275   storeSelection();\r
276 \r
277   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
278   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
279   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
280   myPreviousUpdateViewerEnabled = aDisplayer->enableUpdateViewer(false);\r
281 }\r
282 \r
283 void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()\r
284 {\r
285   if (!isNestedEditOperation(getCurrentOperation(), myModule->sketchMgr()->activeSketch()) ||\r
286       myModule->sketchReentranceMgr()->isInternalEditActive()) {\r
287     myModule->sketchReentranceMgr()->updateInternalEditActiveState();\r
288     return;\r
289   }\r
290   // it is necessary to restore current selection in order to restore it after the values are modified\r
291   restoreSelection();\r
292   myCurrentSelection.clear();\r
293 \r
294   // 3. the flag to disable the update viewer should be set in order to avoid blinking in the \r
295   // viewer happens by deselect/select the modified objects. The flag should be restored after\r
296   // the selection processing. The update viewer should be also called.\r
297   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
298   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
299   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
300   aDisplayer->enableUpdateViewer(myPreviousUpdateViewerEnabled);\r
301   aDisplayer->updateViewer();\r
302 \r
303 \r
304 }\r
305 \r
306 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)\r
307 {\r
308   if (myModule->sketchReentranceMgr()->processMousePressed(theWnd, theEvent))\r
309     return;\r
310 \r
311   //get2dPoint(theWnd, theEvent, myClickedPoint);\r
312 \r
313   if (!(theEvent->buttons() & Qt::LeftButton))\r
314     return;\r
315 \r
316   // Clear dragging mode\r
317   myIsDragging = false;\r
318 \r
319   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
320   ModuleBase_IViewer* aViewer = aWorkshop->viewer();\r
321   if (!aViewer->canDragByMouse())\r
322     return;\r
323 \r
324   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
325                                                                (getCurrentOperation());\r
326   if (!aFOperation)\r
327     return;\r
328 \r
329   if (aFOperation->isEditOperation()) {\r
330     // If the current widget is a selector, do nothing, it processes the mouse press\r
331     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
332     if(anActiveWidget && anActiveWidget->isViewerSelector()) {\r
333       return;\r
334     }\r
335   }\r
336 \r
337   // Use only for sketch operations\r
338   if (myCurrentSketch) {\r
339     if (!PartSet_Tools::sketchPlane(myCurrentSketch))\r
340       return;\r
341 \r
342     bool isSketcher = isSketchOperation(aFOperation);\r
343     bool isSketchOpe = isNestedSketchOperation(aFOperation);\r
344 \r
345     // Avoid non-sketch operations\r
346     if ((!isSketchOpe) && (!isSketcher))\r
347       return;\r
348 \r
349     bool isEditing = aFOperation->isEditOperation();\r
350 \r
351     // Ignore creation sketch operation\r
352     if ((!isSketcher) && (!isEditing))\r
353       return;\r
354 \r
355     Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();\r
356     // Remember highlighted objects for editing\r
357     ModuleBase_ISelection* aSelect = aWorkshop->selection();\r
358 \r
359     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);\r
360     storeSelection(!aHasShift);\r
361 \r
362     if (myCurrentSelection.empty()) {\r
363       if (isSketchOpe && (!isSketcher))\r
364         // commit previous operation\r
365         if (!aFOperation->commit())\r
366           aFOperation->abort();\r
367       return;\r
368     }\r
369     // Init flyout point for radius rotation\r
370     FeaturePtr aFeature = myCurrentSelection.begin().key();\r
371 \r
372     if (isSketcher) {\r
373       myIsDragging = true;\r
374       get2dPoint(theWnd, theEvent, myCurrentPoint);\r
375       myDragDone = false;\r
376 \r
377       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);\r
378       // selection should be restored before edit operation start to process the\r
379       // selected entities, e.g. selection of point(attribute on a line) should edit the point\r
380       restoreSelection();\r
381       launchEditing();\r
382       if (aFeature.get() != NULL) {\r
383         std::shared_ptr<SketchPlugin_Feature> aSPFeature = \r
384                   std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
385       if (aSPFeature.get() && aSPFeature->getKind() == SketchPlugin_ConstraintRadius::ID()) {\r
386           DataPtr aData = aSPFeature->data();\r
387           AttributePtr aAttr = aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());\r
388           std::shared_ptr<GeomDataAPI_Point2D> aFPAttr = \r
389             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aAttr);\r
390           aFPAttr->setValue(myCurrentPoint.myCurX, myCurrentPoint.myCurY);\r
391         }\r
392       }\r
393     } else if (isSketchOpe && isEditing) {\r
394       // If selected another object commit current result\r
395       aFOperation->commit();\r
396 \r
397       myIsDragging = true;\r
398       get2dPoint(theWnd, theEvent, myCurrentPoint);\r
399       myDragDone = false;\r
400 \r
401       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);\r
402       // selection should be restored before edit operation start to process the\r
403       // selected entities, e.g. selection of point(attribute on a line) should edit the point\r
404       restoreSelection();\r
405       launchEditing();\r
406       restoreSelection();\r
407     }\r
408   }\r
409 }\r
410 \r
411 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)\r
412 {\r
413   if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))\r
414     return;\r
415 \r
416   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
417   ModuleBase_IViewer* aViewer = aWorkshop->viewer();\r
418   if (!aViewer->canDragByMouse())\r
419     return;\r
420   ModuleBase_Operation* aOp = getCurrentOperation();\r
421   if (aOp) {\r
422     if (isNestedSketchOperation(aOp)) {\r
423       // Only for sketcher operations\r
424       if (myIsDragging) {\r
425         if (myDragDone) {\r
426           myCurrentSelection.clear();\r
427         }\r
428       }\r
429     }\r
430   }\r
431 \r
432   aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);\r
433   myIsDragging = false;\r
434 \r
435   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
436   PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);\r
437   if (aProcessor)\r
438     aProcessor->mouseReleased(theWnd, theEvent);\r
439 }\r
440 \r
441 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)\r
442 {\r
443 #ifdef DEBUG_SKETCH_ENTITIES_ON_MOVE\r
444   CompositeFeaturePtr aSketch = activeSketch();\r
445   if (aSketch.get()) {\r
446     std::cout << "mouse move SKETCH FEATURES [" << aSketch->numberOfSubs() << "]:" << std::endl;\r
447     QStringList anInfo;\r
448     for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {\r
449       //std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;\r
450       anInfo.append(ModuleBase_Tools::objectInfo(aSketch->subFeature(i)));\r
451     }\r
452     QString anInfoStr = anInfo.join("\n");\r
453     qDebug(QString("%1").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());\r
454   }\r
455 #endif\r
456 \r
457   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))\r
458     return;\r
459 \r
460   if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {\r
461     // 1. perform the widget mouse move functionality and display the presentation\r
462     // the mouse move should be processed in the widget, if it can in order to visualize correct\r
463     // presentation. These widgets correct the feature attribute according to the mouse position\r
464     ModuleBase_ModelWidget* anActiveWidget = myModule->activeWidget();\r
465     PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);\r
466     if (aProcessor)\r
467       aProcessor->mouseMoved(theWnd, theEvent);\r
468     if (!myIsMouseOverViewProcessed) {\r
469       myIsMouseOverViewProcessed = true;\r
470 \r
471       // the feature is to be erased here, but it is correct to call canDisplayObject because\r
472       // there can be additional check (e.g. editor widget in distance constraint)\r
473       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
474                                                                                (getCurrentOperation());\r
475       if (aFOperation) {\r
476         FeaturePtr aFeature = aFOperation->feature();\r
477         visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));\r
478       }\r
479     }\r
480   }\r
481   //myClickedPoint.clear();\r
482 \r
483   if (myIsDragging) {\r
484     // 1. the current selection is saved in the mouse press method in order to restore it after moving\r
485     // 2. the enable selection in the viewer should be temporary switched off in order to ignore\r
486     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are\r
487     // deselected). This flag should be restored in the slot, processed the mouse release signal.\r
488 \r
489     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();\r
490     if (!aCurrentOperation)\r
491       return;\r
492     if (isSketchOperation(aCurrentOperation))\r
493       return; // No edit operation activated\r
494 \r
495     Handle(V3d_View) aView = theWnd->v3dView();\r
496     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);\r
497     double aX, aY;\r
498     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);\r
499     double dX =  aX - myCurrentPoint.myCurX;\r
500     double dY =  aY - myCurrentPoint.myCurY;\r
501 \r
502     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
503     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
504     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
505     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the \r
506     // viewer happens by deselect/select the modified objects. The flag should be restored after\r
507     // the selection processing. The update viewer should be also called.\r
508     bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);\r
509 \r
510     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);\r
511     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);\r
512     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),\r
513                                           aLast = myCurrentSelection.end();\r
514     // 4. the features and attributes modification(move)\r
515     bool isModified = false;\r
516     for (; anIt != aLast; anIt++) {\r
517       FeaturePtr aFeature = anIt.key();\r
518 \r
519       std::set<AttributePtr> anAttributes = anIt.value().first;\r
520       // Process selection by attribute: the priority to the attribute\r
521       if (!anAttributes.empty()) {\r
522         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),\r
523                                                anAttLast = anAttributes.end();\r
524         for (; anAttIt != anAttLast; anAttIt++) {\r
525           AttributePtr anAttr = *anAttIt;\r
526           if (anAttr.get() == NULL)\r
527             continue;\r
528           std::string aAttrId = anAttr->id();\r
529           DataPtr aData = aFeature->data();\r
530           if (aData->isValid()) {\r
531             std::shared_ptr<GeomDataAPI_Point2D> aPoint = \r
532               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));\r
533             if (aPoint.get() != NULL) {\r
534               bool isImmutable = aPoint->setImmutable(true);\r
535               aPoint->move(dX, dY);\r
536               isModified = true;\r
537               ModelAPI_EventCreator::get()->sendUpdated(aFeature, aMoveEvent);\r
538               aPoint->setImmutable(isImmutable);\r
539             }\r
540           }\r
541         }\r
542       } else {\r
543         // Process selection by feature\r
544         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =\r
545           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
546         if (aSketchFeature) {\r
547           aSketchFeature->move(dX, dY);\r
548           isModified = true;\r
549           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, aMoveEvent);\r
550         }\r
551       }\r
552     }\r
553     // the modified state of the current operation should be updated if there are features, which\r
554     // were changed here\r
555     if (isModified) {\r
556       aCurrentOperation->onValuesChanged();\r
557     }\r
558     Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver\r
559     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations\r
560 \r
561     // 5. it is necessary to save current selection in order to restore it after the features moving\r
562     restoreSelection();\r
563     // 6. restore the update viewer flag and call this update\r
564     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);\r
565     aDisplayer->updateViewer();\r
566 \r
567     myDragDone = true;\r
568     myCurrentPoint.setValue(aX, aY);\r
569   }\r
570 }\r
571 \r
572 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)\r
573 {\r
574   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
575                                                                (getCurrentOperation());\r
576   if (aFOperation && aFOperation->isEditOperation()) {\r
577     std::string aId = aFOperation->id().toStdString();\r
578     if (isDistanceOperation(aFOperation))\r
579     {\r
580       // Activate dimension value editing on double click\r
581       ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();\r
582       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();\r
583       // Find corresponded widget to activate value editing\r
584       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {\r
585         if (aWgt->attributeID() == SketchPlugin_Constraint::VALUE() ||\r
586             aWgt->attributeID() == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) {\r
587           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);\r
588           if (anEditor)\r
589             anEditor->showPopupEditor();\r
590           return;\r
591         }\r
592       }\r
593     }\r
594   }\r
595 }\r
596 \r
597 void PartSet_SketcherMgr::onApplicationStarted()\r
598 {\r
599   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();\r
600   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);\r
601   XGUI_Workshop* aWorkshop = aConnector->workshop();\r
602   PartSet_SketcherReetntrantMgr* aReentranceMgr = myModule->sketchReentranceMgr();\r
603 \r
604   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();\r
605   if (aPropertyPanel) {\r
606     //connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),\r
607     //        this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));\r
608 \r
609     connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),\r
610             aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));\r
611     connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),\r
612             aReentranceMgr, SLOT(onWidgetActivated()));\r
613   }\r
614 \r
615   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();\r
616   connect(aViewerProxy, SIGNAL(enterViewPort()), this, SLOT(onEnterViewPort()));\r
617   connect(aViewerProxy, SIGNAL(leaveViewPort()), this, SLOT(onLeaveViewPort()));\r
618 \r
619   XGUI_ContextMenuMgr* aContextMenuMgr = aWorkshop->contextMenuMgr();\r
620   connect(aContextMenuMgr, SIGNAL(beforeContextMenu()), this, SLOT(onBeforeContextMenu()));\r
621   connect(aContextMenuMgr, SIGNAL(afterContextMenu()), this, SLOT(onAfterContextMenu()));\r
622 }\r
623 \r
624 //void PartSet_SketcherMgr::onBeforeWidgetActivated(ModuleBase_ModelWidget* theWidget)\r
625 //{\r
626   //if (!myClickedPoint.myIsInitialized)\r
627   //  return;\r
628 \r
629   //ModuleBase_Operation* aOperation = getCurrentOperation();\r
630   // the distance constraint feature should not use the clickedd point\r
631   // this is workaround in order to don't throw down the flyout point value,\r
632   // set by execute() method of these type of features\r
633   //if (isDistanceOperation(aOperation))\r
634   //  return;\r
635 \r
636   //PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(theWidget);\r
637   //if (aPnt2dWgt) {\r
638   //  aPnt2dWgt->setPoint(myClickedPoint.myCurX, myClickedPoint.myCurY);\r
639   //}\r
640 //}\r
641 \r
642 void PartSet_SketcherMgr::onBeforeContextMenu()\r
643 {\r
644   myIsPopupMenuActive = true;\r
645 }\r
646 \r
647 void PartSet_SketcherMgr::onAfterContextMenu()\r
648 {\r
649   myIsPopupMenuActive = false;\r
650 }\r
651 \r
652 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, \r
653                                      Point& thePoint)\r
654 {\r
655   Handle(V3d_View) aView = theWnd->v3dView();\r
656   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);\r
657   double aX, anY;\r
658   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, anY);\r
659   thePoint.setValue(aX, anY);\r
660 }\r
661 \r
662 void PartSet_SketcherMgr::launchEditing()\r
663 {\r
664   if (!myCurrentSelection.empty()) {\r
665     FeaturePtr aFeature = myCurrentSelection.begin().key();\r
666     std::shared_ptr<SketchPlugin_Feature> aSPFeature = \r
667               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
668     if (aSPFeature && (!aSPFeature->isExternal())) {\r
669       myModule->editFeature(aSPFeature);\r
670     }\r
671   }\r
672 }\r
673 \r
674 bool PartSet_SketcherMgr::sketchSolverError()\r
675 {\r
676   bool anError = false;\r
677   CompositeFeaturePtr aSketch = activeSketch();\r
678   if (aSketch.get()) {\r
679     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());\r
680     anError = !aAttributeString->value().empty();\r
681   }\r
682   return anError;\r
683 }\r
684 \r
685 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)\r
686 {\r
687   std::string anError = "";\r
688   if (!theFeature.get() || !theFeature->data()->isValid())\r
689     return anError.c_str();\r
690 \r
691   CompositeFeaturePtr aSketch = activeSketch();\r
692   if (aSketch.get() && aSketch == theFeature) {\r
693     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());\r
694     anError = aAttributeString->value();\r
695     ModuleBase_Tools::translate(aSketch->getKind(), anError);\r
696   }\r
697   return anError.c_str();\r
698 }\r
699 \r
700 void PartSet_SketcherMgr::clearClickedFlags()\r
701 {\r
702   //myClickedPoint.clear();\r
703   myCurrentPoint.clear();\r
704 }\r
705 \r
706 const QStringList& PartSet_SketcherMgr::replicationsIdList()\r
707 {\r
708   static QStringList aReplicationIds;\r
709   if (aReplicationIds.size() == 0) {\r
710     aReplicationIds << SketchPlugin_ConstraintMirror::ID().c_str();\r
711     aReplicationIds << SketchPlugin_MultiRotation::ID().c_str();\r
712     aReplicationIds << SketchPlugin_MultiTranslation::ID().c_str();\r
713   }\r
714   return aReplicationIds;\r
715 }\r
716 \r
717 const QStringList& PartSet_SketcherMgr::constraintsIdList()\r
718 {\r
719   static QStringList aConstraintIds;\r
720   if (aConstraintIds.size() == 0) {\r
721     aConstraintIds << SketchPlugin_ConstraintLength::ID().c_str();\r
722     aConstraintIds << SketchPlugin_ConstraintDistance::ID().c_str();\r
723     aConstraintIds << SketchPlugin_ConstraintRigid::ID().c_str();\r
724     aConstraintIds << SketchPlugin_ConstraintRadius::ID().c_str();\r
725     aConstraintIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();\r
726     aConstraintIds << SketchPlugin_ConstraintParallel::ID().c_str();\r
727     aConstraintIds << SketchPlugin_ConstraintHorizontal::ID().c_str();\r
728     aConstraintIds << SketchPlugin_ConstraintVertical::ID().c_str();\r
729     aConstraintIds << SketchPlugin_ConstraintEqual::ID().c_str();\r
730     aConstraintIds << SketchPlugin_ConstraintTangent::ID().c_str();\r
731     aConstraintIds << SketchPlugin_ConstraintCoincidence::ID().c_str();\r
732     aConstraintIds << SketchPlugin_ConstraintAngle::ID().c_str();\r
733     aConstraintIds << SketchPlugin_ConstraintCollinear::ID().c_str();\r
734     aConstraintIds << SketchPlugin_ConstraintMiddle::ID().c_str();\r
735   }\r
736   return aConstraintIds;\r
737 }\r
738 \r
739 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)\r
740 {\r
741   theModes.clear();\r
742 \r
743   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);\r
744   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);\r
745   theModes.append(SketcherPrs_Tools::Sel_Constraint);\r
746   theModes.append(TopAbs_VERTEX);\r
747   theModes.append(TopAbs_EDGE);\r
748 }\r
749 \r
750 Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ResultPtr& theResult)\r
751 {\r
752   Handle(AIS_InteractiveObject) aPrs;\r
753 \r
754   FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);\r
755   if (aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID()) {\r
756     aPrs = new PartSet_ResultSketchPrs(theResult);\r
757   }\r
758   return aPrs;\r
759 }\r
760 \r
761 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)\r
762 {\r
763   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();\r
764 }\r
765 \r
766 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation) const\r
767 {\r
768   bool aNestedSketch = false;\r
769 \r
770   FeaturePtr anActiveSketch = activeSketch();\r
771   if (anActiveSketch.get() && theOperation) {\r
772     ModuleBase_Operation* aSketchOperation = operationMgr()->findOperation(\r
773                                                               anActiveSketch->getKind().c_str());\r
774     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
775                                                                                   (theOperation);\r
776     if (aSketchOperation && aFOperation) {\r
777       FeaturePtr aFeature = aFOperation->feature();\r
778       if (aFeature.get()) {\r
779         QStringList aGrantedOpIds = aSketchOperation->grantedOperationIds();\r
780         aNestedSketch = aGrantedOpIds.contains(aFeature->getKind().c_str());\r
781       }\r
782     }\r
783   }\r
784   return aNestedSketch;\r
785 }\r
786 \r
787 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation,\r
788                                                   const CompositeFeaturePtr& theSketch) const\r
789 {\r
790   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
791                                                                (theOperation);\r
792   return aFOperation && !aFOperation->isEditOperation() &&\r
793          isNestedSketchOperation(aFOperation);\r
794 }\r
795 \r
796 bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation,\r
797                                                 const CompositeFeaturePtr& theSketch) const\r
798 {\r
799   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
800                                                                (theOperation);\r
801   return aFOperation && aFOperation->isEditOperation() &&\r
802     isNestedSketchOperation(aFOperation);\r
803 }\r
804 \r
805 bool PartSet_SketcherMgr::isEntity(const std::string& theId)\r
806 {\r
807   return (theId == SketchPlugin_Line::ID()) ||\r
808          (theId == SketchPlugin_Point::ID()) ||\r
809          (theId == SketchPlugin_Arc::ID()) ||\r
810          (theId == SketchPlugin_Circle::ID());\r
811 }\r
812 \r
813 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)\r
814 {\r
815   std::string anId = theOperation ? theOperation->id().toStdString() : "";\r
816 \r
817   return isDistanceKind(anId);\r
818 }\r
819 \r
820 bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)\r
821 {\r
822   return (theKind == SketchPlugin_ConstraintLength::ID()) ||\r
823          (theKind == SketchPlugin_ConstraintDistance::ID()) ||\r
824          (theKind == SketchPlugin_ConstraintRadius::ID()) ||\r
825          (theKind == SketchPlugin_ConstraintAngle::ID());\r
826 }\r
827 \r
828 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)\r
829 {\r
830   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
831                                                                (getCurrentOperation());\r
832   if (!aFOperation)\r
833     return;\r
834 \r
835   myModule->onViewTransformed();\r
836 \r
837   // Display all sketcher sub-Objects\r
838   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());\r
839   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());\r
840 \r
841   // Hide sketcher result\r
842   std::list<ResultPtr> aResults = myCurrentSketch->results();\r
843   std::list<ResultPtr>::const_iterator aIt;\r
844   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
845     (*aIt)->setDisplayed(false);\r
846   }\r
847   myCurrentSketch->setDisplayed(false);\r
848 \r
849   // Remove invalid sketch entities\r
850   std::set<FeaturePtr> anInvalidFeatures;\r
851   ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();\r
852   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
853     FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
854     if (aFeature.get()) {\r
855       if (!aFactory->validate(aFeature))\r
856         anInvalidFeatures.insert(aFeature);\r
857     }\r
858   }\r
859   if (!anInvalidFeatures.empty()) {\r
860     std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;\r
861     ModelAPI_Tools::findAllReferences(anInvalidFeatures, aReferences, false);\r
862 \r
863     std::set<FeaturePtr>::const_iterator anIt = anInvalidFeatures.begin(),\r
864                                          aLast = anInvalidFeatures.end();\r
865     // separate features to references to parameter features and references to others\r
866     QStringList anInvalidFeatureNames;\r
867     for (; anIt != aLast; anIt++) {\r
868       FeaturePtr aFeature = *anIt;\r
869       if (aFeature.get())\r
870         anInvalidFeatureNames.append(aFeature->name().c_str());\r
871     }\r
872     std::string aPrefixInfo = QString("Invalid features of the sketch will be deleted: %1.\n\n").\r
873                                   arg(anInvalidFeatureNames.join(", ")).toStdString().c_str();\r
874     std::set<FeaturePtr> aFeatureRefsToDelete;\r
875     if (ModuleBase_Tools::askToDelete(anInvalidFeatures, aReferences, aConnector->desktop(),\r
876                                       aFeatureRefsToDelete, aPrefixInfo)) {\r
877       if (!aFeatureRefsToDelete.empty())\r
878         anInvalidFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());\r
879       ModelAPI_Tools::removeFeatures(anInvalidFeatures, true);\r
880       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));\r
881       // TODO: call the next method in the XGUI_OperationMgr::onOperationStarted().\r
882       workshop()->errorMgr()->updateAcceptAllAction(myCurrentSketch);\r
883     }\r
884   }\r
885 \r
886   // Display sketcher objects\r
887   QStringList anInfo;\r
888   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
889     FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
890 #ifdef DEBUG_SKETCHER_ENTITIES\r
891     anInfo.append(ModuleBase_Tools::objectInfo(aFeature));\r
892 #endif\r
893     std::list<ResultPtr> aResults = aFeature->results();\r
894     std::list<ResultPtr>::const_iterator aIt;\r
895     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
896       (*aIt)->setDisplayed(true);\r
897     }\r
898     aFeature->setDisplayed(true);\r
899   }\r
900 #ifdef DEBUG_SKETCHER_ENTITIES\r
901   QString anInfoStr = anInfo.join(";\t");\r
902   qDebug(QString("startSketch: %1, %2").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());\r
903 #endif\r
904 \r
905   if(myCirclePointFilter.IsNull()) {\r
906     myCirclePointFilter = new PartSet_CirclePointFilter(myModule->workshop());\r
907   }\r
908 \r
909   myModule->workshop()->viewer()->addSelectionFilter(myCirclePointFilter);\r
910 \r
911   if (myPlaneFilter.IsNull()) \r
912     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();\r
913 \r
914   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);\r
915   bool aHasPlane = false;\r
916   std::shared_ptr<GeomAPI_Pln> aPln;\r
917   aPln = PartSet_Tools::sketchPlane(myCurrentSketch);\r
918   myPlaneFilter->setPlane(aPln);\r
919 \r
920   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
921   // all displayed objects should be activated in current selection modes according to switched\r
922   // plane filter\r
923   if (aPln.get())\r
924     aConnector->activateModuleSelectionModes();\r
925 }\r
926 \r
927 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)\r
928 {\r
929   myIsMouseOverWindow = false;\r
930   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;\r
931   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;\r
932   myIsConstraintsShown[PartSet_Tools::Expressions] = false;\r
933 \r
934   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());\r
935 \r
936   DataPtr aData = myCurrentSketch->data();\r
937   if (!aData->isValid()) {\r
938     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
939     // The sketch was aborted\r
940     myCurrentSketch = CompositeFeaturePtr();\r
941     // TODO: move this outside of if-else\r
942     myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);\r
943     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);\r
944 \r
945     // Erase all sketcher objects\r
946     QObjectPtrList aObjects = aDisplayer->displayedObjects();\r
947     foreach (ObjectPtr aObj, aObjects) {\r
948       DataPtr aObjData = aObj->data();\r
949       if (!aObjData->isValid())\r
950         aObj->setDisplayed(false);\r
951     }\r
952   }\r
953   else {\r
954     // Hide all sketcher sub-Objects\r
955     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
956       FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
957       std::list<ResultPtr> aResults = aFeature->results();\r
958       std::list<ResultPtr>::const_iterator aIt;\r
959       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
960         (*aIt)->setDisplayed(false);\r
961       }\r
962       aFeature->setDisplayed(false);\r
963     }\r
964     // Display sketcher result\r
965     std::list<ResultPtr> aResults = myCurrentSketch->results();\r
966     std::list<ResultPtr>::const_iterator aIt;\r
967     Events_Loop* aLoop = Events_Loop::loop();\r
968     static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);\r
969 \r
970     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
971                                                                            (theOperation);\r
972     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
973       if (!aFOperation->isDisplayedOnStart(*aIt)) {\r
974         (*aIt)->setDisplayed(true);\r
975         // this display event is needed because sketch already may have "displayed" state,\r
976         // but not displayed while it is still active (issue 613, abort of existing sketch)\r
977         ModelAPI_EventCreator::get()->sendUpdated(*aIt, aDispEvent);\r
978       }\r
979     }\r
980     if (!aFOperation->isDisplayedOnStart(myCurrentSketch))\r
981       myCurrentSketch->setDisplayed(true);\r
982     \r
983     myCurrentSketch = CompositeFeaturePtr();\r
984 \r
985     myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);\r
986     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);\r
987 \r
988     Events_Loop::loop()->flush(aDispEvent);\r
989   }\r
990   // restore the module selection modes, which were changed on startSketch\r
991   aConnector->activateModuleSelectionModes();\r
992 }\r
993 \r
994 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)\r
995 {\r
996   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {\r
997     QCursor* aCurrentCursor = QApplication::overrideCursor();\r
998     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {\r
999       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));\r
1000 #ifdef DEBUG_CURSOR\r
1001       qDebug("startNestedSketch() : Qt::CrossCursor");\r
1002 #endif\r
1003     }\r
1004   }\r
1005 }\r
1006 \r
1007 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)\r
1008 {\r
1009   myIsMouseOverViewProcessed = true;\r
1010   operationMgr()->onValidateOperation();\r
1011   // when sketch nested operation is stopped the cursor should be restored unconditionally\r
1012   //if (canChangeCursor(theOperation)) {\r
1013     QApplication::restoreOverrideCursor();\r
1014 #ifdef DEBUG_CURSOR\r
1015     qDebug("stopNestedSketch() : None");\r
1016 #endif\r
1017   //}\r
1018   /// improvement to deselect automatically all eventual selected objects, when\r
1019   // returning to the neutral point of the Sketcher\r
1020   workshop()->selector()->clearSelection();\r
1021 }\r
1022 \r
1023 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)\r
1024 {\r
1025   if (isNestedCreateOperation(theOperation, activeSketch())) {\r
1026     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1027                                                                              (theOperation);\r
1028     if (aFOperation) {\r
1029       FeaturePtr aFeature = aFOperation->feature();\r
1030       // it is necessary to check the the feature data validity because\r
1031       // some kind of features are removed by an operation commit(the macro state of a feature)\r
1032       if (aFeature.get() && aFeature->data()->isValid()) {\r
1033         visualizeFeature(aFeature, aFOperation->isEditOperation(), true);\r
1034       }\r
1035     }\r
1036   }\r
1037 }\r
1038 \r
1039 void PartSet_SketcherMgr::activatePlaneFilter(const bool& toActivate)\r
1040 {\r
1041   if (toActivate)\r
1042     myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);\r
1043   else\r
1044     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);\r
1045 }\r
1046 \r
1047 bool PartSet_SketcherMgr::operationActivatedByPreselection()\r
1048 {\r
1049   bool isOperationStopped = false;\r
1050   ModuleBase_Operation* anOperation = getCurrentOperation();\r
1051   if(anOperation && isNestedSketchOperation(anOperation)) {\r
1052     // Set final definitions if they are necessary\r
1053     //propertyPanelDefined(aOperation);\r
1054     /// Commit sketcher operations automatically\r
1055     /// distance operation are able to show popup editor to modify the distance value\r
1056     /// after entering the value, the operation should be committed/aborted(by Esc key)\r
1057     bool aCanCommitOperation = true;\r
1058     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1059                                                                             (anOperation);\r
1060     if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {\r
1061       bool aValueAccepted = setDistanceValueByPreselection(anOperation, myModule->workshop(),\r
1062                                                            aCanCommitOperation);\r
1063       if (!aValueAccepted)\r
1064         return isOperationStopped;\r
1065     }\r
1066 \r
1067     if (aCanCommitOperation)\r
1068       isOperationStopped = anOperation->commit();\r
1069     else {\r
1070       anOperation->abort();\r
1071       isOperationStopped = true;\r
1072     }\r
1073   }\r
1074   return isOperationStopped;\r
1075 }\r
1076 \r
1077 bool PartSet_SketcherMgr::canUndo() const\r
1078 {\r
1079   return isNestedCreateOperation(getCurrentOperation(), activeSketch());\r
1080 }\r
1081 \r
1082 bool PartSet_SketcherMgr::canRedo() const\r
1083 {\r
1084   return isNestedCreateOperation(getCurrentOperation(), activeSketch());\r
1085 }\r
1086 \r
1087 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const\r
1088 {\r
1089   bool aCanErase = true;\r
1090   // when the sketch operation is active, results of sketch sub-feature can not be hidden\r
1091   if (myCurrentSketch.get()) {\r
1092     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);\r
1093     if (aResult.get()) {\r
1094       // Display sketcher objects\r
1095       for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {\r
1096 \r
1097         FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
1098         std::list<ResultPtr> aResults = aFeature->results();\r
1099         std::list<ResultPtr>::const_iterator anIt;\r
1100         for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {\r
1101           aCanErase = *anIt != aResult;\r
1102         }\r
1103       }\r
1104     }\r
1105   }\r
1106   return aCanErase;\r
1107 }\r
1108 \r
1109 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const\r
1110 {\r
1111   bool aCanDisplay = true;\r
1112 \r
1113   bool aHasActiveSketch = activeSketch().get() != NULL;\r
1114   if (aHasActiveSketch) {\r
1115     // 1. the sketch feature should not be displayed during the sketch active operation\r
1116     // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch \r
1117     // nested features can be visualized\r
1118     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1119     if (aFeature.get() != NULL && aFeature == activeSketch()) {\r
1120       aCanDisplay = false;\r
1121     }\r
1122     std::shared_ptr<SketchPlugin_Feature> aSketchFeature =\r
1123                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
1124     /// some sketch entities should be never shown, e.g. projection feature\r
1125     if (aSketchFeature.get())\r
1126       aCanDisplay = aSketchFeature->canBeDisplayed();\r
1127   }\r
1128   else { // there are no an active sketch\r
1129     // 2. sketch sub-features should not be visualized if the sketch operation is not active\r
1130     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1131     if (aFeature.get() != NULL) {\r
1132       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =\r
1133                               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
1134       if (aSketchFeature.get()) {\r
1135         aCanDisplay = false;\r
1136       }\r
1137     }\r
1138   }\r
1139 \r
1140   // 3. the method should not filter the objects, which are not related to the current operation.\r
1141   // The object is filtered just if it is a current operation feature or this feature result\r
1142   if (aCanDisplay) {\r
1143     bool isObjectFound = false;\r
1144     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1145                                                                  (getCurrentOperation());\r
1146     if (aFOperation) {\r
1147       FeaturePtr aFeature = aFOperation->feature();\r
1148       if (aFeature.get()) {\r
1149         std::list<ResultPtr> aResults = aFeature->results();\r
1150         if (theObject == aFeature)\r
1151           isObjectFound = true;\r
1152         else {\r
1153           std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();\r
1154           for (; anIt != aLast && !isObjectFound; anIt++) {\r
1155             isObjectFound = *anIt == theObject;\r
1156           }\r
1157         }\r
1158       }\r
1159     }\r
1160     if (isObjectFound) {\r
1161       // 4. For created nested feature operation do not display the created feature if\r
1162       // the mouse curstor leaves the OCC window.\r
1163       // The correction cases, which ignores this condition:\r
1164       // a. the property panel values modification\r
1165       // b. the popup menu activated\r
1166       // c. widget editor control\r
1167       #ifndef DEBUG_DO_NOT_BY_ENTER\r
1168       if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {\r
1169         ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
1170         ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;\r
1171         // the active widget editor should not influence here. The presentation should be visible always\r
1172         // when this widget is active.\r
1173         if (!anEditorWdg && !myIsPopupMenuActive) {\r
1174           // during a nested create operation, the feature is redisplayed only if the mouse over view\r
1175           // of there was a value modified in the property panel after the mouse left the view\r
1176           aCanDisplay = canDisplayCurrentCreatedFeature();\r
1177         }\r
1178       }\r
1179       #endif\r
1180     }\r
1181   }\r
1182 \r
1183   // checks the sketcher constraints visibility according to active sketch check box states\r
1184   if (aCanDisplay) {\r
1185     bool aProcessed = false;\r
1186     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1187     if (aFeature.get()) {\r
1188       bool aConstraintDisplayed = canDisplayConstraint(aFeature, PartSet_Tools::Any, aProcessed);\r
1189       if (aProcessed)\r
1190         aCanDisplay = aConstraintDisplayed;\r
1191     }\r
1192   }\r
1193 \r
1194   return aCanDisplay;\r
1195 }\r
1196 \r
1197 bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,\r
1198                                              const PartSet_Tools::ConstraintVisibleState& theState,\r
1199                                              bool& isProcessed) const\r
1200 {\r
1201   bool aSwitchedOn = true;\r
1202 \r
1203   const QStringList& aConstrIds = constraintsIdList();\r
1204 \r
1205   std::string aKind = theFeature->getKind();\r
1206   if (aConstrIds.contains(QString(aKind.c_str()))) {\r
1207     bool isTypedConstraint = false;\r
1208 \r
1209     switch (theState) {\r
1210       case PartSet_Tools::Dimensional: {\r
1211         bool isDistance = isDistanceKind(aKind);\r
1212         if (isDistance) {\r
1213           isProcessed = true;\r
1214           aSwitchedOn = myIsConstraintsShown[theState];\r
1215         }\r
1216       }\r
1217       break;\r
1218       case PartSet_Tools::Geometrical: {\r
1219         bool isGeometrical = !isDistanceKind(aKind);\r
1220         if (isGeometrical) {\r
1221           isProcessed = true;\r
1222           aSwitchedOn = myIsConstraintsShown[theState];\r
1223         }\r
1224       }\r
1225       break;\r
1226       case PartSet_Tools::Any: {\r
1227         isProcessed = true;\r
1228         bool isDistance = isDistanceKind(aKind);\r
1229         if (isDistance)\r
1230           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Dimensional];\r
1231         else\r
1232           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Geometrical];\r
1233       }\r
1234       break;\r
1235     default:\r
1236       break;\r
1237     }\r
1238   }\r
1239   return aSwitchedOn;\r
1240 }\r
1241 \r
1242 /*void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)\r
1243 {\r
1244   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1245                                                                            (getCurrentOperation());\r
1246   if (aFOperation && myCurrentSketch.get()) {\r
1247     // find results of the current operation\r
1248     // these results should not be proposed to be deleted\r
1249     FeaturePtr anOperationFeature = aFOperation->feature();\r
1250     std::list<ResultPtr> anOperationResultList = anOperationFeature->results();\r
1251     std::set<ResultPtr> anOperationResults;\r
1252     std::list<ResultPtr>::const_iterator aRIt = anOperationResultList.begin(),\r
1253                                         aRLast = anOperationResultList.end();\r
1254     for (; aRIt != aRLast; aRIt++)\r
1255       anOperationResults.insert(*aRIt);\r
1256 \r
1257     std::set<FeaturePtr> anObjectsToBeDeleted;\r
1258     QStringList anObjectsToBeDeletedNames;\r
1259     std::list<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();\r
1260     for (; anIt != aLast; anIt++) {\r
1261       ObjectPtr anObject = *anIt;\r
1262       bool aCanErase = true;\r
1263       // when the sketch operation is active, results of sketch sub-feature can not be hidden\r
1264       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);\r
1265       // the result is found between current feature results\r
1266       if (anOperationResults.find(aResult) != anOperationResults.end())\r
1267         continue;\r
1268 \r
1269       if (aResult.get()) {\r
1270         // Display sketcher objects\r
1271         for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {\r
1272           FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
1273           std::list<ResultPtr> aResults = aFeature->results();\r
1274           std::list<ResultPtr>::const_iterator anIt;\r
1275           for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {\r
1276             aCanErase = *anIt != aResult;\r
1277           }\r
1278         }\r
1279       }\r
1280       if (!aCanErase) {\r
1281         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);\r
1282         if (aFeature.get() && anObjectsToBeDeleted.find(aFeature) == anObjectsToBeDeleted.end()) {\r
1283           anObjectsToBeDeleted.insert(aFeature);\r
1284           anObjectsToBeDeletedNames.append(aFeature->name().c_str());\r
1285         }\r
1286       }\r
1287     }\r
1288     if (!anObjectsToBeDeleted.empty()) {\r
1289       QString aFeatureNames = anObjectsToBeDeletedNames.join(", ");\r
1290       QString aMessage = tr("The following features have incorrect presentation and \\r
1291 will be hidden: %1. Would you like to delete them?")\r
1292                          .arg(aFeatureNames);\r
1293       int anAnswer = QMessageBox::question(qApp->activeWindow(), tr("Features hide"),\r
1294                                            aMessage, QMessageBox::Ok | QMessageBox::Cancel,\r
1295                                            QMessageBox::Cancel);\r
1296       if (anAnswer == QMessageBox::Ok) {\r
1297         QObjectPtrList anObjects;\r
1298         std::set<FeaturePtr>::const_iterator anIt = anObjectsToBeDeleted.begin(),\r
1299                                              aLast = anObjectsToBeDeleted.end();\r
1300         for (; anIt != aLast; anIt++)\r
1301           anObjects.append(*anIt);\r
1302         SessionPtr aMgr = ModelAPI_Session::get();\r
1303         DocumentPtr aDoc = aMgr->activeDocument();\r
1304         bool aIsOp = aMgr->isOperation();\r
1305         if (!aIsOp)\r
1306           aMgr->startOperation();\r
1307         workshop()->deleteFeatures(anObjects);\r
1308         //static Events_ID aDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);\r
1309         //static Events_ID aRedispEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);\r
1310         //Events_Loop::loop()->flush(aDeletedEvent);\r
1311         //Events_Loop::loop()->flush(aRedispEvent);\r
1312 \r
1313         if (!aIsOp)\r
1314           aMgr->finishOperation();\r
1315       }\r
1316     }\r
1317   }\r
1318 }*/\r
1319 \r
1320 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const\r
1321 {\r
1322   bool aCanDisplay = myIsMouseOverWindow;\r
1323   if (!aCanDisplay) {\r
1324     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
1325     if (anActiveWidget)\r
1326       aCanDisplay = anActiveWidget->getValueState() == ModuleBase_ModelWidget::Stored;\r
1327   }\r
1328   return aCanDisplay;\r
1329 }\r
1330 \r
1331 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const\r
1332 {\r
1333   return isNestedCreateOperation(theOperation, activeSketch()) ||\r
1334          myModule->sketchReentranceMgr()->isInternalEditActive();\r
1335 }\r
1336 \r
1337 const QMap<PartSet_Tools::ConstraintVisibleState, bool>& PartSet_SketcherMgr::showConstraintStates()\r
1338 {\r
1339   return myIsConstraintsShown;\r
1340 }\r
1341 \r
1342 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const\r
1343 {\r
1344   bool isFoundObject = false;\r
1345 \r
1346   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);\r
1347   if (anObjectFeature.get()) {\r
1348     int aSize = myCurrentSketch->numberOfSubs();\r
1349     for (int i = 0; i < myCurrentSketch->numberOfSubs() && !isFoundObject; i++) {\r
1350       FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);\r
1351       isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;\r
1352     }\r
1353   }\r
1354   return isFoundObject;\r
1355 }\r
1356 \r
1357 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)\r
1358 {\r
1359   if (myPlaneFilter.IsNull()) \r
1360    myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();\r
1361 \r
1362   myPlaneFilter->setPlane(thePln);\r
1363 }\r
1364 \r
1365 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,\r
1366                                                          ModuleBase_IWorkshop* theWorkshop,\r
1367                                                          bool& theCanCommitOperation)\r
1368 {\r
1369   bool isValueAccepted = false;\r
1370   theCanCommitOperation = false;\r
1371 \r
1372   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1373                                                                               (theOperation);\r
1374   FeaturePtr aFeature = aFOperation->feature();\r
1375   // editor is shown only if all attribute references are filled by preseletion\r
1376   bool anAllRefAttrInitialized = true;\r
1377 \r
1378   std::list<AttributePtr> aRefAttrs = aFeature->data()->attributes(\r
1379                                               ModelAPI_AttributeRefAttr::typeId());\r
1380   std::list<AttributePtr>::const_iterator anIt = aRefAttrs.begin(), aLast = aRefAttrs.end();\r
1381   for (; anIt != aLast && anAllRefAttrInitialized; anIt++) {\r
1382     anAllRefAttrInitialized = (*anIt)->isInitialized();\r
1383   }\r
1384   if (anAllRefAttrInitialized) {\r
1385     // Activate dimension value editing on double click\r
1386     ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();\r
1387     QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();\r
1388     // Find corresponded widget to activate value editing\r
1389     foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {\r
1390       if (aWgt->attributeID() == "ConstraintValue") {\r
1391         // the featue should be displayed in order to find the AIS text position,\r
1392         // the place where the editor will be shown\r
1393         aFeature->setDisplayed(true);\r
1394         /// the execute is necessary to perform in the feature compute for flyout position\r
1395         aFeature->execute();\r
1396 \r
1397         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));\r
1398         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
1399 \r
1400         PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);\r
1401         if (anEditor) {\r
1402           int aX = 0, anY = 0;\r
1403 \r
1404           XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);\r
1405           XGUI_Displayer* aDisplayer = aWorkshop->displayer();\r
1406           AISObjectPtr anAIS = aDisplayer->getAISObject(aFeature);\r
1407           Handle(AIS_InteractiveObject) anAISIO;\r
1408           if (anAIS.get() != NULL) {\r
1409             anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();\r
1410           }\r
1411           if (anAIS.get() != NULL) {\r
1412             Handle(AIS_InteractiveObject) anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();\r
1413 \r
1414             if (!anAISIO.IsNull()) {\r
1415               Handle(AIS_Dimension) aDim = Handle(AIS_Dimension)::DownCast(anAISIO);\r
1416               if (!aDim.IsNull()) {\r
1417                 gp_Pnt aPosition = aDim->GetTextPosition();\r
1418 \r
1419                 ModuleBase_IViewer* aViewer = aWorkshop->viewer();\r
1420                 Handle(V3d_View) aView = aViewer->activeView();\r
1421                 int aCX, aCY;\r
1422                 aView->Convert(aPosition.X(), aPosition.Y(), aPosition.Z(), aCX, aCY);\r
1423 \r
1424                 QWidget* aViewPort = aViewer->activeViewPort();\r
1425                 QPoint aGlPoint = aViewPort->mapToGlobal(QPoint(aCX, aCY));\r
1426                 aX = aGlPoint.x();\r
1427                 anY = aGlPoint.y();\r
1428               }\r
1429             }\r
1430             anEditor->setCursorPosition(aX, anY);\r
1431             isValueAccepted = anEditor->showPopupEditor(false);\r
1432             theCanCommitOperation = true;\r
1433           }\r
1434         }\r
1435       }\r
1436     }\r
1437   }\r
1438   return isValueAccepted;\r
1439 }\r
1440 \r
1441 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,\r
1442                                              const FeaturePtr& theSketch,\r
1443                                              ModuleBase_IWorkshop* theWorkshop,\r
1444                                              const FeatureToSelectionMap& theSelection,\r
1445                                              SelectMgr_IndexedMapOfOwner& theOwnersToSelect)\r
1446 {\r
1447   if (theFeature.get() == NULL)\r
1448     return;\r
1449 \r
1450   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);\r
1451   std::set<AttributePtr> aSelectedAttributes = anIt.value().first;\r
1452   std::set<ResultPtr> aSelectedResults = anIt.value().second;\r
1453 \r
1454   ModuleBase_IViewer* aViewer = theWorkshop->viewer();\r
1455 \r
1456   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);\r
1457   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
1458 \r
1459   // 1. found the feature's owners. Check the AIS objects of the constructions\r
1460   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);\r
1461   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {\r
1462     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();\r
1463 \r
1464     SelectMgr_IndexedMapOfOwner aSelectedOwners;\r
1465     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);\r
1466     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {\r
1467       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);\r
1468       if (!anOwner.IsNull())\r
1469         theOwnersToSelect.Add(anOwner);\r
1470     }\r
1471   }\r
1472 \r
1473   // 2. found the feature results's owners\r
1474   std::list<ResultPtr> aResults = theFeature->results();\r
1475   std::list<ResultPtr>::const_iterator aIt;\r
1476   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)\r
1477   {\r
1478     ResultPtr aResult = *aIt;\r
1479     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);\r
1480     if (aAISObj.get() == NULL)\r
1481       continue; \r
1482     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();\r
1483 \r
1484     SelectMgr_IndexedMapOfOwner aSelectedOwners;  \r
1485     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);\r
1486     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {\r
1487       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));\r
1488       if ( anOwner.IsNull() || !anOwner->HasShape() )\r
1489         continue;\r
1490       const TopoDS_Shape& aShape = anOwner->Shape();\r
1491       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();\r
1492       if (aShapeType == TopAbs_VERTEX) {\r
1493         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);\r
1494         if (aPntAttr.get() != NULL &&\r
1495             aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end()) {\r
1496           theOwnersToSelect.Add(anOwner);\r
1497         }\r
1498       }\r
1499       else if (aShapeType == TopAbs_EDGE) {\r
1500         bool aFound = aSelectedResults.find(aResult) != aSelectedResults.end();\r
1501         if (aSelectedResults.find(aResult) != aSelectedResults.end() &&\r
1502             theOwnersToSelect.FindIndex(anOwner) <= 0)\r
1503           theOwnersToSelect.Add(anOwner);\r
1504       }\r
1505     }\r
1506   }\r
1507 }\r
1508 \r
1509 void PartSet_SketcherMgr::connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect)\r
1510 {\r
1511   if (isToConnect) {\r
1512     connect(theWidget, SIGNAL(beforeValuesChanged()),\r
1513             this, SLOT(onBeforeValuesChangedInPropertyPanel()));\r
1514     connect(theWidget, SIGNAL(afterValuesChanged()),\r
1515             this, SLOT(onAfterValuesChangedInPropertyPanel()));\r
1516   }\r
1517   else {\r
1518     disconnect(theWidget, SIGNAL(beforeValuesChanged()),\r
1519                 this, SLOT(onBeforeValuesChangedInPropertyPanel()));\r
1520     disconnect(theWidget, SIGNAL(afterValuesChanged()),\r
1521                 this, SLOT(onAfterValuesChangedInPropertyPanel()));\r
1522   }\r
1523 }\r
1524 \r
1525 void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)\r
1526 {\r
1527   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1528                                                                            (getCurrentOperation());\r
1529   if (aFOperation) {\r
1530     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||\r
1531         isNestedSketchOperation(aFOperation) &&\r
1532         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {\r
1533       FeaturePtr aFeature = aFOperation->feature();\r
1534       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));\r
1535     }\r
1536   }\r
1537 }\r
1538 \r
1539 void PartSet_SketcherMgr::customizePresentation(const ObjectPtr& theObject)\r
1540 {\r
1541   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1542                                                                            (getCurrentOperation());\r
1543   if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||\r
1544                       isNestedSketchOperation(aFOperation)))\r
1545     SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);\r
1546 \r
1547   // update entities selection priorities\r
1548   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1549   if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {\r
1550     // update priority for feature\r
1551     updateSelectionPriority(aFeature, aFeature);\r
1552     // update priority for results of the feature\r
1553     std::list<ResultPtr> aResults = aFeature->results();\r
1554     std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();\r
1555     for (; anIt != aLastIt; anIt++)\r
1556       updateSelectionPriority(*anIt, aFeature);\r
1557   }\r
1558 }\r
1559 \r
1560 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const\r
1561 {\r
1562   return myModule->workshop()->currentOperation();\r
1563 }\r
1564 \r
1565 //**************************************************************\r
1566 ModuleBase_ModelWidget* PartSet_SketcherMgr::getActiveWidget() const\r
1567 {\r
1568   ModuleBase_ModelWidget* aWidget = 0;\r
1569   ModuleBase_Operation* anOperation = getCurrentOperation();\r
1570   if (anOperation) {\r
1571     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();\r
1572     if (aPanel)\r
1573       aWidget = aPanel->activeWidget();\r
1574   }\r
1575   return aWidget;\r
1576 }\r
1577 \r
1578 void PartSet_SketcherMgr::visualizeFeature(const FeaturePtr& theFeature,\r
1579                                            const bool isEditOperation,\r
1580                                            const bool isToDisplay,\r
1581                                            const bool isFlushRedisplay)\r
1582 {\r
1583   #ifdef DEBUG_DO_NOT_BY_ENTER\r
1584   return;\r
1585   #endif\r
1586 \r
1587   if (isEditOperation || !theFeature.get())\r
1588     return;\r
1589 \r
1590   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1591   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
1592 \r
1593   // 1. change visibility of the object itself, here the presentable object is processed,\r
1594   // e.g. constraints features\r
1595   //FeaturePtr aFeature = aFOperation->feature();\r
1596   std::list<ResultPtr> aResults = theFeature->results();\r
1597   if (isToDisplay)\r
1598     theFeature->setDisplayed(true);\r
1599   else\r
1600     theFeature->setDisplayed(false);\r
1601 \r
1602   // change visibility of the object results, e.g. non-constraint features\r
1603   std::list<ResultPtr>::const_iterator aIt;\r
1604   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
1605     if (isToDisplay) {\r
1606       (*aIt)->setDisplayed(true);\r
1607     }\r
1608     else {\r
1609       (*aIt)->setDisplayed(false);\r
1610     }\r
1611   }\r
1612   if (isFlushRedisplay)\r
1613     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
1614 }\r
1615 \r
1616 void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)\r
1617 {\r
1618   if (!myCurrentSketch.get())\r
1619     return;\r
1620 \r
1621   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1622   ModuleBase_ISelection* aSelect = aWorkshop->selection();\r
1623   QList<ModuleBase_ViewerPrsPtr> aStoredPrs = aSelect->getHighlighted();\r
1624 \r
1625   QList<FeaturePtr> aFeatureList;\r
1626   if (!theHighlightedOnly) {\r
1627     QList<ModuleBase_ViewerPrsPtr> aSelected = aSelect->getSelected(\r
1628                                                               ModuleBase_ISelection::AllControls);\r
1629     aStoredPrs.append(aSelected);\r
1630   }\r
1631 \r
1632   // 1. it is necessary to save current selection in order to restore it after the features moving\r
1633   myCurrentSelection.clear();\r
1634 \r
1635   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = aStoredPrs.begin(), aLast = aStoredPrs.end();\r
1636 \r
1637   CompositeFeaturePtr aSketch = activeSketch();\r
1638   for (; anIt != aLast; anIt++) {\r
1639     ModuleBase_ViewerPrsPtr aPrs = *anIt;\r
1640     ObjectPtr anObject = aPrs->object();\r
1641     if (!anObject.get())\r
1642       continue;\r
1643 \r
1644     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);\r
1645     FeaturePtr aFeature;\r
1646     if (aResult.get())\r
1647       aFeature = ModelAPI_Feature::feature(aResult);\r
1648     else\r
1649       aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);\r
1650 \r
1651 \r
1652     std::set<AttributePtr> aSelectedAttributes;\r
1653     std::set<ResultPtr> aSelectedResults;\r
1654     if (myCurrentSelection.find(aFeature) != myCurrentSelection.end()) {\r
1655       std::pair<std::set<AttributePtr>, std::set<ResultPtr> > aPair = myCurrentSelection.find(aFeature).value();\r
1656       aSelectedAttributes = aPair.first;\r
1657       aSelectedResults = aPair.second;\r
1658     }\r
1659 \r
1660     Handle(SelectMgr_EntityOwner) anOwner = aPrs->owner();\r
1661     if (aResult.get()) {\r
1662       getAttributesOrResults(anOwner, aFeature, aSketch, aResult,\r
1663                              aSelectedAttributes, aSelectedResults);\r
1664     }\r
1665     else {\r
1666       std::list<ResultPtr> aResults = aFeature->results();\r
1667       std::list<ResultPtr>::const_iterator aIt;\r
1668       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
1669         ResultPtr aResult = *aIt;\r
1670         getAttributesOrResults(anOwner, aFeature, aSketch, aResult,\r
1671                                aSelectedAttributes, aSelectedResults);\r
1672       }\r
1673     }\r
1674     myCurrentSelection[aFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);\r
1675   }\r
1676   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());\r
1677 }\r
1678 \r
1679 void PartSet_SketcherMgr::restoreSelection()\r
1680 {\r
1681   if (!myCurrentSketch.get())\r
1682     return;\r
1683 \r
1684   //qDebug(QString("restoreSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());\r
1685   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1686   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
1687   FeatureToSelectionMap::const_iterator aSIt = myCurrentSelection.begin(),\r
1688                                         aSLast = myCurrentSelection.end();\r
1689   SelectMgr_IndexedMapOfOwner anOwnersToSelect;\r
1690   for (; aSIt != aSLast; aSIt++) {\r
1691     anOwnersToSelect.Clear();\r
1692     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, myCurrentSelection,\r
1693                         anOwnersToSelect);\r
1694     aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);\r
1695   }\r
1696 }\r
1697 \r
1698 void PartSet_SketcherMgr::onShowConstraintsToggle(int theType, bool theState)\r
1699 {\r
1700   PartSet_Tools::ConstraintVisibleState aType = (PartSet_Tools::ConstraintVisibleState)theType;\r
1701 \r
1702   updateBySketchParameters(aType, theState);\r
1703 }\r
1704 \r
1705 void PartSet_SketcherMgr::updateBySketchParameters(\r
1706                                    const PartSet_Tools::ConstraintVisibleState& theType,\r
1707                                    bool theState)\r
1708 {\r
1709   if (myCurrentSketch.get() == NULL)\r
1710     return;\r
1711 \r
1712   bool aPrevState = myIsConstraintsShown[theType];\r
1713   myIsConstraintsShown[theType] = theState;\r
1714 \r
1715   switch (theType) {\r
1716     case PartSet_Tools::Geometrical:\r
1717     case PartSet_Tools::Dimensional: {\r
1718       if (aPrevState != theState) {\r
1719         ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1720         XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
1721         for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
1722           FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);\r
1723           bool aProcessed = false;\r
1724           bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, theType, aProcessed);\r
1725           if (aProcessed)\r
1726             aSubFeature->setDisplayed(aConstraintDisplayed);\r
1727         }\r
1728         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
1729       }\r
1730     }\r
1731     break;\r
1732     case PartSet_Tools::Expressions: {\r
1733       if (aPrevState != theState) {\r
1734         /// call all sketch features redisplay, the expression state will be corrected in customize\r
1735         /// of distance presentation\r
1736         Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);\r
1737         PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);\r
1738       }\r
1739     }\r
1740     break;\r
1741   }\r
1742 }\r
1743 \r
1744 void PartSet_SketcherMgr::updateSelectionPriority(ObjectPtr theObject,\r
1745                                                   FeaturePtr theFeature)\r
1746 {\r
1747   if (!theObject.get() || !theFeature.get())\r
1748     return;\r
1749 \r
1750   AISObjectPtr anAIS = workshop()->displayer()->getAISObject(theObject);\r
1751   Handle(AIS_InteractiveObject) anAISIO;\r
1752   if (anAIS.get() != NULL) {\r
1753     anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();\r
1754   }\r
1755 \r
1756   if (!anAISIO.IsNull()) { // the presentation for the object is visualized\r
1757     int anAdditionalPriority = 0;\r
1758     // current feature\r
1759     std::shared_ptr<SketchPlugin_Feature> aSPFeature =\r
1760             std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);\r
1761     if (aSPFeature.get() != NULL) {\r
1762       // 1. Vertices\r
1763       // 2. Simple segments\r
1764       // 3. External objects (violet color)\r
1765       // 4. Auxiliary segments (dotted)\r
1766       // StdSelect_BRepSelectionTool::Load uses priority calculating:\r
1767       // Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;\r
1768       // Priority of Vertex is 8, edge(segment) is 7.\r
1769       // It might be not corrected as provides the condition above.\r
1770       bool isExternal = aSPFeature->isExternal();\r
1771       bool isAuxiliary = PartSet_Tools::isAuxiliarySketchEntity(aSPFeature);\r
1772       // current feature\r
1773       if (!isExternal && !isAuxiliary)\r
1774         anAdditionalPriority = 30;\r
1775       // external feature\r
1776       if (isExternal)\r
1777         anAdditionalPriority = 20;\r
1778       // auxiliary feature\r
1779       if (isAuxiliary) {\r
1780         anAdditionalPriority = 10; /// auxiliary objects should have less priority that\r
1781         // edges/vertices of local selection on not-sketch objects\r
1782       }\r
1783       Handle(ModuleBase_ResultPrs) aResult = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);\r
1784       if (!aResult.IsNull()) {\r
1785         aResult->setAdditionalSelectionPriority(anAdditionalPriority);\r
1786       }\r
1787     }\r
1788   }\r
1789 }\r
1790 \r
1791 XGUI_Workshop* PartSet_SketcherMgr::workshop() const\r
1792 {\r
1793   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();\r
1794   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);\r
1795   return aConnector->workshop();\r
1796 }\r
1797 \r
1798 XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const\r
1799 {\r
1800   return workshop()->operationMgr();\r
1801 }\r
1802 \r