]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_SketcherMgr.cpp
Salome HOME
0e2e7a56b6ae16673afd3bb05ef68ff3d9239b6a
[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     aConstraintIds << SketchPlugin_ConstraintMirror::ID().c_str();\r
736     aConstraintIds << SketchPlugin_MultiTranslation::ID().c_str();\r
737     aConstraintIds << SketchPlugin_MultiRotation::ID().c_str();\r
738   }\r
739   return aConstraintIds;\r
740 }\r
741 \r
742 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)\r
743 {\r
744   theModes.clear();\r
745 \r
746   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);\r
747   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);\r
748   theModes.append(SketcherPrs_Tools::Sel_Constraint);\r
749   theModes.append(TopAbs_VERTEX);\r
750   theModes.append(TopAbs_EDGE);\r
751 }\r
752 \r
753 Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ResultPtr& theResult)\r
754 {\r
755   Handle(AIS_InteractiveObject) aPrs;\r
756 \r
757   FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);\r
758   if (aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID()) {\r
759     aPrs = new PartSet_ResultSketchPrs(theResult);\r
760   }\r
761   return aPrs;\r
762 }\r
763 \r
764 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)\r
765 {\r
766   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();\r
767 }\r
768 \r
769 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation) const\r
770 {\r
771   bool aNestedSketch = false;\r
772 \r
773   FeaturePtr anActiveSketch = activeSketch();\r
774   if (anActiveSketch.get() && theOperation) {\r
775     ModuleBase_Operation* aSketchOperation = operationMgr()->findOperation(\r
776                                                               anActiveSketch->getKind().c_str());\r
777     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
778                                                                                   (theOperation);\r
779     if (aSketchOperation && aFOperation) {\r
780       FeaturePtr aFeature = aFOperation->feature();\r
781       if (aFeature.get()) {\r
782         QStringList aGrantedOpIds = aSketchOperation->grantedOperationIds();\r
783         aNestedSketch = aGrantedOpIds.contains(aFeature->getKind().c_str());\r
784       }\r
785     }\r
786   }\r
787   return aNestedSketch;\r
788 }\r
789 \r
790 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation,\r
791                                                   const CompositeFeaturePtr& theSketch) const\r
792 {\r
793   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
794                                                                (theOperation);\r
795   return aFOperation && !aFOperation->isEditOperation() &&\r
796          isNestedSketchOperation(aFOperation);\r
797 }\r
798 \r
799 bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation,\r
800                                                 const CompositeFeaturePtr& theSketch) const\r
801 {\r
802   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
803                                                                (theOperation);\r
804   return aFOperation && aFOperation->isEditOperation() &&\r
805     isNestedSketchOperation(aFOperation);\r
806 }\r
807 \r
808 bool PartSet_SketcherMgr::isEntity(const std::string& theId)\r
809 {\r
810   return (theId == SketchPlugin_Line::ID()) ||\r
811          (theId == SketchPlugin_Point::ID()) ||\r
812          (theId == SketchPlugin_Arc::ID()) ||\r
813          (theId == SketchPlugin_Circle::ID());\r
814 }\r
815 \r
816 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)\r
817 {\r
818   std::string anId = theOperation ? theOperation->id().toStdString() : "";\r
819 \r
820   return isDistanceKind(anId);\r
821 }\r
822 \r
823 bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)\r
824 {\r
825   return (theKind == SketchPlugin_ConstraintLength::ID()) ||\r
826          (theKind == SketchPlugin_ConstraintDistance::ID()) ||\r
827          (theKind == SketchPlugin_ConstraintRadius::ID()) ||\r
828          (theKind == SketchPlugin_ConstraintAngle::ID());\r
829 }\r
830 \r
831 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)\r
832 {\r
833   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
834                                                                (getCurrentOperation());\r
835   if (!aFOperation)\r
836     return;\r
837 \r
838   myModule->onViewTransformed();\r
839 \r
840   // Display all sketcher sub-Objects\r
841   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());\r
842   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());\r
843 \r
844   // Hide sketcher result\r
845   std::list<ResultPtr> aResults = myCurrentSketch->results();\r
846   std::list<ResultPtr>::const_iterator aIt;\r
847   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
848     (*aIt)->setDisplayed(false);\r
849   }\r
850   myCurrentSketch->setDisplayed(false);\r
851 \r
852   // Remove invalid sketch entities\r
853   std::set<FeaturePtr> anInvalidFeatures;\r
854   ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();\r
855   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
856     FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
857     if (aFeature.get()) {\r
858       if (!aFactory->validate(aFeature))\r
859         anInvalidFeatures.insert(aFeature);\r
860     }\r
861   }\r
862   if (!anInvalidFeatures.empty()) {\r
863     std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;\r
864     ModelAPI_Tools::findAllReferences(anInvalidFeatures, aReferences, false);\r
865 \r
866     std::set<FeaturePtr>::const_iterator anIt = anInvalidFeatures.begin(),\r
867                                          aLast = anInvalidFeatures.end();\r
868     // separate features to references to parameter features and references to others\r
869     QStringList anInvalidFeatureNames;\r
870     for (; anIt != aLast; anIt++) {\r
871       FeaturePtr aFeature = *anIt;\r
872       if (aFeature.get())\r
873         anInvalidFeatureNames.append(aFeature->name().c_str());\r
874     }\r
875     std::string aPrefixInfo = QString("Invalid features of the sketch will be deleted: %1.\n\n").\r
876                                   arg(anInvalidFeatureNames.join(", ")).toStdString().c_str();\r
877     std::set<FeaturePtr> aFeatureRefsToDelete;\r
878     if (ModuleBase_Tools::askToDelete(anInvalidFeatures, aReferences, aConnector->desktop(),\r
879                                       aFeatureRefsToDelete, aPrefixInfo)) {\r
880       if (!aFeatureRefsToDelete.empty())\r
881         anInvalidFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());\r
882       ModelAPI_Tools::removeFeatures(anInvalidFeatures, true);\r
883       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));\r
884       // TODO: call the next method in the XGUI_OperationMgr::onOperationStarted().\r
885       workshop()->errorMgr()->updateAcceptAllAction(myCurrentSketch);\r
886     }\r
887   }\r
888 \r
889   // Display sketcher objects\r
890   QStringList anInfo;\r
891   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
892     FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
893 #ifdef DEBUG_SKETCHER_ENTITIES\r
894     anInfo.append(ModuleBase_Tools::objectInfo(aFeature));\r
895 #endif\r
896     std::list<ResultPtr> aResults = aFeature->results();\r
897     std::list<ResultPtr>::const_iterator aIt;\r
898     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
899       (*aIt)->setDisplayed(true);\r
900     }\r
901     aFeature->setDisplayed(true);\r
902   }\r
903 #ifdef DEBUG_SKETCHER_ENTITIES\r
904   QString anInfoStr = anInfo.join(";\t");\r
905   qDebug(QString("startSketch: %1, %2").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());\r
906 #endif\r
907 \r
908   if(myCirclePointFilter.IsNull()) {\r
909     myCirclePointFilter = new PartSet_CirclePointFilter(myModule->workshop());\r
910   }\r
911 \r
912   myModule->workshop()->viewer()->addSelectionFilter(myCirclePointFilter);\r
913 \r
914   if (myPlaneFilter.IsNull()) \r
915     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();\r
916 \r
917   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);\r
918   bool aHasPlane = false;\r
919   std::shared_ptr<GeomAPI_Pln> aPln;\r
920   aPln = PartSet_Tools::sketchPlane(myCurrentSketch);\r
921   myPlaneFilter->setPlane(aPln);\r
922 \r
923   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
924   // all displayed objects should be activated in current selection modes according to switched\r
925   // plane filter\r
926   if (aPln.get())\r
927     aConnector->activateModuleSelectionModes();\r
928 }\r
929 \r
930 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)\r
931 {\r
932   myIsMouseOverWindow = false;\r
933   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;\r
934   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;\r
935   myIsConstraintsShown[PartSet_Tools::Expressions] = false;\r
936 \r
937   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());\r
938 \r
939   DataPtr aData = myCurrentSketch->data();\r
940   if (!aData->isValid()) {\r
941     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
942     // The sketch was aborted\r
943     myCurrentSketch = CompositeFeaturePtr();\r
944     // TODO: move this outside of if-else\r
945     myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);\r
946     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);\r
947 \r
948     // Erase all sketcher objects\r
949     QObjectPtrList aObjects = aDisplayer->displayedObjects();\r
950     foreach (ObjectPtr aObj, aObjects) {\r
951       DataPtr aObjData = aObj->data();\r
952       if (!aObjData->isValid())\r
953         aObj->setDisplayed(false);\r
954     }\r
955   }\r
956   else {\r
957     // Hide all sketcher sub-Objects\r
958     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
959       FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
960       std::list<ResultPtr> aResults = aFeature->results();\r
961       std::list<ResultPtr>::const_iterator aIt;\r
962       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
963         (*aIt)->setDisplayed(false);\r
964       }\r
965       aFeature->setDisplayed(false);\r
966     }\r
967     // Display sketcher result\r
968     std::list<ResultPtr> aResults = myCurrentSketch->results();\r
969     std::list<ResultPtr>::const_iterator aIt;\r
970     Events_Loop* aLoop = Events_Loop::loop();\r
971     static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);\r
972 \r
973     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
974                                                                            (theOperation);\r
975     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
976       if (!aFOperation->isDisplayedOnStart(*aIt)) {\r
977         (*aIt)->setDisplayed(true);\r
978         // this display event is needed because sketch already may have "displayed" state,\r
979         // but not displayed while it is still active (issue 613, abort of existing sketch)\r
980         ModelAPI_EventCreator::get()->sendUpdated(*aIt, aDispEvent);\r
981       }\r
982     }\r
983     if (!aFOperation->isDisplayedOnStart(myCurrentSketch))\r
984       myCurrentSketch->setDisplayed(true);\r
985     \r
986     myCurrentSketch = CompositeFeaturePtr();\r
987 \r
988     myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);\r
989     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);\r
990 \r
991     Events_Loop::loop()->flush(aDispEvent);\r
992   }\r
993   // restore the module selection modes, which were changed on startSketch\r
994   aConnector->activateModuleSelectionModes();\r
995 }\r
996 \r
997 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)\r
998 {\r
999   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {\r
1000     QCursor* aCurrentCursor = QApplication::overrideCursor();\r
1001     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {\r
1002       QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));\r
1003 #ifdef DEBUG_CURSOR\r
1004       qDebug("startNestedSketch() : Qt::CrossCursor");\r
1005 #endif\r
1006     }\r
1007   }\r
1008 }\r
1009 \r
1010 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)\r
1011 {\r
1012   myIsMouseOverViewProcessed = true;\r
1013   operationMgr()->onValidateOperation();\r
1014   // when sketch nested operation is stopped the cursor should be restored unconditionally\r
1015   //if (canChangeCursor(theOperation)) {\r
1016     QApplication::restoreOverrideCursor();\r
1017 #ifdef DEBUG_CURSOR\r
1018     qDebug("stopNestedSketch() : None");\r
1019 #endif\r
1020   //}\r
1021   /// improvement to deselect automatically all eventual selected objects, when\r
1022   // returning to the neutral point of the Sketcher\r
1023   workshop()->selector()->clearSelection();\r
1024 }\r
1025 \r
1026 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)\r
1027 {\r
1028   if (isNestedCreateOperation(theOperation, activeSketch())) {\r
1029     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1030                                                                              (theOperation);\r
1031     if (aFOperation) {\r
1032       FeaturePtr aFeature = aFOperation->feature();\r
1033       // it is necessary to check the the feature data validity because\r
1034       // some kind of features are removed by an operation commit(the macro state of a feature)\r
1035       if (aFeature.get() && aFeature->data()->isValid()) {\r
1036         visualizeFeature(aFeature, aFOperation->isEditOperation(), true);\r
1037       }\r
1038     }\r
1039   }\r
1040 }\r
1041 \r
1042 void PartSet_SketcherMgr::activatePlaneFilter(const bool& toActivate)\r
1043 {\r
1044   if (toActivate)\r
1045     myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);\r
1046   else\r
1047     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);\r
1048 }\r
1049 \r
1050 bool PartSet_SketcherMgr::operationActivatedByPreselection()\r
1051 {\r
1052   bool isOperationStopped = false;\r
1053   ModuleBase_Operation* anOperation = getCurrentOperation();\r
1054   if(anOperation && isNestedSketchOperation(anOperation)) {\r
1055     // Set final definitions if they are necessary\r
1056     //propertyPanelDefined(aOperation);\r
1057     /// Commit sketcher operations automatically\r
1058     /// distance operation are able to show popup editor to modify the distance value\r
1059     /// after entering the value, the operation should be committed/aborted(by Esc key)\r
1060     bool aCanCommitOperation = true;\r
1061     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1062                                                                             (anOperation);\r
1063     if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {\r
1064       bool aValueAccepted = setDistanceValueByPreselection(anOperation, myModule->workshop(),\r
1065                                                            aCanCommitOperation);\r
1066       if (!aValueAccepted)\r
1067         return isOperationStopped;\r
1068     }\r
1069 \r
1070     if (aCanCommitOperation)\r
1071       isOperationStopped = anOperation->commit();\r
1072     else {\r
1073       anOperation->abort();\r
1074       isOperationStopped = true;\r
1075     }\r
1076   }\r
1077   return isOperationStopped;\r
1078 }\r
1079 \r
1080 bool PartSet_SketcherMgr::canUndo() const\r
1081 {\r
1082   return isNestedCreateOperation(getCurrentOperation(), activeSketch());\r
1083 }\r
1084 \r
1085 bool PartSet_SketcherMgr::canRedo() const\r
1086 {\r
1087   return isNestedCreateOperation(getCurrentOperation(), activeSketch());\r
1088 }\r
1089 \r
1090 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const\r
1091 {\r
1092   bool aCanErase = true;\r
1093   // when the sketch operation is active, results of sketch sub-feature can not be hidden\r
1094   if (myCurrentSketch.get()) {\r
1095     return !isObjectOfSketch(theObject);\r
1096   }\r
1097   return aCanErase;\r
1098 }\r
1099 \r
1100 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const\r
1101 {\r
1102   bool aCanDisplay = true;\r
1103 \r
1104   bool aHasActiveSketch = activeSketch().get() != NULL;\r
1105   if (aHasActiveSketch) {\r
1106     // 1. the sketch feature should not be displayed during the sketch active operation\r
1107     // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch \r
1108     // nested features can be visualized\r
1109     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1110     if (aFeature.get() != NULL && aFeature == activeSketch()) {\r
1111       aCanDisplay = false;\r
1112     }\r
1113     std::shared_ptr<SketchPlugin_Feature> aSketchFeature =\r
1114                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
1115     /// some sketch entities should be never shown, e.g. projection feature\r
1116     if (aSketchFeature.get())\r
1117       aCanDisplay = aSketchFeature->canBeDisplayed();\r
1118   }\r
1119   else { // there are no an active sketch\r
1120     // 2. sketch sub-features should not be visualized if the sketch operation is not active\r
1121     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1122     if (aFeature.get() != NULL) {\r
1123       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =\r
1124                               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);\r
1125       if (aSketchFeature.get()) {\r
1126         aCanDisplay = false;\r
1127       }\r
1128     }\r
1129   }\r
1130 \r
1131   // 3. the method should not filter the objects, which are not related to the current operation.\r
1132   // The object is filtered just if it is a current operation feature or this feature result\r
1133   if (aCanDisplay) {\r
1134     bool isObjectFound = false;\r
1135     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1136                                                                  (getCurrentOperation());\r
1137     if (aFOperation) {\r
1138       FeaturePtr aFeature = aFOperation->feature();\r
1139       if (aFeature.get()) {\r
1140         std::list<ResultPtr> aResults = aFeature->results();\r
1141         if (theObject == aFeature)\r
1142           isObjectFound = true;\r
1143         else {\r
1144           std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();\r
1145           for (; anIt != aLast && !isObjectFound; anIt++) {\r
1146             isObjectFound = *anIt == theObject;\r
1147           }\r
1148         }\r
1149       }\r
1150     }\r
1151     if (isObjectFound) {\r
1152       // 4. For created nested feature operation do not display the created feature if\r
1153       // the mouse curstor leaves the OCC window.\r
1154       // The correction cases, which ignores this condition:\r
1155       // a. the property panel values modification\r
1156       // b. the popup menu activated\r
1157       // c. widget editor control\r
1158       #ifndef DEBUG_DO_NOT_BY_ENTER\r
1159       if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {\r
1160         ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
1161         ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;\r
1162         // the active widget editor should not influence here. The presentation should be visible always\r
1163         // when this widget is active.\r
1164         if (!anEditorWdg && !myIsPopupMenuActive) {\r
1165           // during a nested create operation, the feature is redisplayed only if the mouse over view\r
1166           // of there was a value modified in the property panel after the mouse left the view\r
1167           aCanDisplay = canDisplayCurrentCreatedFeature();\r
1168         }\r
1169       }\r
1170       #endif\r
1171     }\r
1172   }\r
1173 \r
1174   // checks the sketcher constraints visibility according to active sketch check box states\r
1175   if (aCanDisplay) {\r
1176     bool aProcessed = false;\r
1177     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1178     if (aFeature.get()) {\r
1179       bool aConstraintDisplayed = canDisplayConstraint(aFeature, PartSet_Tools::Any, aProcessed);\r
1180       if (aProcessed)\r
1181         aCanDisplay = aConstraintDisplayed;\r
1182     }\r
1183   }\r
1184 \r
1185   return aCanDisplay;\r
1186 }\r
1187 \r
1188 bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,\r
1189                                              const PartSet_Tools::ConstraintVisibleState& theState,\r
1190                                              bool& isProcessed) const\r
1191 {\r
1192   bool aSwitchedOn = true;\r
1193 \r
1194   const QStringList& aConstrIds = constraintsIdList();\r
1195 \r
1196   std::string aKind = theFeature->getKind();\r
1197   if (aConstrIds.contains(QString(aKind.c_str()))) {\r
1198     bool isTypedConstraint = false;\r
1199 \r
1200     switch (theState) {\r
1201       case PartSet_Tools::Dimensional: {\r
1202         bool isDistance = isDistanceKind(aKind);\r
1203         if (isDistance) {\r
1204           isProcessed = true;\r
1205           aSwitchedOn = myIsConstraintsShown[theState];\r
1206         }\r
1207       }\r
1208       break;\r
1209       case PartSet_Tools::Geometrical: {\r
1210         bool isGeometrical = !isDistanceKind(aKind);\r
1211         if (isGeometrical) {\r
1212           isProcessed = true;\r
1213           aSwitchedOn = myIsConstraintsShown[theState];\r
1214         }\r
1215       }\r
1216       break;\r
1217       case PartSet_Tools::Any: {\r
1218         isProcessed = true;\r
1219         bool isDistance = isDistanceKind(aKind);\r
1220         if (isDistance)\r
1221           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Dimensional];\r
1222         else\r
1223           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Geometrical];\r
1224       }\r
1225       break;\r
1226     default:\r
1227       break;\r
1228     }\r
1229   }\r
1230   return aSwitchedOn;\r
1231 }\r
1232 \r
1233 /*void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)\r
1234 {\r
1235   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1236                                                                            (getCurrentOperation());\r
1237   if (aFOperation && myCurrentSketch.get()) {\r
1238     // find results of the current operation\r
1239     // these results should not be proposed to be deleted\r
1240     FeaturePtr anOperationFeature = aFOperation->feature();\r
1241     std::list<ResultPtr> anOperationResultList = anOperationFeature->results();\r
1242     std::set<ResultPtr> anOperationResults;\r
1243     std::list<ResultPtr>::const_iterator aRIt = anOperationResultList.begin(),\r
1244                                         aRLast = anOperationResultList.end();\r
1245     for (; aRIt != aRLast; aRIt++)\r
1246       anOperationResults.insert(*aRIt);\r
1247 \r
1248     std::set<FeaturePtr> anObjectsToBeDeleted;\r
1249     QStringList anObjectsToBeDeletedNames;\r
1250     std::list<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();\r
1251     for (; anIt != aLast; anIt++) {\r
1252       ObjectPtr anObject = *anIt;\r
1253       bool aCanErase = true;\r
1254       // when the sketch operation is active, results of sketch sub-feature can not be hidden\r
1255       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);\r
1256       // the result is found between current feature results\r
1257       if (anOperationResults.find(aResult) != anOperationResults.end())\r
1258         continue;\r
1259 \r
1260       if (aResult.get()) {\r
1261         // Display sketcher objects\r
1262         for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {\r
1263           FeaturePtr aFeature = myCurrentSketch->subFeature(i);\r
1264           std::list<ResultPtr> aResults = aFeature->results();\r
1265           std::list<ResultPtr>::const_iterator anIt;\r
1266           for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {\r
1267             aCanErase = *anIt != aResult;\r
1268           }\r
1269         }\r
1270       }\r
1271       if (!aCanErase) {\r
1272         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);\r
1273         if (aFeature.get() && anObjectsToBeDeleted.find(aFeature) == anObjectsToBeDeleted.end()) {\r
1274           anObjectsToBeDeleted.insert(aFeature);\r
1275           anObjectsToBeDeletedNames.append(aFeature->name().c_str());\r
1276         }\r
1277       }\r
1278     }\r
1279     if (!anObjectsToBeDeleted.empty()) {\r
1280       QString aFeatureNames = anObjectsToBeDeletedNames.join(", ");\r
1281       QString aMessage = tr("The following features have incorrect presentation and \\r
1282 will be hidden: %1. Would you like to delete them?")\r
1283                          .arg(aFeatureNames);\r
1284       int anAnswer = QMessageBox::question(qApp->activeWindow(), tr("Features hide"),\r
1285                                            aMessage, QMessageBox::Ok | QMessageBox::Cancel,\r
1286                                            QMessageBox::Cancel);\r
1287       if (anAnswer == QMessageBox::Ok) {\r
1288         QObjectPtrList anObjects;\r
1289         std::set<FeaturePtr>::const_iterator anIt = anObjectsToBeDeleted.begin(),\r
1290                                              aLast = anObjectsToBeDeleted.end();\r
1291         for (; anIt != aLast; anIt++)\r
1292           anObjects.append(*anIt);\r
1293         SessionPtr aMgr = ModelAPI_Session::get();\r
1294         DocumentPtr aDoc = aMgr->activeDocument();\r
1295         bool aIsOp = aMgr->isOperation();\r
1296         if (!aIsOp)\r
1297           aMgr->startOperation();\r
1298         workshop()->deleteFeatures(anObjects);\r
1299         //static Events_ID aDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);\r
1300         //static Events_ID aRedispEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);\r
1301         //Events_Loop::loop()->flush(aDeletedEvent);\r
1302         //Events_Loop::loop()->flush(aRedispEvent);\r
1303 \r
1304         if (!aIsOp)\r
1305           aMgr->finishOperation();\r
1306       }\r
1307     }\r
1308   }\r
1309 }*/\r
1310 \r
1311 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const\r
1312 {\r
1313   bool aCanDisplay = myIsMouseOverWindow;\r
1314   if (!aCanDisplay) {\r
1315     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();\r
1316     if (anActiveWidget)\r
1317       aCanDisplay = anActiveWidget->getValueState() == ModuleBase_ModelWidget::Stored;\r
1318   }\r
1319   return aCanDisplay;\r
1320 }\r
1321 \r
1322 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const\r
1323 {\r
1324   return isNestedCreateOperation(theOperation, activeSketch()) ||\r
1325          myModule->sketchReentranceMgr()->isInternalEditActive();\r
1326 }\r
1327 \r
1328 const QMap<PartSet_Tools::ConstraintVisibleState, bool>& PartSet_SketcherMgr::showConstraintStates()\r
1329 {\r
1330   return myIsConstraintsShown;\r
1331 }\r
1332 \r
1333 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const\r
1334 {\r
1335   bool isFoundObject = false;\r
1336 \r
1337   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);\r
1338   if (anObjectFeature.get()) {\r
1339     int aSize = myCurrentSketch->numberOfSubs();\r
1340     for (int i = 0; i < myCurrentSketch->numberOfSubs() && !isFoundObject; i++) {\r
1341       FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);\r
1342       isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;\r
1343     }\r
1344   }\r
1345   return isFoundObject;\r
1346 }\r
1347 \r
1348 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)\r
1349 {\r
1350   if (myPlaneFilter.IsNull()) \r
1351    myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();\r
1352 \r
1353   myPlaneFilter->setPlane(thePln);\r
1354 }\r
1355 \r
1356 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,\r
1357                                                          ModuleBase_IWorkshop* theWorkshop,\r
1358                                                          bool& theCanCommitOperation)\r
1359 {\r
1360   bool isValueAccepted = false;\r
1361   theCanCommitOperation = false;\r
1362 \r
1363   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1364                                                                               (theOperation);\r
1365   FeaturePtr aFeature = aFOperation->feature();\r
1366   // editor is shown only if all attribute references are filled by preseletion\r
1367   bool anAllRefAttrInitialized = true;\r
1368 \r
1369   std::list<AttributePtr> aRefAttrs = aFeature->data()->attributes(\r
1370                                               ModelAPI_AttributeRefAttr::typeId());\r
1371   std::list<AttributePtr>::const_iterator anIt = aRefAttrs.begin(), aLast = aRefAttrs.end();\r
1372   for (; anIt != aLast && anAllRefAttrInitialized; anIt++) {\r
1373     anAllRefAttrInitialized = (*anIt)->isInitialized();\r
1374   }\r
1375   if (anAllRefAttrInitialized) {\r
1376     // Activate dimension value editing on double click\r
1377     ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();\r
1378     QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();\r
1379     // Find corresponded widget to activate value editing\r
1380     foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {\r
1381       if (aWgt->attributeID() == "ConstraintValue") {\r
1382         // the featue should be displayed in order to find the AIS text position,\r
1383         // the place where the editor will be shown\r
1384         aFeature->setDisplayed(true);\r
1385         /// the execute is necessary to perform in the feature compute for flyout position\r
1386         aFeature->execute();\r
1387 \r
1388         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));\r
1389         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
1390 \r
1391         PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);\r
1392         if (anEditor) {\r
1393           int aX = 0, anY = 0;\r
1394 \r
1395           XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);\r
1396           XGUI_Displayer* aDisplayer = aWorkshop->displayer();\r
1397           AISObjectPtr anAIS = aDisplayer->getAISObject(aFeature);\r
1398           Handle(AIS_InteractiveObject) anAISIO;\r
1399           if (anAIS.get() != NULL) {\r
1400             anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();\r
1401           }\r
1402           if (anAIS.get() != NULL) {\r
1403             Handle(AIS_InteractiveObject) anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();\r
1404 \r
1405             if (!anAISIO.IsNull()) {\r
1406               Handle(AIS_Dimension) aDim = Handle(AIS_Dimension)::DownCast(anAISIO);\r
1407               if (!aDim.IsNull()) {\r
1408                 gp_Pnt aPosition = aDim->GetTextPosition();\r
1409 \r
1410                 ModuleBase_IViewer* aViewer = aWorkshop->viewer();\r
1411                 Handle(V3d_View) aView = aViewer->activeView();\r
1412                 int aCX, aCY;\r
1413                 aView->Convert(aPosition.X(), aPosition.Y(), aPosition.Z(), aCX, aCY);\r
1414 \r
1415                 QWidget* aViewPort = aViewer->activeViewPort();\r
1416                 QPoint aGlPoint = aViewPort->mapToGlobal(QPoint(aCX, aCY));\r
1417                 aX = aGlPoint.x();\r
1418                 anY = aGlPoint.y();\r
1419               }\r
1420             }\r
1421             anEditor->setCursorPosition(aX, anY);\r
1422             isValueAccepted = anEditor->showPopupEditor(false);\r
1423             theCanCommitOperation = true;\r
1424           }\r
1425         }\r
1426       }\r
1427     }\r
1428   }\r
1429   return isValueAccepted;\r
1430 }\r
1431 \r
1432 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,\r
1433                                              const FeaturePtr& theSketch,\r
1434                                              ModuleBase_IWorkshop* theWorkshop,\r
1435                                              const FeatureToSelectionMap& theSelection,\r
1436                                              SelectMgr_IndexedMapOfOwner& theOwnersToSelect)\r
1437 {\r
1438   if (theFeature.get() == NULL)\r
1439     return;\r
1440 \r
1441   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);\r
1442   std::set<AttributePtr> aSelectedAttributes = anIt.value().first;\r
1443   std::set<ResultPtr> aSelectedResults = anIt.value().second;\r
1444 \r
1445   ModuleBase_IViewer* aViewer = theWorkshop->viewer();\r
1446 \r
1447   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);\r
1448   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();\r
1449 \r
1450   // 1. found the feature's owners. Check the AIS objects of the constructions\r
1451   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);\r
1452   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {\r
1453     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();\r
1454 \r
1455     SelectMgr_IndexedMapOfOwner aSelectedOwners;\r
1456     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);\r
1457     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {\r
1458       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);\r
1459       if (!anOwner.IsNull())\r
1460         theOwnersToSelect.Add(anOwner);\r
1461     }\r
1462   }\r
1463 \r
1464   // 2. found the feature results's owners\r
1465   std::list<ResultPtr> aResults = theFeature->results();\r
1466   std::list<ResultPtr>::const_iterator aIt;\r
1467   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)\r
1468   {\r
1469     ResultPtr aResult = *aIt;\r
1470     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);\r
1471     if (aAISObj.get() == NULL)\r
1472       continue; \r
1473     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();\r
1474 \r
1475     SelectMgr_IndexedMapOfOwner aSelectedOwners;  \r
1476     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);\r
1477     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {\r
1478       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));\r
1479       if ( anOwner.IsNull() || !anOwner->HasShape() )\r
1480         continue;\r
1481       const TopoDS_Shape& aShape = anOwner->Shape();\r
1482       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();\r
1483       if (aShapeType == TopAbs_VERTEX) {\r
1484         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);\r
1485         if (aPntAttr.get() != NULL &&\r
1486             aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end()) {\r
1487           theOwnersToSelect.Add(anOwner);\r
1488         }\r
1489       }\r
1490       else if (aShapeType == TopAbs_EDGE) {\r
1491         bool aFound = aSelectedResults.find(aResult) != aSelectedResults.end();\r
1492         if (aSelectedResults.find(aResult) != aSelectedResults.end() &&\r
1493             theOwnersToSelect.FindIndex(anOwner) <= 0)\r
1494           theOwnersToSelect.Add(anOwner);\r
1495       }\r
1496     }\r
1497   }\r
1498 }\r
1499 \r
1500 void PartSet_SketcherMgr::connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect)\r
1501 {\r
1502   if (isToConnect) {\r
1503     connect(theWidget, SIGNAL(beforeValuesChanged()),\r
1504             this, SLOT(onBeforeValuesChangedInPropertyPanel()));\r
1505     connect(theWidget, SIGNAL(afterValuesChanged()),\r
1506             this, SLOT(onAfterValuesChangedInPropertyPanel()));\r
1507   }\r
1508   else {\r
1509     disconnect(theWidget, SIGNAL(beforeValuesChanged()),\r
1510                 this, SLOT(onBeforeValuesChangedInPropertyPanel()));\r
1511     disconnect(theWidget, SIGNAL(afterValuesChanged()),\r
1512                 this, SLOT(onAfterValuesChangedInPropertyPanel()));\r
1513   }\r
1514 }\r
1515 \r
1516 void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)\r
1517 {\r
1518   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1519                                                                            (getCurrentOperation());\r
1520   if (aFOperation) {\r
1521     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||\r
1522         isNestedSketchOperation(aFOperation) &&\r
1523         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {\r
1524       FeaturePtr aFeature = aFOperation->feature();\r
1525       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));\r
1526     }\r
1527   }\r
1528 }\r
1529 \r
1530 void PartSet_SketcherMgr::customizePresentation(const ObjectPtr& theObject)\r
1531 {\r
1532   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>\r
1533                                                                            (getCurrentOperation());\r
1534   if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||\r
1535                       isNestedSketchOperation(aFOperation)))\r
1536     SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);\r
1537 \r
1538   // update entities selection priorities\r
1539   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);\r
1540   if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {\r
1541     // update priority for feature\r
1542     updateSelectionPriority(aFeature, aFeature);\r
1543     // update priority for results of the feature\r
1544     std::list<ResultPtr> aResults = aFeature->results();\r
1545     std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();\r
1546     for (; anIt != aLastIt; anIt++)\r
1547       updateSelectionPriority(*anIt, aFeature);\r
1548   }\r
1549 }\r
1550 \r
1551 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const\r
1552 {\r
1553   return myModule->workshop()->currentOperation();\r
1554 }\r
1555 \r
1556 //**************************************************************\r
1557 ModuleBase_ModelWidget* PartSet_SketcherMgr::getActiveWidget() const\r
1558 {\r
1559   ModuleBase_ModelWidget* aWidget = 0;\r
1560   ModuleBase_Operation* anOperation = getCurrentOperation();\r
1561   if (anOperation) {\r
1562     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();\r
1563     if (aPanel)\r
1564       aWidget = aPanel->activeWidget();\r
1565   }\r
1566   return aWidget;\r
1567 }\r
1568 \r
1569 void PartSet_SketcherMgr::visualizeFeature(const FeaturePtr& theFeature,\r
1570                                            const bool isEditOperation,\r
1571                                            const bool isToDisplay,\r
1572                                            const bool isFlushRedisplay)\r
1573 {\r
1574   #ifdef DEBUG_DO_NOT_BY_ENTER\r
1575   return;\r
1576   #endif\r
1577 \r
1578   if (isEditOperation || !theFeature.get())\r
1579     return;\r
1580 \r
1581   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1582   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
1583 \r
1584   // 1. change visibility of the object itself, here the presentable object is processed,\r
1585   // e.g. constraints features\r
1586   //FeaturePtr aFeature = aFOperation->feature();\r
1587   std::list<ResultPtr> aResults = theFeature->results();\r
1588   if (isToDisplay)\r
1589     theFeature->setDisplayed(true);\r
1590   else\r
1591     theFeature->setDisplayed(false);\r
1592 \r
1593   // change visibility of the object results, e.g. non-constraint features\r
1594   std::list<ResultPtr>::const_iterator aIt;\r
1595   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
1596     if (isToDisplay) {\r
1597       (*aIt)->setDisplayed(true);\r
1598     }\r
1599     else {\r
1600       (*aIt)->setDisplayed(false);\r
1601     }\r
1602   }\r
1603   if (isFlushRedisplay)\r
1604     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
1605 }\r
1606 \r
1607 void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)\r
1608 {\r
1609   if (!myCurrentSketch.get())\r
1610     return;\r
1611 \r
1612   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1613   ModuleBase_ISelection* aSelect = aWorkshop->selection();\r
1614   QList<ModuleBase_ViewerPrsPtr> aStoredPrs = aSelect->getHighlighted();\r
1615 \r
1616   QList<FeaturePtr> aFeatureList;\r
1617   if (!theHighlightedOnly) {\r
1618     QList<ModuleBase_ViewerPrsPtr> aSelected = aSelect->getSelected(\r
1619                                                               ModuleBase_ISelection::AllControls);\r
1620     aStoredPrs.append(aSelected);\r
1621   }\r
1622 \r
1623   // 1. it is necessary to save current selection in order to restore it after the features moving\r
1624   myCurrentSelection.clear();\r
1625 \r
1626   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = aStoredPrs.begin(), aLast = aStoredPrs.end();\r
1627 \r
1628   CompositeFeaturePtr aSketch = activeSketch();\r
1629   for (; anIt != aLast; anIt++) {\r
1630     ModuleBase_ViewerPrsPtr aPrs = *anIt;\r
1631     ObjectPtr anObject = aPrs->object();\r
1632     if (!anObject.get())\r
1633       continue;\r
1634 \r
1635     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);\r
1636     FeaturePtr aFeature;\r
1637     if (aResult.get())\r
1638       aFeature = ModelAPI_Feature::feature(aResult);\r
1639     else\r
1640       aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);\r
1641 \r
1642 \r
1643     std::set<AttributePtr> aSelectedAttributes;\r
1644     std::set<ResultPtr> aSelectedResults;\r
1645     if (myCurrentSelection.find(aFeature) != myCurrentSelection.end()) {\r
1646       std::pair<std::set<AttributePtr>, std::set<ResultPtr> > aPair = myCurrentSelection.find(aFeature).value();\r
1647       aSelectedAttributes = aPair.first;\r
1648       aSelectedResults = aPair.second;\r
1649     }\r
1650 \r
1651     Handle(SelectMgr_EntityOwner) anOwner = aPrs->owner();\r
1652     if (aResult.get()) {\r
1653       getAttributesOrResults(anOwner, aFeature, aSketch, aResult,\r
1654                              aSelectedAttributes, aSelectedResults);\r
1655     }\r
1656     else {\r
1657       std::list<ResultPtr> aResults = aFeature->results();\r
1658       std::list<ResultPtr>::const_iterator aIt;\r
1659       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {\r
1660         ResultPtr aResult = *aIt;\r
1661         getAttributesOrResults(anOwner, aFeature, aSketch, aResult,\r
1662                                aSelectedAttributes, aSelectedResults);\r
1663       }\r
1664     }\r
1665     myCurrentSelection[aFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);\r
1666   }\r
1667   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());\r
1668 }\r
1669 \r
1670 void PartSet_SketcherMgr::restoreSelection()\r
1671 {\r
1672   if (!myCurrentSketch.get())\r
1673     return;\r
1674 \r
1675   //qDebug(QString("restoreSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());\r
1676   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1677   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
1678   FeatureToSelectionMap::const_iterator aSIt = myCurrentSelection.begin(),\r
1679                                         aSLast = myCurrentSelection.end();\r
1680   SelectMgr_IndexedMapOfOwner anOwnersToSelect;\r
1681   for (; aSIt != aSLast; aSIt++) {\r
1682     anOwnersToSelect.Clear();\r
1683     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, myCurrentSelection,\r
1684                         anOwnersToSelect);\r
1685     aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);\r
1686   }\r
1687 }\r
1688 \r
1689 void PartSet_SketcherMgr::onShowConstraintsToggle(int theType, bool theState)\r
1690 {\r
1691   PartSet_Tools::ConstraintVisibleState aType = (PartSet_Tools::ConstraintVisibleState)theType;\r
1692 \r
1693   updateBySketchParameters(aType, theState);\r
1694 }\r
1695 \r
1696 void PartSet_SketcherMgr::updateBySketchParameters(\r
1697                                    const PartSet_Tools::ConstraintVisibleState& theType,\r
1698                                    bool theState)\r
1699 {\r
1700   if (myCurrentSketch.get() == NULL)\r
1701     return;\r
1702 \r
1703   bool aPrevState = myIsConstraintsShown[theType];\r
1704   myIsConstraintsShown[theType] = theState;\r
1705 \r
1706   switch (theType) {\r
1707     case PartSet_Tools::Geometrical:\r
1708     case PartSet_Tools::Dimensional: {\r
1709       if (aPrevState != theState) {\r
1710         ModuleBase_IWorkshop* aWorkshop = myModule->workshop();\r
1711         XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);\r
1712         for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {\r
1713           FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);\r
1714           bool aProcessed = false;\r
1715           bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, theType, aProcessed);\r
1716           if (aProcessed)\r
1717             aSubFeature->setDisplayed(aConstraintDisplayed);\r
1718         }\r
1719         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));\r
1720       }\r
1721     }\r
1722     break;\r
1723     case PartSet_Tools::Expressions: {\r
1724       if (aPrevState != theState) {\r
1725         /// call all sketch features redisplay, the expression state will be corrected in customize\r
1726         /// of distance presentation\r
1727         Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);\r
1728         PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);\r
1729       }\r
1730     }\r
1731     break;\r
1732   }\r
1733 }\r
1734 \r
1735 void PartSet_SketcherMgr::updateSelectionPriority(ObjectPtr theObject,\r
1736                                                   FeaturePtr theFeature)\r
1737 {\r
1738   if (!theObject.get() || !theFeature.get())\r
1739     return;\r
1740 \r
1741   AISObjectPtr anAIS = workshop()->displayer()->getAISObject(theObject);\r
1742   Handle(AIS_InteractiveObject) anAISIO;\r
1743   if (anAIS.get() != NULL) {\r
1744     anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();\r
1745   }\r
1746 \r
1747   if (!anAISIO.IsNull()) { // the presentation for the object is visualized\r
1748     int anAdditionalPriority = 0;\r
1749     // current feature\r
1750     std::shared_ptr<SketchPlugin_Feature> aSPFeature =\r
1751             std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);\r
1752     if (aSPFeature.get() != NULL) {\r
1753       // 1. Vertices\r
1754       // 2. Simple segments\r
1755       // 3. External objects (violet color)\r
1756       // 4. Auxiliary segments (dotted)\r
1757       // StdSelect_BRepSelectionTool::Load uses priority calculating:\r
1758       // Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;\r
1759       // Priority of Vertex is 8, edge(segment) is 7.\r
1760       // It might be not corrected as provides the condition above.\r
1761       bool isExternal = aSPFeature->isExternal();\r
1762       bool isAuxiliary = PartSet_Tools::isAuxiliarySketchEntity(aSPFeature);\r
1763       // current feature\r
1764       if (!isExternal && !isAuxiliary)\r
1765         anAdditionalPriority = 30;\r
1766       // external feature\r
1767       if (isExternal)\r
1768         anAdditionalPriority = 20;\r
1769       // auxiliary feature\r
1770       if (isAuxiliary) {\r
1771         anAdditionalPriority = 10; /// auxiliary objects should have less priority that\r
1772         // edges/vertices of local selection on not-sketch objects\r
1773       }\r
1774       Handle(ModuleBase_ResultPrs) aResult = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);\r
1775       if (!aResult.IsNull()) {\r
1776         aResult->setAdditionalSelectionPriority(anAdditionalPriority);\r
1777       }\r
1778     }\r
1779   }\r
1780 }\r
1781 \r
1782 XGUI_Workshop* PartSet_SketcherMgr::workshop() const\r
1783 {\r
1784   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();\r
1785   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);\r
1786   return aConnector->workshop();\r
1787 }\r
1788 \r
1789 XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const\r
1790 {\r
1791   return workshop()->operationMgr();\r
1792 }\r
1793 \r