]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_SketcherReetntrantMgr.cpp
Salome HOME
Correction for: 1. crash by popup menu call on origin, 2. reentered presentation...
[modules/shaper.git] / src / PartSet / PartSet_SketcherReetntrantMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include "PartSet_SketcherReetntrantMgr.h"
4 #include "PartSet_Module.h"
5 #include "PartSet_SketcherMgr.h"
6 #include "PartSet_WidgetPoint2d.h"
7
8 #include "ModelAPI_Session.h"
9
10 #include <ModuleBase_IPropertyPanel.h>
11 #include <ModuleBase_OperationFeature.h>
12 #include <ModuleBase_ModelWidget.h>
13 #include <ModuleBase_ViewerPrs.h>
14 #include <ModuleBase_WidgetSelector.h>
15 #include <ModuleBase_PageWidget.h>
16 #include <ModuleBase_PageBase.h>
17 #include <ModuleBase_WidgetFactory.h>
18 #include <ModuleBase_OperationDescription.h>
19
20 #include <SketchPlugin_Feature.h>
21 #include <SketchPlugin_Line.h>
22
23 #include <XGUI_Workshop.h>
24 #include <XGUI_ModuleConnector.h>
25 #include <XGUI_OperationMgr.h>
26 #include <XGUI_PropertyPanel.h>
27
28 PartSet_SketcherReetntrantMgr::PartSet_SketcherReetntrantMgr(ModuleBase_IWorkshop* theWorkshop)
29 : QObject(theWorkshop),
30   myWorkshop(theWorkshop),
31   myRestartingMode(RM_None),
32   myIsFlagsBlocked(false),
33   myIsInternalEditOperation(false),
34   myNoMoreWidgetsAttribute("")
35 {
36 }
37
38 PartSet_SketcherReetntrantMgr::~PartSet_SketcherReetntrantMgr()
39 {
40 }
41
42 ModuleBase_ModelWidget* PartSet_SketcherReetntrantMgr::internalActiveWidget() const
43 {
44   ModuleBase_ModelWidget* aWidget = 0;
45   if (!isActiveMgr())
46     return aWidget;
47
48   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
49   if (aOperation) {
50     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
51     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
52     if (myIsInternalEditOperation && (!anActiveWidget || !anActiveWidget->isViewerSelector()))
53       aWidget = myInternalActiveWidget;
54   }
55   return aWidget;
56 }
57
58 bool PartSet_SketcherReetntrantMgr::isInternalEditActive() const
59 {
60   return myIsInternalEditOperation;
61 }
62
63 bool PartSet_SketcherReetntrantMgr::operationCommitted(ModuleBase_Operation* theOperation)
64 {
65   bool aProcessed = false;
66   if (!isActiveMgr())
67     return aProcessed;
68
69   aProcessed = myIsInternalEditOperation;
70   resetFlags();
71
72   return aProcessed;
73 }
74
75 void PartSet_SketcherReetntrantMgr::operationStarted(ModuleBase_Operation* theOperation)
76 {
77   if (!isActiveMgr())
78     return;
79
80   resetFlags();
81 }
82
83 void PartSet_SketcherReetntrantMgr::operationAborted(ModuleBase_Operation* theOperation)
84 {
85   if (!isActiveMgr())
86     return;
87
88   resetFlags();
89 }
90
91 bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* /* theWnd*/,
92                                                       QMouseEvent* /* theEvent*/)
93 {
94   bool aProcessed = false;
95   if (!isActiveMgr())
96     return aProcessed;
97
98   if  (myIsInternalEditOperation) {
99     PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
100     if (aPoint2DWdg && aPoint2DWdg->canBeActivatedByMove()) {
101       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
102                                                          (myWorkshop->currentOperation());
103       FeaturePtr aLastFeature = myRestartingMode == RM_LastFeatureUsed ? aFOperation->feature() : FeaturePtr();
104       restartOperation();
105       aProcessed = true;
106
107       if (aLastFeature) {
108         ModuleBase_IPropertyPanel* aPanel = myWorkshop->currentOperation()->propertyPanel();
109         PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(aPanel->activeWidget());
110         if (aPoint2DWdg && aPoint2DWdg->canBeActivatedByMove()) {
111           QList<ModuleBase_ViewerPrs> aSelection;
112           aSelection.append(ModuleBase_ViewerPrs(aLastFeature, TopoDS_Shape(), NULL));
113           if (aPoint2DWdg->setSelection(aSelection, true))
114             aPanel->activateNextWidget(aPoint2DWdg);
115         }
116       }
117     }
118   }
119   return aProcessed;
120 }
121
122 bool PartSet_SketcherReetntrantMgr::processMousePressed(ModuleBase_IViewWindow* /* theWnd*/,
123                                                         QMouseEvent* /* theEvent*/)
124 {
125   return isActiveMgr() && myIsInternalEditOperation;
126 }
127
128 bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* theWnd,
129                                                          QMouseEvent* theEvent)
130 {
131   bool aProcessed = false;
132   if (!isActiveMgr())
133     return aProcessed;
134
135   if (myIsInternalEditOperation) {
136     ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
137     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
138
139     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
140     if (!anActiveWidget || !anActiveWidget->isViewerSelector()) {
141       restartOperation();
142       aProcessed = true;
143
144       // fill the first widget by the mouse event point
145       // if the active widget is not the first, it means that the restarted operation is filled by
146       // the current preselection.
147       PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
148       ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget();
149       if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) {
150         aPoint2DWdg->onMouseRelease(theWnd, theEvent);
151       }
152     }
153   }
154
155   return aProcessed;
156 }
157
158 void PartSet_SketcherReetntrantMgr::onWidgetActivated()
159 {
160   if (!isActiveMgr())
161     return;
162   if (!myIsInternalEditOperation)
163     return;
164
165   PartSet_Module* aModule = module();
166   ModuleBase_ModelWidget* aFirstWidget = aModule->activeWidget();
167   ModuleBase_IPropertyPanel* aPanel = aModule->currentOperation()->propertyPanel();
168   if (aFirstWidget != aPanel->activeWidget()) {
169     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(aFirstWidget);
170     if (aWSelector)
171       aWSelector->activateSelectionAndFilters(true);
172   }
173 }
174
175 void PartSet_SketcherReetntrantMgr::onNoMoreWidgets(const std::string& thePreviousAttributeID)
176 {
177   if (!isActiveMgr())
178     return;
179
180   // we should avoid processing of the signal about no more widgets attributes and 
181   // do this after the restart operaion is finished if it was called
182   // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
183   // if it should be called after restart
184   if (myIsFlagsBlocked) {
185     myNoMoreWidgetsAttribute = thePreviousAttributeID;
186     return;
187   }
188
189   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
190                                                        (myWorkshop->currentOperation());
191   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
192     return;
193
194   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
195     bool isStarted = false;
196     if (!module()->sketchMgr()->sketchSolverError()) {
197       if (myRestartingMode != RM_Forbided) {
198         myRestartingMode = RM_LastFeatureUsed;
199         isStarted = startInternalEdit(thePreviousAttributeID);
200       }
201     }
202     if (!isStarted)
203       aFOperation->commit();
204   }
205 }
206
207 bool PartSet_SketcherReetntrantMgr::processEnter(const std::string& thePreviousAttributeID)
208 {
209   bool isDone = false;
210
211   if (!isActiveMgr())
212     return isDone;
213
214   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
215                                                        (myWorkshop->currentOperation());
216   if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
217     return isDone;
218
219   bool isSketchSolverError = module()->sketchMgr()->sketchSolverError();
220   if (!isSketchSolverError) {
221     myRestartingMode = RM_EmptyFeatureUsed;
222     isDone = startInternalEdit(thePreviousAttributeID);
223   }
224
225   return isDone;
226 }
227
228 void PartSet_SketcherReetntrantMgr::onVertexSelected()
229 {
230   if (!isActiveMgr())
231     return;
232
233   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
234   if (aOperation->id().toStdString() == SketchPlugin_Line::ID()) {
235     /// If last line finished on vertex the lines creation sequence has to be break
236     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
237     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
238     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
239     QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
240     bool aFoundWidget = false;
241     bool aFoundObligatory = false;
242     for (; anIt != aLast && !aFoundObligatory; anIt++) {
243       if (!aFoundWidget)
244         aFoundWidget = *anIt == anActiveWidget;
245       else
246         aFoundObligatory = (*anIt)->isObligatory();
247     }
248     if (!aFoundObligatory)
249       myRestartingMode = RM_Forbided;
250   }
251 }
252
253 void PartSet_SketcherReetntrantMgr::onBeforeStopped()
254 {
255   if (!isActiveMgr() || !myIsInternalEditOperation)
256     return;
257
258   beforeStopInternalEdit();
259 }
260
261 bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
262 {
263   return !isActiveMgr() || myRestartingMode == RM_None;
264 }
265
266 bool PartSet_SketcherReetntrantMgr::isActiveMgr() const
267 {
268   ModuleBase_Operation* aCurrentOperation = myWorkshop->currentOperation();
269
270   bool anActive = PartSet_SketcherMgr::isSketchOperation(aCurrentOperation);
271   if (!anActive) {
272     anActive = PartSet_SketcherMgr::isNestedSketchOperation(aCurrentOperation);
273     if (anActive) { // the manager is not active when the current operation is a usual Edit
274       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
275                                                        (myWorkshop->currentOperation());
276       if (aFOperation->isEditOperation())
277         anActive = myIsInternalEditOperation;
278     }
279   }
280   return anActive;
281 }
282
283 bool PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePreviousAttributeID)
284 {
285   bool isDone = false;
286   /// this is workaround for ModuleBase_WidgetEditor, used in SALOME mode. Sometimes key enter
287   /// event comes two times, so we should not start another internal edit operation
288   /// the Apply button becomes disabled becase the second additional internal feature is created
289   if (myIsInternalEditOperation)
290     return true;
291
292   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
293                                                      (myWorkshop->currentOperation());
294
295   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
296     aFOperation->setEditOperation(false);
297     workshop()->operationMgr()->updateApplyOfOperations();
298
299     createInternalFeature();
300
301     myIsInternalEditOperation = true;
302     isDone = true;
303     connect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
304     connect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
305
306     // activate selection filters of the first widget in the viewer
307     onWidgetActivated();
308
309     // activate the last active widget in the Property Panel
310     if (!thePreviousAttributeID.empty()) {
311       ModuleBase_Operation* anEditOperation = module()->currentOperation();
312       if (anEditOperation) {
313         ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
314         ModuleBase_ModelWidget* aPreviousAttributeWidget = 0;
315         QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
316         for (int i = 0, aNb = aWidgets.size(); i < aNb && !aPreviousAttributeWidget; i++) {
317           if (aWidgets[i]->attributeID() == thePreviousAttributeID)
318             aPreviousAttributeWidget = aWidgets[i];
319         }
320         // If the current widget is a selector, do nothing, it processes the mouse press
321         if (aPreviousAttributeWidget && !aPreviousAttributeWidget->isViewerSelector()) {
322           aPreviousAttributeWidget->focusTo();
323           aPreviousAttributeWidget->selectContent();
324         }
325       }
326     }
327   }
328   if (isDone)
329     module()->sketchMgr()->clearClickedFlags();
330
331   return isDone;
332 }
333
334 void PartSet_SketcherReetntrantMgr::beforeStopInternalEdit()
335 {
336   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
337                                                       (myWorkshop->currentOperation());
338   if (aFOperation) {
339     disconnect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
340     disconnect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
341   }
342
343   deleteInternalFeature();
344 }
345
346 void PartSet_SketcherReetntrantMgr::restartOperation()
347 {
348   if (myIsInternalEditOperation) {
349     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(
350                                                                   myWorkshop->currentOperation());
351     if (aFOperation) {
352       myNoMoreWidgetsAttribute = "";
353       myIsFlagsBlocked = true;
354       aFOperation->commit();
355       module()->launchOperation(aFOperation->id());
356       myIsFlagsBlocked = false;
357       resetFlags();
358       // we should avoid processing of the signal about no more widgets attributes and 
359       // do this after the restart operaion is finished if it was called
360       // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
361       // if it should be called after restart
362       if (!myNoMoreWidgetsAttribute.empty()) {
363         onNoMoreWidgets(myNoMoreWidgetsAttribute);
364         myNoMoreWidgetsAttribute = "";
365       }
366     }
367   }
368 }
369
370 void PartSet_SketcherReetntrantMgr::createInternalFeature()
371 {
372   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
373                                                      (myWorkshop->currentOperation());
374
375   if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
376     FeaturePtr anOperationFeature = aFOperation->feature();
377
378     CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
379     myInternalFeature = aSketch->addFeature(anOperationFeature->getKind());
380     XGUI_PropertyPanel* aPropertyPanel = dynamic_cast<XGUI_PropertyPanel*>
381                                                   (aFOperation->propertyPanel());
382
383     myInternalWidget = new QWidget(aPropertyPanel->contentWidget()->pageWidget());
384     myInternalWidget->setVisible(false);
385
386     ModuleBase_PageWidget* anInternalPage = new ModuleBase_PageWidget(myInternalWidget);
387
388     QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
389     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myWorkshop);
390
391     aFactory.createWidget(anInternalPage);
392     QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
393
394     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
395       bool isStoreValue = !aFOperation->isEditOperation() &&
396                           !aWidget->getDefaultValue().empty() &&
397                           !aWidget->isComputedDefault();
398       aWidget->setFeature(myInternalFeature, isStoreValue);
399     }
400     ModuleBase_ModelWidget* aFirstWidget = ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget
401                                                                                         (aWidgets);
402     if (aFirstWidget)
403       myInternalActiveWidget = aFirstWidget;
404   }
405 }
406
407 void PartSet_SketcherReetntrantMgr::deleteInternalFeature()
408 {
409   if (myInternalActiveWidget) {
410     ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(myInternalActiveWidget);
411     if (aWSelector)
412       aWSelector->activateSelectionAndFilters(false);
413     myInternalActiveWidget = 0;
414   }
415   delete myInternalWidget;
416   myInternalWidget = 0;
417
418   QObjectPtrList anObjects;
419   anObjects.append(myInternalFeature);
420   workshop()->deleteFeatures(anObjects);
421 }
422
423 void PartSet_SketcherReetntrantMgr::resetFlags()
424 {
425   if (!myIsFlagsBlocked) {
426     myIsInternalEditOperation = false;
427     myRestartingMode = RM_None;
428   }
429 }
430
431 XGUI_Workshop* PartSet_SketcherReetntrantMgr::workshop() const
432 {
433   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
434   return aConnector->workshop();
435 }
436
437 PartSet_Module* PartSet_SketcherReetntrantMgr::module() const
438 {
439   return dynamic_cast<PartSet_Module*>(myWorkshop->module());
440 }
441