]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_SketcherReetntrantMgr.cpp
Salome HOME
fb8ce49e7211efc81f2a6044784380bb6ca97046
[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, module()->sketchMgr()->activeSketch()))
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                                                     module()->sketchMgr()->activeSketch())) {
259     bool isStarted = false;
260     if (!module()->sketchMgr()->sketchSolverError()) {
261       if (myRestartingMode != RM_Forbided) {
262         myRestartingMode = RM_LastFeatureUsed;
263         isStarted = startInternalEdit(thePreviousAttributeID);
264       }
265     }
266     if (!isStarted)
267       aFOperation->commit();
268   }
269 }
270
271 bool PartSet_SketcherReetntrantMgr::processEnter(const std::string& thePreviousAttributeID)
272 {
273   bool isDone = false;
274
275   if (!isActiveMgr())
276     return isDone;
277
278   // empty previous attribute means that the Apply/Ok button has focus and the enter
279   // should not lead to start edition mode of the previous operation
280   if (thePreviousAttributeID.empty())
281     return isDone;
282
283   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
284                                                        (myWorkshop->currentOperation());
285   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
286     return isDone;
287
288   bool isSketchSolverError = module()->sketchMgr()->sketchSolverError();
289
290   if (!isSketchSolverError) {
291     myRestartingMode = RM_EmptyFeatureUsed;
292     isDone = startInternalEdit(thePreviousAttributeID);
293   }
294
295   return isDone;
296 }
297
298 void PartSet_SketcherReetntrantMgr::onVertexSelected()
299 {
300   if (!isActiveMgr())
301     return;
302
303   ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
304   std::string anOperationId = anOperation->id().toStdString();
305   if (anOperationId == SketchPlugin_Line::ID() ||
306       isTangentArc(anOperation, module()->sketchMgr()->activeSketch())) {
307     /// If last line finished on vertex the lines creation sequence has to be break
308     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
309     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
310     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
311     QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
312     bool aFoundWidget = false;
313     bool aFoundObligatory = false;
314     for (; anIt != aLast && !aFoundObligatory; anIt++) {
315       if (!aFoundWidget)
316         aFoundWidget = *anIt == anActiveWidget;
317       else
318         aFoundObligatory = (*anIt)->isObligatory();
319     }
320     if (!aFoundObligatory)
321       myRestartingMode = RM_Forbided;
322   }
323 }
324
325 void PartSet_SketcherReetntrantMgr::onBeforeStopped()
326 {
327   if (!isActiveMgr() || !myIsInternalEditOperation)
328     return;
329
330   beforeStopInternalEdit();
331 }
332
333 bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
334 {
335   return !isActiveMgr() || myRestartingMode == RM_None;
336 }
337
338 bool PartSet_SketcherReetntrantMgr::isInternalEditStarted() const
339 {
340   return myIsInternalEditOperation;
341 }
342
343 bool PartSet_SketcherReetntrantMgr::isActiveMgr() const
344 {
345   ModuleBase_Operation* aCurrentOperation = myWorkshop->currentOperation();
346
347   bool anActive = PartSet_SketcherMgr::isSketchOperation(aCurrentOperation);
348   if (!anActive) {
349     anActive = PartSet_SketcherMgr::isNestedSketchOperation(aCurrentOperation,
350                                                     module()->sketchMgr()->activeSketch());
351     if (anActive) { // the manager is not active when the current operation is a usual Edit
352       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
353                                                        (myWorkshop->currentOperation());
354       if (aFOperation->isEditOperation())
355         anActive = myIsInternalEditOperation;
356     }
357   }
358   return anActive;
359 }
360
361 bool PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePreviousAttributeID)
362 {
363   bool isDone = false;
364   /// this is workaround for ModuleBase_WidgetEditor, used in SALOME mode. Sometimes key enter
365   /// event comes two times, so we should not start another internal edit operation
366   /// the Apply button becomes disabled becase the second additional internal feature is created
367   if (myIsInternalEditOperation)
368     return true;
369
370   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
371                                                      (myWorkshop->currentOperation());
372
373   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation,
374                                                 module()->sketchMgr()->activeSketch())) {
375     aFOperation->setEditOperation(true/*, false*/);
376     createInternalFeature();
377
378     myIsInternalEditOperation = true;
379     updateAcceptAllAction();
380
381     isDone = true;
382     connect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
383     connect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
384
385     // activate selection filters of the first widget in the viewer
386     onWidgetActivated();
387
388     // activate the last active widget in the Property Panel
389     if (!thePreviousAttributeID.empty()) {
390       ModuleBase_Operation* anEditOperation = module()->currentOperation();
391       if (anEditOperation) {
392         ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
393         ModuleBase_ModelWidget* aPreviousAttributeWidget = 0;
394         QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
395         for (int i = 0, aNb = aWidgets.size(); i < aNb && !aPreviousAttributeWidget; i++) {
396           if (aWidgets[i]->attributeID() == thePreviousAttributeID) {
397           /// workaround for the same attributes used in different stacked widgets(attribute types)
398           if (ModuleBase_ToolBox::isOffToolBoxParent(aWidgets[i]))
399             continue;
400             aPreviousAttributeWidget = aWidgets[i];
401           }
402         }
403         // If the current widget is a selector, do nothing, it processes the mouse press
404         if (aPreviousAttributeWidget) {
405           if (!aPreviousAttributeWidget->isViewerSelector()) {
406             aPreviousAttributeWidget->focusTo();
407             aPreviousAttributeWidget->selectContent();
408           }
409           else {
410             // in case of shape multi selector, the widget does not lose focus by filling
411             // like it is in shape selector. So, if enter is pressed, the multi shape selector
412             // control should be deactivated. The focus is moved to Apply button and there
413             // should not be active control visualized in property panel
414             if (aPreviousAttributeWidget == aPanel->activeWidget()) {
415               aPanel->activateWidget(NULL, false);
416             }
417             // if there is no the next widget to be automatically activated, the Ok button in property
418             // panel should accept the focus(example is parallel constraint on sketch lines)
419             QToolButton* anOkBtn = dynamic_cast<XGUI_PropertyPanel*>(aPanel)->findButton(PROP_PANEL_OK);
420             if (anOkBtn)
421               anOkBtn->setFocus(Qt::TabFocusReason);
422           }
423         }
424       }
425     }
426   }
427   if (isDone)
428     module()->sketchMgr()->clearClickedFlags();
429
430   return isDone;
431 }
432
433 void PartSet_SketcherReetntrantMgr::beforeStopInternalEdit()
434 {
435   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
436                                                       (myWorkshop->currentOperation());
437   if (aFOperation) {
438     disconnect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
439     disconnect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
440   }
441
442   deleteInternalFeature();
443 }
444
445 void PartSet_SketcherReetntrantMgr::restartOperation()
446 {
447   if (myIsInternalEditOperation) {
448     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(
449                                                                   myWorkshop->currentOperation());
450     if (aFOperation) {
451       myNoMoreWidgetsAttribute = "";
452       myIsFlagsBlocked = true;
453       FeaturePtr aPrevFeature = aFOperation->feature();
454       aFOperation->commit();
455       module()->launchOperation(aFOperation->id());
456       myIsFlagsBlocked = false;
457       resetFlags();
458       // we should avoid processing of the signal about no more widgets attributes and 
459       // do this after the restart operaion is finished if it was called
460       // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
461       // if it should be called after restart
462       if (!myNoMoreWidgetsAttribute.empty()) {
463         onNoMoreWidgets(myNoMoreWidgetsAttribute);
464         myNoMoreWidgetsAttribute = "";
465       }
466     }
467   }
468 }
469
470 void PartSet_SketcherReetntrantMgr::createInternalFeature()
471 {
472   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
473                                                      (myWorkshop->currentOperation());
474
475   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation,
476                                                           module()->sketchMgr()->activeSketch())) {
477     FeaturePtr anOperationFeature = aFOperation->feature();
478
479     CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
480     myInternalFeature = aSketch->addFeature(anOperationFeature->getKind());
481
482     bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature,
483                                                      aSketch, false);
484     XGUI_PropertyPanel* aPropertyPanel = dynamic_cast<XGUI_PropertyPanel*>
485                                                   (aFOperation->propertyPanel());
486
487     myInternalWidget = new QWidget(aPropertyPanel->contentWidget()->pageWidget());
488     myInternalWidget->setVisible(false);
489
490     ModuleBase_PageWidget* anInternalPage = new ModuleBase_PageWidget(myInternalWidget);
491
492     QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
493     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myWorkshop);
494
495     aFactory.createWidget(anInternalPage);
496     QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
497
498     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
499       bool isStoreValue = !aFOperation->isEditOperation() &&
500                           !aWidget->getDefaultValue().empty() &&
501                           !aWidget->isComputedDefault();
502       aWidget->setFeature(myInternalFeature, isStoreValue);
503       if (!isStoreValue && isFeatureChanged)
504         aWidget->restoreValue();
505     }
506
507     ModuleBase_ModelWidget* aFirstWidget = ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget
508                                                                                         (aWidgets);
509     if (aFirstWidget)
510       myInternalActiveWidget = aFirstWidget;
511   }
512 }
513
514 void PartSet_SketcherReetntrantMgr::deleteInternalFeature()
515 {
516   if (myInternalActiveWidget) {
517     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(myInternalActiveWidget);
518     if (aWSelector)
519       aWSelector->activateSelectionAndFilters(false);
520     myInternalActiveWidget = 0;
521   }
522   delete myInternalWidget;
523   myInternalWidget = 0;
524
525   QObjectPtrList anObjects;
526   anObjects.append(myInternalFeature);
527   workshop()->deleteFeatures(anObjects);
528   myInternalFeature = FeaturePtr();
529 }
530
531 void PartSet_SketcherReetntrantMgr::resetFlags()
532 {
533   if (!myIsFlagsBlocked) {
534     myIsInternalEditOperation = false;
535     updateAcceptAllAction();
536     myRestartingMode = RM_None;
537   }
538 }
539
540 bool PartSet_SketcherReetntrantMgr::copyReetntrantAttributes(const FeaturePtr& theSourceFeature,
541                                                              const FeaturePtr& theNewFeature,
542                                                              const CompositeFeaturePtr& theSketch,
543                                                              const bool isTemporary)
544 {
545   bool aChanged = false;
546   if (!theSourceFeature.get())
547     return aChanged;
548
549   std::string aFeatureKind = theSourceFeature->getKind();
550   if (aFeatureKind == SketchPlugin_Line::ID()) {
551     // Initialize new line with first point equal to end of previous
552     std::shared_ptr<ModelAPI_Data> aSFData = theSourceFeature->data();
553     std::shared_ptr<GeomDataAPI_Point2D> aSPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
554                                                  aSFData->attribute(SketchPlugin_Line::END_ID()));
555     std::shared_ptr<ModelAPI_Data> aNFData = theNewFeature->data();
556     std::shared_ptr<GeomDataAPI_Point2D> aNPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
557                                                  aNFData->attribute(SketchPlugin_Line::START_ID()));
558     aNPoint->setValue(aSPoint->x(), aSPoint->y());
559     PartSet_Tools::createConstraint(theSketch, aSPoint, aNPoint);
560
561     aNPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
562                                                  aSFData->attribute(SketchPlugin_Line::END_ID()));
563     aNPoint->setValue(aSPoint->x(), aSPoint->y());
564   }
565   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
566     // set circle type
567     std::string aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE();
568     AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
569     AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
570     aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
571     //ModuleBase_Tools::flushUpdated(theNewFeature);
572     aChanged = true;
573   }
574   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
575     // set arc type
576     std::string aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE();
577     AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
578     AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
579     aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
580
581     // if the arc is tangent, set coincidence to end point of the previous arc
582     std::string anArcType = aSourceFeatureTypeAttr->value();
583     if (anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT()) {
584       // get the last point of the previuos arc feature(geom point 2d)
585       std::shared_ptr<ModelAPI_Data> aSData = theSourceFeature->data();
586       std::shared_ptr<GeomDataAPI_Point2D> aSPointAttr = 
587                                       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
588                                       aSData->attribute(SketchPlugin_Arc::END_ID()));
589       // get point attribute on the current feature
590       AttributeRefAttrPtr aTangentPointAttr = theNewFeature->data()->refattr(
591                                                     SketchPlugin_Arc::TANGENT_POINT_ID());
592       aTangentPointAttr->setAttr(aSPointAttr);
593
594       std::shared_ptr<GeomDataAPI_Point2D> aNPointAttr = 
595                                     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
596                                     theNewFeature->data()->attribute(SketchPlugin_Arc::END_ID()));
597       aNPointAttr->setValue(aSPointAttr->x(), aSPointAttr->y());
598
599     }
600     //ModuleBase_Tools::flushUpdated(theNewFeature);
601     aChanged = true;
602   }
603   return aChanged;
604 }
605
606 bool PartSet_SketcherReetntrantMgr::isTangentArc(ModuleBase_Operation* theOperation,
607                                                  const CompositeFeaturePtr& theSketch)
608 {
609   bool aTangentArc = false;
610   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
611                                                                         (theOperation);
612   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation, theSketch)) {
613     FeaturePtr aFeature = aFOperation->feature();
614     if (aFeature.get() && aFeature->getKind() == SketchPlugin_Arc::ID()) {
615       AttributeStringPtr aTypeAttr = aFeature->data()->string(SketchPlugin_Arc::ARC_TYPE());
616       std::string anArcType = aTypeAttr.get() ? aTypeAttr->value() : "";
617       aTangentArc = anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT();
618     }
619   }
620   return aTangentArc;
621 }
622
623 void PartSet_SketcherReetntrantMgr::updateAcceptAllAction()
624 {
625   CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
626   if (aSketch.get())
627     workshop()->errorMgr()->updateAcceptAllAction(aSketch);
628 }
629
630 XGUI_Workshop* PartSet_SketcherReetntrantMgr::workshop() const
631 {
632   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
633   return aConnector->workshop();
634 }
635
636 PartSet_Module* PartSet_SketcherReetntrantMgr::module() const
637 {
638   return dynamic_cast<PartSet_Module*>(myWorkshop->module());
639 }
640