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