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