1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: XGUI_OperationMgr.h
4 // Created: 20 Apr 2014
5 // Author: Natalia ERMOLAEVA
7 #include "XGUI_OperationMgr.h"
9 #include "ModuleBase_Operation.h"
10 #include "ModuleBase_IWorkshop.h"
11 #include "ModuleBase_IModule.h"
13 #include "ModelAPI_CompositeFeature.h"
14 #include "ModelAPI_Session.h"
16 #include <QMessageBox>
17 #include <QApplication>
20 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
21 ModuleBase_IWorkshop* theWorkshop)
22 : QObject(theParent), myIsValidationLock(false), myIsApplyEnabled(false),
23 myWorkshop(theWorkshop)
27 XGUI_OperationMgr::~XGUI_OperationMgr()
31 ModuleBase_Operation* XGUI_OperationMgr::currentOperation() const
33 return myOperations.count() > 0 ? myOperations.last() : 0;
36 bool XGUI_OperationMgr::isCurrentOperation(ModuleBase_Operation* theOperation)
40 return currentOperation() == theOperation;
43 bool XGUI_OperationMgr::hasOperation() const
45 return !myOperations.isEmpty() && (myOperations.last() != NULL);
48 bool XGUI_OperationMgr::hasOperation(const QString& theId) const
50 foreach(ModuleBase_Operation* aOp, myOperations) {
51 if (aOp->id() == theId)
57 ModuleBase_Operation* XGUI_OperationMgr::findOperation(const QString& theId) const
59 foreach(ModuleBase_Operation* aOp, myOperations) {
60 if (aOp->id() == theId)
67 int XGUI_OperationMgr::operationsCount() const
69 return myOperations.count();
72 QStringList XGUI_OperationMgr::operationList() const
75 foreach(ModuleBase_Operation* eachOperation, myOperations) {
76 FeaturePtr aFeature = eachOperation->feature();
78 result << QString::fromStdString(aFeature->getKind());
84 ModuleBase_Operation* XGUI_OperationMgr::previousOperation(ModuleBase_Operation* theOperation) const
86 int idx = myOperations.lastIndexOf(theOperation);
87 if(idx == -1 || idx == 0) {
90 return myOperations.at(idx - 1);
93 bool XGUI_OperationMgr::eventFilter(QObject *theObject, QEvent *theEvent)
95 if (theEvent->type() == QEvent::KeyRelease) {
96 QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
98 return onKeyReleased(aKeyEvent);
101 return QObject::eventFilter(theObject, theEvent);
104 bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
107 currentOperation()->postpone();
108 myOperations.append(theOperation);
110 connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
111 connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
112 connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
113 connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
114 connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
115 connect(theOperation, SIGNAL(triggered(bool)), SLOT(onOperationTriggered(bool)));
116 connect(theOperation, SIGNAL(activatedByPreselection()),
117 SIGNAL(operationActivatedByPreselection()));
119 theOperation->start();
120 onValidateOperation();
124 bool XGUI_OperationMgr::abortAllOperations()
126 if(!hasOperation()) {
128 } else if (operationsCount() == 1) {
132 QString aMessage = tr("All active operations will be aborted.");
133 int anAnswer = QMessageBox::question(qApp->activeWindow(),
134 tr("Abort operation"),
136 QMessageBox::Ok | QMessageBox::Cancel,
137 QMessageBox::Cancel);
138 bool result = anAnswer == QMessageBox::Ok;
139 while(result && hasOperation()) {
140 currentOperation()->abort();
145 bool XGUI_OperationMgr::commitAllOperations()
147 bool isCompositeCommitted = false;
148 while (hasOperation()) {
149 ModuleBase_Operation* anOperation = currentOperation();
150 if (isApplyEnabled()) {
153 anOperation->abort();
155 FeaturePtr aFeature = anOperation->feature();
156 CompositeFeaturePtr aComposite =
157 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
158 isCompositeCommitted = aComposite.get();
159 if (isCompositeCommitted)
165 void XGUI_OperationMgr::onValidateOperation()
169 ModuleBase_Operation* anOperation = currentOperation();
171 bool aCanCommit = myWorkshop->module()->canCommitOperation();
172 setApplyEnabled(!myIsValidationLock && aCanCommit && anOperation->isValid());
176 void XGUI_OperationMgr::setLockValidating(bool toLock)
178 myIsValidationLock = toLock;
179 onValidateOperation();
182 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
184 myIsApplyEnabled = theEnabled;
185 emit validationStateChanged(theEnabled);
188 bool XGUI_OperationMgr::isApplyEnabled() const
190 return myIsApplyEnabled;
193 bool XGUI_OperationMgr::isParentOperationValid() const
195 bool isValid = false;
196 // the enable state of the parent operation of the nested one is defined by the rules that
197 // firstly there are nested operations and secondly the parent operation is valid
198 ModuleBase_Operation* aPrevOp = 0;
199 Operations::const_iterator anIt = myOperations.end();
200 if (anIt != myOperations.begin()) { // there are items in the operations list
202 aPrevOp = *anIt; // the last top operation, the operation which is started
203 if (anIt != myOperations.begin()) { // find the operation where the started operation is nested
208 return aPrevOp && aPrevOp->isValid();
211 bool XGUI_OperationMgr::canStopOperation()
213 ModuleBase_Operation* anOperation = currentOperation();
214 if(operationsCount() > 1) //in case of nested (sketch) operation no confirmation needed
216 if (anOperation && anOperation->isModified()) {
217 QString aMessage = tr("%1 operation will be aborted.").arg(anOperation->id());
218 int anAnswer = QMessageBox::question(qApp->activeWindow(),
219 tr("Abort operation"),
221 QMessageBox::Ok | QMessageBox::Cancel,
222 QMessageBox::Cancel);
223 return anAnswer == QMessageBox::Ok;
228 bool XGUI_OperationMgr::commitOperation()
230 if (hasOperation() && currentOperation()->isValid()) {
237 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
239 theOperation->resume();
242 bool XGUI_OperationMgr::canStartOperation(QString theId)
244 bool aCanStart = true;
245 ModuleBase_Operation* aCurrentOp = currentOperation();
247 if (!aCurrentOp->isGranted(theId)) {
248 if (canStopOperation()) {
249 if (myIsApplyEnabled)
250 aCurrentOp->commit();
262 void XGUI_OperationMgr::onCommitOperation()
264 ModuleBase_Operation* anOperation = currentOperation();
266 anOperation->commit();
269 void XGUI_OperationMgr::onAbortOperation()
271 if (hasOperation() && canStopOperation()) {
272 currentOperation()->abort();
276 void XGUI_OperationMgr::onOperationStarted()
278 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
280 bool aParentValid = isParentOperationValid();
281 // in order to apply is enabled only if there are modifications in the model
282 // e.g. sketch can be applyed only if at least one nested element modification is finished
283 bool aCanUndo = ModelAPI_Session::get()->canUndo();
284 emit nestedStateChanged(aParentValid && aCanUndo);
286 emit operationStarted(aSenderOperation);
289 void XGUI_OperationMgr::onOperationAborted()
291 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
292 emit operationAborted(aSenderOperation);
295 void XGUI_OperationMgr::onOperationCommitted()
297 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
298 // in order to apply is enabled only if there are modifications in the model
299 // e.g. sketch can be applyed only if at least one nested element create is finished
300 bool aCanUndo = ModelAPI_Session::get()->canUndo();
301 emit nestedStateChanged(myOperations.count() >= 1 && aCanUndo);
302 emit operationCommitted(aSenderOperation);
305 void XGUI_OperationMgr::onOperationResumed()
307 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
308 emit operationResumed(aSenderOperation);
311 void XGUI_OperationMgr::onOperationStopped()
313 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
314 ModuleBase_Operation* aCurrentOperation = currentOperation();
315 if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
318 myOperations.removeAll(aCurrentOperation);
319 aCurrentOperation->deleteLater();
321 emit operationStopped(aCurrentOperation);
323 // get last operation which can be resumed
324 ModuleBase_Operation* aResultOp = 0;
325 QListIterator<ModuleBase_Operation*> anIt(myOperations);
327 while (anIt.hasPrevious()) {
328 ModuleBase_Operation* anOp = anIt.previous();
335 bool isModified = aCurrentOperation->isModified();
336 aResultOp->setIsModified(isModified);
337 resumeOperation(aResultOp);
338 onValidateOperation();
342 void XGUI_OperationMgr::onOperationTriggered(bool theState)
344 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
345 if (aSenderOperation && !theState) {
346 ModuleBase_Operation* aCurrentOperation = currentOperation();
347 if (aSenderOperation == aCurrentOperation)
348 aCurrentOperation->abort();
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 while(hasOperation()) {
353 ModuleBase_Operation* aCurrentOperation = currentOperation();
354 aCurrentOperation->abort();
355 if(aSenderOperation == aCurrentOperation)
362 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
364 // Let the manager decide what to do with the given key combination.
365 ModuleBase_Operation* anOperation = currentOperation();
366 bool isAccepted = true;
367 switch (theEvent->key()) {
369 case Qt::Key_Enter: {
370 emit keyEnterReleased();
379 // anOperation->keyReleased(theEvent->key());