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"
8 #include "XGUI_ModuleConnector.h"
9 #include "XGUI_Workshop.h"
10 #include "XGUI_ErrorMgr.h"
12 #include "ModuleBase_Operation.h"
13 #include "ModuleBase_IWorkshop.h"
14 #include "ModuleBase_IModule.h"
15 #include <ModuleBase_IViewer.h>
16 #include "ModuleBase_OperationDescription.h"
17 #include "ModuleBase_OperationFeature.h"
19 #include "ModelAPI_CompositeFeature.h"
20 #include "ModelAPI_Session.h"
22 #include <QMessageBox>
23 #include <QApplication>
26 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
27 ModuleBase_IWorkshop* theWorkshop)
28 : QObject(theParent), myIsValidationLock(false), myIsApplyEnabled(false),
29 myWorkshop(theWorkshop)
33 XGUI_OperationMgr::~XGUI_OperationMgr()
37 ModuleBase_Operation* XGUI_OperationMgr::currentOperation() const
39 return myOperations.count() > 0 ? myOperations.last() : 0;
42 bool XGUI_OperationMgr::isCurrentOperation(ModuleBase_Operation* theOperation)
46 return currentOperation() == theOperation;
49 bool XGUI_OperationMgr::hasOperation() const
51 return !myOperations.isEmpty() && (myOperations.last() != NULL);
54 bool XGUI_OperationMgr::hasOperation(const QString& theId) const
56 foreach(ModuleBase_Operation* aOp, myOperations) {
57 if (aOp->id() == theId)
63 ModuleBase_Operation* XGUI_OperationMgr::findOperation(const QString& theId) const
65 foreach(ModuleBase_Operation* aOp, myOperations) {
66 if (aOp->id() == theId)
73 int XGUI_OperationMgr::operationsCount() const
75 return myOperations.count();
78 QStringList XGUI_OperationMgr::operationList() const
81 foreach(ModuleBase_Operation* eachOperation, myOperations) {
82 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(eachOperation);
84 FeaturePtr aFeature = aFOperation->feature();
86 result << QString::fromStdString(aFeature->getKind());
93 ModuleBase_Operation* XGUI_OperationMgr::previousOperation(ModuleBase_Operation* theOperation) const
95 int idx = myOperations.lastIndexOf(theOperation);
96 if(idx == -1 || idx == 0) {
99 return myOperations.at(idx - 1);
102 bool XGUI_OperationMgr::eventFilter(QObject *theObject, QEvent *theEvent)
104 if (theEvent->type() == QEvent::KeyRelease) {
105 QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
107 return onKeyReleased(aKeyEvent);
110 return QObject::eventFilter(theObject, theEvent);
113 bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
116 currentOperation()->postpone();
117 myOperations.append(theOperation);
119 connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
120 connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
121 connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
122 connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
123 connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
124 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
127 connect(aFOperation, SIGNAL(activatedByPreselection()),
128 SIGNAL(operationActivatedByPreselection()));
130 theOperation->start();
131 onValidateOperation();
135 bool XGUI_OperationMgr::abortAllOperations()
141 if (operationsCount() == 1) {
142 ModuleBase_Operation* aCurrentOperation = currentOperation();
143 if (canStopOperation(aCurrentOperation)) {
144 abortOperation(aCurrentOperation);
150 aResult = QMessageBox::question(qApp->activeWindow(),
151 tr("Abort operation"),
152 tr("All active operations will be aborted."),
153 QMessageBox::Ok | QMessageBox::Cancel,
154 QMessageBox::Cancel) == QMessageBox::Ok;
155 while(aResult && hasOperation()) {
156 abortOperation(currentOperation());
162 bool XGUI_OperationMgr::commitAllOperations()
164 bool isCompositeCommitted = false;
165 while (hasOperation()) {
166 ModuleBase_Operation* anOperation = currentOperation();
167 if (isApplyEnabled()) {
170 abortOperation(anOperation);
172 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
175 FeaturePtr aFeature = aFOperation->feature();
176 CompositeFeaturePtr aComposite =
177 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
178 isCompositeCommitted = aComposite.get();
179 if (isCompositeCommitted)
186 void XGUI_OperationMgr::onValidateOperation()
190 //ModuleBase_Operation* anOperation = currentOperation();
191 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
192 (currentOperation());
193 if(aFOperation && aFOperation->feature().get()) {
194 //bool aCanCommit = myWorkshop->module()->canCommitOperation();
195 //setApplyEnabled(!myIsValidationLock && aCanCommit && anOperation->isValid());
196 setApplyEnabled(myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty());
200 void XGUI_OperationMgr::setLockValidating(bool toLock)
202 myIsValidationLock = toLock;
203 onValidateOperation();
206 void XGUI_OperationMgr::setApplyEnabled(const bool theEnabled)
208 myIsApplyEnabled = theEnabled;
209 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
210 (currentOperation());
212 workshop()->errorMgr()->updateActions(aFOperation->feature());
214 //emit validationStateChanged(theEnabled);
217 void XGUI_OperationMgr::updateApplyOfOperations(ModuleBase_Operation* theOperation)
219 XGUI_ErrorMgr* anErrorMgr = workshop()->errorMgr();
221 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
223 anErrorMgr->updateAcceptAllAction(aFOperation->feature());
224 //emit nestedStateChanged(theOperation->getDescription()->operationId().toStdString(),
225 // theOperation->isValid());
228 foreach(ModuleBase_Operation* anOperation, myOperations) {
230 updateApplyOfOperations(anOperation);
231 //emit nestedStateChanged(anOperation->getDescription()->operationId().toStdString(),
232 // anOperation->isValid());
237 bool XGUI_OperationMgr::isApplyEnabled() const
239 return myIsApplyEnabled;
242 bool XGUI_OperationMgr::isParentOperationValid() const
244 bool isValid = false;
245 // the enable state of the parent operation of the nested one is defined by the rules that
246 // firstly there are nested operations and secondly the parent operation is valid
247 ModuleBase_Operation* aPrevOp = 0;
248 Operations::const_iterator anIt = myOperations.end();
249 if (anIt != myOperations.begin()) { // there are items in the operations list
251 aPrevOp = *anIt; // the last top operation, the operation which is started
252 if (anIt != myOperations.begin()) { // find the operation where the started operation is nested
257 return aPrevOp && aPrevOp->isValid();
260 bool XGUI_OperationMgr::canStopOperation(ModuleBase_Operation* theOperation)
262 //in case of nested (sketch) operation no confirmation needed
263 if (isGrantedOperation(theOperation))
265 if (theOperation && theOperation->isModified()) {
266 QString aMessage = tr("%1 operation will be aborted.").arg(theOperation->id());
267 int anAnswer = QMessageBox::question(qApp->activeWindow(),
268 tr("Abort operation"),
270 QMessageBox::Ok | QMessageBox::Cancel,
271 QMessageBox::Cancel);
272 return anAnswer == QMessageBox::Ok;
277 bool XGUI_OperationMgr::commitOperation()
279 if (hasOperation() && currentOperation()->isValid()) {
286 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
288 theOperation->resume();
291 bool XGUI_OperationMgr::isGrantedOperation(ModuleBase_Operation* theOperation)
293 bool isGranted = false;
295 QListIterator<ModuleBase_Operation*> anIt(myOperations);
297 ModuleBase_Operation* aPreviousOperation = 0;
298 while (anIt.hasPrevious()) {
299 ModuleBase_Operation* anOp = anIt.previous();
300 if (anOp == theOperation) {
301 if (anIt.hasPrevious())
302 aPreviousOperation = anIt.previous();
306 if (aPreviousOperation)
307 isGranted = aPreviousOperation->isGranted(theOperation->id());
312 bool XGUI_OperationMgr::canStartOperation(const QString& theId, const bool isAdditionallyGranted)
314 bool aCanStart = true;
315 ModuleBase_Operation* aCurrentOp = currentOperation();
317 bool aGranted = aCurrentOp->isGranted(theId) || isAdditionallyGranted;
319 if (canStopOperation(aCurrentOp)) {
320 if (myIsApplyEnabled && aCurrentOp->isModified())
321 aCurrentOp->commit();
323 abortOperation(aCurrentOp);
332 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
334 ModuleBase_Operation* aCurrentOperation = currentOperation();
335 if (theOperation == aCurrentOperation)
336 theOperation->abort();
338 // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
339 // all operation from the current to triggered should also be aborted
340 // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
341 while(hasOperation()) {
342 ModuleBase_Operation* aCurrentOperation = currentOperation();
343 aCurrentOperation->abort();
344 if(theOperation == aCurrentOperation)
350 void XGUI_OperationMgr::onCommitOperation()
352 ModuleBase_Operation* anOperation = currentOperation();
354 anOperation->commit();
357 void XGUI_OperationMgr::onAbortOperation()
359 ModuleBase_Operation* aCurrentOperation = currentOperation();
360 if (aCurrentOperation && canStopOperation(aCurrentOperation)) {
361 abortOperation(aCurrentOperation);
365 void XGUI_OperationMgr::onOperationStarted()
367 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
368 updateApplyOfOperations(aSenderOperation);
369 emit operationStarted(aSenderOperation);
372 void XGUI_OperationMgr::onOperationAborted()
374 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
375 emit operationAborted(aSenderOperation);
378 void XGUI_OperationMgr::onOperationCommitted()
380 // apply state for all features from the stack of operations should be updated
381 updateApplyOfOperations();
383 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
384 emit operationCommitted(aSenderOperation);
387 void XGUI_OperationMgr::onOperationResumed()
389 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
390 emit operationResumed(aSenderOperation);
393 void XGUI_OperationMgr::onOperationStopped()
395 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
396 ModuleBase_Operation* aCurrentOperation = currentOperation();
397 if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
400 myOperations.removeAll(aCurrentOperation);
401 aCurrentOperation->deleteLater();
403 emit operationStopped(aCurrentOperation);
405 // get last operation which can be resumed
406 ModuleBase_Operation* aResultOp = 0;
407 QListIterator<ModuleBase_Operation*> anIt(myOperations);
409 while (anIt.hasPrevious()) {
410 ModuleBase_Operation* anOp = anIt.previous();
417 bool isModified = aCurrentOperation->isModified();
418 aResultOp->setIsModified(aResultOp->isModified() || isModified);
419 resumeOperation(aResultOp);
420 onValidateOperation();
424 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
426 // Let the manager decide what to do with the given key combination.
427 ModuleBase_Operation* anOperation = currentOperation();
428 bool isAccepted = true;
429 switch (theEvent->key()) {
431 case Qt::Key_Enter: {
432 emit keyEnterReleased();
437 bool noModifiers = (theEvent->modifiers() == Qt::NoModifier);
439 ModuleBase_IViewer* aViewer = myWorkshop->viewer();
440 Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
441 if (!aContext.IsNull()) {
442 Handle(V3d_View) aView = aViewer->activeView();
443 if ((theEvent->key() == Qt::Key_N))
444 aContext->HilightNextDetected(aView);
445 else if ((theEvent->key() == Qt::Key_P))
446 aContext->HilightPreviousDetected(aView);
457 // anOperation->keyReleased(theEvent->key());
462 XGUI_Workshop* XGUI_OperationMgr::workshop() const
464 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
465 return aConnector->workshop();