]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_OperationMgr.cpp
Salome HOME
361547bbfad2fbb9bb492dbd8c7c8903127729e2
[modules/shaper.git] / src / XGUI / XGUI_OperationMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        XGUI_OperationMgr.cpp
4 // Created:     20 Apr 2014
5 // Author:      Natalia ERMOLAEVA
6
7 #include "XGUI_OperationMgr.h"
8 #include "XGUI_ModuleConnector.h"
9 #include "XGUI_Workshop.h"
10 #include "XGUI_ErrorMgr.h"
11
12 #include "ModuleBase_Operation.h"
13 #include "ModuleBase_IWorkshop.h"
14 #include "ModuleBase_IModule.h"
15 #include <ModuleBase_IViewer.h>
16 #include "ModuleBase_OperationDescription.h"
17 #include "ModuleBase_OperationFeature.h"
18
19 #include "ModelAPI_CompositeFeature.h"
20 #include "ModelAPI_Session.h"
21
22 #include <QMessageBox>
23 #include <QApplication>
24 #include <QKeyEvent>
25
26 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
27                                      ModuleBase_IWorkshop* theWorkshop)
28 : QObject(theParent), myIsValidationLock(false), myIsApplyEnabled(false),
29   myWorkshop(theWorkshop)
30 {
31 }
32
33 XGUI_OperationMgr::~XGUI_OperationMgr()
34 {
35 }
36
37 ModuleBase_Operation* XGUI_OperationMgr::currentOperation() const
38 {
39   return myOperations.count() > 0 ? myOperations.last() : 0;
40 }
41
42 bool XGUI_OperationMgr::isCurrentOperation(ModuleBase_Operation* theOperation)
43 {
44   if(!hasOperation())
45     return false;
46   return currentOperation() == theOperation;
47 }
48
49 bool XGUI_OperationMgr::hasOperation() const
50 {
51   return !myOperations.isEmpty() && (myOperations.last() != NULL);
52 }
53
54 bool XGUI_OperationMgr::hasOperation(const QString& theId) const
55 {
56   foreach(ModuleBase_Operation* aOp, myOperations) {
57     if (aOp->id() == theId)
58       return true;
59   }
60   return false;
61 }
62
63 ModuleBase_Operation* XGUI_OperationMgr::findOperation(const QString& theId) const
64 {
65   foreach(ModuleBase_Operation* aOp, myOperations) {
66     if (aOp->id() == theId)
67       return aOp;
68   }
69   return 0;
70 }
71
72
73 int XGUI_OperationMgr::operationsCount() const
74 {
75   return myOperations.count();
76 }
77
78 QStringList XGUI_OperationMgr::operationList() const
79 {
80   QStringList result;
81   foreach(ModuleBase_Operation* eachOperation, myOperations) {
82     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(eachOperation);
83     if (aFOperation) {
84       FeaturePtr aFeature = aFOperation->feature();
85       if(aFeature) {
86         result << QString::fromStdString(aFeature->getKind());
87       }
88     }
89   }
90   return result;
91 }
92
93 ModuleBase_Operation* XGUI_OperationMgr::previousOperation(ModuleBase_Operation* theOperation) const
94 {
95   int idx = myOperations.lastIndexOf(theOperation);
96   if(idx == -1 || idx == 0) {
97     return NULL;
98   }
99   return myOperations.at(idx - 1);
100 }
101
102 bool XGUI_OperationMgr::eventFilter(QObject *theObject, QEvent *theEvent)
103 {
104   if (theEvent->type() == QEvent::KeyRelease) {
105     QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
106     if(aKeyEvent) {
107       return onKeyReleased(aKeyEvent);
108     }
109   }
110   return QObject::eventFilter(theObject, theEvent);
111 }
112
113 bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
114 {
115   if (hasOperation())
116     currentOperation()->postpone();
117   myOperations.append(theOperation);
118
119   connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
120   connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
121   connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
122   connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
123   connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
124   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
125                                                                         (theOperation);
126   if (aFOperation)
127     connect(aFOperation, SIGNAL(activatedByPreselection()),
128             SIGNAL(operationActivatedByPreselection()));
129
130   theOperation->start();
131   onValidateOperation();
132   return true;
133 }
134
135 bool XGUI_OperationMgr::abortAllOperations()
136 {
137   bool aResult = true;
138   if(!hasOperation())
139     return aResult;
140
141   if (operationsCount() == 1) {
142     ModuleBase_Operation* aCurrentOperation = currentOperation();
143     if (canStopOperation(aCurrentOperation)) {
144       abortOperation(aCurrentOperation);
145     }
146     else
147       aResult = false;
148   }
149   else {
150     aResult = QMessageBox::question(qApp->activeWindow(),
151                                     tr("Abort operation"),
152                                     tr("All active operations will be aborted."),
153                                     QMessageBox::Ok | QMessageBox::Cancel,
154                                     QMessageBox::Cancel) == QMessageBox::Ok;
155     while(aResult && hasOperation()) {
156       abortOperation(currentOperation());
157     }
158   }
159   return aResult;
160 }
161
162 bool XGUI_OperationMgr::commitAllOperations()
163 {
164   bool isCompositeCommitted = false;
165   while (hasOperation()) {
166     ModuleBase_Operation* anOperation = currentOperation();
167     if (isApplyEnabled()) {
168       onCommitOperation();
169     } else {
170       abortOperation(anOperation);
171     }
172     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
173                                                                             (anOperation);
174     if (aFOperation) {
175       FeaturePtr aFeature = aFOperation->feature();
176       CompositeFeaturePtr aComposite = 
177           std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
178       isCompositeCommitted = aComposite.get();
179       if (isCompositeCommitted)
180         break;
181     }
182   }
183   return true;
184 }
185
186 void XGUI_OperationMgr::onValidateOperation()
187 {
188   if (!hasOperation())
189     return;
190   //ModuleBase_Operation* anOperation = currentOperation();
191   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
192                                                                           (currentOperation());
193   if(aFOperation && aFOperation->feature().get()) {
194     //bool aCanCommit = myWorkshop->module()->canCommitOperation();
195     //setApplyEnabled(!myIsValidationLock && aCanCommit && anOperation->isValid());
196     setApplyEnabled(myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty());
197   }
198 }
199
200 void XGUI_OperationMgr::setLockValidating(bool toLock)
201 {
202   myIsValidationLock = toLock;
203   onValidateOperation();
204 }
205
206 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
207 {
208   myIsApplyEnabled = theEnabled;
209   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
210                                                                           (currentOperation());
211   if (aFOperation) {
212     workshop()->errorMgr()->updateActions(aFOperation->feature());
213   }
214   //emit validationStateChanged(theEnabled);
215 }
216
217 void XGUI_OperationMgr::updateApplyOfOperations(ModuleBase_Operation* theOperation)
218 {
219   XGUI_ErrorMgr* anErrorMgr = workshop()->errorMgr();
220   if (theOperation) {
221     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
222     if (aFOperation)
223       anErrorMgr->updateAcceptAllAction(aFOperation->feature());
224     //emit nestedStateChanged(theOperation->getDescription()->operationId().toStdString(),
225     //                        theOperation->isValid());
226   }
227   else {
228     foreach(ModuleBase_Operation* anOperation, myOperations) {
229       if (anOperation)
230         updateApplyOfOperations(anOperation);
231       //emit nestedStateChanged(anOperation->getDescription()->operationId().toStdString(),
232       //                        anOperation->isValid());
233     }
234   }
235 }
236
237 bool XGUI_OperationMgr::isApplyEnabled() const
238 {
239   return myIsApplyEnabled;
240 }
241
242 bool XGUI_OperationMgr::isParentOperationValid() const
243 {
244   bool isValid = false;
245   // the enable state of the parent operation of the nested one is defined by the rules that
246   // firstly there are nested operations and secondly the parent operation is valid
247   ModuleBase_Operation* aPrevOp = 0;
248   Operations::const_iterator anIt = myOperations.end();
249   if (anIt != myOperations.begin()) { // there are items in the operations list
250     --anIt;
251     aPrevOp = *anIt; // the last top operation, the operation which is started
252     if (anIt != myOperations.begin()) { // find the operation where the started operation is nested
253       --anIt;
254       aPrevOp = *anIt;
255     }
256   }
257   return aPrevOp && aPrevOp->isValid();
258 }
259
260 bool XGUI_OperationMgr::canStopOperation(ModuleBase_Operation* theOperation)
261 {
262   //in case of nested (sketch) operation no confirmation needed
263   if (isGrantedOperation(theOperation->id()))
264     return true;
265   if (theOperation && theOperation->isModified()) {
266     QString aMessage = tr("%1 operation will be aborted.").arg(theOperation->id());
267     int anAnswer = QMessageBox::question(qApp->activeWindow(),
268                                          tr("Abort operation"),
269                                          aMessage,
270                                          QMessageBox::Ok | QMessageBox::Cancel,
271                                          QMessageBox::Cancel);
272     return anAnswer == QMessageBox::Ok;
273   }
274   return true;
275 }
276
277 bool XGUI_OperationMgr::commitOperation()
278 {
279   if (hasOperation() && currentOperation()->isValid()) {
280     onCommitOperation();
281     return true;
282   }
283   return false;
284 }
285
286 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
287 {
288   theOperation->resume();
289 }
290
291 bool XGUI_OperationMgr::isGrantedOperation(const QString& theId)
292 {
293   bool isGranted = false;
294
295   QListIterator<ModuleBase_Operation*> anIt(myOperations);
296   anIt.toBack();
297   ModuleBase_Operation* aPreviousOperation = 0;
298   while (anIt.hasPrevious()) {
299     ModuleBase_Operation* anOp = anIt.previous();
300     if (anOp->id() == theId) {
301       if (anIt.hasPrevious())
302         aPreviousOperation = anIt.previous();
303       break;
304     }
305   }
306   if (aPreviousOperation)
307     isGranted = aPreviousOperation->isGranted(theId);
308
309   return isGranted;
310 }
311
312 bool XGUI_OperationMgr::canStartOperation(const QString& theId, const bool isAdditionallyGranted)
313 {
314   bool aCanStart = true;
315   ModuleBase_Operation* aCurrentOp = currentOperation();
316   if (aCurrentOp) {
317     bool aGranted = aCurrentOp->isGranted(theId) || isAdditionallyGranted;
318     // the started operation is granted for the current one,
319     // e.g. current - Sketch, started - Line
320     if (aGranted) {
321       aCanStart = true;
322     }
323     else {
324       if (!isGrantedOperation(theId)) {
325         // the operation is not granted in the current list of operations
326         // e.g. Edit Parameter when Sketch, Line in Sketch is active.
327         aCanStart = abortAllOperations();
328       }
329       else if (canStopOperation(aCurrentOp)) {
330         // the started operation is granted in the parrent operation,
331         // e.g. current - Line in Sketch, started Circle 
332         if (myIsApplyEnabled && aCurrentOp->isModified())
333           aCurrentOp->commit();
334         else
335           abortOperation(aCurrentOp);
336       } else {
337         aCanStart = false;
338       }
339     }
340   }
341   return aCanStart;
342 }
343
344 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
345 {
346   ModuleBase_Operation* aCurrentOperation = currentOperation();
347   if (theOperation == aCurrentOperation)
348     theOperation->abort();
349   else {
350     // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
351     // all operation from the current to triggered should also be aborted
352     // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
353     while(hasOperation()) {
354       ModuleBase_Operation* aCurrentOperation = currentOperation();
355       aCurrentOperation->abort();
356       if(theOperation == aCurrentOperation)
357         break;
358     }
359   }
360 }
361
362 void XGUI_OperationMgr::onCommitOperation()
363 {
364   ModuleBase_Operation* anOperation = currentOperation();
365   if (anOperation)
366     anOperation->commit();
367 }
368
369 void XGUI_OperationMgr::onAbortOperation()
370 {
371   ModuleBase_Operation* aCurrentOperation = currentOperation();
372   if (aCurrentOperation && canStopOperation(aCurrentOperation)) {
373     abortOperation(aCurrentOperation);
374   }
375 }
376
377 void XGUI_OperationMgr::onOperationStarted()
378 {
379   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
380   updateApplyOfOperations(aSenderOperation);
381   emit operationStarted(aSenderOperation);
382 }
383
384 void XGUI_OperationMgr::onOperationAborted()
385 {
386   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
387   emit operationAborted(aSenderOperation);
388 }
389
390 void XGUI_OperationMgr::onOperationCommitted()
391 {
392   // apply state for all features from the stack of operations should be updated
393   updateApplyOfOperations();
394
395   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
396   emit operationCommitted(aSenderOperation);
397 }
398
399 void XGUI_OperationMgr::onOperationResumed()
400 {
401   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
402   emit operationResumed(aSenderOperation);
403 }
404
405 void XGUI_OperationMgr::onOperationStopped()
406 {
407   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
408   ModuleBase_Operation* aCurrentOperation = currentOperation();
409   if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
410     return;
411
412   myOperations.removeAll(aCurrentOperation);
413   aCurrentOperation->deleteLater();
414
415   emit operationStopped(aCurrentOperation);
416
417   // get last operation which can be resumed
418   ModuleBase_Operation* aResultOp = 0;
419   QListIterator<ModuleBase_Operation*> anIt(myOperations);
420   anIt.toBack();
421   while (anIt.hasPrevious()) {
422     ModuleBase_Operation* anOp = anIt.previous();
423     if (anOp) {
424       aResultOp = anOp;
425       break;
426     }
427   }
428   if (aResultOp) {
429     bool isModified = aCurrentOperation->isModified();
430     aResultOp->setIsModified(aResultOp->isModified() || isModified);
431     resumeOperation(aResultOp);
432     onValidateOperation();
433   }
434 }
435
436 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
437 {
438   // Let the manager decide what to do with the given key combination.
439   ModuleBase_Operation* anOperation = currentOperation();
440   bool isAccepted = true;
441   switch (theEvent->key()) {
442     case Qt::Key_Return:
443     case Qt::Key_Enter: {
444       emit keyEnterReleased();
445       commitOperation();
446     }
447     case Qt::Key_N:
448     case Qt::Key_P: {
449       bool noModifiers = (theEvent->modifiers() == Qt::NoModifier);
450       if (noModifiers) {
451         ModuleBase_IViewer* aViewer = myWorkshop->viewer();
452         Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
453         if (!aContext.IsNull()) {
454           Handle(V3d_View) aView = aViewer->activeView();
455           if ((theEvent->key() == Qt::Key_N))
456             aContext->HilightNextDetected(aView);
457           else if ((theEvent->key() == Qt::Key_P))
458             aContext->HilightPreviousDetected(aView);
459         }
460       }
461     }
462
463     break;
464     default:
465       isAccepted = false;
466       break;
467   }
468   //if(anOperation) {
469   //  anOperation->keyReleased(theEvent->key());
470   //}
471   return isAccepted;
472 }
473
474 XGUI_Workshop* XGUI_OperationMgr::workshop() const
475 {
476   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
477   return aConnector->workshop();
478 }
479