]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_SketcherReetntrantMgr.cpp
Salome HOME
Issue #1664: In the Sketcher, add the function Split a segment:
[modules/shaper.git] / src / PartSet / PartSet_SketcherReetntrantMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include "PartSet_SketcherReetntrantMgr.h"
4 #include "PartSet_Module.h"
5 #include "PartSet_SketcherMgr.h"
6 #include "PartSet_WidgetPoint2d.h"
7
8 #include "ModelAPI_Session.h"
9 #include "ModelAPI_AttributeString.h"
10 #include "ModelAPI_AttributeRefAttr.h"
11
12 #include "GeomDataAPI_Point2D.h"
13
14 #include <ModuleBase_IPropertyPanel.h>
15 #include <ModuleBase_OperationFeature.h>
16 #include <ModuleBase_ModelWidget.h>
17 #include <ModuleBase_ViewerPrs.h>
18 #include <ModuleBase_WidgetSelector.h>
19 #include <ModuleBase_PageWidget.h>
20 #include <ModuleBase_PageBase.h>
21 #include <ModuleBase_WidgetFactory.h>
22 #include <ModuleBase_OperationDescription.h>
23 #include "ModuleBase_ToolBox.h"
24
25 #include <SketchPlugin_Feature.h>
26 #include <SketchPlugin_Line.h>
27 #include <SketchPlugin_Arc.h>
28 #include <SketchPlugin_Circle.h>
29
30 #include <XGUI_Workshop.h>
31 #include <XGUI_ModuleConnector.h>
32 #include <XGUI_OperationMgr.h>
33 #include <XGUI_PropertyPanel.h>
34 #include <XGUI_ErrorMgr.h>
35
36 #include <QToolButton>
37
38 PartSet_SketcherReetntrantMgr::PartSet_SketcherReetntrantMgr(ModuleBase_IWorkshop* theWorkshop)
39 : QObject(theWorkshop),
40   myWorkshop(theWorkshop),
41   myRestartingMode(RM_None),
42   myIsFlagsBlocked(false),
43   myIsInternalEditOperation(false),
44   myNoMoreWidgetsAttribute("")
45 {
46 }
47
48 PartSet_SketcherReetntrantMgr::~PartSet_SketcherReetntrantMgr()
49 {
50 }
51
52 ModuleBase_ModelWidget* PartSet_SketcherReetntrantMgr::internalActiveWidget() const
53 {
54   ModuleBase_ModelWidget* aWidget = 0;
55   if (!isActiveMgr())
56     return aWidget;
57
58   ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
59   if (anOperation) {
60     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
61     if (aPanel) { // check for case when the operation is started but property panel is not filled
62       ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
63       if (myIsInternalEditOperation && (!anActiveWidget || !anActiveWidget->isViewerSelector()))
64         aWidget = myInternalActiveWidget;
65     }
66   }
67   return aWidget;
68 }
69
70 bool PartSet_SketcherReetntrantMgr::isInternalEditActive() const
71 {
72   return myIsInternalEditOperation;
73 }
74
75 void PartSet_SketcherReetntrantMgr::updateInternalEditActiveState()
76 {
77   if  (myIsInternalEditOperation) {
78     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
79                                                          (myWorkshop->currentOperation());
80     if (aFOperation) {
81       FeaturePtr aFeature = aFOperation->feature();
82       QString anError = myWorkshop->module()->getFeatureError(aFeature);
83       // stop started internal edit operation as soon as the operation becomes invalid
84       // it is especially important for the sketch tangent arc feature
85       if (!anError.isEmpty()) {
86         aFOperation->setEditOperation(false);
87         //workshop()->operationMgr()->updateApplyOfOperations();
88         beforeStopInternalEdit();
89         myIsInternalEditOperation = false;
90         updateAcceptAllAction();
91       }
92     }
93   }
94 }
95
96 bool PartSet_SketcherReetntrantMgr::operationCommitted(ModuleBase_Operation* theOperation)
97 {
98   bool aProcessed = false;
99   if (!isActiveMgr())
100     return aProcessed;
101
102   aProcessed = myIsInternalEditOperation;
103   resetFlags();
104
105   return aProcessed;
106 }
107
108 void PartSet_SketcherReetntrantMgr::operationStarted(ModuleBase_Operation* theOperation)
109 {
110   if (!isActiveMgr())
111     return;
112
113   if (myPreviousFeature.get() && myRestartingMode == RM_LastFeatureUsed) {
114     ModuleBase_OperationFeature* aCurrentOperation = dynamic_cast<ModuleBase_OperationFeature*>(
115                                                                 myWorkshop->currentOperation());
116     CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
117     copyReetntrantAttributes(myPreviousFeature, aCurrentOperation->feature(), aSketch);
118   }
119   resetFlags();
120 }
121
122 void PartSet_SketcherReetntrantMgr::operationAborted(ModuleBase_Operation* theOperation)
123 {
124   if (!isActiveMgr())
125     return;
126
127   resetFlags();
128 }
129
130 bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* theWnd,
131                                                       QMouseEvent* theEvent)
132 {
133   bool aProcessed = false;
134   if (!isActiveMgr())
135     return aProcessed;
136
137   if  (myIsInternalEditOperation) {
138     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
139                                                          (myWorkshop->currentOperation());
140     FeaturePtr aLastFeature = myRestartingMode == RM_LastFeatureUsed ? aFOperation->feature()
141                                                                      : FeaturePtr();
142     if (aLastFeature) {
143       ModuleBase_ModelWidget* anActiveWidget = module()->activeWidget();
144       ModuleBase_IPropertyPanel* aPanel = myWorkshop->currentOperation()->propertyPanel();
145
146       FeaturePtr aCurrentFeature = aFOperation->feature();
147       bool isLineFeature = false, isArcFeature = false;
148       if (aCurrentFeature->getKind() == SketchPlugin_Line::ID())
149         isLineFeature = anActiveWidget->attributeID() == SketchPlugin_Line::START_ID();
150       else if (isTangentArc(aFOperation, module()->sketchMgr()->activeSketch()))
151         isArcFeature = anActiveWidget->attributeID() == SketchPlugin_Arc::TANGENT_POINT_ID();
152
153       bool aCanBeActivatedByMove = isLineFeature || isArcFeature;
154       if (aCanBeActivatedByMove) {
155         myPreviousFeature = aFOperation->feature();
156         restartOperation();
157         myPreviousFeature = FeaturePtr();
158
159         anActiveWidget = module()->activeWidget();
160         aCurrentFeature = anActiveWidget->feature();
161         aProcessed = true;
162         aPanel->activateNextWidget(anActiveWidget);
163       } else {
164         // processing mouse move in active widget of restarted operation
165         ModuleBase_ModelWidget* anActiveWidget = module()->activeWidget();
166         PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
167         if (aProcessor)
168           aProcessor->mouseMoved(theWnd, theEvent);
169       }
170     }
171   }
172   return aProcessed;
173 }
174
175 bool PartSet_SketcherReetntrantMgr::processMousePressed(ModuleBase_IViewWindow* /* theWnd*/,
176                                                         QMouseEvent* /* theEvent*/)
177 {
178   return isActiveMgr() && myIsInternalEditOperation;
179 }
180
181 bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* theWnd,
182                                                          QMouseEvent* theEvent)
183 {
184   bool aProcessed = false;
185   if (!isActiveMgr())
186     return aProcessed;
187
188   if (myIsInternalEditOperation) {
189     ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
190     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
191
192     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
193     if (!anActiveWidget || !anActiveWidget->isViewerSelector()) {
194
195       // block of viewer update
196       // we need to block update content of the viewer because of Sketch Point feature
197       // in activate() the value of the point is initialized and it can be displayed
198       // but the default value is [0, 0]. So, we block update viewer contentent until
199       // onMouseRelease happens, which correct the point position
200       ModuleBase_Tools::blockUpdateViewer(true);
201
202       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
203                                                            (myWorkshop->currentOperation());
204       myPreviousFeature = aFOperation->feature();
205       restartOperation();
206       myPreviousFeature = FeaturePtr();
207       aProcessed = true;
208
209       // fill the first widget by the mouse event point
210       // if the active widget is not the first, it means that the restarted operation is filled by
211       // the current preselection.
212       PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
213       ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget();
214       if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) {
215         aPoint2DWdg->mouseReleased(theWnd, theEvent);
216       }
217       // unblock viewer update
218       ModuleBase_Tools::blockUpdateViewer(false);
219     }
220   }
221
222   return aProcessed;
223 }
224
225 void PartSet_SketcherReetntrantMgr::onWidgetActivated()
226 {
227   if (!isActiveMgr())
228     return;
229   if (!myIsInternalEditOperation)
230     return;
231
232   PartSet_Module* aModule = module();
233   ModuleBase_ModelWidget* aFirstWidget = aModule->activeWidget();
234   ModuleBase_IPropertyPanel* aPanel = aModule->currentOperation()->propertyPanel();
235   if (aFirstWidget != aPanel->activeWidget()) {
236     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(aFirstWidget);
237     if (aWSelector)
238       aWSelector->activateSelectionAndFilters(true);
239   }
240 }
241
242 void PartSet_SketcherReetntrantMgr::onNoMoreWidgets(const std::string& thePreviousAttributeID)
243 {
244   if (!isActiveMgr())
245     return;
246
247   // we should avoid processing of the signal about no more widgets attributes and 
248   // do this after the restart operaion is finished if it was called
249   // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
250   // if it should be called after restart
251   if (myIsFlagsBlocked) {
252     myNoMoreWidgetsAttribute = thePreviousAttributeID;
253     return;
254   }
255
256   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
257                                                        (myWorkshop->currentOperation());
258   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
259     return;
260
261   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation,
262                                                     module()->sketchMgr()->activeSketch())) {
263     bool isStarted = false;
264     if (!module()->sketchMgr()->sketchSolverError()) {
265       if (myRestartingMode != RM_Forbided) {
266         myRestartingMode = RM_LastFeatureUsed;
267         isStarted = startInternalEdit(thePreviousAttributeID);
268       }
269     }
270     if (!isStarted)
271       aFOperation->commit();
272   }
273 }
274
275 bool PartSet_SketcherReetntrantMgr::processEnter(const std::string& thePreviousAttributeID)
276 {
277   bool isDone = false;
278
279   if (!isActiveMgr())
280     return isDone;
281
282   // empty previous attribute means that the Apply/Ok button has focus and the enter
283   // should not lead to start edition mode of the previous operation
284   if (thePreviousAttributeID.empty())
285     return isDone;
286
287   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
288                                                        (myWorkshop->currentOperation());
289   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
290     return isDone;
291
292   bool isSketchSolverError = module()->sketchMgr()->sketchSolverError();
293
294   if (!isSketchSolverError) {
295     myRestartingMode = RM_EmptyFeatureUsed;
296     isDone = startInternalEdit(thePreviousAttributeID);
297   }
298
299   return isDone;
300 }
301
302 void PartSet_SketcherReetntrantMgr::onVertexSelected()
303 {
304   if (!isActiveMgr())
305     return;
306
307   ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
308   std::string anOperationId = anOperation->id().toStdString();
309   if (anOperationId == SketchPlugin_Line::ID() ||
310       isTangentArc(anOperation, module()->sketchMgr()->activeSketch())) {
311     /// If last line finished on vertex the lines creation sequence has to be break
312     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
313     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
314     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
315     QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
316     bool aFoundWidget = false;
317     bool aFoundObligatory = false;
318     for (; anIt != aLast && !aFoundObligatory; anIt++) {
319       if (!aFoundWidget)
320         aFoundWidget = *anIt == anActiveWidget;
321       else
322         aFoundObligatory = (*anIt)->isObligatory();
323     }
324     if (!aFoundObligatory)
325       myRestartingMode = RM_Forbided;
326   }
327 }
328
329 void PartSet_SketcherReetntrantMgr::onBeforeStopped()
330 {
331   if (!isActiveMgr() || !myIsInternalEditOperation)
332     return;
333
334   beforeStopInternalEdit();
335 }
336
337 bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
338 {
339   return !isActiveMgr() || myRestartingMode == RM_None;
340 }
341
342 bool PartSet_SketcherReetntrantMgr::isInternalEditStarted() const
343 {
344   return myIsInternalEditOperation;
345 }
346
347 bool PartSet_SketcherReetntrantMgr::isActiveMgr() const
348 {
349   ModuleBase_Operation* aCurrentOperation = myWorkshop->currentOperation();
350
351   bool anActive = PartSet_SketcherMgr::isSketchOperation(aCurrentOperation);
352   if (!anActive) {
353     anActive = PartSet_SketcherMgr::isNestedSketchOperation(aCurrentOperation,
354                                                     module()->sketchMgr()->activeSketch());
355     if (anActive) { // the manager is not active when the current operation is a usual Edit
356       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
357                                                        (myWorkshop->currentOperation());
358       if (aFOperation->isEditOperation())
359         anActive = myIsInternalEditOperation;
360     }
361   }
362   return anActive;
363 }
364
365 bool PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePreviousAttributeID)
366 {
367   bool isDone = false;
368   /// this is workaround for ModuleBase_WidgetEditor, used in SALOME mode. Sometimes key enter
369   /// event comes two times, so we should not start another internal edit operation
370   /// the Apply button becomes disabled becase the second additional internal feature is created
371   if (myIsInternalEditOperation)
372     return true;
373
374   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
375                                                      (myWorkshop->currentOperation());
376
377   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation,
378                                                 module()->sketchMgr()->activeSketch())) {
379     aFOperation->setEditOperation(true/*, false*/);
380     createInternalFeature();
381
382     myIsInternalEditOperation = true;
383     updateAcceptAllAction();
384
385     isDone = true;
386     connect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
387     connect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
388
389     // activate selection filters of the first widget in the viewer
390     onWidgetActivated();
391
392     // activate the last active widget in the Property Panel
393     if (!thePreviousAttributeID.empty()) {
394       ModuleBase_Operation* anEditOperation = module()->currentOperation();
395       if (anEditOperation) {
396         ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
397         ModuleBase_ModelWidget* aPreviousAttributeWidget = 0;
398         QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
399         for (int i = 0, aNb = aWidgets.size(); i < aNb && !aPreviousAttributeWidget; i++) {
400           if (aWidgets[i]->attributeID() == thePreviousAttributeID) {
401           /// workaround for the same attributes used in different stacked widgets(attribute types)
402           if (ModuleBase_ToolBox::isOffToolBoxParent(aWidgets[i]))
403             continue;
404             aPreviousAttributeWidget = aWidgets[i];
405           }
406         }
407         // If the current widget is a selector, do nothing, it processes the mouse press
408         if (aPreviousAttributeWidget) {
409           if (!aPreviousAttributeWidget->isViewerSelector()) {
410             aPreviousAttributeWidget->focusTo();
411             aPreviousAttributeWidget->selectContent();
412           }
413           else {
414             // in case of shape multi selector, the widget does not lose focus by filling
415             // like it is in shape selector. So, if enter is pressed, the multi shape selector
416             // control should be deactivated. The focus is moved to Apply button and there
417             // should not be active control visualized in property panel
418             if (aPreviousAttributeWidget == aPanel->activeWidget()) {
419               aPanel->activateWidget(NULL, false);
420             }
421             // if there is no the next widget to be automatically activated, the Ok button in property
422             // panel should accept the focus(example is parallel constraint on sketch lines)
423             QToolButton* anOkBtn = dynamic_cast<XGUI_PropertyPanel*>(aPanel)->findButton(PROP_PANEL_OK);
424             if (anOkBtn)
425               anOkBtn->setFocus(Qt::TabFocusReason);
426           }
427         }
428       }
429     }
430   }
431   if (isDone)
432     module()->sketchMgr()->clearClickedFlags();
433
434   return isDone;
435 }
436
437 void PartSet_SketcherReetntrantMgr::beforeStopInternalEdit()
438 {
439   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
440                                                       (myWorkshop->currentOperation());
441   if (aFOperation) {
442     disconnect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
443     disconnect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
444   }
445
446   deleteInternalFeature();
447 }
448
449 void PartSet_SketcherReetntrantMgr::restartOperation()
450 {
451   if (myIsInternalEditOperation) {
452     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(
453                                                                   myWorkshop->currentOperation());
454     if (aFOperation) {
455       myNoMoreWidgetsAttribute = "";
456       myIsFlagsBlocked = true;
457       FeaturePtr aPrevFeature = aFOperation->feature();
458       aFOperation->commit();
459       module()->launchOperation(aFOperation->id());
460       myIsFlagsBlocked = false;
461       resetFlags();
462       // we should avoid processing of the signal about no more widgets attributes and 
463       // do this after the restart operaion is finished if it was called
464       // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
465       // if it should be called after restart
466       if (!myNoMoreWidgetsAttribute.empty()) {
467         onNoMoreWidgets(myNoMoreWidgetsAttribute);
468         myNoMoreWidgetsAttribute = "";
469       }
470     }
471   }
472 }
473
474 void PartSet_SketcherReetntrantMgr::createInternalFeature()
475 {
476   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
477                                                      (myWorkshop->currentOperation());
478
479   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation,
480                                                           module()->sketchMgr()->activeSketch())) {
481     FeaturePtr anOperationFeature = aFOperation->feature();
482
483     CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
484     myInternalFeature = aSketch->addFeature(anOperationFeature->getKind());
485
486     bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature,
487                                                      aSketch, false);
488     XGUI_PropertyPanel* aPropertyPanel = dynamic_cast<XGUI_PropertyPanel*>
489                                                   (aFOperation->propertyPanel());
490
491     myInternalWidget = new QWidget(aPropertyPanel->contentWidget()->pageWidget());
492     myInternalWidget->setVisible(false);
493
494     ModuleBase_PageWidget* anInternalPage = new ModuleBase_PageWidget(myInternalWidget);
495
496     QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
497     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myWorkshop);
498
499     aFactory.createWidget(anInternalPage);
500     QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
501
502     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
503       bool isStoreValue = !aFOperation->isEditOperation() &&
504                           !aWidget->getDefaultValue().empty() &&
505                           !aWidget->isComputedDefault();
506       aWidget->setFeature(myInternalFeature, isStoreValue);
507       if (!isStoreValue && isFeatureChanged)
508         aWidget->restoreValue();
509     }
510
511     ModuleBase_ModelWidget* aFirstWidget = ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget
512                                                                                         (aWidgets);
513     if (aFirstWidget)
514       myInternalActiveWidget = aFirstWidget;
515   }
516 }
517
518 void PartSet_SketcherReetntrantMgr::deleteInternalFeature()
519 {
520   if (myInternalActiveWidget) {
521     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(myInternalActiveWidget);
522     if (aWSelector)
523       aWSelector->activateSelectionAndFilters(false);
524     myInternalActiveWidget = 0;
525   }
526   delete myInternalWidget;
527   myInternalWidget = 0;
528
529   QObjectPtrList anObjects;
530   anObjects.append(myInternalFeature);
531   workshop()->deleteFeatures(anObjects);
532   myInternalFeature = FeaturePtr();
533 }
534
535 void PartSet_SketcherReetntrantMgr::resetFlags()
536 {
537   if (!myIsFlagsBlocked) {
538     myIsInternalEditOperation = false;
539     updateAcceptAllAction();
540     myRestartingMode = RM_None;
541   }
542 }
543
544 bool PartSet_SketcherReetntrantMgr::copyReetntrantAttributes(const FeaturePtr& theSourceFeature,
545                                                              const FeaturePtr& theNewFeature,
546                                                              const CompositeFeaturePtr& theSketch,
547                                                              const bool isTemporary)
548 {
549   bool aChanged = false;
550   if (!theSourceFeature.get())
551     return aChanged;
552
553   std::string aFeatureKind = theSourceFeature->getKind();
554   if (aFeatureKind == SketchPlugin_Line::ID()) {
555     // Initialize new line with first point equal to end of previous
556     std::shared_ptr<ModelAPI_Data> aSFData = theSourceFeature->data();
557     std::shared_ptr<GeomDataAPI_Point2D> aSPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
558                                                  aSFData->attribute(SketchPlugin_Line::END_ID()));
559     std::shared_ptr<ModelAPI_Data> aNFData = theNewFeature->data();
560     std::shared_ptr<GeomDataAPI_Point2D> aNPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
561                                                  aNFData->attribute(SketchPlugin_Line::START_ID()));
562     aNPoint->setValue(aSPoint->x(), aSPoint->y());
563     PartSet_Tools::createConstraint(theSketch, aSPoint, aNPoint);
564
565     aNPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
566                                                  aSFData->attribute(SketchPlugin_Line::END_ID()));
567     aNPoint->setValue(aSPoint->x(), aSPoint->y());
568   }
569   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
570     // set circle type
571     std::string aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE();
572     AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
573     AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
574     aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
575     //ModuleBase_Tools::flushUpdated(theNewFeature);
576     aChanged = true;
577   }
578   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
579     // set arc type
580     std::string aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE();
581     AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
582     AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
583     aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
584
585     // if the arc is tangent, set coincidence to end point of the previous arc
586     std::string anArcType = aSourceFeatureTypeAttr->value();
587     if (anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT()) {
588       // get the last point of the previuos arc feature(geom point 2d)
589       std::shared_ptr<ModelAPI_Data> aSData = theSourceFeature->data();
590       std::shared_ptr<GeomDataAPI_Point2D> aSPointAttr = 
591                                       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
592                                       aSData->attribute(SketchPlugin_Arc::END_ID()));
593       // get point attribute on the current feature
594       AttributeRefAttrPtr aTangentPointAttr = theNewFeature->data()->refattr(
595                                                     SketchPlugin_Arc::TANGENT_POINT_ID());
596       aTangentPointAttr->setAttr(aSPointAttr);
597
598       std::shared_ptr<GeomDataAPI_Point2D> aNPointAttr = 
599                                     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
600                                     theNewFeature->data()->attribute(SketchPlugin_Arc::END_ID()));
601       aNPointAttr->setValue(aSPointAttr->x(), aSPointAttr->y());
602
603     }
604     //ModuleBase_Tools::flushUpdated(theNewFeature);
605     aChanged = true;
606   }
607   return aChanged;
608 }
609
610 bool PartSet_SketcherReetntrantMgr::isTangentArc(ModuleBase_Operation* theOperation,
611                                                  const CompositeFeaturePtr& theSketch)
612 {
613   bool aTangentArc = false;
614   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
615                                                                         (theOperation);
616   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation, theSketch)) {
617     FeaturePtr aFeature = aFOperation->feature();
618     if (aFeature.get() && aFeature->getKind() == SketchPlugin_Arc::ID()) {
619       AttributeStringPtr aTypeAttr = aFeature->data()->string(SketchPlugin_Arc::ARC_TYPE());
620       std::string anArcType = aTypeAttr.get() ? aTypeAttr->value() : "";
621       aTangentArc = anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT();
622     }
623   }
624   return aTangentArc;
625 }
626
627 void PartSet_SketcherReetntrantMgr::updateAcceptAllAction()
628 {
629   CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
630   if (aSketch.get())
631     workshop()->errorMgr()->updateAcceptAllAction(aSketch);
632 }
633
634 XGUI_Workshop* PartSet_SketcherReetntrantMgr::workshop() const
635 {
636   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
637   return aConnector->workshop();
638 }
639
640 PartSet_Module* PartSet_SketcherReetntrantMgr::module() const
641 {
642   return dynamic_cast<PartSet_Module*>(myWorkshop->module());
643 }
644