Salome HOME
7ecd6033b6905972b5214d9abda3640c414cc35e
[modules/shaper.git] / src / PartSet / PartSet_Module.cpp
1 #include "PartSet_Module.h"
2 #include <PartSet_OperationSketch.h>
3 #include <PartSet_WidgetSketchLabel.h>
4 #include <PartSet_Validators.h>
5 #include <PartSet_Tools.h>
6 #include <PartSet_WidgetPoint2d.h>
7 #include <PartSet_WidgetPoint2dDistance.h>
8 #include <PartSet_WidgetShapeSelector.h>
9
10 #include <ModuleBase_Operation.h>
11 #include <ModuleBase_IViewer.h>
12 #include <ModuleBase_IViewWindow.h>
13 #include <ModuleBase_IPropertyPanel.h>
14 #include <ModuleBase_WidgetEditor.h>
15
16 #include <ModelAPI_Object.h>
17 #include <ModelAPI_Events.h>
18 #include <ModelAPI_Validator.h>
19 #include <ModelAPI_Data.h>
20 #include <ModelAPI_Session.h>
21
22 #include <GeomDataAPI_Point2D.h>
23 #include <GeomDataAPI_Point.h>
24 #include <GeomDataAPI_Dir.h>
25
26 #include <XGUI_MainWindow.h>
27 #include <XGUI_Displayer.h>
28 #include <XGUI_Viewer.h>
29 #include <XGUI_Workshop.h>
30 #include <XGUI_OperationMgr.h>
31 #include <XGUI_ViewPort.h>
32 #include <XGUI_ActionsMgr.h>
33 #include <XGUI_ViewerProxy.h>
34 #include <XGUI_ContextMenuMgr.h>
35 #include <XGUI_PropertyPanel.h>
36 #include <XGUI_ModuleConnector.h>
37 #include <XGUI_Tools.h>
38
39 #include <SketchPlugin_Line.h>
40 #include <SketchPlugin_Sketch.h>
41 #include <SketchPlugin_Point.h>
42 #include <SketchPlugin_Arc.h>
43 #include <SketchPlugin_Circle.h>
44 #include <SketchPlugin_ConstraintLength.h>
45 #include <SketchPlugin_ConstraintDistance.h>
46 #include <SketchPlugin_ConstraintParallel.h>
47 #include <SketchPlugin_ConstraintPerpendicular.h>
48 #include <SketchPlugin_ConstraintRadius.h>
49 #include <SketchPlugin_ConstraintRigid.h>
50
51 #include <Events_Loop.h>
52
53 #include <StdSelect_TypeOfFace.hxx>
54 #include <TopoDS_Vertex.hxx>
55 #include <TopoDS.hxx>
56 #include <TopoDS_Shape.hxx>
57 #include <BRep_Tool.hxx>
58
59 #include <QObject>
60 #include <QMouseEvent>
61 #include <QString>
62 #include <QTimer>
63 #include <QApplication>
64
65 #include <GeomAlgoAPI_FaceBuilder.h>
66 #include <GeomDataAPI_Dir.h>
67
68 #ifdef _DEBUG
69 #include <QDebug>
70 #endif
71
72
73 /// Returns list of unique objects by sum of objects from List1 and List2
74 QList<ObjectPtr> getSumList(const QList<ModuleBase_ViewerPrs>& theList1,
75                                        const QList<ModuleBase_ViewerPrs>& theList2)
76 {
77   QList<ObjectPtr> aRes;
78   foreach (ModuleBase_ViewerPrs aPrs, theList1) {
79     if (!aRes.contains(aPrs.object()))
80       aRes.append(aPrs.object());
81   }
82   foreach (ModuleBase_ViewerPrs aPrs, theList2) {
83     if (!aRes.contains(aPrs.object()))
84       aRes.append(aPrs.object());
85   }
86   return aRes;
87 }
88
89 /*!Create and return new instance of XGUI_Module*/
90 extern "C" PARTSET_EXPORT ModuleBase_IModule* createModule(ModuleBase_IWorkshop* theWshop)
91 {
92   return new PartSet_Module(theWshop);
93 }
94
95 PartSet_Module::PartSet_Module(ModuleBase_IWorkshop* theWshop)
96   : ModuleBase_IModule(theWshop), 
97   myIsDragging(false), myRestartingMode(RM_None), myDragDone(false)
98 {
99   //myWorkshop = dynamic_cast<XGUI_Workshop*>(theWshop);
100   ModuleBase_IViewer* aViewer = aViewer = theWshop->viewer();
101   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),
102           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));
103
104   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),
105           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));
106
107   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
108           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));
109
110   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),
111           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));
112
113   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWshop);
114   XGUI_Workshop* aWorkshop = aConnector->workshop();
115
116   XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr();
117   connect(anOpMgr, SIGNAL(keyEnterReleased()), this, SLOT(onEnterReleased()));
118
119   connect(aViewer, SIGNAL(keyRelease(ModuleBase_IViewWindow*, QKeyEvent*)),
120           this, SLOT(onKeyRelease(ModuleBase_IViewWindow*, QKeyEvent*)));
121 }
122
123 PartSet_Module::~PartSet_Module()
124 {
125   if (!myDocumentShapeFilter.IsNull())
126     myDocumentShapeFilter.Nullify();
127   if (!myPlaneFilter.IsNull())
128     myPlaneFilter.Nullify();
129 }
130
131 void PartSet_Module::registerValidators()
132 {
133   //Registering of validators
134   SessionPtr aMgr = ModelAPI_Session::get();
135   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
136   aFactory->registerValidator("PartSet_DistanceValidator", new PartSet_DistanceValidator);
137   aFactory->registerValidator("PartSet_LengthValidator", new PartSet_LengthValidator);
138   aFactory->registerValidator("PartSet_PerpendicularValidator", new PartSet_PerpendicularValidator);
139   aFactory->registerValidator("PartSet_ParallelValidator", new PartSet_ParallelValidator);
140   aFactory->registerValidator("PartSet_RadiusValidator", new PartSet_RadiusValidator);
141   aFactory->registerValidator("PartSet_DifferentObjects", new PartSet_DifferentObjectsValidator);
142 }
143
144
145 void PartSet_Module::onOperationComitted(ModuleBase_Operation* theOperation) 
146 {
147   if (theOperation->isEditOperation())
148     return;
149   /// Restart sketcher operations automatically
150   FeaturePtr aFeature = theOperation->feature();
151   std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
152             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
153   if (aSPFeature && (myRestartingMode == RM_LastFeatureUsed ||
154                      myRestartingMode == RM_EmptyFeatureUsed)) {
155     myLastOperationId = theOperation->id();
156     myLastFeature = myRestartingMode == RM_LastFeatureUsed ? theOperation->feature() : FeaturePtr();
157     launchOperation(myLastOperationId);
158   }
159   breakOperationSequence();
160 }
161
162 void PartSet_Module::breakOperationSequence()
163 {
164   myLastOperationId = "";
165   myLastFeature = FeaturePtr();
166   myRestartingMode = RM_None;
167 }
168
169 void PartSet_Module::onOperationAborted(ModuleBase_Operation* theOperation)
170 {
171   breakOperationSequence();
172 }
173
174 void PartSet_Module::onOperationStarted(ModuleBase_Operation* theOperation)
175 {
176   if (theOperation->id().toStdString() == SketchPlugin_Sketch::ID()) {
177     // Display all sketcher sub-Objects
178     myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theOperation->feature());
179     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
180     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
181
182     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
183       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
184       std::list<ResultPtr> aResults = aFeature->results();
185       std::list<ResultPtr>::const_iterator aIt;
186       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
187         aDisplayer->display((*aIt), false);
188       }
189       aDisplayer->display(aFeature);
190     }
191     // Hide sketcher result
192     std::list<ResultPtr> aResults = myCurrentSketch->results();
193     std::list<ResultPtr>::const_iterator aIt;
194     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
195       aDisplayer->erase((*aIt), false);
196     }
197     aDisplayer->erase(myCurrentSketch);
198
199
200     if (myPlaneFilter.IsNull()) 
201       myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
202     myWorkshop->viewer()->addSelectionFilter(myPlaneFilter);
203     if (theOperation->isEditOperation()) {
204       // If it is editing of sketch then it means that plane is already defined
205       std::shared_ptr<GeomAPI_Pln> aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
206       myPlaneFilter->setPlane(aPln->impl<gp_Pln>());
207     }
208   }
209   if (myDocumentShapeFilter.IsNull())
210     myDocumentShapeFilter = new PartSet_GlobalFilter(myWorkshop);
211   myWorkshop->viewer()->addSelectionFilter(myDocumentShapeFilter);
212 }
213
214 void PartSet_Module::onOperationStopped(ModuleBase_Operation* theOperation)
215 {
216   if (theOperation->id().toStdString() == SketchPlugin_Sketch::ID()) {
217     DataPtr aData = myCurrentSketch->data();
218     if ((!aData) || (!aData->isValid())) {
219       // The sketch was aborted
220       myCurrentSketch = CompositeFeaturePtr();
221       return; 
222     }
223     // Hide all sketcher sub-Objects
224     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
225     XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
226     for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
227       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
228       std::list<ResultPtr> aResults = aFeature->results();
229       std::list<ResultPtr>::const_iterator aIt;
230       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
231         aDisplayer->erase((*aIt), false);
232       }
233       aDisplayer->erase(aFeature, false);
234     }
235     // Display sketcher result
236     std::list<ResultPtr> aResults = myCurrentSketch->results();
237     std::list<ResultPtr>::const_iterator aIt;
238     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
239       aDisplayer->display((*aIt), false);
240     }
241     aDisplayer->display(myCurrentSketch);
242     
243     myCurrentSketch = CompositeFeaturePtr();
244     myWorkshop->viewer()->removeSelectionFilter(myPlaneFilter);
245   }
246   myWorkshop->viewer()->removeSelectionFilter(myDocumentShapeFilter);
247 }
248
249 void PartSet_Module::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
250 {
251   myPlaneFilter->setPlane(thePln->impl<gp_Pln>());
252 }
253
254
255 void PartSet_Module::propertyPanelDefined(ModuleBase_Operation* theOperation)
256 {
257   ModuleBase_IPropertyPanel* aPanel = theOperation->propertyPanel();
258   if ((theOperation->id().toStdString() == SketchPlugin_Sketch::ID()) && 
259     (theOperation->isEditOperation())) {
260     // we have to manually activate the sketch label in edit mode
261       aPanel->activateWidget(aPanel->modelWidgets().first());
262       return;
263   }
264
265   // Restart last operation type 
266   if ((theOperation->id() == myLastOperationId) && myLastFeature) {
267     ModuleBase_ModelWidget* aWgt = aPanel->activeWidget();
268     if (theOperation->id().toStdString() == SketchPlugin_Line::ID()) {
269       // Initialise new line with first point equal to end of previous
270       PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(aWgt);
271       if (aPnt2dWgt) {
272         std::shared_ptr<ModelAPI_Data> aData = myLastFeature->data();
273         std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
274           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Line::END_ID()));
275         if (aPoint) {
276           aPnt2dWgt->setPoint(aPoint->x(), aPoint->y());
277           PartSet_Tools::setConstraints(myCurrentSketch, theOperation->feature(), 
278             aWgt->attributeID(), aPoint->x(), aPoint->y());
279           theOperation->propertyPanel()->activateNextWidget(aPnt2dWgt);
280         }
281       }
282     }
283   } else {
284     // Start editing constraint
285     if (theOperation->isEditOperation()) {
286       std::string aId = theOperation->id().toStdString();
287       if (sketchOperationIdList().contains(QString(aId.c_str()))) {
288         if ((aId == SketchPlugin_ConstraintRadius::ID()) ||
289             (aId == SketchPlugin_ConstraintLength::ID()) || 
290             (aId == SketchPlugin_ConstraintDistance::ID())) {
291           // Find and activate widget for management of point for dimension line position
292           QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
293           foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
294             PartSet_WidgetPoint2D* aPntWgt = dynamic_cast<PartSet_WidgetPoint2D*>(aWgt);
295             if (aPntWgt) {
296               aPanel->activateWidget(aPntWgt);
297               return;
298             }
299           }
300         } 
301       }
302     }
303   }
304 }
305
306
307 void PartSet_Module::onSelectionChanged()
308 {
309   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
310   bool isSketcherOp = false;
311   // An edit operation is enable only if the current opeation is the sketch operation
312   if (aOperation && myCurrentSketch) {
313     if (PartSet_Tools::sketchPlane(myCurrentSketch))
314       isSketcherOp = (aOperation->id().toStdString() == SketchPlugin_Sketch::ID());
315   }
316   if (!isSketcherOp)
317     return;
318
319   // Editing of constraints can be done on selection
320   ModuleBase_ISelection* aSelect = myWorkshop->selection();
321   QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected();
322   if (aSelected.size() == 1) {
323     ModuleBase_ViewerPrs aPrs = aSelected.first();
324     ObjectPtr aObject = aPrs.object();
325     FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
326     if (aFeature) {
327       std::string aId = aFeature->getKind();
328       if ((aId == SketchPlugin_ConstraintRadius::ID()) ||
329           (aId == SketchPlugin_ConstraintLength::ID()) || 
330           (aId == SketchPlugin_ConstraintDistance::ID())) {
331         editFeature(aFeature);
332       }
333     }
334   }
335 }
336
337 void PartSet_Module::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) 
338 {
339   if (!(theEvent->buttons() & Qt::LeftButton))
340     return;
341
342   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
343   // Use only for sketch operations
344   if (aOperation && myCurrentSketch) {
345     if (!PartSet_Tools::sketchPlane(myCurrentSketch))
346       return;
347
348     bool isSketcher = (aOperation->id().toStdString() == SketchPlugin_Sketch::ID());
349     bool isSketchOpe = sketchOperationIdList().contains(aOperation->id());
350
351     // Avoid non-sketch operations
352     if ((!isSketchOpe) && (!isSketcher))
353       return;
354
355     bool isEditing = aOperation->isEditOperation();
356
357     // Ignore creation sketch operation
358     if ((!isSketcher) && (!isEditing))
359       return;
360
361     if (theEvent->modifiers()) {
362       // If user performs multiselection
363       if (isSketchOpe && (!isSketcher))
364         if (!aOperation->commit())
365           aOperation->abort();
366       return;
367     }
368     // Remember highlighted objects for editing
369     ModuleBase_ISelection* aSelect = myWorkshop->selection();
370     QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
371     QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected();
372     myEditingFeatures.clear();
373     myEditingAttr.clear();
374     if ((aHighlighted.size() == 0) && (aSelected.size() == 0)) {
375       if (isSketchOpe && (!isSketcher))
376         // commit previous operation
377         if (!aOperation->commit())
378           aOperation->abort();
379       return;
380     }
381
382     QObjectPtrList aSelObjects = getSumList(aHighlighted, aSelected);
383     if ((aHighlighted.size() == 1) && (aSelected.size() == 0)) {
384       // Move by selected shape (vertex). Can be used only for single selection
385       foreach(ModuleBase_ViewerPrs aPrs, aHighlighted) {
386         FeaturePtr aFeature = ModelAPI_Feature::feature(aHighlighted.first().object());
387         if (aFeature) {
388           myEditingFeatures.append(aFeature);
389           TopoDS_Shape aShape = aPrs.shape();
390           if (!aShape.IsNull()) {
391             if (aShape.ShapeType() == TopAbs_VERTEX) {
392               AttributePtr aAttr = PartSet_Tools::findAttributeBy2dPoint(myEditingFeatures.first(), 
393                                                                          aShape, myCurrentSketch);
394               if (aAttr)
395                 myEditingAttr.append(aAttr);
396             }
397           }
398         }
399       }
400     } else {
401       // Provide multi-selection. Can be used only for features
402       foreach (ObjectPtr aObj, aSelObjects) {
403         FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
404         if (aFeature && (!myEditingFeatures.contains(aFeature)))
405           myEditingFeatures.append(aFeature);
406       }
407
408     }
409     // If nothing highlighted - return
410     if (myEditingFeatures.size() == 0)
411       return;
412
413     if (isSketcher) {
414       myIsDragging = true;
415       get2dPoint(theWnd, theEvent, myCurX, myCurY);
416       myDragDone = false;
417       myWorkshop->viewer()->enableSelection(false);
418       launchEditing();
419
420     } else if (isSketchOpe && isEditing) {
421       // If selected another object
422       aOperation->abort();
423
424       myIsDragging = true;
425       get2dPoint(theWnd, theEvent, myCurX, myCurY);
426       myDragDone = false;
427       myWorkshop->viewer()->enableSelection(false);
428
429       // This is necessary in order to finalize previous operation
430       QApplication::processEvents();
431       launchEditing();
432     }
433   }
434 }
435
436
437 void PartSet_Module::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, 
438                                 double& theX, double& theY)
439 {
440   Handle(V3d_View) aView = theWnd->v3dView();
441   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
442   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, theX, theY);
443 }
444
445
446 void PartSet_Module::launchEditing()
447 {
448   if (myEditingFeatures.size() > 0) {
449     FeaturePtr aFeature = myEditingFeatures.first();
450     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
451               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
452     if (aSPFeature) {
453       editFeature(aSPFeature);
454     }
455   }
456 }
457
458 /// Returns new instance of operation object (used in createOperation for customization)
459 ModuleBase_Operation* PartSet_Module::getNewOperation(const std::string& theFeatureId)
460 {
461   if (theFeatureId == PartSet_OperationSketch::Type()) {
462     return new PartSet_OperationSketch(theFeatureId.c_str(), this);
463   }
464   return ModuleBase_IModule::getNewOperation(theFeatureId);
465 }
466
467
468 void PartSet_Module::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
469 {
470   myWorkshop->viewer()->enableSelection(true);
471   if (myIsDragging) {
472     myIsDragging = false;
473     if (myDragDone) {
474       myWorkshop->currentOperation()->commit();
475       myEditingFeatures.clear();
476       myEditingAttr.clear();
477     }
478   }
479 }
480
481
482 void PartSet_Module::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
483 {
484   if (myIsDragging) {
485     ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
486     if (aOperation->id().toStdString() == SketchPlugin_Sketch::ID())
487       return; // No edit operation activated
488
489     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
490     Handle(V3d_View) aView = theWnd->v3dView();
491     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
492     double aX, aY;
493     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);
494     double dX =  aX - myCurX;
495     double dY =  aY - myCurY;
496
497     if ((aOperation->id().toStdString() == SketchPlugin_Line::ID()) &&
498         (myEditingAttr.size() == 1) && 
499         myEditingAttr.first()) {
500       // probably we have prehighlighted point
501       AttributePtr aAttr = myEditingAttr.first();
502       std::string aAttrId = aAttr->id();
503       ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
504       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
505       // Find corresponded widget to provide dragging
506       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
507         if (aWgt->attributeID() == aAttrId) {
508           PartSet_WidgetPoint2D* aWgt2d = dynamic_cast<PartSet_WidgetPoint2D*>(aWgt);
509           if (aWgt2d) {
510             aWgt2d->setPoint(aWgt2d->x() + dX, aWgt2d->y() + dY);
511             break;
512           }
513         }
514       }
515     } else {
516       foreach(FeaturePtr aFeature, myEditingFeatures) {
517         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
518           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
519         if (aSketchFeature) { 
520           aSketchFeature->move(dX, dY);
521           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, anEvent);
522         }
523       }
524       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_MOVED));
525       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
526     }
527     myDragDone = true;
528     myCurX = aX;
529     myCurY = aY;
530   }
531 }
532
533 void PartSet_Module::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
534 {
535   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
536   if (aOperation->isEditOperation()) {
537     std::string aId = aOperation->id().toStdString();
538     if ((aId == SketchPlugin_ConstraintLength::ID()) ||
539       (aId == SketchPlugin_ConstraintDistance::ID()) ||
540       (aId == SketchPlugin_ConstraintRadius::ID())) 
541     {
542       // Activate dimension value editing on double click
543       ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
544       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
545       // Find corresponded widget to activate value editing
546       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
547         if (aWgt->attributeID() == "ConstraintValue") {
548           aWgt->focusTo();
549           return;
550         }
551       }
552     }
553   }
554 }
555
556 void PartSet_Module::onKeyRelease(ModuleBase_IViewWindow* theWnd, QKeyEvent* theEvent)
557 {
558   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
559   XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
560   anOpMgr->onKeyReleased(theEvent);
561 }
562
563 void PartSet_Module::onEnterReleased()
564 {
565   myRestartingMode = RM_EmptyFeatureUsed;
566 }
567
568 void PartSet_Module::onNoMoreWidgets()
569 {
570   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
571   if (aOperation) {
572     /// Restart sketcher operations automatically
573     FeaturePtr aFeature = aOperation->feature();
574     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
575               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
576     if (aSPFeature) {
577       if (myRestartingMode != RM_Forbided)
578         myRestartingMode = RM_LastFeatureUsed;
579       aOperation->commit();
580     }
581   }
582 }
583
584 QStringList PartSet_Module::sketchOperationIdList() const
585 {
586   QStringList aIds;
587   aIds << SketchPlugin_Line::ID().c_str();
588   aIds << SketchPlugin_Point::ID().c_str();
589   aIds << SketchPlugin_Arc::ID().c_str();
590   aIds << SketchPlugin_Circle::ID().c_str();
591   aIds << SketchPlugin_ConstraintLength::ID().c_str();
592   aIds << SketchPlugin_ConstraintDistance::ID().c_str();
593   aIds << SketchPlugin_ConstraintRigid::ID().c_str();
594   aIds << SketchPlugin_ConstraintRadius::ID().c_str();
595   aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
596   aIds << SketchPlugin_ConstraintParallel::ID().c_str();
597   return aIds;
598 }
599
600 void PartSet_Module::onVertexSelected(ObjectPtr theObject, const TopoDS_Shape& theShape)
601 {
602   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
603   if (aOperation->id().toStdString() == SketchPlugin_Line::ID()) {
604     /// If last line finished on vertex the lines creation sequence has to be break
605     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
606     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
607     if (aWidgets.last() == aPanel->activeWidget()) {
608       myRestartingMode = RM_Forbided;
609     }
610   }
611 }
612
613 QWidget* PartSet_Module::createWidgetByType(const std::string& theType, QWidget* theParent,
614                                             Config_WidgetAPI* theWidgetApi, std::string theParentId,
615                                             QList<ModuleBase_ModelWidget*>& theModelWidgets)
616 {
617   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
618   XGUI_Workshop* aWorkshop = aConnector->workshop();
619   if (theType == "sketch-start-label") {
620     PartSet_WidgetSketchLabel* aWgt = new PartSet_WidgetSketchLabel(theParent, theWidgetApi, theParentId);
621     aWgt->setWorkshop(aWorkshop);
622     connect(aWgt, SIGNAL(planeSelected(const std::shared_ptr<GeomAPI_Pln>&)), 
623       this, SLOT(onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>&)));
624     theModelWidgets.append(aWgt);
625     return aWgt->getControl();
626
627   } else if (theType == "sketch-2dpoint_selector") {
628     PartSet_WidgetPoint2D* aWgt = new PartSet_WidgetPoint2D(theParent, theWidgetApi, theParentId);
629     aWgt->setWorkshop(aWorkshop);
630     aWgt->setSketch(myCurrentSketch);
631
632     connect(aWgt, SIGNAL(vertexSelected(ObjectPtr, const TopoDS_Shape&)), 
633       this, SLOT(onVertexSelected(ObjectPtr, const TopoDS_Shape&)));
634
635     theModelWidgets.append(aWgt);
636     return aWgt->getControl();
637
638   } if (theType == "point2ddistance") {
639     PartSet_WidgetPoint2dDistance* aWgt = new PartSet_WidgetPoint2dDistance(theParent, theWidgetApi, theParentId);
640     aWgt->setWorkshop(aWorkshop);
641     aWgt->setSketch(myCurrentSketch);
642
643     theModelWidgets.append(aWgt);
644     return aWgt->getControl();
645
646   } if (theType == "sketch_shape_selector") {
647     PartSet_WidgetShapeSelector* aWgt = 
648       new PartSet_WidgetShapeSelector(theParent, workshop(), theWidgetApi, theParentId);
649     aWgt->setSketcher(myCurrentSketch);
650
651     theModelWidgets.append(aWgt);
652     return aWgt->getControl();
653
654   } if (theType == "sketch_constraint_shape_selector") {
655     PartSet_WidgetConstraintShapeSelector* aWgt = 
656       new PartSet_WidgetConstraintShapeSelector(theParent, workshop(), theWidgetApi, theParentId);
657     aWgt->setSketcher(myCurrentSketch);
658
659     theModelWidgets.append(aWgt);
660     return aWgt->getControl();
661
662   }else
663     return 0;
664 }
665