Salome HOME
Merge branch 'occ/shaper2smesh'
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "PartSet_SketcherMgr.h"
21
22 #include "PartSet_Filters.h"
23 #include "PartSet_SketcherReentrantMgr.h"
24 #include "PartSet_Module.h"
25 #include "PartSet_MouseProcessor.h"
26 #include "PartSet_Tools.h"
27 #include "PartSet_WidgetSketchLabel.h"
28 #include "PartSet_WidgetEditor.h"
29 #include "PartSet_ResultSketchPrs.h"
30 #include "PartSet_ExternalPointsMgr.h"
31 #include "PartSet_PreviewSketchPlane.h"
32
33 #include <XGUI_ModuleConnector.h>
34 #include <XGUI_Displayer.h>
35 #include <XGUI_Workshop.h>
36 #include <XGUI_ContextMenuMgr.h>
37 #include <XGUI_Selection.h>
38 #include <XGUI_SelectionActivate.h>
39 #include <XGUI_SelectionMgr.h>
40 #include <XGUI_ModuleConnector.h>
41 #include <XGUI_PropertyPanel.h>
42 #include <XGUI_ViewerProxy.h>
43 #include <XGUI_OperationMgr.h>
44 #include <XGUI_ErrorMgr.h>
45 #include <XGUI_Tools.h>
46
47 #include <ModuleBase_IPropertyPanel.h>
48 #include <ModuleBase_ISelection.h>
49 #include <ModuleBase_IViewer.h>
50 #include <ModuleBase_IWorkshop.h>
51 #include <ModuleBase_IViewWindow.h>
52 #include <ModuleBase_ModelWidget.h>
53 #include <ModuleBase_Operation.h>
54 #include <ModuleBase_OperationFeature.h>
55 #include <ModuleBase_Operation.h>
56 #include <ModuleBase_WidgetEditor.h>
57 #include <ModuleBase_ViewerPrs.h>
58 #include <ModuleBase_Tools.h>
59 #include <ModuleBase_ResultPrs.h>
60 #include <ModuleBase_ViewerFilters.h>
61
62 #include <GeomDataAPI_Point2D.h>
63 #include <GeomDataAPI_Point2DArray.h>
64
65 #include <GeomAPI_Shape.h>
66
67 #include <Events_Loop.h>
68
69 #include <SketchPlugin_Line.h>
70 #include <SketchPlugin_Sketch.h>
71 #include <SketchPlugin_Point.h>
72 #include <SketchPlugin_Arc.h>
73 #include <SketchPlugin_Circle.h>
74 #include <SketchPlugin_Ellipse.h>
75 #include <SketchPlugin_EllipticArc.h>
76 #include <SketchPlugin_ConstraintLength.h>
77 #include <SketchPlugin_ConstraintDistance.h>
78 #include <SketchPlugin_ConstraintParallel.h>
79 #include <SketchPlugin_ConstraintPerpendicular.h>
80 #include <SketchPlugin_ConstraintRadius.h>
81 #include <SketchPlugin_ConstraintRigid.h>
82 #include <SketchPlugin_ConstraintHorizontal.h>
83 #include <SketchPlugin_ConstraintVertical.h>
84 #include <SketchPlugin_ConstraintEqual.h>
85 #include <SketchPlugin_ConstraintTangent.h>
86 #include <SketchPlugin_ConstraintCoincidence.h>
87 #include <SketchPlugin_Fillet.h>
88 #include <SketchPlugin_ConstraintMirror.h>
89 #include <SketchPlugin_ConstraintAngle.h>
90 #include <SketchPlugin_ConstraintCollinear.h>
91 #include <SketchPlugin_ConstraintMiddle.h>
92 #include <SketchPlugin_MultiRotation.h>
93 #include <SketchPlugin_MultiTranslation.h>
94 #include <SketchPlugin_IntersectionPoint.h>
95 #include <SketchPlugin_Projection.h>
96 #include <SketchPlugin_ConstraintDistanceAlongDir.h>
97 #include <SketchPlugin_ConstraintDistanceHorizontal.h>
98 #include <SketchPlugin_ConstraintDistanceVertical.h>
99
100 #include <SketcherPrs_Tools.h>
101
102 #include <SelectMgr_IndexedMapOfOwner.hxx>
103 #include <StdSelect_BRepOwner.hxx>
104
105 //#include <AIS_DimensionSelectionMode.hxx>
106 #include <AIS_Shape.hxx>
107 #include <AIS_Dimension.hxx>
108
109 #include <ModelAPI_Events.h>
110 #include <ModelAPI_Session.h>
111 #include <ModelAPI_AttributeString.h>
112
113 #include <ModelAPI_Validator.h>
114 #include <ModelAPI_Tools.h>
115
116 #include <QMouseEvent>
117 #include <QApplication>
118 #include <QCursor>
119 #include <QMessageBox>
120 #include <QMainWindow>
121
122 #include <set>
123
124 //#define DEBUG_DO_NOT_BY_ENTER
125 //#define DEBUG_SKETCHER_ENTITIES
126 //#define DEBUG_SKETCH_ENTITIES_ON_MOVE
127 //#define DRAGGING_DEBUG
128 //#define DEBUG_CURSOR
129
130
131 #ifdef DRAGGING_DEBUG
132 #include <QTime>
133 #endif
134
135 /// Fills attribute and result lists by the selected owner. In case if the attribute is found,
136 /// by the owner shape, it is put to the list. Otherwise if type of owner shape is edge,
137 /// put the function result as is to the list of results.
138 /// \param theOwner a viewer selected owner
139 /// \param theFeature a feature, where the attribute is searched
140 /// \param theSketch a current sketch
141 /// \param theSelectedAttribute an output list of attributes
142 /// \param theSelectedResults an output list of edge results
143 void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,
144                             const FeaturePtr& theFeature, const FeaturePtr& theSketch,
145                             const ResultPtr& theResult,
146                             std::map<AttributePtr, int>& theSelectedAttributes,
147                             std::set<ResultPtr>& theSelectedResults,
148                             TopTools_MapOfShape& theShapes)
149 {
150   Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(theOwner);
151   if (aBRepOwner.IsNull())
152     return;
153   Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast(
154                                                                     aBRepOwner->Selectable());
155   if (aBRepOwner->HasShape()) {
156     const TopoDS_Shape& aShape = aBRepOwner->Shape();
157     theShapes.Add(aShape);
158     TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
159     if (aShapeType == TopAbs_VERTEX) {
160       std::pair<AttributePtr, int> aPntAttrIndex =
161           PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
162       if (aPntAttrIndex.first.get() != NULL)
163         theSelectedAttributes[aPntAttrIndex.first] = aPntAttrIndex.second;
164     }
165     else if (aShapeType == TopAbs_EDGE &&
166              theSelectedResults.find(theResult) == theSelectedResults.end()) {
167       theSelectedResults.insert(theResult);
168     }
169   }
170 }
171
172 PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
173   : QObject(theModule), myModule(theModule), myIsEditLaunching(false), myIsDragging(false),
174     myDragDone(false), myIsMouseOverWindow(false),
175     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),
176     myIsPopupMenuActive(false), myExternalPointsMgr(0), myNoDragMoving(false)
177 {
178   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
179   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
180
181   myPreviousDrawModeEnabled = true;//aViewer->isSelectionEnabled();
182
183   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),
184           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));
185
186   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),
187           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));
188
189   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
190           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));
191
192   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),
193           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));
194
195   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
196   XGUI_Workshop* aWorkshop = aConnector->workshop();
197   connect(aWorkshop, SIGNAL(applicationStarted()), this, SLOT(onApplicationStarted()));
198
199   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
200   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
201   myIsConstraintsShown[PartSet_Tools::Expressions] = false;
202
203   mySketchPlane = new PartSet_PreviewSketchPlane();
204
205   registerSelectionFilter(SF_SketchCirclePointFilter, new PartSet_CirclePointFilter(anIWorkshop));
206   registerSelectionFilter(SF_SketchPlaneFilter, new ModuleBase_ShapeInPlaneFilter());
207
208   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_DOF_OBJECTS));
209 }
210
211 PartSet_SketcherMgr::~PartSet_SketcherMgr()
212 {
213   delete mySketchPlane;
214 }
215
216 void PartSet_SketcherMgr::onEnterViewPort()
217 {
218   // 1. if the mouse over window, update the next flag. Do not perform update visibility of
219   // created feature because it should be done in onMouseMove(). Some widgets watch
220   // the mouse move and use the cursor position to update own values. If the presentaion is
221   // redisplayed before this update, the feature presentation jumps from reset value to current.
222   myIsMouseOverWindow = true;
223
224   #ifdef DEBUG_DO_NOT_BY_ENTER
225   return;
226   #endif
227
228   // It is switched off because of
229   // Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
230     if (canChangeCursor(getCurrentOperation())) {
231       QCursor* aCurrentCursor = QApplication::overrideCursor();
232       if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
233         QApplication::setOverrideCursor(PartSet_Tools::getOperationCursor());
234   //#ifdef DEBUG_CURSOR
235   //      qDebug("onEnterViewPort() : Qt::CrossCursor");
236   //#endif
237       }
238     }
239
240   if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
241     return;
242
243   operationMgr()->onValidateOperation();
244
245   // we need change displayed state of the current operation feature
246   // if the feature is presentable, e.g. distance construction. It has no results, so workshop does
247   // not accept a signal about the result created. Nothing is shown until mouse is moved out/in view
248   // port. If the isDisplayed flag is true, the presentable feature is displayed as soon as the
249   // presentation becomes valid and redisplay happens
250   //ModuleBase_Operation* aOperation = getCurrentOperation();
251   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
252                                                                            (getCurrentOperation());
253   if (aFOperation) {
254     FeaturePtr aFeature = aFOperation->feature();
255     if (aFeature.get() && aFeature->data()->isValid()) {
256       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature), false);
257     }
258   }
259 }
260
261 void PartSet_SketcherMgr::onLeaveViewPort()
262 {
263   myIsMouseOverViewProcessed = false;
264   myIsMouseOverWindow = false;
265
266   #ifdef DEBUG_DO_NOT_BY_ENTER
267   return;
268   #endif
269
270   if (canChangeCursor(getCurrentOperation())) {
271     QApplication::restoreOverrideCursor();
272 //#ifdef DEBUG_CURSOR
273 //    qDebug("onLeaveViewPort() : None");
274 //#endif
275   }
276
277   if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
278     return;
279
280   // the method should be performed if the popup menu is called,
281   // the reset of the current widget should not happen
282   if (myIsPopupMenuActive)
283     return;
284
285   // it is important to validate operation here only if sketch entity create operation is active
286   // because at this operation we reacts to the mouse leave/enter view port
287   operationMgr()->onValidateOperation();
288
289   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation
290   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
291   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
292   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
293   // disable the viewer update in order to avoid visualization of redisplayed feature in viewer
294   // obtained after reset value
295   bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
296   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
297   if (anActiveWidget)
298     anActiveWidget->reset();
299
300   // hides the presentation of the current operation feature
301   // the feature is to be erased here, but it is correct to call canDisplayObject because
302   // there can be additional check (e.g. editor widget in distance constraint)
303   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
304                                                                            (getCurrentOperation());
305   if (aFOperation) {
306     FeaturePtr aFeature = aFOperation->feature();
307     visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
308   }
309   // we should update viewer after the presentation are hidden in the viewer
310   // otherwise the reset presentation(line) appears in the viewer(by quick move from viewer to PP)
311   aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
312 }
313
314 /*
315 //Temporary commented as we do not modify values in property panel
316 void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()
317 {
318   if (!isNestedEditOperation(getCurrentOperation(), myModule->sketchMgr()->activeSketch()) ||
319       myModule->sketchReentranceMgr()->isInternalEditActive())
320     return;
321   // it is necessary to save current selection in order to restore it after the values are modifed
322   storeSelection(ST_SelectAndHighlightType);
323
324   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
325   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
326   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
327   myPreviousUpdateViewerEnabled = aDisplayer->enableUpdateViewer(false);
328 }
329
330 void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()
331 {
332   if (!isNestedEditOperation(getCurrentOperation(), myModule->sketchMgr()->activeSketch()) ||
333       myModule->sketchReentranceMgr()->isInternalEditActive()) {
334     myModule->sketchReentranceMgr()->updateInternalEditActiveState();
335     return;
336   }
337   // it is necessary to restore current selection in order to restore it after values are modified
338   restoreSelection();
339   myCurrentSelection.clear();
340
341   // 3. the flag to disable the update viewer should be set in order to avoid blinking in the
342   // viewer happens by deselect/select the modified objects. The flag should be restored after
343   // the selection processing. The update viewer should be also called.
344   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
345   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
346   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
347   aDisplayer->enableUpdateViewer(myPreviousUpdateViewerEnabled);
348   aDisplayer->updateViewer();
349 }
350 */
351
352 bool PartSet_SketcherMgr::isDragModeCreation() const
353 {
354   ModuleBase_Operation* aOp = getCurrentOperation();
355   if (!aOp)
356     return false;
357   bool aUserPref = Config_PropManager::boolean(SKETCH_TAB_NAME, "create_by_dragging");
358   if (!aUserPref)
359     return false;
360   QString aId = aOp->id();
361   // Acceptable features;
362   QStringList aList;
363   aList << "SketchLine" << "SketchMacroCircle" << "SketchMacroArc" <<
364     "SketchMacroEllipse" << "SketchMacroEllipticArc" << "SketchRectangle";
365   return aList.contains(aId);
366 }
367
368 static bool MyModeByDrag = false;
369 static bool MyMultiselectionState = true;
370
371 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
372 {
373   MyModeByDrag = isDragModeCreation();
374
375   // Clear dragging mode
376   myIsDragging = false;
377
378   myMousePoint.setX(theEvent->x());
379   myMousePoint.setY(theEvent->y());
380
381   if (myModule->sketchReentranceMgr()->processMousePressed(theWnd, theEvent))
382     return;
383   //get2dPoint(theWnd, theEvent, myClickedPoint);
384   if (!(theEvent->buttons() & Qt::LeftButton))
385     return;
386
387   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
388   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
389   //if (!aViewer->canDragByMouse())
390   //  return;
391
392   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
393                                                                (getCurrentOperation());
394   if (!aFOperation)
395     return;
396
397   bool isEditing = aFOperation->isEditOperation();
398   bool aCanDrag = aViewer->canDragByMouse();
399
400   //if (!aViewer->canDragByMouse() && isEditing) {
401   //  // Do not edit by dragging
402   //  return;
403   //}
404
405   if (isEditing) {
406     // If the current widget is a selector, do nothing, it processes the mouse press
407     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
408     if(anActiveWidget && anActiveWidget->isViewerSelector()) {
409       return;
410     }
411   }
412
413   // Use only for sketch operations
414   if (myCurrentSketch) {
415     if (!PartSet_Tools::sketchPlane(myCurrentSketch))
416       return;
417
418     bool isSketcher = isSketchOperation(aFOperation);
419     bool isSketchOpe = isNestedSketchOperation(aFOperation);
420
421     // Avoid non-sketch operations
422     if ((!isSketchOpe) && (!isSketcher))
423       return;
424
425     // Ignore creation sketch operation
426     if ((!isSketcher) && (!isEditing)) {
427       if (MyModeByDrag) {
428         ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
429         PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
430         if (aProcessor) {
431           MyMultiselectionState = aViewer->isMultiSelectionEnabled();
432           aViewer->enableMultiselection(false);
433           myIsDragging = true;
434           ModuleBase_ISelection* aSelection = aWorkshop->selection();
435           QList<ModuleBase_ViewerPrsPtr> aPreSelected = aSelection->getHighlighted();
436           if (!aPreSelected.empty())
437             aProcessor->setPreSelection(aPreSelected.first(), theWnd, theEvent);
438           else
439             aProcessor->mouseReleased(theWnd, theEvent);
440         }
441       }
442       return;
443     }
444     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
445     storeSelection(aHasShift ? ST_SelectAndHighlightType : ST_HighlightType, myCurrentSelection);
446
447     if (myCurrentSelection.empty()) {
448       if (isSketchOpe && (!isSketcher))
449         // commit previous operation
450         if (!aFOperation->commit())
451           aFOperation->abort();
452       return;
453     }
454     // Init flyout point for radius rotation
455     FeaturePtr aFeature = myCurrentSelection.begin().key();
456     get2dPoint(theWnd, theEvent, myCurrentPoint);
457     if (isSketcher) {
458       if (aCanDrag) {
459         myIsDragging = true;
460         myDragDone = false;
461       }
462       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
463       launchEditing();
464       if (aFeature.get() != NULL) {
465         std::shared_ptr<SketchPlugin_Feature> aSPFeature =
466                   std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
467         if (aSPFeature.get() &&
468           (aSPFeature->getKind() == SketchPlugin_ConstraintRadius::ID() ||
469            aSPFeature->getKind() == SketchPlugin_ConstraintAngle::ID())) {
470           DataPtr aData = aSPFeature->data();
471           AttributePtr aAttr = aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
472           std::shared_ptr<GeomDataAPI_Point2D> aFPAttr =
473             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aAttr);
474           aFPAttr->setValue(myCurrentPoint.myCurX, myCurrentPoint.myCurY);
475         }
476       }
477     } else if (isSketchOpe && isEditing) {
478       // If selected another object commit current result
479       bool aPrevLaunchingState = myIsEditLaunching;
480       /// store editing state for Edit operation in order to do not clear highlight by restart
481       /// of edit operation.
482       /// Internal edit should not be stored as editing operation as the result will be a
483       /// creation operation, where previous selection should not be used(and will be cleared)
484       myIsEditLaunching = !myModule->sketchReentranceMgr()->isInternalEditActive();
485
486       std::shared_ptr<SketchPlugin_Feature> aSPFeature =
487         std::dynamic_pointer_cast<SketchPlugin_Feature>(aFOperation->feature());
488       bool isRelaunchEditing = true;
489       if (aSPFeature->isExternal()) {
490         foreach(FeaturePtr aF, myCurrentSelection.keys()) {
491           FeaturePtr aProducerFeature = PartSet_Tools::findRefsToMeFeature(aF,
492             aSPFeature->getKind());
493           if (aProducerFeature == aSPFeature) {
494             isRelaunchEditing = false;
495             break;
496           }
497         }
498       }
499       else {
500         if (myCurrentSelection.size() > 1)
501           isRelaunchEditing = !myCurrentSelection.contains(aSPFeature);
502       }
503       if (isRelaunchEditing)
504         aFOperation->commit();
505
506       if (aCanDrag) {
507         myIsDragging = true;
508         myDragDone = false;
509       }
510       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
511       if (isRelaunchEditing)
512         launchEditing();
513       myIsEditLaunching = aPrevLaunchingState;
514       if (aFeature.get() != NULL) {
515         std::shared_ptr<SketchPlugin_Feature> aSPFeature =
516                   std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
517         if (aSPFeature.get() &&
518           (aSPFeature->getKind() == SketchPlugin_ConstraintRadius::ID() ||
519            aSPFeature->getKind() == SketchPlugin_ConstraintAngle::ID())) {
520           DataPtr aData = aSPFeature->data();
521           AttributePtr aAttr = aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
522           std::shared_ptr<GeomDataAPI_Point2D> aFPAttr =
523             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aAttr);
524           aFPAttr->setValue(myCurrentPoint.myCurX, myCurrentPoint.myCurY);
525         }
526       }
527     }
528   }
529 }
530
531 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
532 {
533   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
534   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
535   if (myIsDragging)
536     aViewer->enableDrawMode(myPreviousDrawModeEnabled);
537
538   bool aWasDragging = myIsDragging;
539   myIsDragging = false;
540
541   if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent)) {
542     return;
543   }
544   // if mouse is pressed when it was over view and at release the mouse is out of view, do nothing
545   if (!myIsMouseOverViewProcessed) {
546     return;
547   }
548
549   ModuleBase_OperationFeature* aOp =
550     dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
551   bool isEditing = false;
552   if (aOp) {
553     isEditing = aOp->isEditOperation();
554     bool aStartNoDragOperation = !aViewer->canDragByMouse() && isEditing;
555     if (aStartNoDragOperation || myNoDragMoving) {
556       // Process edit operation without dragging
557       if (myCurrentSelection.size() > 0)
558         myNoDragMoving = !myNoDragMoving;
559       else
560         myNoDragMoving = false;
561       if (myNoDragMoving)
562         return;
563       else {
564         restoreSelection(myCurrentSelection);
565         myCurrentSelection.clear();
566       }
567     }
568     else {
569       if (isNestedSketchOperation(aOp)) {
570         // Only for sketcher operations
571         if (aWasDragging) {
572           if (myDragDone) {
573             /// the previous selection is lost by mouse release in the viewer(Select method), but
574             /// it is still stored in myCurrentSelection. So, it is possible to restore selection
575             /// It is important for drag(edit with mouse) of sketch entities.
576             restoreSelection(myCurrentSelection);
577             myCurrentSelection.clear();
578           }
579         }
580       }
581     }
582   }
583
584   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
585   PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
586   if (aProcessor) {
587     ModuleBase_ISelection* aSelection = aWorkshop->selection();
588     QList<ModuleBase_ViewerPrsPtr> aPreSelected = aSelection->getHighlighted();
589     if (MyModeByDrag && !aPreSelected.empty() && !isEditing)
590       aProcessor->setPreSelection(aPreSelected.first(), theWnd, theEvent);
591     else
592       aProcessor->mouseReleased(theWnd, theEvent);
593   }
594   if (MyModeByDrag && aOp) {
595     QString aOpId = aOp->id();
596     if (aOpId == "Sketch")
597       return;
598     QPoint aPnt(theEvent->x(), theEvent->y());
599     anActiveWidget = getActiveWidget();
600     if ((aPnt == myMousePoint) && anActiveWidget) {
601       aOp->abort();
602       return;
603     }
604     bool aCanRestart = !anActiveWidget && !isEditing;
605     if (aCanRestart) {
606       module()->launchOperation(aOpId, true);
607     }
608   }
609 }
610
611 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
612 {
613 #ifdef DEBUG_SKETCH_ENTITIES_ON_MOVE
614   CompositeFeaturePtr aSketch = activeSketch();
615   if (aSketch.get()) {
616     std::cout << "mouse move SKETCH FEATURES [" << aSketch->numberOfSubs() << "]:" << std::endl;
617     QStringList anInfo;
618     for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
619       //std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
620       anInfo.append(ModuleBase_Tools::objectInfo(aSketch->subFeature(i)));
621     }
622     QString anInfoStr = anInfo.join("\n");
623     qDebug(QString("%1").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
624   }
625 #endif
626
627   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
628     return;
629
630   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
631   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
632   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
633
634   if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {
635 #ifdef DRAGGING_DEBUG
636     QTime t;
637     t.start();
638 #endif
639     // 1. perform the widget mouse move functionality and display the presentation
640     // the mouse move should be processed in the widget, if it can in order to visualize correct
641     // presentation. These widgets correct the feature attribute according to the mouse position
642     ModuleBase_ModelWidget* anActiveWidget = myModule->activeWidget();
643     PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
644     if (aProcessor)
645       aProcessor->mouseMoved(theWnd, theEvent);
646     if (!myIsMouseOverViewProcessed) {
647       myIsMouseOverViewProcessed = true;
648
649       // the feature is to be erased here, but it is correct to call canDisplayObject because
650       // there can be additional check (e.g. editor widget in distance constraint)
651       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
652         (getCurrentOperation());
653       if (aFOperation) {
654         FeaturePtr aFeature = aFOperation->feature();
655         visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
656       }
657     }
658     aDisplayer->updateViewer();
659 #ifdef DRAGGING_DEBUG
660     cout << "Mouse move processing " << t.elapsed() << endl;
661 #endif
662   }
663   //myClickedPoint.clear();
664
665   if (myIsDragging || myNoDragMoving) {
666     // 1. the current selection is saved in the mouse press method in order to restore it after
667     //    moving
668     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
669     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
670     // deselected). This flag should be restored in the slot, processed the mouse release signal.
671     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
672     if (!aCurrentOperation)
673       return;
674     if (isSketchOperation(aCurrentOperation))
675       return; // No edit operation activated
676
677 #ifdef DRAGGING_DEBUG
678     QTime t;
679     t.start();
680 #endif
681
682     Handle(V3d_View) aView = theWnd->v3dView();
683     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
684     Point aMousePnt;
685     get2dPoint(theWnd, theEvent, aMousePnt);
686
687     std::shared_ptr<GeomAPI_Pnt2d> anOriginalPosition = std::shared_ptr<GeomAPI_Pnt2d>(
688       new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
689     std::shared_ptr<GeomAPI_Pnt2d> aCurrentPosition = std::shared_ptr<GeomAPI_Pnt2d>(
690       new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
691
692     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the
693     // viewer happens by deselect/select the modified objects. The flag should be restored after
694     // the selection processing. The update viewer should be also called.
695     bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
696
697     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
698     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
699     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
700       aLast = myCurrentSelection.end();
701     // 4. the features and attributes modification(move)
702     bool isModified = false;
703     for (; anIt != aLast; anIt++) {
704       FeaturePtr aFeature = anIt.key();
705
706       std::map<AttributePtr, int> anAttributes = anIt.value().myAttributes;
707       // Process selection by attribute: the priority to the attribute
708       if (!anAttributes.empty()) {
709         std::map<AttributePtr, int>::const_iterator anAttIt = anAttributes.begin(),
710           anAttLast = anAttributes.end();
711         for (; anAttIt != anAttLast; anAttIt++) {
712           AttributePtr anAttr = anAttIt->first;
713           if (anAttr.get() == NULL)
714             continue;
715           std::string aAttrId = anAttr->id();
716           DataPtr aData = aFeature->data();
717           if (aData->isValid()) {
718             AttributePtr aPoint = aData->attribute(aAttrId);
719             if (aPoint->attributeType() == GeomDataAPI_Point2D::typeId() ||
720                 aPoint->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
721               bool isImmutable = aPoint->setImmutable(true);
722
723               std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
724                 <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
725               aMessage->setMovedAttribute(aPoint, anAttIt->second);
726               aMessage->setOriginalPosition(anOriginalPosition);
727               aMessage->setCurrentPosition(aCurrentPosition);
728               Events_Loop::loop()->send(aMessage);
729
730               isModified = true;
731               aPoint->setImmutable(isImmutable);
732             }
733           }
734         }
735       }
736       else {
737         // Process selection by feature
738         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
739           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
740         if (aSketchFeature) {
741           std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
742             <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
743           aMessage->setMovedObject(aFeature);
744           aMessage->setOriginalPosition(anOriginalPosition);
745           aMessage->setCurrentPosition(aCurrentPosition);
746           Events_Loop::loop()->send(aMessage);
747           isModified = true;
748         }
749       }
750     }
751     // the modified state of the current operation should be updated if there are features, which
752     // were changed here
753     if (isModified) {
754       aCurrentOperation->onValuesChanged();
755       Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
756     }
757     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations
758
759     // 5. it is necessary to save current selection in order to restore it after the features moving
760     restoreSelection(myCurrentSelection);
761     // 6. restore the update viewer flag and call this update
762     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
763     aDisplayer->updateViewer();
764
765 #ifdef DRAGGING_DEBUG
766     cout << "Mouse move processing " << t.elapsed() << endl;
767 #endif
768
769     myDragDone = true;
770     myCurrentPoint = aMousePnt;
771   }
772 }
773
774 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
775 {
776   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
777                                                                (getCurrentOperation());
778   if (aFOperation && aFOperation->isEditOperation()) {
779     std::string aId = aFOperation->id().toStdString();
780     if (isDistanceOperation(aFOperation))
781     {
782       // Activate dimension value editing on double click
783       ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
784       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
785       // Find corresponded widget to activate value editing
786       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
787         std::string anId = aWgt->attributeID();
788         if (anId == SketchPlugin_Constraint::VALUE() ||
789           anId == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID() ||
790           anId == SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID()) {
791           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
792           if (anEditor)
793             anEditor->showPopupEditor();
794           return;
795         }
796       }
797     }
798   }
799 }
800
801 void PartSet_SketcherMgr::onApplicationStarted()
802 {
803   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
804   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
805   XGUI_Workshop* aWorkshop = aConnector->workshop();
806   PartSet_SketcherReentrantMgr* aReentranceMgr = myModule->sketchReentranceMgr();
807
808   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
809   if (aPropertyPanel) {
810     //connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),
811     //        this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));
812
813     connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),
814             aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));
815     //connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
816     //        aReentranceMgr, SLOT(onWidgetActivated()));
817   }
818
819   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
820   connect(aViewerProxy, SIGNAL(enterViewPort()), this, SLOT(onEnterViewPort()));
821   connect(aViewerProxy, SIGNAL(leaveViewPort()), this, SLOT(onLeaveViewPort()));
822
823   XGUI_ContextMenuMgr* aContextMenuMgr = aWorkshop->contextMenuMgr();
824   connect(aContextMenuMgr, SIGNAL(beforeContextMenu()), this, SLOT(onBeforeContextMenu()));
825   connect(aContextMenuMgr, SIGNAL(afterContextMenu()), this, SLOT(onAfterContextMenu()));
826 }
827
828 //void PartSet_SketcherMgr::onBeforeWidgetActivated(ModuleBase_ModelWidget* theWidget)
829 //{
830   //if (!myClickedPoint.myIsInitialized)
831   //  return;
832
833   //ModuleBase_Operation* aOperation = getCurrentOperation();
834   // the distance constraint feature should not use the clickedd point
835   // this is workaround in order to don't throw down the flyout point value,
836   // set by execute() method of these type of features
837   //if (isDistanceOperation(aOperation))
838   //  return;
839
840   //PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(theWidget);
841   //if (aPnt2dWgt) {
842   //  aPnt2dWgt->setPoint(myClickedPoint.myCurX, myClickedPoint.myCurY);
843   //}
844 //}
845
846 void PartSet_SketcherMgr::onBeforeContextMenu()
847 {
848   myIsPopupMenuActive = true;
849 }
850
851 void PartSet_SketcherMgr::onAfterContextMenu()
852 {
853   myIsPopupMenuActive = false;
854 }
855
856 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent,
857                                      Point& thePoint)
858 {
859   Handle(V3d_View) aView = theWnd->v3dView();
860   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
861   double aX, anY;
862   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, anY);
863   thePoint.setValue(aX, anY);
864 }
865
866 void PartSet_SketcherMgr::launchEditing()
867 {
868   if (!myCurrentSelection.empty()) {
869     FeaturePtr aFeature = myCurrentSelection.begin().key();
870     std::shared_ptr<SketchPlugin_Feature> aSPFeature =
871               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
872     if (aSPFeature) {
873       if (!aSPFeature->isExternal())
874         myModule->editFeature(aSPFeature);
875       else {
876         // need to edit a feature (Projection/IntersectionPoint),
877         // which produces current External feature
878         FeaturePtr aProducerFeature = PartSet_Tools::findRefsToMeFeature(aFeature,
879                                                         SketchPlugin_Projection::ID());
880         if (!aProducerFeature.get())
881           aProducerFeature = PartSet_Tools::findRefsToMeFeature(aFeature,
882                                                         SketchPlugin_IntersectionPoint::ID());
883         if (aProducerFeature.get())
884           myModule->editFeature(aProducerFeature);
885       }
886     }
887   }
888 }
889
890 bool PartSet_SketcherMgr::sketchSolverError()
891 {
892   bool anError = false;
893   CompositeFeaturePtr aSketch = activeSketch();
894   if (aSketch.get()) {
895     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
896     anError = !aAttributeString->value().empty();
897   }
898   return anError;
899 }
900
901 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
902 {
903   QString anError;
904   if (!theFeature.get() || !theFeature->data()->isValid())
905     return anError;
906
907   CompositeFeaturePtr aSketch = activeSketch();
908   if (aSketch.get() && aSketch == theFeature) {
909     std::string aSolverError = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR())->value();
910     anError = ModuleBase_Tools::translate(aSketch->getKind(), aSolverError);
911   }
912   return anError;
913 }
914
915 void PartSet_SketcherMgr::clearClickedFlags()
916 {
917   //myClickedPoint.clear();
918   myCurrentPoint.clear();
919 }
920
921 const QStringList& PartSet_SketcherMgr::replicationsIdList()
922 {
923   static QStringList aReplicationIds;
924   if (aReplicationIds.size() == 0) {
925     aReplicationIds << SketchPlugin_ConstraintMirror::ID().c_str();
926     aReplicationIds << SketchPlugin_MultiRotation::ID().c_str();
927     aReplicationIds << SketchPlugin_MultiTranslation::ID().c_str();
928   }
929   return aReplicationIds;
930 }
931
932 const QStringList& PartSet_SketcherMgr::constraintsIdList()
933 {
934   static QStringList aConstraintIds;
935   if (aConstraintIds.size() == 0) {
936     aConstraintIds << SketchPlugin_ConstraintLength::ID().c_str();
937     aConstraintIds << SketchPlugin_ConstraintDistance::ID().c_str();
938     aConstraintIds << SketchPlugin_ConstraintRigid::ID().c_str();
939     aConstraintIds << SketchPlugin_ConstraintRadius::ID().c_str();
940     aConstraintIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
941     aConstraintIds << SketchPlugin_ConstraintParallel::ID().c_str();
942     aConstraintIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
943     aConstraintIds << SketchPlugin_ConstraintVertical::ID().c_str();
944     aConstraintIds << SketchPlugin_ConstraintEqual::ID().c_str();
945     aConstraintIds << SketchPlugin_ConstraintTangent::ID().c_str();
946     aConstraintIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
947     aConstraintIds << SketchPlugin_ConstraintAngle::ID().c_str();
948     aConstraintIds << SketchPlugin_ConstraintCollinear::ID().c_str();
949     aConstraintIds << SketchPlugin_ConstraintMiddle::ID().c_str();
950     aConstraintIds << SketchPlugin_ConstraintMirror::ID().c_str();
951     aConstraintIds << SketchPlugin_MultiTranslation::ID().c_str();
952     aConstraintIds << SketchPlugin_MultiRotation::ID().c_str();
953     aConstraintIds << SketchPlugin_ConstraintDistanceAlongDir::ID().c_str();
954     aConstraintIds << SketchPlugin_ConstraintDistanceHorizontal::ID().c_str();
955     aConstraintIds << SketchPlugin_ConstraintDistanceVertical::ID().c_str();
956   }
957   return aConstraintIds;
958 }
959
960 void PartSet_SketcherMgr::sketchSelectionModes(const CompositeFeaturePtr& theSketch,
961                                                QIntList& theModes)
962 {
963   if (!theSketch.get() || !PartSet_Tools::sketchPlane(theSketch).get())
964     return;
965
966   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
967   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
968   theModes.append(SketcherPrs_Tools::Sel_Constraint);
969   theModes.append(TopAbs_VERTEX);
970   theModes.append(TopAbs_EDGE);
971 }
972
973 Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ObjectPtr& theObj)
974 {
975   Handle(AIS_InteractiveObject) aPrs;
976
977   FeaturePtr aFeature = ModelAPI_Feature::feature(theObj);
978   if (aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID()) {
979     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObj);
980     if (aResult.get())
981       aPrs = new PartSet_ResultSketchPrs(aResult);
982   }
983   return aPrs;
984 }
985
986 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
987 {
988   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
989 }
990
991 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation) const
992 {
993   bool aNestedSketch = false;
994
995   FeaturePtr anActiveSketch = activeSketch();
996   if (anActiveSketch.get() && theOperation) {
997     ModuleBase_Operation* aSketchOperation = operationMgr()->findOperation(
998                                                               anActiveSketch->getKind().c_str());
999     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1000                                                                                   (theOperation);
1001     if (aSketchOperation && aFOperation) {
1002       FeaturePtr aFeature = aFOperation->feature();
1003       if (aFeature.get()) {
1004         QStringList aGrantedOpIds = aSketchOperation->grantedOperationIds();
1005         aNestedSketch = aGrantedOpIds.contains(aFeature->getKind().c_str());
1006       }
1007     }
1008   }
1009   return aNestedSketch;
1010 }
1011
1012 bool PartSet_SketcherMgr::isNestedSketchFeature(const QString& theFeatureKind) const
1013 {
1014   bool aNestedSketch = false;
1015
1016   FeaturePtr anActiveSketch = activeSketch();
1017   if (anActiveSketch.get()) {
1018     ModuleBase_Operation* aSketchOperation = operationMgr()->findOperation(
1019                                                               anActiveSketch->getKind().c_str());
1020     if (aSketchOperation) {
1021       QStringList aGrantedOpIds = aSketchOperation->grantedOperationIds();
1022       aNestedSketch = aGrantedOpIds.contains(theFeatureKind);
1023     }
1024   }
1025   return aNestedSketch;
1026 }
1027
1028 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation,
1029                                                   const CompositeFeaturePtr& theSketch) const
1030 {
1031   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1032                                                                (theOperation);
1033   return aFOperation && !aFOperation->isEditOperation() &&
1034          isNestedSketchOperation(aFOperation);
1035 }
1036
1037 bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation,
1038                                                 const CompositeFeaturePtr& theSketch) const
1039 {
1040   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1041                                                                (theOperation);
1042   return aFOperation && aFOperation->isEditOperation() &&
1043     isNestedSketchOperation(aFOperation);
1044 }
1045
1046 bool PartSet_SketcherMgr::isEntity(const std::string& theId)
1047 {
1048   return (theId == SketchPlugin_Line::ID()) ||
1049          (theId == SketchPlugin_Point::ID()) ||
1050          (theId == SketchPlugin_Arc::ID()) ||
1051          (theId == SketchPlugin_Circle::ID()) ||
1052          (theId == SketchPlugin_Ellipse::ID()) ||
1053          (theId == SketchPlugin_Projection::ID()) ||
1054          (theId == SketchPlugin_IntersectionPoint::ID()) ||
1055          (theId == SketchPlugin_EllipticArc::ID());
1056 }
1057
1058 bool PartSet_SketcherMgr::isExternalFeature(const FeaturePtr& theFeature)
1059 {
1060   std::shared_ptr<SketchPlugin_Feature> aSPFeature =
1061           std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
1062   return aSPFeature.get() && aSPFeature->isExternal();
1063 }
1064
1065 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)
1066 {
1067   std::string anId = theOperation ? theOperation->id().toStdString() : "";
1068
1069   return isDistanceKind(anId);
1070 }
1071
1072 bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)
1073 {
1074   return (theKind == SketchPlugin_ConstraintLength::ID()) ||
1075          (theKind == SketchPlugin_ConstraintDistance::ID()) ||
1076          (theKind == SketchPlugin_ConstraintRadius::ID()) ||
1077          (theKind == SketchPlugin_ConstraintAngle::ID()) ||
1078          (theKind == SketchPlugin_ConstraintDistanceHorizontal::ID()) ||
1079          (theKind == SketchPlugin_ConstraintDistanceVertical::ID()) ||
1080          (theKind == SketchPlugin_ConstraintDistanceAlongDir::ID());
1081 }
1082
1083 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
1084 {
1085   static Events_ID EVENT_ATTR = Events_Loop::loop()->eventByName(EVENT_VISUAL_ATTRIBUTES);
1086   static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1087
1088   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1089                                                                (getCurrentOperation());
1090   if (!aFOperation)
1091     return;
1092
1093   SketcherPrs_Tools::setPixelRatio(ModuleBase_Tools::currentPixelRatio());
1094
1095   myModule->onViewTransformed();
1096
1097   // Display all sketcher sub-Objects
1098   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
1099   double aSizeOfView = 0;
1100   std::shared_ptr<GeomAPI_Pnt> aCentralPoint;
1101   if (aFOperation->isEditOperation() &&
1102       mySketchPlane->getDefaultSizeOfView(myCurrentSketch, aSizeOfView, aCentralPoint)) {
1103     mySketchPlane->setSizeOfView(aSizeOfView, true, aCentralPoint);
1104   }
1105
1106   mySketchPlane->createSketchPlane(myCurrentSketch, myModule->workshop());
1107   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
1108
1109   // Hide sketcher result
1110   std::list<ResultPtr> aResults = myCurrentSketch->results();
1111   std::list<ResultPtr>::const_iterator aIt;
1112   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1113     (*aIt)->setDisplayed(false);
1114   }
1115   myCurrentSketch->setDisplayed(false);
1116
1117   // Remove invalid sketch entities
1118   std::set<FeaturePtr> anInvalidFeatures;
1119   ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
1120   int aNumberOfSubs = myCurrentSketch->numberOfSubs();
1121   for (int i = 0; i < aNumberOfSubs; i++) {
1122     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1123     if (aFeature.get()) {
1124       if (!aFactory->validate(aFeature))
1125         anInvalidFeatures.insert(aFeature);
1126     }
1127   }
1128   if (!anInvalidFeatures.empty()) {
1129     std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
1130     ModelAPI_Tools::findAllReferences(anInvalidFeatures, aReferences, false);
1131
1132     std::set<FeaturePtr>::const_iterator anIt = anInvalidFeatures.begin(),
1133                                          aLast = anInvalidFeatures.end();
1134     // separate features to references to parameter features and references to others
1135     QStringList anInvalidFeatureNames;
1136     for (; anIt != aLast; anIt++) {
1137       FeaturePtr aFeature = *anIt;
1138       if (aFeature.get())
1139         anInvalidFeatureNames.append(aFeature->name().c_str());
1140     }
1141     std::string aPrefixInfo = QString("Invalid features of the sketch will be deleted: %1.\n\n").
1142                                   arg(anInvalidFeatureNames.join(", ")).toStdString().c_str();
1143     std::set<FeaturePtr> aFeatureRefsToDelete;
1144     if (ModuleBase_Tools::askToDelete(anInvalidFeatures, aReferences, aConnector->desktop(),
1145                                       aFeatureRefsToDelete, aPrefixInfo)) {
1146       if (!aFeatureRefsToDelete.empty())
1147         anInvalidFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());
1148       ModelAPI_Tools::removeFeatures(anInvalidFeatures, true);
1149       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
1150       // TODO: call the next method in the XGUI_OperationMgr::onOperationStarted().
1151       workshop()->errorMgr()->updateAcceptAllAction(myCurrentSketch);
1152     }
1153   }
1154
1155   // update state of overconstraint listener should be done before sketch features/results
1156   // display (as the display will ask custom color from the listener)
1157   myModule->overconstraintListener()->setActive(true);
1158   // Display sketcher objects
1159   QStringList anInfo;
1160   const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
1161   aNumberOfSubs = myCurrentSketch->numberOfSubs();
1162   for (int i = 0; i < aNumberOfSubs; i++) {
1163     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1164 #ifdef DEBUG_SKETCHER_ENTITIES
1165     anInfo.append(ModuleBase_Tools::objectInfo(aFeature));
1166 #endif
1167     std::list<ResultPtr> aResults = aFeature->results();
1168     std::list<ResultPtr>::const_iterator aIt;
1169     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1170       if ((*aIt)->isDisplayed())
1171         // Display object if it was created outside of GUI
1172         aECreator->sendUpdated((*aIt), EVENT_DISP);
1173       else
1174         (*aIt)->setDisplayed(true);
1175     }
1176     if (aFeature->isDisplayed())
1177       aECreator->sendUpdated(aFeature, EVENT_DISP);
1178     else
1179       aFeature->setDisplayed(true);
1180     aECreator->sendUpdated(aFeature, EVENT_ATTR);
1181   }
1182 #ifdef DEBUG_SKETCHER_ENTITIES
1183   QString anInfoStr = anInfo.join(";\t");
1184   qDebug(QString("startSketch: %1, %2").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
1185 #endif
1186
1187   bool aHasPlane = false;
1188   std::shared_ptr<GeomAPI_Pln> aPln;
1189   aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
1190   Handle(SelectMgr_Filter) aFilter = myModule->selectionFilter(SF_SketchPlaneFilter);
1191   if (!aFilter.IsNull())
1192     Handle(ModuleBase_ShapeInPlaneFilter)::DownCast(aFilter)->setPlane(aPln);
1193
1194   workshop()->selectionActivate()->updateSelectionFilters();
1195   workshop()->selectionActivate()->updateSelectionModes();
1196
1197   Events_Loop::loop()->flush(EVENT_DISP);
1198   Events_Loop::loop()->flush(EVENT_ATTR);
1199
1200   myExternalPointsMgr = new PartSet_ExternalPointsMgr(myModule->workshop(), myCurrentSketch);
1201
1202   workshop()->viewer()->set2dMode(true);
1203
1204   PartSet_Fitter* aFitter = new PartSet_Fitter(this);
1205   myModule->workshop()->viewer()->setFitter(aFitter);
1206 }
1207
1208 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
1209 {
1210   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
1211   PartSet_Fitter* aFitter = (PartSet_Fitter*)myModule->workshop()->viewer()->fitter();
1212   myModule->workshop()->viewer()->setFitter(0);
1213   delete aFitter;
1214
1215   myIsMouseOverWindow = false;
1216   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
1217   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
1218   myIsConstraintsShown[PartSet_Tools::Expressions] = false;
1219
1220   if (myExternalPointsMgr) {
1221     delete myExternalPointsMgr;
1222     myExternalPointsMgr = 0;
1223   }
1224   onShowPoints(false);
1225
1226   DataPtr aData = myCurrentSketch->data();
1227   if (!aData->isValid()) {
1228     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1229     // The sketch was aborted
1230     myCurrentSketch = CompositeFeaturePtr();
1231     mySketchPlane->eraseSketchPlane(myModule->workshop());
1232
1233     // Erase all sketcher objects
1234     QObjectPtrList aObjects = aDisplayer->displayedObjects();
1235     foreach (ObjectPtr aObj, aObjects) {
1236       DataPtr aObjData = aObj->data();
1237       if (!aObjData->isValid())
1238         aObj->setDisplayed(false);
1239     }
1240   }
1241   else {
1242     // Hide all sketcher sub-Objects
1243     int aNumberOfSubs = myCurrentSketch->numberOfSubs();
1244     for (int i = 0; i < aNumberOfSubs; i++) {
1245       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1246       std::list<ResultPtr> aResults = aFeature->results();
1247       std::list<ResultPtr>::const_iterator aIt;
1248       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1249         (*aIt)->setDisplayed(false);
1250       }
1251       aFeature->setDisplayed(false);
1252     }
1253     // Display sketcher result
1254     std::list<ResultPtr> aResults = myCurrentSketch->results();
1255     std::list<ResultPtr>::const_iterator aIt;
1256     Events_Loop* aLoop = Events_Loop::loop();
1257     static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
1258
1259     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1260                                                                            (theOperation);
1261     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1262       if (!aFOperation->isDisplayedOnStart(*aIt)) {
1263         (*aIt)->setDisplayed(true);
1264         // this display event is needed because sketch already may have "displayed" state,
1265         // but not displayed while it is still active (issue 613, abort of existing sketch)
1266         ModelAPI_EventCreator::get()->sendUpdated(*aIt, aDispEvent);
1267       }
1268     }
1269     if (!aFOperation->isDisplayedOnStart(myCurrentSketch))
1270       myCurrentSketch->setDisplayed(true);
1271
1272     myCurrentSketch = CompositeFeaturePtr();
1273     mySketchPlane->eraseSketchPlane(myModule->workshop());
1274
1275     Events_Loop::loop()->flush(aDispEvent);
1276   }
1277   workshop()->selectionActivate()->updateSelectionFilters();
1278   workshop()->selectionActivate()->updateSelectionModes();
1279   workshop()->viewer()->set2dMode(false);
1280 }
1281
1282 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
1283 {
1284   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
1285     QCursor* aCurrentCursor = QApplication::overrideCursor();
1286     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
1287       QApplication::setOverrideCursor(PartSet_Tools::getOperationCursor());
1288 //#ifdef DEBUG_CURSOR
1289 //      qDebug("startNestedSketch() : Qt::CrossCursor");
1290 //#endif
1291     }
1292   }
1293 }
1294
1295 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
1296 {
1297   myIsMouseOverViewProcessed = true;
1298   operationMgr()->onValidateOperation();
1299   // when sketch nested operation is stopped the cursor should be restored unconditionally
1300   if (canChangeCursor(theOperation)) {
1301     QApplication::restoreOverrideCursor();
1302 #ifdef DEBUG_CURSOR
1303     qDebug("stopNestedSketch() : None");
1304 #endif
1305   }
1306   /// improvement to deselect automatically all eventual selected objects, when
1307   // returning to the neutral point of the Sketcher
1308   bool isClearSelectionPossible = true;
1309   if (myIsEditLaunching) {
1310     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1311                                                                           (theOperation);
1312     if (aFOperation) {
1313       FeaturePtr aFeature = aFOperation->feature();
1314       if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
1315         isClearSelectionPossible = false;
1316       }
1317     }
1318   }
1319   if (isClearSelectionPossible)
1320     workshop()->selector()->clearSelection();
1321   if (myPointsHighlight.size())
1322     onShowPoints(true);
1323 }
1324
1325 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
1326 {
1327   if (isNestedCreateOperation(theOperation, activeSketch())) {
1328     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1329                                                                              (theOperation);
1330     if (aFOperation) {
1331       FeaturePtr aFeature = aFOperation->feature();
1332       // it is necessary to check the the feature data validity because
1333       // some kind of features are removed by an operation commit(the macro state of a feature)
1334       if (aFeature.get() && aFeature->data()->isValid()) {
1335         visualizeFeature(aFeature, aFOperation->isEditOperation(), true);
1336       }
1337     }
1338   }
1339 }
1340
1341 bool PartSet_SketcherMgr::sketchSelectionFilter(const ModuleBase_SelectionFilterType theFilterType)
1342 {
1343   return mySelectionFilterTypes.find(theFilterType) != mySelectionFilterTypes.end();
1344 }
1345
1346 void PartSet_SketcherMgr::registerSelectionFilter(
1347   const ModuleBase_SelectionFilterType theFilterType, const Handle(SelectMgr_Filter)& theFilter)
1348 {
1349   mySelectionFilterTypes.insert(theFilterType);
1350   myModule->registerSelectionFilter(theFilterType, theFilter);
1351 }
1352
1353 bool PartSet_SketcherMgr::operationActivatedByPreselection()
1354 {
1355   bool isOperationStopped = false;
1356   ModuleBase_Operation* anOperation = getCurrentOperation();
1357   if(anOperation && isNestedSketchOperation(anOperation)) {
1358     // Set final definitions if they are necessary
1359     //propertyPanelDefined(aOperation);
1360     /// Commit sketcher operations automatically
1361     /// distance operation are able to show popup editor to modify the distance value
1362     /// after entering the value, the operation should be committed/aborted(by Esc key)
1363     bool aCanCommitOperation = true;
1364     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1365                                                                             (anOperation);
1366     if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {
1367       bool aValueAccepted = setDistanceValueByPreselection(anOperation, myModule->workshop(),
1368                                                            aCanCommitOperation);
1369       if (!aValueAccepted)
1370         return isOperationStopped;
1371     }
1372
1373     if (aCanCommitOperation)
1374       isOperationStopped = anOperation->commit();
1375     else {
1376       anOperation->abort();
1377       isOperationStopped = true;
1378     }
1379   }
1380   return isOperationStopped;
1381 }
1382
1383 bool PartSet_SketcherMgr::canUndo() const
1384 {
1385   return isNestedCreateOperation(getCurrentOperation(), activeSketch());
1386 }
1387
1388 bool PartSet_SketcherMgr::canRedo() const
1389 {
1390   return isNestedCreateOperation(getCurrentOperation(), activeSketch());
1391 }
1392
1393 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const
1394 {
1395   bool aCanErase = true;
1396   // when the sketch operation is active, results of sketch sub-feature can not be hidden
1397   if (myCurrentSketch.get()) {
1398     return !isObjectOfSketch(theObject);
1399   }
1400   return aCanErase;
1401 }
1402
1403 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
1404 {
1405   bool aCanDisplay = true;
1406
1407   bool aHasActiveSketch = activeSketch().get() != NULL;
1408   if (aHasActiveSketch) {
1409     // 1. the sketch feature should not be displayed during the sketch active operation
1410     // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch
1411     // nested features can be visualized
1412     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1413     if (aFeature.get() != NULL && aFeature == activeSketch()) {
1414       aCanDisplay = false;
1415     }
1416     std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1417                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1418     /// some sketch entities should be never shown, e.g. projection feature
1419     if (aSketchFeature.get())
1420       aCanDisplay = aSketchFeature->canBeDisplayed();
1421   }
1422   else { // there are no an active sketch
1423     // 2. sketch sub-features should not be visualized if the sketch operation is not active
1424     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1425     if (aFeature.get() != NULL) {
1426       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1427                               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1428       if (aSketchFeature.get()) {
1429         aCanDisplay = false;
1430       }
1431     }
1432   }
1433
1434   // 3. the method should not filter the objects, which are not related to the current operation.
1435   // The object is filtered just if it is a current operation feature or this feature result
1436   if (aCanDisplay) {
1437     bool isObjectFound = false;
1438     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1439                                                                  (getCurrentOperation());
1440     if (aFOperation) {
1441       FeaturePtr aFeature = aFOperation->feature();
1442       if (aFeature.get()) {
1443         std::list<ResultPtr> aResults = aFeature->results();
1444         if (theObject == aFeature)
1445           isObjectFound = true;
1446         else {
1447           std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
1448           for (; anIt != aLast && !isObjectFound; anIt++) {
1449             isObjectFound = *anIt == theObject;
1450           }
1451         }
1452       }
1453     }
1454     if (isObjectFound) {
1455       // 4. For created nested feature operation do not display the created feature if
1456       // the mouse curstor leaves the OCC window.
1457       // The correction cases, which ignores this condition:
1458       // a. the property panel values modification
1459       // b. the popup menu activated
1460       // c. widget editor control
1461       #ifndef DEBUG_DO_NOT_BY_ENTER
1462       if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {
1463         ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1464         ModuleBase_WidgetEditor* anEditorWdg =
1465           anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
1466         // the active widget editor should not influence here. The presentation should be visible
1467         // always when this widget is active.
1468         if (!anEditorWdg && !myIsPopupMenuActive) {
1469           // during a nested create operation, the feature is redisplayed only
1470           // if the mouse over view
1471           // of there was a value modified in the property panel after the mouse left the view
1472           aCanDisplay = canDisplayCurrentCreatedFeature();
1473         }
1474       }
1475       #endif
1476     }
1477   }
1478
1479   // checks the sketcher constraints visibility according to active sketch check box states
1480   if (aCanDisplay) {
1481     bool aProcessed = false;
1482     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1483     if (aFeature.get()) {
1484       bool aConstraintDisplayed = canDisplayConstraint(aFeature, PartSet_Tools::Any, aProcessed);
1485       if (aProcessed)
1486         aCanDisplay = aConstraintDisplayed;
1487     }
1488   }
1489
1490   return aCanDisplay;
1491 }
1492
1493 bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,
1494                                              const PartSet_Tools::ConstraintVisibleState& theState,
1495                                              bool& isProcessed) const
1496 {
1497   bool aSwitchedOn = true;
1498
1499   const QStringList& aConstrIds = constraintsIdList();
1500
1501   std::string aKind = theFeature->getKind();
1502   if (aConstrIds.contains(QString(aKind.c_str()))) {
1503     bool isTypedConstraint = false;
1504
1505     switch (theState) {
1506       case PartSet_Tools::Dimensional: {
1507         bool isDistance = isDistanceKind(aKind);
1508         if (isDistance) {
1509           isProcessed = true;
1510           aSwitchedOn = myIsConstraintsShown[theState];
1511         }
1512       }
1513       break;
1514       case PartSet_Tools::Geometrical: {
1515         bool isGeometrical = !isDistanceKind(aKind);
1516         if (isGeometrical) {
1517           isProcessed = true;
1518           aSwitchedOn = myIsConstraintsShown[theState];
1519         }
1520       }
1521       break;
1522       case PartSet_Tools::Any: {
1523         isProcessed = true;
1524         bool isDistance = isDistanceKind(aKind);
1525         if (isDistance)
1526           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Dimensional];
1527         else
1528           aSwitchedOn = myIsConstraintsShown[PartSet_Tools::Geometrical];
1529       }
1530       break;
1531     default:
1532       break;
1533     }
1534   }
1535   return aSwitchedOn;
1536 }
1537
1538 /*void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)
1539 {
1540   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1541                                                                            (getCurrentOperation());
1542   if (aFOperation && myCurrentSketch.get()) {
1543     // find results of the current operation
1544     // these results should not be proposed to be deleted
1545     FeaturePtr anOperationFeature = aFOperation->feature();
1546     std::list<ResultPtr> anOperationResultList = anOperationFeature->results();
1547     std::set<ResultPtr> anOperationResults;
1548     std::list<ResultPtr>::const_iterator aRIt = anOperationResultList.begin(),
1549                                         aRLast = anOperationResultList.end();
1550     for (; aRIt != aRLast; aRIt++)
1551       anOperationResults.insert(*aRIt);
1552
1553     std::set<FeaturePtr> anObjectsToBeDeleted;
1554     QStringList anObjectsToBeDeletedNames;
1555     std::list<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();
1556     for (; anIt != aLast; anIt++) {
1557       ObjectPtr anObject = *anIt;
1558       bool aCanErase = true;
1559       // when the sketch operation is active, results of sketch sub-feature can not be hidden
1560       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1561       // the result is found between current feature results
1562       if (anOperationResults.find(aResult) != anOperationResults.end())
1563         continue;
1564
1565       if (aResult.get()) {
1566         // Display sketcher objects
1567         for (int i = 0; i < myCurrentSketch->numberOfSubs() && aCanErase; i++) {
1568           FeaturePtr aFeature = myCurrentSketch->subFeature(i);
1569           std::list<ResultPtr> aResults = aFeature->results();
1570           std::list<ResultPtr>::const_iterator anIt;
1571           for (anIt = aResults.begin(); anIt != aResults.end() && aCanErase; ++anIt) {
1572             aCanErase = *anIt != aResult;
1573           }
1574         }
1575       }
1576       if (!aCanErase) {
1577         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1578         if (aFeature.get() && anObjectsToBeDeleted.find(aFeature) == anObjectsToBeDeleted.end()) {
1579           anObjectsToBeDeleted.insert(aFeature);
1580           anObjectsToBeDeletedNames.append(aFeature->name().c_str());
1581         }
1582       }
1583     }
1584     if (!anObjectsToBeDeleted.empty()) {
1585       QString aFeatureNames = anObjectsToBeDeletedNames.join(", ");
1586       QString aMessage = tr("The following features have incorrect presentation and \
1587 will be hidden: %1. Would you like to delete them?")
1588                          .arg(aFeatureNames);
1589       int anAnswer = QMessageBox::question(qApp->activeWindow(), tr("Features hide"),
1590                                            aMessage, QMessageBox::Ok | QMessageBox::Cancel,
1591                                            QMessageBox::Cancel);
1592       if (anAnswer == QMessageBox::Ok) {
1593         QObjectPtrList anObjects;
1594         std::set<FeaturePtr>::const_iterator anIt = anObjectsToBeDeleted.begin(),
1595                                              aLast = anObjectsToBeDeleted.end();
1596         for (; anIt != aLast; anIt++)
1597           anObjects.append(*anIt);
1598         SessionPtr aMgr = ModelAPI_Session::get();
1599         DocumentPtr aDoc = aMgr->activeDocument();
1600         bool aIsOp = aMgr->isOperation();
1601         if (!aIsOp)
1602           aMgr->startOperation();
1603         workshop()->deleteFeatures(anObjects);
1604         //static Events_ID aDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
1605         //static Events_ID aRedispEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
1606         //Events_Loop::loop()->flush(aDeletedEvent);
1607         //Events_Loop::loop()->flush(aRedispEvent);
1608
1609         if (!aIsOp)
1610           aMgr->finishOperation();
1611       }
1612     }
1613   }
1614 }*/
1615
1616 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
1617 {
1618   bool aCanDisplay = myIsMouseOverWindow;
1619   if (!aCanDisplay) {
1620     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
1621     if (anActiveWidget)
1622       aCanDisplay = anActiveWidget->getValueState() == ModuleBase_ModelWidget::Stored;
1623   }
1624   return aCanDisplay;
1625 }
1626
1627 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const
1628 {
1629   return isNestedCreateOperation(theOperation, activeSketch()) ||
1630          myModule->sketchReentranceMgr()->isInternalEditActive();
1631 }
1632
1633 const QMap<PartSet_Tools::ConstraintVisibleState, bool>& PartSet_SketcherMgr::showConstraintStates()
1634 {
1635   return myIsConstraintsShown;
1636 }
1637
1638 bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
1639 {
1640   if (!myCurrentSketch.get())
1641     return false;
1642   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
1643   if (anObjectFeature.get()) {
1644     int aSize = myCurrentSketch->numberOfSubs();
1645     FeaturePtr aCurrentFeature;
1646     for (int i = 0; i < aSize; i++) {
1647       aCurrentFeature = myCurrentSketch->subFeature(i);
1648       if (myCurrentSketch->subFeature(i) == anObjectFeature)
1649         return true;
1650     }
1651   }
1652   return false;
1653 }
1654
1655 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePlane)
1656 {
1657   Handle(SelectMgr_Filter) aFilter = myModule->selectionFilter(SF_SketchPlaneFilter);
1658   if (!aFilter.IsNull())
1659     Handle(ModuleBase_ShapeInPlaneFilter)::DownCast(aFilter)->setPlane(thePlane);
1660
1661   workshop()->selectionActivate()->updateSelectionModes();
1662 }
1663
1664 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,
1665                                                          ModuleBase_IWorkshop* theWorkshop,
1666                                                          bool& theCanCommitOperation)
1667 {
1668   bool isValueAccepted = false;
1669   theCanCommitOperation = false;
1670
1671   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1672                                                                               (theOperation);
1673   FeaturePtr aFeature = aFOperation->feature();
1674   // editor is shown only if all attribute references are filled by preseletion
1675   bool anAllRefAttrInitialized = true;
1676
1677   std::list<AttributePtr> aRefAttrs = aFeature->data()->attributes(
1678                                               ModelAPI_AttributeRefAttr::typeId());
1679   std::list<AttributePtr>::const_iterator anIt = aRefAttrs.begin(), aLast = aRefAttrs.end();
1680   for (; anIt != aLast && anAllRefAttrInitialized; anIt++) {
1681     anAllRefAttrInitialized = (*anIt)->isInitialized();
1682   }
1683   if (anAllRefAttrInitialized) {
1684     // Activate dimension value editing on double click
1685     ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
1686     QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
1687     // Find corresponded widget to activate value editing
1688     foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
1689       if (aWgt->attributeID() == "ConstraintValue") {
1690         // the featue should be displayed in order to find the AIS text position,
1691         // the place where the editor will be shown
1692         aFeature->setDisplayed(true);
1693         /// the execute is necessary to perform in the feature compute for flyout position
1694         aFeature->execute();
1695
1696         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
1697         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1698
1699         PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
1700         if (anEditor) {
1701           int aX = 0, anY = 0;
1702
1703           XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);
1704           XGUI_Displayer* aDisplayer = aWorkshop->displayer();
1705           AISObjectPtr anAIS = aDisplayer->getAISObject(aFeature);
1706           Handle(AIS_InteractiveObject) anAISIO;
1707           if (anAIS.get() != NULL) {
1708             anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1709           }
1710           if (anAIS.get() != NULL) {
1711             Handle(AIS_InteractiveObject) anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
1712
1713             if (!anAISIO.IsNull()) {
1714               Handle(AIS_Dimension) aDim = Handle(AIS_Dimension)::DownCast(anAISIO);
1715               if (!aDim.IsNull()) {
1716                 gp_Pnt aPosition = aDim->GetTextPosition();
1717
1718                 ModuleBase_IViewer* aViewer = aWorkshop->viewer();
1719                 Handle(V3d_View) aView = aViewer->activeView();
1720                 int aCX, aCY;
1721                 aView->Convert(aPosition.X(), aPosition.Y(), aPosition.Z(), aCX, aCY);
1722
1723                 QWidget* aViewPort = aViewer->activeViewPort();
1724                 QPoint aGlPoint = aViewPort->mapToGlobal(QPoint(aCX, aCY));
1725                 aX = aGlPoint.x();
1726                 anY = aGlPoint.y();
1727               }
1728             }
1729             anEditor->setCursorPosition(aX, anY);
1730             isValueAccepted = anEditor->showPopupEditor(false);
1731             theCanCommitOperation = true;
1732           }
1733         }
1734       }
1735     }
1736   }
1737   return isValueAccepted;
1738 }
1739
1740 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,
1741                                              const FeaturePtr& theSketch,
1742                                              ModuleBase_IWorkshop* theWorkshop,
1743                                              const FeatureToSelectionMap& theSelection,
1744                                              SelectMgr_IndexedMapOfOwner& theOwnersToSelect)
1745 {
1746   if (theFeature.get() == NULL)
1747     return;
1748
1749   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
1750   SelectionInfo anInfo = anIt.value();
1751   std::map<AttributePtr, int> aSelectedAttributes = anInfo.myAttributes;
1752   std::set<ResultPtr> aSelectedResults = anInfo.myResults;
1753
1754   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
1755
1756   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
1757   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1758
1759   // 1. found the feature's owners. Check the AIS objects of the constructions
1760   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);
1761   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {
1762     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1763
1764     SelectMgr_IndexedMapOfOwner aSelectedOwners;
1765     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1766     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
1767       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
1768       if (!anOwner.IsNull())
1769         theOwnersToSelect.Add(anOwner);
1770     }
1771   }
1772
1773   // 2. found the feature results's owners
1774   std::list<ResultPtr> aResults = theFeature->results();
1775   std::list<ResultPtr>::const_iterator aIt;
1776
1777   bool isSameShape = false;
1778   if (aResults.size() > 0) {
1779     ResultPtr aFirstResult = theFeature->firstResult();
1780     if (aFirstResult.get() && aFirstResult->shape().get()) {
1781       TopoDS_Shape aFirstShape = aFirstResult->shape()->impl<TopoDS_Shape>();
1782       isSameShape = aFirstShape.IsEqual(anInfo.myFirstResultShape);
1783     }
1784   }
1785   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1786     ResultPtr aResult = *aIt;
1787     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
1788     if (aAISObj.get() == NULL)
1789       continue;
1790     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
1791
1792     SelectMgr_IndexedMapOfOwner aSelectedOwners;
1793     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
1794     bool aFoundLocalShape = false;
1795     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
1796       Handle(StdSelect_BRepOwner) anOwner =
1797         Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
1798       if ( anOwner.IsNull() || !anOwner->HasShape() || theOwnersToSelect.FindIndex(anOwner))
1799         continue;
1800       const TopoDS_Shape& aShape = anOwner->Shape();
1801       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
1802       if (aShapeType == TopAbs_VERTEX) {
1803         std::pair<AttributePtr, int> aPntAttrIndex =
1804           PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
1805         if (aPntAttrIndex.first.get() != NULL &&
1806             aSelectedAttributes.find(aPntAttrIndex.first) != aSelectedAttributes.end())
1807           theOwnersToSelect.Add(anOwner);
1808         else if (isSameShape && anInfo.myLocalSelectedShapes.Contains(aShape)) {
1809           theOwnersToSelect.Add(anOwner);
1810         }
1811       }
1812       else if (aShapeType == TopAbs_EDGE) {
1813         if (isSameShape && anInfo.myLocalSelectedShapes.Contains(aShape)) {
1814           // try to restore local selection on Shape result
1815           // we can do this only if the shape was not changed
1816           theOwnersToSelect.Add(anOwner);
1817           aFoundLocalShape = true;
1818           break;
1819         }
1820       }
1821     }
1822     if (!aFoundLocalShape) {
1823       // result owners are put in the list of selection only if local selected shapes were not
1824       // found
1825       if (aSelectedResults.find(aResult) != aSelectedResults.end()) {
1826         for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
1827           Handle(StdSelect_BRepOwner) anOwner =
1828             Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
1829           if ( anOwner.IsNull() || !anOwner->HasShape() || theOwnersToSelect.FindIndex(anOwner))
1830             continue;
1831             // select whole result
1832             theOwnersToSelect.Add(anOwner);
1833         }
1834       }
1835     }
1836   }
1837 }
1838
1839 void PartSet_SketcherMgr::connectToPropertyPanel(ModuleBase_ModelWidget* theWidget,
1840                                                  const bool isToConnect)
1841 {
1842   //Temporary commented as we do not modify values in property panel
1843   if (isToConnect) {
1844     //connect(theWidget, SIGNAL(beforeValuesChanged()),
1845     //        this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1846     //connect(theWidget, SIGNAL(afterValuesChanged()),
1847     //        this, SLOT(onAfterValuesChangedInPropertyPanel()));
1848     connect(theWidget, SIGNAL(afterValuesChanged()),
1849             myModule->sketchReentranceMgr(), SLOT(onAfterValuesChangedInPropertyPanel()));
1850   }
1851   else {
1852     //disconnect(theWidget, SIGNAL(beforeValuesChanged()),
1853     //            this, SLOT(onBeforeValuesChangedInPropertyPanel()));
1854     //disconnect(theWidget, SIGNAL(afterValuesChanged()),
1855     //            this, SLOT(onAfterValuesChangedInPropertyPanel()));
1856     disconnect(theWidget, SIGNAL(afterValuesChanged()),
1857                myModule->sketchReentranceMgr(), SLOT(onAfterValuesChangedInPropertyPanel()));
1858   }
1859 }
1860
1861 void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
1862 {
1863   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1864                                                                            (getCurrentOperation());
1865   if (aFOperation) {
1866     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
1867         isNestedSketchOperation(aFOperation) &&
1868         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {
1869       FeaturePtr aFeature = aFOperation->feature();
1870       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
1871     }
1872   }
1873 }
1874
1875 //void PartSet_SketcherMgr::customisePresentation(const ObjectPtr& theObject)
1876 //{
1877 //  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
1878 //                                                                           (getCurrentOperation());
1879 //  if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
1880 //                      isNestedSketchOperation(aFOperation)))
1881 //    SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
1882 //
1883 //  // update entities selection priorities
1884 //  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1885 //  if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
1886 //    // update priority for feature
1887 //    updateSelectionPriority(aFeature, aFeature);
1888 //    // update priority for results of the feature
1889 //    std::list<ResultPtr> aResults = aFeature->results();
1890 //    std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();
1891 //    for (; anIt != aLastIt; anIt++)
1892 //      updateSelectionPriority(*anIt, aFeature);
1893 //  }
1894 //}
1895
1896 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
1897 {
1898   return myModule->workshop()->currentOperation();
1899 }
1900
1901 //**************************************************************
1902 ModuleBase_ModelWidget* PartSet_SketcherMgr::getActiveWidget() const
1903 {
1904   ModuleBase_ModelWidget* aWidget = 0;
1905   ModuleBase_Operation* anOperation = getCurrentOperation();
1906   if (anOperation) {
1907     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
1908     if (aPanel)
1909       aWidget = aPanel->activeWidget();
1910   }
1911   return aWidget;
1912 }
1913
1914 void PartSet_SketcherMgr::visualizeFeature(const FeaturePtr& theFeature,
1915                                            const bool isEditOperation,
1916                                            const bool isToDisplay,
1917                                            const bool isFlushRedisplay)
1918 {
1919   #ifdef DEBUG_DO_NOT_BY_ENTER
1920   return;
1921   #endif
1922
1923   if (isEditOperation || !theFeature.get())
1924     return;
1925
1926   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1927   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1928
1929   // 1. change visibility of the object itself, here the presentable object is processed,
1930   // e.g. constraints features
1931   //FeaturePtr aFeature = aFOperation->feature();
1932   std::list<ResultPtr> aResults = theFeature->results();
1933   if (isToDisplay)
1934     theFeature->setDisplayed(true);
1935   else
1936     theFeature->setDisplayed(false);
1937
1938   // change visibility of the object results, e.g. non-constraint features
1939   std::list<ResultPtr>::const_iterator aIt;
1940   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1941     if (isToDisplay) {
1942       (*aIt)->setDisplayed(true);
1943     }
1944     else {
1945       (*aIt)->setDisplayed(false);
1946     }
1947   }
1948   if (isFlushRedisplay)
1949     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1950 }
1951
1952 void PartSet_SketcherMgr::storeSelection(const SelectionType theType,
1953                         PartSet_SketcherMgr::FeatureToSelectionMap& theCurrentSelection)
1954 {
1955   if (!myCurrentSketch.get())
1956     return;
1957
1958   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1959   ModuleBase_ISelection* aSelect = aWorkshop->selection();
1960   QList<ModuleBase_ViewerPrsPtr> aStoredPrs;
1961
1962   if (theType == ST_HighlightType || theType == ST_SelectAndHighlightType)
1963     aStoredPrs = aSelect->getHighlighted();
1964
1965   QList<FeaturePtr> aFeatureList;
1966   if (theType == ST_SelectAndHighlightType || theType == ST_SelectType) {
1967     QList<ModuleBase_ViewerPrsPtr> aSelected = aSelect->getSelected(
1968                                                               ModuleBase_ISelection::AllControls);
1969     aStoredPrs.append(aSelected);
1970   }
1971
1972   // 1. it is necessary to save current selection in order to restore it after the features moving
1973   theCurrentSelection.clear();
1974
1975   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = aStoredPrs.begin(),
1976                                                 aLast = aStoredPrs.end();
1977
1978   CompositeFeaturePtr aSketch = activeSketch();
1979   for (; anIt != aLast; anIt++) {
1980     ModuleBase_ViewerPrsPtr aPrs = *anIt;
1981     ObjectPtr anObject = aPrs->object();
1982     if (!anObject.get())
1983       continue;
1984
1985     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1986     FeaturePtr aFeature;
1987     if (aResult.get())
1988       aFeature = ModelAPI_Feature::feature(aResult);
1989     else
1990       aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
1991
1992     if (!aFeature.get())
1993       continue;
1994
1995     std::set<AttributePtr> aSelectedAttributes;
1996     std::set<ResultPtr> aSelectedResults;
1997     SelectionInfo anInfo;
1998     if (theCurrentSelection.find(aFeature) != theCurrentSelection.end())
1999       anInfo = theCurrentSelection.find(aFeature).value();
2000
2001     TopoDS_Shape aFirstShape;
2002     ResultPtr aFirstResult = aFeature->firstResult();
2003     if (aFirstResult.get() && aFirstResult->shape().get())
2004       aFirstShape = aFirstResult->shape()->impl<TopoDS_Shape>();
2005     anInfo.myFirstResultShape = aFirstShape;
2006     Handle(SelectMgr_EntityOwner) anOwner = aPrs->owner();
2007     if (aResult.get()) {
2008       getAttributesOrResults(anOwner, aFeature, aSketch, aResult,
2009           anInfo.myAttributes, anInfo.myResults, anInfo.myLocalSelectedShapes);
2010     }
2011     else {
2012       std::list<ResultPtr> aResults = aFeature->results();
2013       std::list<ResultPtr>::const_iterator aIt;
2014       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
2015         ResultPtr aResult = *aIt;
2016         getAttributesOrResults(anOwner, aFeature, aSketch, aResult,
2017           anInfo.myAttributes, anInfo.myResults, anInfo.myLocalSelectedShapes);
2018       }
2019     }
2020     theCurrentSelection[aFeature] = anInfo;
2021   }
2022   //qDebug(QString("  storeSelection: %1").arg(theCurrentSelection.size()).toStdString().c_str());
2023 }
2024
2025 void PartSet_SketcherMgr::restoreSelection(
2026                                 PartSet_SketcherMgr::FeatureToSelectionMap& theCurrentSelection)
2027 {
2028   if (!myCurrentSketch.get())
2029     return;
2030
2031   //qDebug(QString("restoreSelection: %1").arg(theCurrentSelection.size()).toStdString().c_str());
2032   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
2033   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
2034   FeatureToSelectionMap::const_iterator aSIt = theCurrentSelection.begin(),
2035                                         aSLast = theCurrentSelection.end();
2036   SelectMgr_IndexedMapOfOwner anOwnersToSelect;
2037   anOwnersToSelect.Clear();
2038   for (; aSIt != aSLast; aSIt++) {
2039     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, theCurrentSelection,
2040                        anOwnersToSelect);
2041   }
2042   aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);
2043 }
2044
2045 void PartSet_SketcherMgr::onShowConstraintsToggle(int theType, bool theState)
2046 {
2047   PartSet_Tools::ConstraintVisibleState aType = (PartSet_Tools::ConstraintVisibleState)theType;
2048
2049   updateBySketchParameters(aType, theState);
2050   myModule->workshop()->viewer()->update();
2051 }
2052
2053 void PartSet_SketcherMgr::updateBySketchParameters(
2054                                    const PartSet_Tools::ConstraintVisibleState& theType,
2055                                    bool theState)
2056 {
2057   if (myCurrentSketch.get() == NULL)
2058     return;
2059
2060   bool aPrevState = myIsConstraintsShown[theType];
2061   myIsConstraintsShown[theType] = theState;
2062
2063   switch (theType) {
2064     case PartSet_Tools::Geometrical:
2065     case PartSet_Tools::Dimensional: {
2066       if (aPrevState != theState) {
2067         ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
2068         XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
2069         int aNumberOfSubs = myCurrentSketch->numberOfSubs();
2070         for (int i = 0; i < aNumberOfSubs; i++) {
2071           FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
2072           bool aProcessed = false;
2073           bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, theType, aProcessed);
2074           if (aProcessed)
2075             aSubFeature->setDisplayed(aConstraintDisplayed);
2076         }
2077         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2078       }
2079     }
2080     break;
2081     case PartSet_Tools::Expressions: {
2082       if (aPrevState != theState) {
2083         /// call all sketch features redisplay, the expression state will be corrected in customize
2084         /// of distance presentation
2085         SketcherPrs_Tools::ParameterStyle aStyle = myIsConstraintsShown[PartSet_Tools::Expressions]
2086           ? SketcherPrs_Tools::ParameterText : SketcherPrs_Tools::ParameterValue;
2087         SketcherPrs_Tools::setParameterStyle(aStyle);
2088         Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
2089         PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
2090       }
2091     }
2092     break;
2093   }
2094 }
2095
2096 void PartSet_SketcherMgr::updateSelectionPriority(ObjectPtr theObject,
2097                                                   FeaturePtr theFeature)
2098 {
2099   if (!theObject.get() || !theFeature.get())
2100     return;
2101
2102   AISObjectPtr anAIS = workshop()->displayer()->getAISObject(theObject);
2103   Handle(AIS_InteractiveObject) anAISIO;
2104   if (anAIS.get() != NULL) {
2105     anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
2106   }
2107
2108   if (!anAISIO.IsNull()) { // the presentation for the object is visualized
2109     int anAdditionalPriority = 0;
2110     // current feature
2111     std::shared_ptr<SketchPlugin_Feature> aSPFeature =
2112             std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
2113     if (aSPFeature.get() != NULL) {
2114       // 1. Vertices
2115       // 2. Simple segments
2116       // 3. External objects (violet color)
2117       // 4. Auxiliary segments (dotted)
2118       // StdSelect_BRepSelectionTool::Load uses priority calculating:
2119       // Standard_Integer aPriority =
2120       // (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;
2121       // Priority of Vertex is 8, edge(segment) is 7.
2122       // It might be not corrected as provides the condition above.
2123       bool isExternal = aSPFeature->isExternal();
2124       bool isAuxiliary = PartSet_Tools::isAuxiliarySketchEntity(aSPFeature);
2125       // current feature
2126       if (!isExternal && !isAuxiliary)
2127         anAdditionalPriority = 30;
2128       // external feature
2129       if (isExternal)
2130         anAdditionalPriority = 20;
2131       // auxiliary feature
2132       if (isAuxiliary) {
2133         anAdditionalPriority = 10; /// auxiliary objects should have less priority that
2134         // edges/vertices of local selection on not-sketch objects
2135       }
2136       Handle(ModuleBase_ResultPrs) aResult = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);
2137       if (!aResult.IsNull()) {
2138         aResult->setAdditionalSelectionPriority(anAdditionalPriority);
2139       }
2140     }
2141   }
2142 }
2143
2144 XGUI_Workshop* PartSet_SketcherMgr::workshop() const
2145 {
2146   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
2147   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
2148   return aConnector->workshop();
2149 }
2150
2151 XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const
2152 {
2153   return workshop()->operationMgr();
2154 }
2155
2156 void PartSet_SketcherMgr::onShowPoints(bool toShow)
2157 {
2158   if (!myCurrentSketch.get())
2159     return;
2160   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
2161   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
2162   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
2163
2164   bool aToUpdate = false;
2165   if (toShow) {
2166     std::list<ResultPtr> aFreePoints = SketcherPrs_Tools::getFreePoints(myCurrentSketch);
2167
2168     // Delete obsolete presentations
2169     std::list<ResultPtr> aDelList;
2170     foreach(ResultPtr aObj, myPointsHighlight.keys()) {
2171       bool aFound = (std::find(aFreePoints.begin(), aFreePoints.end(), aObj) != aFreePoints.end());
2172       if (!aFound)
2173         aDelList.push_back(aObj);
2174     }
2175     foreach(ResultPtr aObj, aDelList) {
2176       aContext->Remove(myPointsHighlight[aObj], false);
2177       aToUpdate = true;
2178       myPointsHighlight.remove(aObj);
2179     }
2180
2181     // Display new objects
2182     QList<ResultPtr> aKeysList = myPointsHighlight.keys();
2183     std::list<ResultPtr>::const_iterator aIt;
2184     for (aIt = aFreePoints.cbegin(); aIt != aFreePoints.cend(); aIt++) {
2185       if (!aKeysList.contains(*aIt)) {
2186         GeomShapePtr aShapePtr = (*aIt)->shape();
2187         TopoDS_Shape aShape = aShapePtr->impl<TopoDS_Shape>();
2188         Handle(AIS_Shape) aShapePrs = new AIS_Shape(aShape);
2189         aShapePrs->SetColor(Quantity_NOC_BLUE1);
2190         aShapePrs->SetZLayer(Graphic3d_ZLayerId_Top);
2191         Handle(Prs3d_Drawer) aDrawer = aShapePrs->Attributes();
2192         if (aDrawer->HasOwnPointAspect()) {
2193           aDrawer->PointAspect()->SetTypeOfMarker(Aspect_TOM_O_STAR);
2194           aDrawer->PointAspect()->SetColor(Quantity_NOC_BLUE1);
2195           aDrawer->PointAspect()->SetScale(2);
2196         }
2197         else
2198           aDrawer->SetPointAspect(new Prs3d_PointAspect(Aspect_TOM_O_STAR, Quantity_NOC_BLUE1, 2));
2199         aContext->Display(aShapePrs, false);
2200         aContext->Deactivate(aShapePrs);
2201         myPointsHighlight[*aIt] = aShapePrs;
2202         aToUpdate = true;
2203       }
2204     }
2205   }
2206   else {
2207     foreach(Handle(AIS_Shape) aPrs, myPointsHighlight.values()) {
2208       aContext->Remove(aPrs, false);
2209       aToUpdate = true;
2210     }
2211     myPointsHighlight.clear();
2212   }
2213   if (aToUpdate)
2214     aViewer->update();
2215 }
2216
2217 void PartSet_SketcherMgr::processEvent(const std::shared_ptr<Events_Message>& theMessage)
2218 {
2219   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOF_OBJECTS)) {
2220     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
2221       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
2222     std::set<ObjectPtr> aObjects = anUpdateMsg->objects();
2223     std::set<ObjectPtr>::const_iterator aIt;
2224     QList<ModuleBase_ViewerPrsPtr> aPrsList;
2225     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
2226       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aIt);
2227       if (aFeature.get()) {
2228         std::list<ResultPtr> aRes = aFeature->results();
2229         std::list<ResultPtr>::const_iterator aIt;
2230         for (aIt = aRes.cbegin(); aIt != aRes.cend(); ++aIt) {
2231           ModuleBase_ViewerPrsPtr aPrsPtr(new ModuleBase_ViewerPrs(*aIt));
2232           aPrsList.append(aPrsPtr);
2233         }
2234       }
2235     }
2236     if (aPrsList.size() > 0) {
2237       myModule->workshop()->setSelected(aPrsList);
2238     }
2239   }
2240 }
2241
2242 bool isExternal(const ObjectPtr& theObject)
2243 {
2244   AttributeSelectionPtr aAttr =
2245     theObject->data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
2246   if (aAttr)
2247     return aAttr->context().get() != NULL && !aAttr->isInvalid();
2248   return false;
2249 }
2250
2251 bool isCopy(const ObjectPtr& theObject)
2252 {
2253   AttributeBooleanPtr anAttr = theObject->data()->boolean(SketchPlugin_SketchEntity::COPY_ID());
2254   if (anAttr.get())
2255     return anAttr->value();
2256   return false;
2257 }
2258
2259 bool isIncludeToResult(const ObjectPtr& theObject)
2260 {
2261   AttributeBooleanPtr anAttr;
2262   std::set<AttributePtr> aRefsToMe = theObject->data()->refsToMe();
2263   std::set<AttributePtr>::const_iterator aIt;
2264   for (aIt = aRefsToMe.cbegin(); aIt != aRefsToMe.cend(); ++aIt) {
2265     if ((*aIt)->id() == SketchPlugin_Projection::PROJECTED_FEATURE_ID()) {
2266       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
2267       if (aFeature.get()) {
2268         anAttr = aFeature->data()->boolean(SketchPlugin_Projection::INCLUDE_INTO_RESULT());
2269         if (anAttr.get())
2270           return anAttr->value();
2271       }
2272     }
2273   }
2274   return true;
2275 }
2276
2277 //**************************************************************************************
2278 std::vector<int> PartSet_SketcherMgr::colorOfObject(const ObjectPtr& theObject,
2279   const FeaturePtr& theFeature, bool isConstruction) const
2280 {
2281   static const QStringList& aConstrIds = constraintsIdList();
2282   PartSet_OverconstraintListener* aOCListener = myModule->overconstraintListener();
2283   std::string aKind = theFeature->getKind();
2284
2285   if (isDistanceKind(aKind)) {
2286     if (aOCListener->isConflictingObject(theObject))
2287       return Config_PropManager::color("Visualization", "sketch_overconstraint_color");
2288     return Config_PropManager::color("Visualization", "sketch_dimension_color");
2289   }
2290   if (isExternal(theFeature))
2291     return Config_PropManager::color("Visualization", "sketch_external_color");
2292   if (isConstruction)
2293     return Config_PropManager::color("Visualization", "sketch_auxiliary_color");
2294
2295   if (aOCListener->isFullyConstrained()) {
2296     return Config_PropManager::color("Visualization", "sketch_fully_constrained_color");
2297   }
2298   else if (aOCListener->isConflictingObject(theObject)) {
2299     return Config_PropManager::color("Visualization", "sketch_overconstraint_color");
2300   }
2301   return Config_PropManager::color("Visualization", "sketch_entity_color");
2302 }
2303
2304 //**************************************************************************************
2305 void PartSet_SketcherMgr::customizeSketchPresentation(const ObjectPtr& theObject,
2306   const AISObjectPtr& thePrs) const
2307 {
2308   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
2309
2310   // set color from preferences
2311   std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
2312     aFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
2313   bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
2314
2315   std::vector<int> aColor = colorOfObject(theObject, aFeature, isConstruction);
2316   if (!aColor.empty()) {
2317     // The code below causes redisplay again
2318     if (ModelAPI_Session::get()->isOperation()) {
2319       AttributeIntArrayPtr aColorAttr = theObject->data()->intArray(ModelAPI_Result::COLOR_ID());
2320       if (aColorAttr.get()) {
2321         aColorAttr->setSize(3, false);
2322         // Set the color attribute in order do not use default colors in the presentation object
2323         for (int i = 0; i < 3; i++)
2324           aColorAttr->setValue(i, aColor[i], false);
2325       }
2326     }
2327     thePrs->setColor(aColor[0], aColor[1], aColor[2]);
2328   }
2329
2330   int aShapeType = thePrs->getShapeType();
2331   // a compound is processed like the edge because the
2332   // arc feature uses the compound for presentable AIS
2333   if (aShapeType != 6/*an edge*/ && aShapeType != 7/*a vertex*/ && aShapeType != 0/*compound*/)
2334     return;
2335
2336   int aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
2337   if (isExternal(aFeature)) {
2338     thePrs->setWidth(isIncludeToResult(aFeature)? aWidth : 1);
2339     return;
2340   }
2341   std::string aKind = aFeature->getKind();
2342   if (isDistanceKind(aKind))
2343     return;
2344
2345   if (aShapeType == 6 || aShapeType == 0) { // if this is an edge or a compound
2346     if (isConstruction) {
2347       // Set axilliary line
2348       thePrs->setWidth(SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY());
2349       thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY());
2350     }
2351     else {
2352       thePrs->setWidth(aWidth);
2353       thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE());
2354     }
2355   }
2356   else if (aShapeType == 7) { // otherwise this is a vertex
2357                               // The width value do not have effect on the point presentation.
2358                               // It is defined in order to extend selection area of the object.
2359     thePrs->setWidth(17);
2360     //  thePrs->setPointMarker(1, 1.); // Set point as a '+' symbol
2361   }
2362   if (isCopy(aFeature) && !isIncludeToResult(aFeature)) {
2363     double aWidth = thePrs->width();
2364     thePrs->setWidth(aWidth / 2.5);
2365   }
2366
2367   double aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
2368   thePrs->setDeflection(aDeflection);
2369 }
2370
2371 //*************************************************************************************
2372 void PartSet_Fitter::fitAll(Handle(V3d_View) theView)
2373 {
2374   CompositeFeaturePtr aSketch = mySketchMgr->activeSketch();
2375
2376   ModuleBase_IWorkshop* aWorkshop = mySketchMgr->module()->workshop();
2377   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
2378   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
2379
2380   Bnd_Box aBndBox;
2381   int aNumberOfSubs = aSketch->numberOfSubs();
2382   double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
2383   for (int i = 0; i < aNumberOfSubs; i++) {
2384     FeaturePtr aFeature = aSketch->subFeature(i);
2385     if (aDisplayer->isVisible(aFeature)) {
2386       AISObjectPtr aAisPtr = aDisplayer->getAISObject(aFeature);
2387       Handle(AIS_InteractiveObject) aAisObj = aAisPtr->impl<Handle(AIS_InteractiveObject)>();
2388       if (!aAisObj->IsInfinite()) {
2389         Bnd_Box aBox;
2390         aAisObj->BoundingBox(aBox);
2391         aBndBox.Add(aBox);
2392       }
2393     }
2394     else {
2395       std::list<ResultPtr> aResults = aFeature->results();
2396       std::list<ResultPtr>::const_iterator aIt;
2397       ResultPtr aRes;
2398       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
2399         aRes = (*aIt);
2400         if (aRes->isDisplayed()) {
2401           FeaturePtr aFeature = ModelAPI_Feature::feature(aRes);
2402           if (aFeature.get()) {
2403             std::shared_ptr<SketchPlugin_Feature> aSPFeature =
2404               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
2405             if (aSPFeature.get()) {
2406               bool isAxiliary =
2407                 aSPFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value();
2408               if (!(aSPFeature->isExternal() || isAxiliary)) {
2409                 GeomShapePtr aShape = aRes->shape();
2410                 aShape->computeSize(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
2411                 Bnd_Box aBox;
2412                 aBox.Update(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
2413                 aBndBox.Add(aBox);
2414               }
2415             }
2416           }
2417         }
2418       }
2419     }
2420   }
2421   if (aBndBox.IsVoid())
2422     theView->FitAll();
2423   else
2424     theView->FitAll(aBndBox, 0.01);
2425 }