Salome HOME
52826dc65b0f20801353c2328c4055d229bb05bd
[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   connect(theOperation, SIGNAL(triggered(bool)), SLOT(onOperationTriggered(bool)));
121   connect(theOperation, SIGNAL(activatedByPreselection()),
122           SIGNAL(operationActivatedByPreselection()));
123
124   theOperation->start();
125   onValidateOperation();
126   return true;
127 }
128
129 bool XGUI_OperationMgr::abortAllOperations()
130 {
131   bool aResult = true;
132   if(!hasOperation())
133     return aResult;
134
135   if (operationsCount() == 1) {
136     if (canStopOperation()) {
137       abortOperation(currentOperation());
138     }
139     else
140       aResult = false;
141   }
142   else {
143     aResult = QMessageBox::question(qApp->activeWindow(),
144                                     tr("Abort operation"),
145                                     tr("All active operations will be aborted."),
146                                     QMessageBox::Ok | QMessageBox::Cancel,
147                                     QMessageBox::Cancel) == QMessageBox::Ok;
148     while(aResult && hasOperation()) {
149       abortOperation(currentOperation());
150     }
151   }
152   return aResult;
153 }
154
155 bool XGUI_OperationMgr::commitAllOperations()
156 {
157   bool isCompositeCommitted = false;
158   while (hasOperation()) {
159     ModuleBase_Operation* anOperation = currentOperation();
160     if (isApplyEnabled()) {
161       onCommitOperation();
162     } else {
163       abortOperation(anOperation);
164     }
165     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
166                                                                             (anOperation);
167     if (aFOperation) {
168       FeaturePtr aFeature = aFOperation->feature();
169       CompositeFeaturePtr aComposite = 
170           std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
171       isCompositeCommitted = aComposite.get();
172       if (isCompositeCommitted)
173         break;
174     }
175   }
176   return true;
177 }
178
179 void XGUI_OperationMgr::onValidateOperation()
180 {
181   if (!hasOperation())
182     return;
183   ModuleBase_Operation* anOperation = currentOperation();
184   if(anOperation) {
185     bool aCanCommit = myWorkshop->module()->canCommitOperation();
186     setApplyEnabled(!myIsValidationLock && aCanCommit && anOperation->isValid());
187   }
188 }
189
190 void XGUI_OperationMgr::setLockValidating(bool toLock)
191 {
192   myIsValidationLock = toLock;
193   onValidateOperation();
194 }
195
196 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
197 {
198   myIsApplyEnabled = theEnabled;
199   emit validationStateChanged(theEnabled);
200 }
201
202 void XGUI_OperationMgr::updateApplyOfOperations(ModuleBase_Operation* theOperation)
203 {
204   if (theOperation)
205     emit nestedStateChanged(theOperation->getDescription()->operationId().toStdString(),
206                             theOperation->isValid());
207   else {
208     foreach(ModuleBase_Operation* anOperation, myOperations) {
209       emit nestedStateChanged(anOperation->getDescription()->operationId().toStdString(),
210                               anOperation->isValid());
211     }
212   }
213 }
214
215 bool XGUI_OperationMgr::isApplyEnabled() const
216 {
217   return myIsApplyEnabled;
218 }
219
220 bool XGUI_OperationMgr::isParentOperationValid() const
221 {
222   bool isValid = false;
223   // the enable state of the parent operation of the nested one is defined by the rules that
224   // firstly there are nested operations and secondly the parent operation is valid
225   ModuleBase_Operation* aPrevOp = 0;
226   Operations::const_iterator anIt = myOperations.end();
227   if (anIt != myOperations.begin()) { // there are items in the operations list
228     --anIt;
229     aPrevOp = *anIt; // the last top operation, the operation which is started
230     if (anIt != myOperations.begin()) { // find the operation where the started operation is nested
231       --anIt;
232       aPrevOp = *anIt;
233     }
234   }
235   return aPrevOp && aPrevOp->isValid();
236 }
237
238 bool XGUI_OperationMgr::canStopOperation()
239 {
240   ModuleBase_Operation* anOperation = currentOperation();
241   if(operationsCount() > 1) //in case of nested (sketch) operation no confirmation needed
242     return true;
243   if (anOperation && anOperation->isModified()) {
244     QString aMessage = tr("%1 operation will be aborted.").arg(anOperation->id());
245     int anAnswer = QMessageBox::question(qApp->activeWindow(),
246                                          tr("Abort operation"),
247                                          aMessage,
248                                          QMessageBox::Ok | QMessageBox::Cancel,
249                                          QMessageBox::Cancel);
250     return anAnswer == QMessageBox::Ok;
251   }
252   return true;
253 }
254
255 bool XGUI_OperationMgr::commitOperation()
256 {
257   if (hasOperation() && currentOperation()->isValid()) {
258     onCommitOperation();
259     return true;
260   }
261   return false;
262 }
263
264 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
265 {
266   theOperation->resume();
267 }
268
269 bool XGUI_OperationMgr::canStartOperation(QString theId)
270 {
271   bool aCanStart = true;
272   ModuleBase_Operation* aCurrentOp = currentOperation();
273   if (aCurrentOp) {
274     if (!aCurrentOp->isGranted(theId)) {
275       if (canStopOperation()) {
276         if (myIsApplyEnabled)
277           aCurrentOp->commit();
278         else
279           abortOperation(aCurrentOp);
280       } else {
281         aCanStart = false;
282       }
283     }
284   }
285   return aCanStart;
286 }
287
288 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
289 {
290   ModuleBase_Operation* aCurrentOperation = currentOperation();
291   if (theOperation == aCurrentOperation)
292     theOperation->abort();
293   else {
294     // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
295     // all operation from the current to triggered should also be aborted
296     // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
297     while(hasOperation()) {
298       ModuleBase_Operation* aCurrentOperation = currentOperation();
299       aCurrentOperation->abort();
300       if(theOperation == aCurrentOperation)
301         break;
302     }
303   }
304 }
305
306 void XGUI_OperationMgr::onCommitOperation()
307 {
308   ModuleBase_Operation* anOperation = currentOperation();
309   if (anOperation)
310     anOperation->commit();
311 }
312
313 void XGUI_OperationMgr::onAbortOperation()
314 {
315   if (hasOperation() && canStopOperation()) {
316     abortOperation(currentOperation());
317   }
318 }
319
320 void XGUI_OperationMgr::onOperationStarted()
321 {
322   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
323   updateApplyOfOperations(aSenderOperation);
324   emit operationStarted(aSenderOperation);
325 }
326
327 void XGUI_OperationMgr::onOperationAborted()
328 {
329   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
330   emit operationAborted(aSenderOperation);
331 }
332
333 void XGUI_OperationMgr::onOperationCommitted()
334 {
335   updateApplyOfOperations();
336
337   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
338   emit operationCommitted(aSenderOperation);
339 }
340
341 void XGUI_OperationMgr::onOperationResumed()
342 {
343   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
344   emit operationResumed(aSenderOperation);
345 }
346
347 void XGUI_OperationMgr::onOperationStopped()
348 {
349   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
350   ModuleBase_Operation* aCurrentOperation = currentOperation();
351   if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
352     return;
353
354   myOperations.removeAll(aCurrentOperation);
355   aCurrentOperation->deleteLater();
356
357   emit operationStopped(aCurrentOperation);
358
359   // get last operation which can be resumed
360   ModuleBase_Operation* aResultOp = 0;
361   QListIterator<ModuleBase_Operation*> anIt(myOperations);
362   anIt.toBack();
363   while (anIt.hasPrevious()) {
364     ModuleBase_Operation* anOp = anIt.previous();
365     if (anOp) {
366       aResultOp = anOp;
367       break;
368     }
369   }
370   if (aResultOp) {
371     bool isModified = aCurrentOperation->isModified();
372     aResultOp->setIsModified(aResultOp->isModified() || isModified);
373     resumeOperation(aResultOp);
374     onValidateOperation();
375   }
376 }
377
378 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
379 {
380   // Let the manager decide what to do with the given key combination.
381   ModuleBase_Operation* anOperation = currentOperation();
382   bool isAccepted = true;
383   switch (theEvent->key()) {
384     case Qt::Key_Return:
385     case Qt::Key_Enter: {
386       emit keyEnterReleased();
387       commitOperation();
388     }
389     break;
390     default:
391       isAccepted = false;
392       break;
393   }
394   //if(anOperation) {
395   //  anOperation->keyReleased(theEvent->key());
396   //}
397   return isAccepted;
398 }
399