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