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