1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: XGUI_OperationMgr.cpp
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()
130 if (operationsCount() == 1) {
131 if (canStopOperation()) {
132 abortOperation(currentOperation());
138 aResult = QMessageBox::question(qApp->activeWindow(),
139 tr("Abort operation"),
140 tr("All active operations will be aborted."),
141 QMessageBox::Ok | QMessageBox::Cancel,
142 QMessageBox::Cancel) == QMessageBox::Ok;
143 while(aResult && hasOperation()) {
144 abortOperation(currentOperation());
150 bool XGUI_OperationMgr::commitAllOperations()
152 bool isCompositeCommitted = false;
153 while (hasOperation()) {
154 ModuleBase_Operation* anOperation = currentOperation();
155 if (isApplyEnabled()) {
158 abortOperation(anOperation);
160 FeaturePtr aFeature = anOperation->feature();
161 CompositeFeaturePtr aComposite =
162 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
163 isCompositeCommitted = aComposite.get();
164 if (isCompositeCommitted)
170 void XGUI_OperationMgr::onValidateOperation()
174 ModuleBase_Operation* anOperation = currentOperation();
176 bool aCanCommit = myWorkshop->module()->canCommitOperation();
177 setApplyEnabled(!myIsValidationLock && aCanCommit && anOperation->isValid());
181 void XGUI_OperationMgr::setLockValidating(bool toLock)
183 myIsValidationLock = toLock;
184 onValidateOperation();
187 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
189 myIsApplyEnabled = theEnabled;
190 emit validationStateChanged(theEnabled);
193 bool XGUI_OperationMgr::isApplyEnabled() const
195 return myIsApplyEnabled;
198 bool XGUI_OperationMgr::isParentOperationValid() const
200 bool isValid = false;
201 // the enable state of the parent operation of the nested one is defined by the rules that
202 // firstly there are nested operations and secondly the parent operation is valid
203 ModuleBase_Operation* aPrevOp = 0;
204 Operations::const_iterator anIt = myOperations.end();
205 if (anIt != myOperations.begin()) { // there are items in the operations list
207 aPrevOp = *anIt; // the last top operation, the operation which is started
208 if (anIt != myOperations.begin()) { // find the operation where the started operation is nested
213 return aPrevOp && aPrevOp->isValid();
216 bool XGUI_OperationMgr::canStopOperation()
218 ModuleBase_Operation* anOperation = currentOperation();
219 if(operationsCount() > 1) //in case of nested (sketch) operation no confirmation needed
221 if (anOperation && anOperation->isModified()) {
222 QString aMessage = tr("%1 operation will be aborted.").arg(anOperation->id());
223 int anAnswer = QMessageBox::question(qApp->activeWindow(),
224 tr("Abort operation"),
226 QMessageBox::Ok | QMessageBox::Cancel,
227 QMessageBox::Cancel);
228 return anAnswer == QMessageBox::Ok;
233 bool XGUI_OperationMgr::commitOperation()
235 if (hasOperation() && currentOperation()->isValid()) {
242 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
244 theOperation->resume();
247 bool XGUI_OperationMgr::canStartOperation(QString theId)
249 bool aCanStart = true;
250 ModuleBase_Operation* aCurrentOp = currentOperation();
252 if (!aCurrentOp->isGranted(theId)) {
253 if (canStopOperation()) {
254 if (myIsApplyEnabled)
255 aCurrentOp->commit();
257 abortOperation(aCurrentOp);
266 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
268 ModuleBase_Operation* aCurrentOperation = currentOperation();
269 if (theOperation == aCurrentOperation)
270 theOperation->abort();
272 // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
273 // all operation from the current to triggered should also be aborted
274 // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
275 while(hasOperation()) {
276 ModuleBase_Operation* aCurrentOperation = currentOperation();
277 aCurrentOperation->abort();
278 if(theOperation == aCurrentOperation)
284 void XGUI_OperationMgr::onCommitOperation()
286 ModuleBase_Operation* anOperation = currentOperation();
288 anOperation->commit();
291 void XGUI_OperationMgr::onAbortOperation()
293 if (hasOperation() && canStopOperation()) {
294 abortOperation(currentOperation());
298 void XGUI_OperationMgr::onOperationStarted()
300 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
302 bool aParentValid = isParentOperationValid();
303 // in order to apply is enabled only if there are modifications in the model
304 // e.g. sketch can be applyed only if at least one nested element modification is finished
305 bool aCanUndo = ModelAPI_Session::get()->canUndo();
306 emit nestedStateChanged(aParentValid && aCanUndo);
308 emit operationStarted(aSenderOperation);
311 void XGUI_OperationMgr::onOperationAborted()
313 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
314 emit operationAborted(aSenderOperation);
317 void XGUI_OperationMgr::onOperationCommitted()
319 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
320 // in order to apply is enabled only if there are modifications in the model
321 // e.g. sketch can be applyed only if at least one nested element create is finished
322 bool aCanUndo = ModelAPI_Session::get()->canUndo();
323 emit nestedStateChanged(myOperations.count() >= 1 && aCanUndo);
324 emit operationCommitted(aSenderOperation);
327 void XGUI_OperationMgr::onOperationResumed()
329 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
330 emit operationResumed(aSenderOperation);
333 void XGUI_OperationMgr::onOperationStopped()
335 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
336 ModuleBase_Operation* aCurrentOperation = currentOperation();
337 if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
340 myOperations.removeAll(aCurrentOperation);
341 aCurrentOperation->deleteLater();
343 emit operationStopped(aCurrentOperation);
345 // get last operation which can be resumed
346 ModuleBase_Operation* aResultOp = 0;
347 QListIterator<ModuleBase_Operation*> anIt(myOperations);
349 while (anIt.hasPrevious()) {
350 ModuleBase_Operation* anOp = anIt.previous();
357 bool isModified = aCurrentOperation->isModified();
358 aResultOp->setIsModified(aResultOp->isModified() || isModified);
359 resumeOperation(aResultOp);
360 onValidateOperation();
364 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
366 // Let the manager decide what to do with the given key combination.
367 ModuleBase_Operation* anOperation = currentOperation();
368 bool isAccepted = true;
369 switch (theEvent->key()) {
371 case Qt::Key_Enter: {
372 emit keyEnterReleased();
381 // anOperation->keyReleased(theEvent->key());