Salome HOME
b5579b88c70dc9039863dce28cdef98da28658a9
[modules/shaper.git] / src / XGUI / XGUI_OperationMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        XGUI_OperationMgr.h
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
13 #include <QMessageBox>
14 #include <QApplication>
15 #include <QKeyEvent>
16
17 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
18                                      ModuleBase_IWorkshop* theWorkshop)
19 : QObject(theParent), myIsValidationLock(false), myIsApplyEnabled(false),
20   myWorkshop(theWorkshop)
21 {
22 }
23
24 XGUI_OperationMgr::~XGUI_OperationMgr()
25 {
26 }
27
28 ModuleBase_Operation* XGUI_OperationMgr::currentOperation() const
29 {
30   return myOperations.count() > 0 ? myOperations.last() : 0;
31 }
32
33 bool XGUI_OperationMgr::isCurrentOperation(ModuleBase_Operation* theOperation)
34 {
35   if(!hasOperation())
36     return false;
37   return currentOperation() == theOperation;
38 }
39
40 bool XGUI_OperationMgr::hasOperation() const
41 {
42   return !myOperations.isEmpty() && (myOperations.last() != NULL);
43 }
44
45 bool XGUI_OperationMgr::hasOperation(const QString& theId) const
46 {
47   foreach(ModuleBase_Operation* aOp, myOperations) {
48     if (aOp->id() == theId)
49       return true;
50   }
51   return false;
52 }
53
54 ModuleBase_Operation* XGUI_OperationMgr::findOperation(const QString& theId) const
55 {
56   foreach(ModuleBase_Operation* aOp, myOperations) {
57     if (aOp->id() == theId)
58       return aOp;
59   }
60   return 0;
61 }
62
63
64 int XGUI_OperationMgr::operationsCount() const
65 {
66   return myOperations.count();
67 }
68
69 QStringList XGUI_OperationMgr::operationList() const
70 {
71   QStringList result;
72   foreach(ModuleBase_Operation* eachOperation, myOperations) {
73     FeaturePtr aFeature = eachOperation->feature();
74     if(aFeature) {
75       result << QString::fromStdString(aFeature->getKind());
76     }
77   }
78   return result;
79 }
80
81 ModuleBase_Operation* XGUI_OperationMgr::previousOperation(ModuleBase_Operation* theOperation) const
82 {
83   int idx = myOperations.lastIndexOf(theOperation);
84   if(idx == -1 || idx == 0) {
85     return NULL;
86   }
87   return myOperations.at(idx - 1);
88 }
89
90 bool XGUI_OperationMgr::eventFilter(QObject *theObject, QEvent *theEvent)
91 {
92   if (theEvent->type() == QEvent::KeyRelease) {
93     QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
94     if(aKeyEvent) {
95       return onKeyReleased(aKeyEvent);
96     }
97   }
98   return QObject::eventFilter(theObject, theEvent);
99 }
100
101 bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
102 {
103   if (hasOperation())
104     currentOperation()->postpone();
105   myOperations.append(theOperation);
106
107   connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
108   connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
109   connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
110   connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
111   connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
112   connect(theOperation, SIGNAL(triggered(bool)), SLOT(onOperationTriggered(bool)));
113   connect(theOperation, SIGNAL(activatedByPreselection()),
114           SIGNAL(operationActivatedByPreselection()));
115
116   theOperation->start();
117   onValidateOperation();
118   return true;
119 }
120
121 bool XGUI_OperationMgr::abortAllOperations()
122 {
123   if(!hasOperation()) {
124     return true;
125   } else if (operationsCount() == 1) {
126     onAbortOperation();
127     return true;
128   }
129   QString aMessage = tr("All active operations will be aborted.");
130   int anAnswer = QMessageBox::question(qApp->activeWindow(),
131                                        tr("Abort operation"),
132                                        aMessage,
133                                        QMessageBox::Ok | QMessageBox::Cancel,
134                                        QMessageBox::Cancel);
135   bool result = anAnswer == QMessageBox::Ok;
136   while(result && hasOperation()) {
137     currentOperation()->abort();
138   }
139   return result;
140 }
141
142 bool XGUI_OperationMgr::commitAllOperations()
143 {
144   while (hasOperation()) {
145     if (isApplyEnabled()) {
146       onCommitOperation();
147     } else {
148       currentOperation()->abort();
149     }
150   }
151   return true;
152 }
153
154 void XGUI_OperationMgr::onValidateOperation()
155 {
156   if (!hasOperation())
157     return;
158   ModuleBase_Operation* anOperation = currentOperation();
159   if(anOperation) {
160     bool aCanCommit = myWorkshop->module()->canCommitOperation();
161     setApplyEnabled(!myIsValidationLock && aCanCommit && anOperation->isValid());
162   }
163 }
164
165 void XGUI_OperationMgr::setLockValidating(bool toLock)
166 {
167   myIsValidationLock = toLock;
168   onValidateOperation();
169 }
170
171 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
172 {
173   myIsApplyEnabled = theEnabled;
174   emit validationStateChanged(theEnabled);
175 }
176
177 bool XGUI_OperationMgr::isApplyEnabled() const
178 {
179   return myIsApplyEnabled;
180 }
181
182 bool XGUI_OperationMgr::canStopOperation()
183 {
184   ModuleBase_Operation* anOperation = currentOperation();
185   if(operationsCount() > 1) //in case of nested (sketch) operation no confirmation needed
186     return true;
187   if (anOperation && anOperation->isModified()) {
188     QString aMessage = tr("%1 operation will be aborted.").arg(anOperation->id());
189     int anAnswer = QMessageBox::question(qApp->activeWindow(),
190                                          tr("Abort operation"),
191                                          aMessage,
192                                          QMessageBox::Ok | QMessageBox::Cancel,
193                                          QMessageBox::Cancel);
194     return anAnswer == QMessageBox::Ok;
195   }
196   return true;
197 }
198
199 bool XGUI_OperationMgr::commitOperation()
200 {
201   if (hasOperation() && currentOperation()->isValid()) {
202     onCommitOperation();
203     return true;
204   }
205   return false;
206 }
207
208 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
209 {
210   theOperation->resume();
211 }
212
213 bool XGUI_OperationMgr::canStartOperation(QString theId)
214 {
215   bool aCanStart = true;
216   ModuleBase_Operation* aCurrentOp = currentOperation();
217   if (aCurrentOp) {
218     if (!aCurrentOp->isGranted(theId)) {
219       if (canStopOperation()) {
220         if (myIsApplyEnabled)
221           aCurrentOp->commit();
222         else
223           aCurrentOp->abort();
224       } else {
225         aCanStart = false;
226       }
227     }
228   }
229   return aCanStart;
230 }
231
232
233 void XGUI_OperationMgr::onCommitOperation()
234 {
235   ModuleBase_Operation* anOperation = currentOperation();
236   if (anOperation)
237     anOperation->commit();
238 }
239
240 void XGUI_OperationMgr::onAbortOperation()
241 {
242   if (hasOperation() && canStopOperation()) {
243     currentOperation()->abort();
244   }
245 }
246
247 void XGUI_OperationMgr::onOperationStarted()
248 {
249   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
250   
251   bool isNestedOk = (myOperations.count() >= 1) && 
252                      myOperations.at(0)->isValid();
253   emit nestedStateChanged(isNestedOk);
254   emit operationStarted(aSenderOperation);
255 }
256
257 void XGUI_OperationMgr::onOperationAborted()
258 {
259   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
260   emit operationAborted(aSenderOperation);
261 }
262
263 void XGUI_OperationMgr::onOperationCommitted()
264 {
265   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
266   emit nestedStateChanged(myOperations.count() >= 1);
267   emit operationCommitted(aSenderOperation);
268 }
269
270 void XGUI_OperationMgr::onOperationResumed()
271 {
272   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
273   emit operationResumed(aSenderOperation);
274 }
275
276 void XGUI_OperationMgr::onOperationStopped()
277 {
278   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
279   ModuleBase_Operation* aCurrentOperation = currentOperation();
280   if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
281     return;
282
283   myOperations.removeAll(aCurrentOperation);
284   aCurrentOperation->deleteLater();
285
286   emit operationStopped(aCurrentOperation);
287
288   // get last operation which can be resumed
289   ModuleBase_Operation* aResultOp = 0;
290   QListIterator<ModuleBase_Operation*> anIt(myOperations);
291   anIt.toBack();
292   while (anIt.hasPrevious()) {
293     ModuleBase_Operation* anOp = anIt.previous();
294     if (anOp) {
295       aResultOp = anOp;
296       break;
297     }
298   }
299   if (aResultOp) {
300     bool isModified = aCurrentOperation->isModified();
301     aResultOp->setIsModified(isModified);
302     resumeOperation(aResultOp);
303     onValidateOperation();
304   }
305 }
306
307 void XGUI_OperationMgr::onOperationTriggered(bool theState)
308 {
309   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
310   if (aSenderOperation && !theState) {
311     ModuleBase_Operation* aCurrentOperation = currentOperation();
312     if (aSenderOperation == aCurrentOperation)
313       aCurrentOperation->abort();
314     else {
315       // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
316       // all operation from the current to triggered should also be aborted
317       while(hasOperation()) {
318         ModuleBase_Operation* aCurrentOperation = currentOperation();
319         aCurrentOperation->abort();
320         if(aSenderOperation == aCurrentOperation)
321           break;
322       }
323     }
324   }
325 }
326
327 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
328 {
329   // Let the manager decide what to do with the given key combination.
330   ModuleBase_Operation* anOperation = currentOperation();
331   bool isAccepted = true;
332   switch (theEvent->key()) {
333     case Qt::Key_Return:
334     case Qt::Key_Enter: {
335       emit keyEnterReleased();
336       commitOperation();
337     }
338     break;
339     default:
340       isAccepted = false;
341       break;
342   }
343   //if(anOperation) {
344   //  anOperation->keyReleased(theEvent->key());
345   //}
346   return isAccepted;
347 }
348