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