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