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