Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom.git into Dev_1.1.0
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_SketcherMgr.cpp
4 // Created:     19 Dec 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_SketcherMgr.h"
8 #include "PartSet_Module.h"
9 #include "PartSet_WidgetPoint2d.h"
10 #include "PartSet_WidgetPoint2dDistance.h"
11 #include "PartSet_Tools.h"
12
13 #include <ModuleBase_WidgetEditor.h>
14
15 #include <XGUI_ModuleConnector.h>
16 #include <XGUI_Displayer.h>
17 #include <XGUI_Workshop.h>
18 #include <XGUI_ContextMenuMgr.h>
19 #include <XGUI_Selection.h>
20 #include <XGUI_SelectionMgr.h>
21 #include <ModuleBase_ModelWidget.h>
22 #include <XGUI_ModuleConnector.h>
23 #include <XGUI_PropertyPanel.h>
24 #include <XGUI_ViewerProxy.h>
25
26 #include <AppElements_MainWindow.h>
27
28 #include <ModuleBase_IViewer.h>
29 #include <ModuleBase_IWorkshop.h>
30 #include <ModuleBase_IViewWindow.h>
31 #include <ModuleBase_Operation.h>
32 #include <ModuleBase_ISelection.h>
33 #include <ModuleBase_IPropertyPanel.h>
34 #include <ModuleBase_Operation.h>
35
36 #include <GeomDataAPI_Point2D.h>
37
38 #include <Events_Loop.h>
39
40 #include <SketchPlugin_Line.h>
41 #include <SketchPlugin_Sketch.h>
42 #include <SketchPlugin_Point.h>
43 #include <SketchPlugin_Arc.h>
44 #include <SketchPlugin_Circle.h>
45 #include <SketchPlugin_ConstraintLength.h>
46 #include <SketchPlugin_ConstraintDistance.h>
47 #include <SketchPlugin_ConstraintParallel.h>
48 #include <SketchPlugin_ConstraintPerpendicular.h>
49 #include <SketchPlugin_ConstraintRadius.h>
50 #include <SketchPlugin_ConstraintRigid.h>
51
52 #include <SelectMgr_IndexedMapOfOwner.hxx>
53 #include <StdSelect_BRepOwner.hxx>
54
55 //#include <AIS_DimensionSelectionMode.hxx>
56 //#include <AIS_Shape.hxx>
57
58 #include <ModelAPI_Events.h>
59 #include <ModelAPI_Session.h>
60
61 #include <QMouseEvent>
62 #include <QApplication>
63
64
65 /// Returns list of unique objects by sum of objects from List1 and List2
66 /*QList<ModuleBase_ViewerPrs> getSumList(const QList<ModuleBase_ViewerPrs>& theList1,
67                                        const QList<ModuleBase_ViewerPrs>& theList2)
68 {
69   QList<ModuleBase_ViewerPrs> aRes;
70   foreach (ModuleBase_ViewerPrs aPrs, theList1) {
71     if (!aRes.contains(aPrs))
72       aRes.append(aPrs);
73   }
74   foreach (ModuleBase_ViewerPrs aPrs, theList2) {
75     if (!aRes.contains(aPrs))
76       aRes.append(aPrs);
77   }
78   return aRes;
79 }*/
80
81 void fillFeature2Attribute(const QList<ModuleBase_ViewerPrs>& theList,
82                            QMap<FeaturePtr, QList<AttributePtr> >& theFeature2AttributeMap,
83                            const FeaturePtr theSketch)
84 {
85   QList<ModuleBase_ViewerPrs> aRes;
86
87   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theList.begin(),
88                                               aLast = theList.end();
89   for (; anIt != aLast; anIt++)
90   {
91     ModuleBase_ViewerPrs aPrs = *anIt;
92     FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs.object());
93     if (aFeature.get() == NULL)
94       continue;
95
96     QList<AttributePtr> anAttributes;
97     if (theFeature2AttributeMap.contains(aFeature)) {
98       anAttributes = theFeature2AttributeMap[aFeature];
99     }
100     AttributePtr anAttr;
101     TopoDS_Shape aShape = aPrs.shape();
102     if (!aShape.IsNull()) {
103       if (aShape.ShapeType() == TopAbs_VERTEX) {
104         anAttr = PartSet_Tools::findAttributeBy2dPoint(aFeature, aShape, theSketch);
105         if (anAttr.get() != NULL && !anAttributes.contains(anAttr))
106           anAttributes.push_back(anAttr);
107       }
108     }
109     theFeature2AttributeMap[aFeature] = anAttributes;
110   }
111 }
112
113
114
115
116 PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
117   : QObject(theModule), myModule(theModule), myIsDragging(false), myDragDone(false),
118     myIsPropertyPanelValueChanged(false), myIsMouseOverWindow(false),
119     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true)
120 {
121   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
122   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
123
124   myPreviousSelectionEnabled = true;//aViewer->isSelectionEnabled();
125
126   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),
127           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));
128
129   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),
130           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));
131
132   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
133           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));
134
135   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),
136           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));
137
138   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
139   XGUI_Workshop* aWorkshop = aConnector->workshop();
140   connect(aWorkshop, SIGNAL(applicationStarted()), this, SLOT(onApplicationStarted()));
141 }
142
143 PartSet_SketcherMgr::~PartSet_SketcherMgr()
144 {
145   if (!myPlaneFilter.IsNull())
146     myPlaneFilter.Nullify();
147 }
148
149 void PartSet_SketcherMgr::onEnterViewPort()
150 {
151   if (!isNestedCreateOperation(getCurrentOperation()))
152     return;
153   // 1. if the mouse over window, update the next flag. Do not perform update visibility of
154   // created feature because it should be done in onMouseMove(). Some widgets watch
155   // the mouse move and use the cursor position to update own values. If the presentaion is
156   // redisplayed before this update, the feature presentation jumps from reset value to current.
157   myIsMouseOverWindow = true;
158   myIsPropertyPanelValueChanged = false;
159 }
160
161 void PartSet_SketcherMgr::onLeaveViewPort()
162 {
163   if (!isNestedCreateOperation(getCurrentOperation()))
164     return;
165
166   myIsMouseOverViewProcessed = false;
167   myIsMouseOverWindow = false;
168
169   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation
170   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
171   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
172   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
173   // disable the viewer update in order to avoid visualization of redisplayed feature in viewer
174   // obtained after reset value
175   bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
176   ModuleBase_Operation* aOperation = getCurrentOperation();
177   ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
178   ModuleBase_ModelWidget* aActiveWgt = aPanel->activeWidget();
179   if (aActiveWgt) {
180     aActiveWgt->reset();
181   }
182   aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
183
184   // hides the presentation of the current operation feature
185   myIsPropertyPanelValueChanged = false;
186   // the feature is to be erased here, but it is correct to call canDisplayObject because
187   // there can be additional check (e.g. editor widget in distance constraint)
188   visualizeFeature(aOperation, canDisplayObject());
189 }
190
191 void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()
192 {
193   if (isNestedCreateOperation(getCurrentOperation()))
194     return;
195   // it is necessary to save current selection in order to restore it after the values are modifed
196   storeSelection();
197
198   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
199   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
200   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
201   myPreviousUpdateViewerEnabled = aDisplayer->enableUpdateViewer(false);
202 }
203
204 void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()
205 {
206   if (isNestedCreateOperation(getCurrentOperation()))
207     return;
208   // it is necessary to restore current selection in order to restore it after the values are modified
209   restoreSelection();
210   myCurrentSelection.clear();
211
212   // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
213   // viewer happens by deselect/select the modified objects. The flag should be restored after
214   // the selection processing. The update viewer should be also called.
215   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
216   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
217   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
218   aDisplayer->enableUpdateViewer(myPreviousUpdateViewerEnabled);
219   aDisplayer->updateViewer();
220 }
221
222 void PartSet_SketcherMgr::onValuesChangedInPropertyPanel()
223 {
224   if (!isNestedCreateOperation(getCurrentOperation()))
225     return;
226
227   // visualize the current operation feature
228   myIsPropertyPanelValueChanged = true;
229   ModuleBase_Operation* aOperation = getCurrentOperation();
230   // the feature is to be erased here, but it is correct to call canDisplayObject because
231   // there can be additional check (e.g. editor widget in distance constraint)
232   visualizeFeature(aOperation, canDisplayObject());
233 }
234
235 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
236 {
237   get2dPoint(theWnd, theEvent, myClickedPoint);
238
239   if (!(theEvent->buttons() & Qt::LeftButton))
240     return;
241
242   // Clear dragging mode
243   myIsDragging = false;
244
245   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
246   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
247   if (!aViewer->canDragByMouse())
248     return;
249
250   ModuleBase_Operation* aOperation = getCurrentOperation();
251   if (aOperation && aOperation->isEditOperation()) {
252     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
253     ModuleBase_ModelWidget* aActiveWgt = aPanel->activeWidget();
254     // If the current widget is a selector, do do nothing, it processes the mouse press
255     if(aActiveWgt && aActiveWgt->isViewerSelector()) {
256       return;
257     }
258   }
259
260   // Use only for sketch operations
261   if (aOperation && myCurrentSketch) {
262     if (!PartSet_Tools::sketchPlane(myCurrentSketch))
263       return;
264
265     bool isSketcher = isSketchOperation(aOperation);
266     bool isSketchOpe = isNestedSketchOperation(aOperation);
267
268     // Avoid non-sketch operations
269     if ((!isSketchOpe) && (!isSketcher))
270       return;
271
272     bool isEditing = aOperation->isEditOperation();
273
274     // Ignore creation sketch operation
275     if ((!isSketcher) && (!isEditing))
276       return;
277
278     // MoveTo in order to highlight current object
279     aViewer->AISContext()->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
280
281     // Remember highlighted objects for editing
282     ModuleBase_ISelection* aSelect = aWorkshop->selection();
283
284     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
285     storeSelection(!aHasShift);
286
287     if (myCurrentSelection.empty()) {
288       if (isSketchOpe && (!isSketcher))
289         // commit previous operation
290         if (!aOperation->commit())
291           aOperation->abort();
292       return;
293     }
294
295     if (isSketcher) {
296       myIsDragging = true;
297       get2dPoint(theWnd, theEvent, myCurrentPoint);
298       myDragDone = false;
299       launchEditing();
300
301     } else if (isSketchOpe && isEditing) {
302       // If selected another object commit current result
303       aOperation->commit();
304
305       myIsDragging = true;
306       get2dPoint(theWnd, theEvent, myCurrentPoint);
307       myDragDone = false;
308
309       // This is necessary in order to finalize previous operation
310       QApplication::processEvents();
311       launchEditing();
312     }
313   }
314 }
315
316 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
317 {
318   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
319   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
320   if (!aViewer->canDragByMouse())
321     return;
322   ModuleBase_Operation* aOp = getCurrentOperation();
323   if (aOp) {
324     if (isNestedSketchOperation(aOp)) {
325       get2dPoint(theWnd, theEvent, myClickedPoint);
326
327       // Only for sketcher operations
328       if (myIsDragging) {
329         if (myDragDone) {
330           //aOp->commit();
331           myCurrentSelection.clear();
332           // Reselect edited object
333           /*aViewer->AISContext()->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
334           if (theEvent->modifiers() & Qt::ShiftModifier)
335             aViewer->AISContext()->ShiftSelect();
336           else
337             aViewer->AISContext()->Select();
338             */
339         }
340       }
341     }
342   }
343   aWorkshop->viewer()->enableSelection(myPreviousSelectionEnabled);
344   myIsDragging = false;
345 }
346
347 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
348 {
349   if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
350     myIsMouseOverViewProcessed = true;
351     // 1. perform the widget mouse move functionality and display the presentation
352     ModuleBase_Operation* aOperation = getCurrentOperation();
353     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
354     ModuleBase_ModelWidget* anActiveWdg = aPanel->activeWidget();
355     // the mouse move should be processed in the widget, if it can in order to visualize correct
356     // presentation. These widgets correct the feature attribute according to the mouse position
357     PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWdg);
358     if (aPoint2DWdg) {
359       aPoint2DWdg->onMouseMove(theWnd, theEvent);
360     }
361     PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast<PartSet_WidgetPoint2dDistance*>
362                                                                 (anActiveWdg);
363     if (aDistanceWdg) {
364       aDistanceWdg->onMouseMove(theWnd, theEvent);
365     }
366     // the feature is to be erased here, but it is correct to call canDisplayObject because
367     // there can be additional check (e.g. editor widget in distance constraint)
368     visualizeFeature(aOperation, canDisplayObject());
369   }
370
371   myClickedPoint.clear();
372
373   if (myIsDragging) {
374     // 1. the current selection is saved in the mouse press method in order to restore it after moving
375     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
376     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
377     // deselected). This flag should be restored in the slot, processed the mouse release signal.
378     ModuleBase_IViewer* aViewer = myModule->workshop()->viewer();
379     aViewer->enableSelection(false);
380
381     ModuleBase_Operation* aOperation = getCurrentOperation();
382     if (!aOperation)
383       return;
384     if (isSketchOperation(aOperation))
385       return; // No edit operation activated
386
387     Handle(V3d_View) aView = theWnd->v3dView();
388     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
389     double aX, aY;
390     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);
391     double dX =  aX - myCurrentPoint.myCurX;
392     double dY =  aY - myCurrentPoint.myCurY;
393
394     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
395     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
396     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
397     // 3. the flag to disable the update viewer should be set in order to avoid blinking in the 
398     // viewer happens by deselect/select the modified objects. The flag should be restored after
399     // the selection processing. The update viewer should be also called.
400     bool isEnableUpdateViewer = aDisplayer->enableUpdateViewer(false);
401
402     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
403     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
404     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
405                                           aLast = myCurrentSelection.end();
406     // 4. the features and attributes modification(move)
407     for (; anIt != aLast; anIt++) {
408       FeaturePtr aFeature = anIt.key();
409
410       std::set<AttributePtr> anAttributes = anIt.value().first;
411       // Process selection by attribute: the priority to the attribute
412       if (!anAttributes.empty()) {
413         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
414                                                anAttLast = anAttributes.end();
415         for (; anAttIt != anAttLast; anAttIt++) {
416           AttributePtr anAttr = *anAttIt;
417           if (anAttr.get() == NULL)
418             continue;
419           std::string aAttrId = anAttr->id();
420           DataPtr aData = aFeature->data();
421           if (aData.get() != NULL) {
422             std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
423               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
424             if (aPoint.get() != NULL) {
425               bool isImmutable = aPoint->setImmutable(true);
426               aPoint->move(dX, dY);
427               ModelAPI_EventCreator::get()->sendUpdated(aFeature, aMoveEvent);
428               aPoint->setImmutable(isImmutable);
429             }
430           }
431         }
432       } else {
433         // Process selection by feature
434         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
435           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
436         if (aSketchFeature) {
437           aSketchFeature->move(dX, dY);
438           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, aMoveEvent);
439         }
440       }
441     }
442     Events_Loop::loop()->flush(aMoveEvent); // up all move events - to be processed in the solver
443     //Events_Loop::loop()->flush(aUpdateEvent); // up update events - to redisplay presentations
444
445     // 5. it is necessary to save current selection in order to restore it after the features moving
446     restoreSelection();
447     // 6. restore the update viewer flag and call this update
448     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
449     aDisplayer->updateViewer();
450
451     myDragDone = true;
452     myCurrentPoint.setValue(aX, aY);
453   }
454 }
455
456 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
457 {
458   ModuleBase_Operation* aOperation = getCurrentOperation();
459   if (aOperation && aOperation->isEditOperation()) {
460     std::string aId = aOperation->id().toStdString();
461     if (isDistanceOperation(aOperation))
462     {
463       // Activate dimension value editing on double click
464       ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
465       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
466       // Find corresponded widget to activate value editing
467       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
468         if (aWgt->attributeID() == "ConstraintValue") {
469           aWgt->focusTo();
470           return;
471         }
472       }
473     }
474   }
475 }
476
477 void PartSet_SketcherMgr::onApplicationStarted()
478 {
479   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
480   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
481   XGUI_Workshop* aWorkshop = aConnector->workshop();
482   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
483   if (aPropertyPanel) {
484     connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),
485             this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));
486   }
487
488   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
489   connect(aViewerProxy, SIGNAL(enterViewPort()), this, SLOT(onEnterViewPort()));
490   connect(aViewerProxy, SIGNAL(leaveViewPort()), this, SLOT(onLeaveViewPort()));
491 }
492
493 void PartSet_SketcherMgr::onBeforeWidgetActivated(ModuleBase_ModelWidget* theWidget)
494 {
495   if (!myClickedPoint.myIsInitialized)
496     return;
497
498   ModuleBase_Operation* aOperation = getCurrentOperation();
499   // the distance constraint feature should not use the clickedd point
500   // this is workaround in order to don't throw down the flyout point value,
501   // set by execute() method of these type of features
502   if (isDistanceOperation(aOperation))
503     return;
504
505   PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(theWidget);
506   if (aPnt2dWgt) {
507     aPnt2dWgt->setPoint(myClickedPoint.myCurX, myClickedPoint.myCurY);
508   }
509 }
510
511 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, 
512                                      Point& thePoint)
513 {
514   Handle(V3d_View) aView = theWnd->v3dView();
515   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
516   double aX, anY;
517   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, anY);
518   thePoint.setValue(aX, anY);
519 }
520
521 void PartSet_SketcherMgr::launchEditing()
522 {
523   // there should be activate the vertex selection mode because the edit can happens by the selected
524   // point
525   QIntList aModes;
526   aModes << TopAbs_VERTEX << TopAbs_EDGE;
527   // TODO: #391 - to be uncommented
528   /*aModes.append(AIS_DSM_Text);
529   aModes.append(AIS_DSM_Line);
530   aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum) TopAbs_VERTEX));
531   aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum) TopAbs_EDGE));*/
532
533   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
534   aConnector->activateSubShapesSelection(aModes);
535
536   if (!myCurrentSelection.empty()) {
537     FeaturePtr aFeature = myCurrentSelection.begin().key();
538     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
539               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
540     if (aSPFeature) {
541       myModule->editFeature(aSPFeature);
542     }
543   }
544  
545 }
546
547
548 QStringList PartSet_SketcherMgr::sketchOperationIdList()
549 {
550   static QStringList aIds;
551   if (aIds.size() == 0) {
552     aIds << SketchPlugin_Line::ID().c_str();
553     aIds << SketchPlugin_Point::ID().c_str();
554     aIds << SketchPlugin_Arc::ID().c_str();
555     aIds << SketchPlugin_Circle::ID().c_str();
556     aIds << SketchPlugin_ConstraintLength::ID().c_str();
557     aIds << SketchPlugin_ConstraintDistance::ID().c_str();
558     aIds << SketchPlugin_ConstraintRigid::ID().c_str();
559     aIds << SketchPlugin_ConstraintRadius::ID().c_str();
560     aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
561     aIds << SketchPlugin_ConstraintParallel::ID().c_str();
562   }
563   return aIds;
564 }
565
566 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
567 {
568   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
569 }
570
571 bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation)
572 {
573   return theOperation &&
574          PartSet_SketcherMgr::sketchOperationIdList().contains(theOperation->id());
575 }
576
577 bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation)
578 {
579   return theOperation && !theOperation->isEditOperation() && isNestedSketchOperation(theOperation);
580 }
581
582 bool PartSet_SketcherMgr::isEntityOperation(ModuleBase_Operation* theOperation)
583 {
584   std::string aId = theOperation ? theOperation->id().toStdString() : "";
585
586   return (aId == SketchPlugin_Line::ID()) ||
587          (aId == SketchPlugin_Point::ID()) ||
588          (aId == SketchPlugin_Arc::ID()) ||
589          (aId == SketchPlugin_Circle::ID());
590 }
591
592 bool PartSet_SketcherMgr::isDistanceOperation(ModuleBase_Operation* theOperation)
593 {
594   std::string aId = theOperation ? theOperation->id().toStdString() : "";
595
596   return (aId == SketchPlugin_ConstraintLength::ID()) ||
597          (aId == SketchPlugin_ConstraintDistance::ID()) ||
598          (aId == SketchPlugin_ConstraintRadius::ID());
599 }
600
601 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
602 {
603   // Display all sketcher sub-Objects
604   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theOperation->feature());
605   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
606   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
607
608   // Hide sketcher result
609   std::list<ResultPtr> aResults = myCurrentSketch->results();
610   std::list<ResultPtr>::const_iterator aIt;
611   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
612     aDisplayer->erase((*aIt), false);
613   }
614   aDisplayer->erase(myCurrentSketch, false);
615
616   // Display sketcher objects
617   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
618     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
619     std::list<ResultPtr> aResults = aFeature->results();
620     std::list<ResultPtr>::const_iterator aIt;
621     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
622       aDisplayer->display((*aIt), false);
623     }
624     aDisplayer->display(aFeature, false);
625   }
626
627   if (myPlaneFilter.IsNull()) 
628     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
629
630   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
631   if (theOperation->isEditOperation()) {
632     // If it is editing of sketch then it means that plane is already defined
633     std::shared_ptr<GeomAPI_Pln> aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
634     myPlaneFilter->setPlane(aPln->impl<gp_Pln>());
635   }
636   aDisplayer->updateViewer();
637 }
638
639 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
640 {
641   myIsMouseOverWindow = false;
642
643   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
644   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
645
646   DataPtr aData = myCurrentSketch->data();
647   if ((!aData) || (!aData->isValid())) {
648     // The sketch was aborted
649     myCurrentSketch = CompositeFeaturePtr();
650     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
651
652     // Erase all sketcher objects
653     QStringList aSketchIds = sketchOperationIdList();
654     QObjectPtrList aObjects = aDisplayer->displayedObjects();
655     foreach (ObjectPtr aObj, aObjects) {
656       DataPtr aObjData = aObj->data();
657       if ((!aObjData) || (!aObjData->isValid()))
658         aDisplayer->erase(aObj);
659     }
660     return; 
661   }
662   // Hide all sketcher sub-Objects
663   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
664     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
665     std::list<ResultPtr> aResults = aFeature->results();
666     std::list<ResultPtr>::const_iterator aIt;
667     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
668       aDisplayer->erase((*aIt), false);
669     }
670     aDisplayer->erase(aFeature, false);
671   }
672   // Display sketcher result
673   std::list<ResultPtr> aResults = myCurrentSketch->results();
674   std::list<ResultPtr>::const_iterator aIt;
675   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
676     aDisplayer->display((*aIt), false);
677   }
678   aDisplayer->display(myCurrentSketch);
679     
680   myCurrentSketch = CompositeFeaturePtr();
681   myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
682   aDisplayer->updateViewer();
683 }
684
685 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* )
686 {
687   connectToPropertyPanel(true);
688 }
689
690 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
691 {
692   connectToPropertyPanel(false);
693   myIsPropertyPanelValueChanged = false;
694   myIsMouseOverViewProcessed = true;
695 }
696
697 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
698 {
699   if (isNestedCreateOperation(theOperation))
700     visualizeFeature(theOperation, true);
701 }
702
703 bool PartSet_SketcherMgr::canUndo() const
704 {
705   return isNestedCreateOperation(getCurrentOperation());
706 }
707
708 bool PartSet_SketcherMgr::canRedo() const
709 {
710   return isNestedCreateOperation(getCurrentOperation());
711 }
712
713 bool PartSet_SketcherMgr::canDisplayObject() const
714 {
715   bool aCanDisplay = true;
716   if (!isNestedCreateOperation(getCurrentOperation()))
717     return aCanDisplay;
718
719   ModuleBase_Operation* aOperation = getCurrentOperation();
720   ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
721   ModuleBase_ModelWidget* anActiveWdg = aPanel ? aPanel->activeWidget() : 0;
722   // the active widget editor should not influence here. The presentation should be visible always
723   // when this widget is active.
724   if (anActiveWdg) {
725     ModuleBase_WidgetEditor* anEditorWdg = dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWdg);
726     if (anEditorWdg) {
727       return aCanDisplay;
728     }
729   }
730
731   // during a nested create operation, the feature is redisplayed only if the mouse over view
732   // of there was a value modified in the property panel after the mouse left the view
733   aCanDisplay = myIsPropertyPanelValueChanged || myIsMouseOverWindow;
734   return aCanDisplay;
735 }
736
737 bool PartSet_SketcherMgr::canChangeConstruction(bool& isConstruction) const
738 {
739   bool anEnabled = false;
740   ModuleBase_Operation* anOperation = getCurrentOperation();
741
742   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
743                         PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
744   if (!isActiveSketch)
745     return anEnabled;
746
747   QObjectPtrList anObjects;
748   // 1. change construction type of a created feature
749   if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
750       PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
751     anObjects.append(anOperation->feature());
752   }
753   else {
754     if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
755       anOperation->abort();
756     // 2. change construction type of selected sketch entities
757     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
758     anObjects = aSelection->selectedPresentations();
759   }
760   anEnabled = anObjects.size() > 0;
761
762   bool isNotConstructedFound = false;
763   if (anObjects.size() > 0) {
764     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
765     for (; anIt != aLast && !isNotConstructedFound; anIt++) {
766       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
767       if (aFeature.get() != NULL) {
768         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
769                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
770         if (aSketchFeature.get() != NULL) {
771           std::string anAttribute = SketchPlugin_Feature::CONSTRUCTION_ID();
772
773           std::shared_ptr<ModelAPI_AttributeBoolean> aConstructionAttr = 
774             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
775           isNotConstructedFound = !aConstructionAttr->value();
776         }
777       }
778     }
779   }
780   isConstruction = anObjects.size() && !isNotConstructedFound;
781   return anEnabled;
782 }
783   
784 void PartSet_SketcherMgr::setConstruction(const bool isChecked)
785 {
786   ModuleBase_Operation* anOperation = getCurrentOperation();
787
788   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
789                         PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
790   if (!isActiveSketch)
791     return;
792
793   QObjectPtrList anObjects;
794   bool isUseTransaction = false;
795   // 1. change construction type of a created feature
796   if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
797       PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
798     anObjects.append(anOperation->feature());
799   }
800   else {
801     isUseTransaction = true;
802     // 2. change construction type of selected sketch entities
803     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
804     anObjects = aSelection->selectedPresentations();
805   }
806
807   QAction* anAction = myModule->action("CONSTRUCTION_CMD");
808   SessionPtr aMgr = ModelAPI_Session::get();
809   if (isUseTransaction) {
810     if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
811       anOperation->abort();
812     aMgr->startOperation(anAction->text().toStdString());
813   }
814   storeSelection();
815
816   if (anObjects.size() > 0) {
817     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
818     for (; anIt != aLast; anIt++) {
819       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
820       if (aFeature.get() != NULL) {
821         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
822                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
823         if (aSketchFeature.get() != NULL) {
824           std::string anAttribute = SketchPlugin_Feature::CONSTRUCTION_ID();
825
826           std::shared_ptr<ModelAPI_AttributeBoolean> aConstructionAttr = 
827             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
828           aConstructionAttr->setValue(isChecked);
829         }
830       }
831     }
832   }
833   if (isUseTransaction) {
834     aMgr->finishOperation();
835   }
836   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
837   restoreSelection();
838 }
839
840 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
841 {
842   myPlaneFilter->setPlane(thePln->impl<gp_Pln>());
843 }
844
845 void PartSet_SketcherMgr::getCurrentSelection(const FeaturePtr& theFeature,
846                                               const FeaturePtr& theSketch,
847                                               ModuleBase_IWorkshop* theWorkshop,
848                                               FeatureToSelectionMap& theSelection)
849 {
850   if (theFeature.get() == NULL)
851     return;
852
853   std::set<AttributePtr> aSelectedAttributes;
854   std::set<ResultPtr> aSelectedResults;
855
856   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
857   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
858   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
859   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
860
861   std::list<ResultPtr> aResults = theFeature->results();
862   std::list<ResultPtr>::const_iterator aIt;
863   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
864   {
865     ResultPtr aResult = *aIt;
866     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
867     if (aAISObj.get() == NULL)
868       continue;
869     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
870     for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
871     {
872       Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(
873                                                                       aContext->SelectedOwner());
874       if (aBRepOwner.IsNull())
875         continue;
876       Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast(
877                                                                         aBRepOwner->Selectable());
878       if (anIO != anAISIO)
879         continue;
880
881       if (aBRepOwner->HasShape()) {
882         const TopoDS_Shape& aShape = aBRepOwner->Shape();
883         TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
884         if (aShapeType == TopAbs_VERTEX) {
885           AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,
886                                                                         aShape, theSketch);
887           if (aPntAttr.get() != NULL)
888             aSelectedAttributes.insert(aPntAttr);
889         }
890         else if (aShapeType == TopAbs_EDGE &&
891                  aSelectedResults.find(aResult) == aSelectedResults.end()) {
892           aSelectedResults.insert(aResult);
893         }
894       }
895     }
896   }
897   theSelection[theFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);
898 }
899
900 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,
901                                              const FeaturePtr& theSketch,
902                                              ModuleBase_IWorkshop* theWorkshop,
903                                              const FeatureToSelectionMap& theSelection,
904                                              SelectMgr_IndexedMapOfOwner& anOwnersToSelect)
905 {
906   if (theFeature.get() == NULL)
907     return;
908
909   FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
910   std::set<AttributePtr> aSelectedAttributes = anIt.value().first;
911   std::set<ResultPtr> aSelectedResults = anIt.value().second;
912
913   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
914   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
915   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
916   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
917
918   // 1. found the feature's owners. Check the AIS objects of the constructions
919   AISObjectPtr aAISObj = aDisplayer->getAISObject(theFeature);
920   if (aAISObj.get() != NULL && aSelectedAttributes.empty() && aSelectedResults.empty()) {
921     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
922
923     SelectMgr_IndexedMapOfOwner aSelectedOwners;  
924     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
925     for  (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
926       Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
927       if (!anOwner.IsNull())
928         anOwnersToSelect.Add(anOwner);
929     }
930   }
931
932   // 2. found the feature results's owners
933   std::list<ResultPtr> aResults = theFeature->results();
934   std::list<ResultPtr>::const_iterator aIt;
935   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
936   {
937     ResultPtr aResult = *aIt;
938     AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
939     if (aAISObj.get() == NULL)
940       continue; 
941     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
942
943     SelectMgr_IndexedMapOfOwner aSelectedOwners;  
944     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
945     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
946       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
947       if ( anOwner.IsNull() || !anOwner->HasShape() )
948         continue;
949       const TopoDS_Shape& aShape = anOwner->Shape();
950       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
951       if (aShapeType == TopAbs_VERTEX) {
952         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
953         if (aPntAttr.get() != NULL &&
954             aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end()) {
955           anOwnersToSelect.Add(anOwner);
956         }
957       }
958       else if (aShapeType == TopAbs_EDGE) {
959         bool aFound = aSelectedResults.find(aResult) != aSelectedResults.end();
960         if (aSelectedResults.find(aResult) != aSelectedResults.end() &&
961             anOwnersToSelect.FindIndex(anOwner) <= 0)
962           anOwnersToSelect.Add(anOwner);
963       }
964     }
965   }
966 }
967
968 void PartSet_SketcherMgr::connectToPropertyPanel(const bool isToConnect)
969 {
970   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
971   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
972   XGUI_Workshop* aWorkshop = aConnector->workshop();
973   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
974   if (aPropertyPanel) {
975     const QList<ModuleBase_ModelWidget*>& aWidgets = aPropertyPanel->modelWidgets();
976     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
977       if (isToConnect) {
978         connect(aWidget, SIGNAL(beforeValuesChanged()),
979                 this, SLOT(onBeforeValuesChangedInPropertyPanel()));
980         connect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChangedInPropertyPanel()));
981         connect(aWidget, SIGNAL(afterValuesChanged()),
982                 this, SLOT(onAfterValuesChangedInPropertyPanel()));
983       }
984       else {
985         disconnect(aWidget, SIGNAL(beforeValuesChanged()),
986                    this, SLOT(onBeforeValuesChangedInPropertyPanel()));
987         disconnect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChangedInPropertyPanel()));
988         disconnect(aWidget, SIGNAL(afterValuesChanged()),
989                    this, SLOT(onAfterValuesChangedInPropertyPanel()));
990       }
991     }
992   }
993 }
994
995 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
996 {
997   return myModule->workshop()->currentOperation();
998 }
999
1000 void PartSet_SketcherMgr::visualizeFeature(ModuleBase_Operation* theOperation,
1001                                            const bool isToDisplay)
1002 {
1003   if (!theOperation || theOperation->isEditOperation())
1004     return;
1005
1006   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1007   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1008   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
1009
1010   // 1. change visibility of the object itself, here the presentable object is processed,
1011   // e.g. constraints features
1012   FeaturePtr aFeature = theOperation->feature();
1013   std::list<ResultPtr> aResults = aFeature->results();
1014   if (isToDisplay)
1015     aDisplayer->display(aFeature, false);
1016   else
1017     aDisplayer->erase(aFeature, false);
1018
1019   // change visibility of the object results, e.g. non-constraint features
1020   std::list<ResultPtr>::const_iterator aIt;
1021   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
1022     if (isToDisplay) {
1023       aDisplayer->display(*aIt, false);
1024     }
1025     else {
1026       aDisplayer->erase(*aIt, false);
1027     }
1028   }
1029   aDisplayer->updateViewer();
1030 }
1031
1032 void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
1033 {
1034   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1035   ModuleBase_ISelection* aSelect = aWorkshop->selection();
1036   QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
1037     
1038   QMap<FeaturePtr, QList<AttributePtr> > aFeature2AttributeMap;
1039   if (theHighlightedOnly) {
1040     fillFeature2Attribute(aHighlighted, aFeature2AttributeMap, myCurrentSketch);
1041   }
1042   else {
1043     fillFeature2Attribute(aHighlighted, aFeature2AttributeMap, myCurrentSketch);
1044
1045     QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected();
1046     fillFeature2Attribute(aSelected, aFeature2AttributeMap, myCurrentSketch);
1047   }
1048
1049   // 1. it is necessary to save current selection in order to restore it after the features moving
1050   myCurrentSelection.clear();
1051   QMap<FeaturePtr, QList<AttributePtr> >::const_iterator anIt = aFeature2AttributeMap.begin(),
1052                                                          aLast = aFeature2AttributeMap.end();
1053   for (; anIt != aLast; anIt++) {
1054     FeaturePtr aFeature = anIt.key();
1055     getCurrentSelection(aFeature, myCurrentSketch, aWorkshop, myCurrentSelection);
1056   }
1057   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1058 }
1059
1060 void PartSet_SketcherMgr::restoreSelection()
1061 {
1062   //qDebug(QString("restoreSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
1063   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
1064   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
1065   FeatureToSelectionMap::const_iterator aSIt = myCurrentSelection.begin(),
1066                                         aSLast = myCurrentSelection.end();
1067   SelectMgr_IndexedMapOfOwner anOwnersToSelect;
1068   for (; aSIt != aSLast; aSIt++) {
1069     anOwnersToSelect.Clear();
1070     getSelectionOwners(aSIt.key(), myCurrentSketch, aWorkshop, myCurrentSelection,
1071                         anOwnersToSelect);
1072     aConnector->workshop()->selector()->setSelectedOwners(anOwnersToSelect, false);
1073   }
1074 }