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