Salome HOME
Hidden constraints should not be shown by Replication operation start. Because it...
[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_ViewerPrsPtr> aSelection;
156             aSelection.append(std::shared_ptr<ModuleBase_ViewerPrs>(
157                new ModuleBase_ViewerPrs(aLastFeature, GeomShapePtr(), NULL)));
158             aWidgetIsFilled = aPoint2DWdg->setSelection(aSelection, true);
159           }
160         }
161         else if (isArcFeature) { // arc, start point should be equal last point of the last feature arc
162           if (aCurrentFeature->getKind() == SketchPlugin_Arc::ID()) {
163             // get the last point of the previuos arc feature(geom point 2d)
164             std::shared_ptr<ModelAPI_Data> aData = aLastFeature->data();
165             std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = 
166                 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
167                                            aData->attribute(SketchPlugin_Arc::END_ID()));
168             // get point attribute on the current feature
169             AttributeRefAttrPtr aTangentPointAttr = aCurrentFeature->data()->refattr(
170                                                          SketchPlugin_Arc::TANGENT_POINT_ID());
171             aTangentPointAttr->setAttr(aPointAttr);
172             aWidgetIsFilled = true;
173           }
174         }
175       }
176       if (aWidgetIsFilled)
177         aPanel->activateNextWidget(anActiveWidget);
178     }
179   }
180   return aProcessed;
181 }
182
183 bool PartSet_SketcherReetntrantMgr::processMousePressed(ModuleBase_IViewWindow* /* theWnd*/,
184                                                         QMouseEvent* /* theEvent*/)
185 {
186   return isActiveMgr() && myIsInternalEditOperation;
187 }
188
189 bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* theWnd,
190                                                          QMouseEvent* theEvent)
191 {
192   bool aProcessed = false;
193   if (!isActiveMgr())
194     return aProcessed;
195
196   if (myIsInternalEditOperation) {
197     ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
198     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
199
200     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
201     if (!anActiveWidget || !anActiveWidget->isViewerSelector()) {
202
203       // block of viewer update
204       // we need to block update content of the viewer because of Sketch Point feature
205       // in activate() the value of the point is initialized and it can be displayed
206       // but the default value is [0, 0]. So, we block update viewer contentent until
207       // onMouseRelease happens, which correct the point position
208       ModuleBase_Tools::blockUpdateViewer(true);
209
210       restartOperation();
211       aProcessed = true;
212
213       // fill the first widget by the mouse event point
214       // if the active widget is not the first, it means that the restarted operation is filled by
215       // the current preselection.
216       PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
217       ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget();
218       if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) {
219         aPoint2DWdg->onMouseRelease(theWnd, theEvent);
220       }
221       // unblock viewer update
222       ModuleBase_Tools::blockUpdateViewer(false);
223     }
224   }
225
226   return aProcessed;
227 }
228
229 void PartSet_SketcherReetntrantMgr::onWidgetActivated()
230 {
231   if (!isActiveMgr())
232     return;
233   if (!myIsInternalEditOperation)
234     return;
235
236   PartSet_Module* aModule = module();
237   ModuleBase_ModelWidget* aFirstWidget = aModule->activeWidget();
238   ModuleBase_IPropertyPanel* aPanel = aModule->currentOperation()->propertyPanel();
239   if (aFirstWidget != aPanel->activeWidget()) {
240     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(aFirstWidget);
241     if (aWSelector)
242       aWSelector->activateSelectionAndFilters(true);
243   }
244 }
245
246 void PartSet_SketcherReetntrantMgr::onNoMoreWidgets(const std::string& thePreviousAttributeID)
247 {
248   if (!isActiveMgr())
249     return;
250
251   // we should avoid processing of the signal about no more widgets attributes and 
252   // do this after the restart operaion is finished if it was called
253   // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
254   // if it should be called after restart
255   if (myIsFlagsBlocked) {
256     myNoMoreWidgetsAttribute = thePreviousAttributeID;
257     return;
258   }
259
260   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
261                                                        (myWorkshop->currentOperation());
262   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
263     return;
264
265   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
266     bool isStarted = false;
267     if (!module()->sketchMgr()->sketchSolverError()) {
268       if (myRestartingMode != RM_Forbided) {
269         myRestartingMode = RM_LastFeatureUsed;
270         isStarted = startInternalEdit(thePreviousAttributeID);
271       }
272     }
273     if (!isStarted)
274       aFOperation->commit();
275   }
276 }
277
278 bool PartSet_SketcherReetntrantMgr::processEnter(const std::string& thePreviousAttributeID)
279 {
280   bool isDone = false;
281
282   if (!isActiveMgr())
283     return isDone;
284
285   // empty previous attribute means that the Apply/Ok button has focus and the enter
286   // should not lead to start edition mode of the previous operation
287   if (thePreviousAttributeID.empty())
288     return isDone;
289
290   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
291                                                        (myWorkshop->currentOperation());
292   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
293     return isDone;
294
295   bool isSketchSolverError = module()->sketchMgr()->sketchSolverError();
296
297   if (!isSketchSolverError) {
298     myRestartingMode = RM_EmptyFeatureUsed;
299     isDone = startInternalEdit(thePreviousAttributeID);
300   }
301
302   return isDone;
303 }
304
305 void PartSet_SketcherReetntrantMgr::onVertexSelected()
306 {
307   if (!isActiveMgr())
308     return;
309
310   ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
311   std::string anOperationId = anOperation->id().toStdString();
312   if (anOperationId == SketchPlugin_Line::ID() || isTangentArc(anOperation)) {
313     /// If last line finished on vertex the lines creation sequence has to be break
314     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
315     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
316     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
317     QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
318     bool aFoundWidget = false;
319     bool aFoundObligatory = false;
320     for (; anIt != aLast && !aFoundObligatory; anIt++) {
321       if (!aFoundWidget)
322         aFoundWidget = *anIt == anActiveWidget;
323       else
324         aFoundObligatory = (*anIt)->isObligatory();
325     }
326     if (!aFoundObligatory)
327       myRestartingMode = RM_Forbided;
328   }
329 }
330
331 void PartSet_SketcherReetntrantMgr::onBeforeStopped()
332 {
333   if (!isActiveMgr() || !myIsInternalEditOperation)
334     return;
335
336   beforeStopInternalEdit();
337 }
338
339 bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
340 {
341   return !isActiveMgr() || myRestartingMode == RM_None;
342 }
343
344 bool PartSet_SketcherReetntrantMgr::isActiveMgr() const
345 {
346   ModuleBase_Operation* aCurrentOperation = myWorkshop->currentOperation();
347
348   bool anActive = PartSet_SketcherMgr::isSketchOperation(aCurrentOperation);
349   if (!anActive) {
350     anActive = PartSet_SketcherMgr::isNestedSketchOperation(aCurrentOperation);
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     aFOperation->setEditOperation(true/*, false*/);
375     workshop()->operationMgr()->updateApplyOfOperations();
376
377     createInternalFeature();
378
379     myIsInternalEditOperation = true;
380     isDone = true;
381     connect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
382     connect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
383
384     // activate selection filters of the first widget in the viewer
385     onWidgetActivated();
386
387     // activate the last active widget in the Property Panel
388     if (!thePreviousAttributeID.empty()) {
389       ModuleBase_Operation* anEditOperation = module()->currentOperation();
390       if (anEditOperation) {
391         ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
392         ModuleBase_ModelWidget* aPreviousAttributeWidget = 0;
393         QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
394         for (int i = 0, aNb = aWidgets.size(); i < aNb && !aPreviousAttributeWidget; i++) {
395           if (aWidgets[i]->attributeID() == thePreviousAttributeID) {
396           /// workaround for the same attributes used in different stacked widgets(attribute types)
397           if (ModuleBase_ToolBox::isOffToolBoxParent(aWidgets[i]))
398             continue;
399             aPreviousAttributeWidget = aWidgets[i];
400           }
401         }
402         // If the current widget is a selector, do nothing, it processes the mouse press
403         if (aPreviousAttributeWidget) {
404           if (!aPreviousAttributeWidget->isViewerSelector()) {
405             aPreviousAttributeWidget->focusTo();
406             aPreviousAttributeWidget->selectContent();
407           }
408           else {
409             // in case of shape multi selector, the widget does not lose focus by filling
410             // like it is in shape selector. So, if enter is pressed, the multi shape selector
411             // control should be deactivated. The focus is moved to Apply button and there
412             // should not be active control visualized in property panel
413             if (aPreviousAttributeWidget == aPanel->activeWidget()) {
414               aPanel->activateWidget(NULL, false);
415             }
416             // if there is no the next widget to be automatically activated, the Ok button in property
417             // panel should accept the focus(example is parallel constraint on sketch lines)
418             QToolButton* anOkBtn = dynamic_cast<XGUI_PropertyPanel*>(aPanel)->findButton(PROP_PANEL_OK);
419             if (anOkBtn)
420               anOkBtn->setFocus(Qt::TabFocusReason);
421           }
422         }
423       }
424     }
425   }
426   if (isDone)
427     module()->sketchMgr()->clearClickedFlags();
428
429   return isDone;
430 }
431
432 void PartSet_SketcherReetntrantMgr::beforeStopInternalEdit()
433 {
434   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
435                                                       (myWorkshop->currentOperation());
436   if (aFOperation) {
437     disconnect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
438     disconnect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
439   }
440
441   deleteInternalFeature();
442 }
443
444 void PartSet_SketcherReetntrantMgr::restartOperation()
445 {
446   if (myIsInternalEditOperation) {
447     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(
448                                                                   myWorkshop->currentOperation());
449     if (aFOperation) {
450       myNoMoreWidgetsAttribute = "";
451       myIsFlagsBlocked = true;
452       FeaturePtr aPrevFeature = aFOperation->feature();
453       aFOperation->commit();
454       module()->launchOperation(aFOperation->id());
455       // allow the same attribute values in restarted operation
456       ModuleBase_OperationFeature* aCurrentOperation = dynamic_cast<ModuleBase_OperationFeature*>(
457                                                                   myWorkshop->currentOperation());
458       copyReetntrantAttributes(aPrevFeature, aCurrentOperation->feature());
459
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     FeaturePtr anOperationFeature = aFOperation->feature();
481
482     CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
483     myInternalFeature = aSketch->addFeature(anOperationFeature->getKind());
484
485     bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature);
486     XGUI_PropertyPanel* aPropertyPanel = dynamic_cast<XGUI_PropertyPanel*>
487                                                   (aFOperation->propertyPanel());
488
489     myInternalWidget = new QWidget(aPropertyPanel->contentWidget()->pageWidget());
490     myInternalWidget->setVisible(false);
491
492     ModuleBase_PageWidget* anInternalPage = new ModuleBase_PageWidget(myInternalWidget);
493
494     QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
495     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myWorkshop);
496
497     aFactory.createWidget(anInternalPage);
498     QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
499
500     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
501       bool isStoreValue = !aFOperation->isEditOperation() &&
502                           !aWidget->getDefaultValue().empty() &&
503                           !aWidget->isComputedDefault();
504       aWidget->setFeature(myInternalFeature, isStoreValue);
505       if (!isStoreValue && isFeatureChanged)
506         aWidget->restoreValue();
507     }
508
509     ModuleBase_ModelWidget* aFirstWidget = ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget
510                                                                                         (aWidgets);
511     if (aFirstWidget)
512       myInternalActiveWidget = aFirstWidget;
513   }
514 }
515
516 void PartSet_SketcherReetntrantMgr::deleteInternalFeature()
517 {
518   if (myInternalActiveWidget) {
519     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(myInternalActiveWidget);
520     if (aWSelector)
521       aWSelector->activateSelectionAndFilters(false);
522     myInternalActiveWidget = 0;
523   }
524   delete myInternalWidget;
525   myInternalWidget = 0;
526
527   QObjectPtrList anObjects;
528   anObjects.append(myInternalFeature);
529   workshop()->deleteFeatures(anObjects);
530 }
531
532 void PartSet_SketcherReetntrantMgr::resetFlags()
533 {
534   if (!myIsFlagsBlocked) {
535     myIsInternalEditOperation = false;
536     myRestartingMode = RM_None;
537   }
538 }
539
540 bool PartSet_SketcherReetntrantMgr::copyReetntrantAttributes(const FeaturePtr& theSourceFeature,
541                                                              const FeaturePtr& theNewFeature)
542 {
543   bool aChanged = false;
544   std::string aTypeAttributeId;
545   if (theSourceFeature->getKind() == SketchPlugin_Circle::ID()) {
546     aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE();
547   }
548   if (theSourceFeature->getKind() == SketchPlugin_Arc::ID()) {
549     aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE();
550   }
551   if (!aTypeAttributeId.empty()) {
552     AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId);
553     AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId);
554     aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value());
555     ModuleBase_Tools::flushUpdated(theNewFeature);
556     aChanged = true;
557   }
558   return aChanged;
559 }
560
561 bool PartSet_SketcherReetntrantMgr::isTangentArc(ModuleBase_Operation* theOperation)
562 {
563   bool aTangentArc = false;
564   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
565                                                                         (theOperation);
566   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
567     FeaturePtr aFeature = aFOperation->feature();
568     if (aFeature.get() && aFeature->getKind() == SketchPlugin_Arc::ID()) {
569       AttributeStringPtr aTypeAttr = aFeature->data()->string(SketchPlugin_Arc::ARC_TYPE());
570       std::string anArcType = aTypeAttr.get() ? aTypeAttr->value() : "";
571       aTangentArc = anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT();
572     }
573   }
574   return aTangentArc;
575 }
576
577 XGUI_Workshop* PartSet_SketcherReetntrantMgr::workshop() const
578 {
579   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
580   return aConnector->workshop();
581 }
582
583 PartSet_Module* PartSet_SketcherReetntrantMgr::module() const
584 {
585   return dynamic_cast<PartSet_Module*>(myWorkshop->module());
586 }
587