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