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->id()))
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(const QString& theId)
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->id() == theId) {
301 if (anIt.hasPrevious())
302 aPreviousOperation = anIt.previous();
306 if (aPreviousOperation)
307 isGranted = aPreviousOperation->isGranted(theId);
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;
318 // the started operation is granted for the current one,
319 // e.g. current - Sketch, started - Line
324 if (!isGrantedOperation(theId)) {
325 // the operation is not granted in the current list of operations
326 // e.g. Edit Parameter when Sketch, Line in Sketch is active.
327 aCanStart = abortAllOperations();
329 else if (canStopOperation(aCurrentOp)) {
330 // the started operation is granted in the parrent operation,
331 // e.g. current - Line in Sketch, started Circle
332 if (myIsApplyEnabled && aCurrentOp->isModified())
333 aCurrentOp->commit();
335 abortOperation(aCurrentOp);
344 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
346 ModuleBase_Operation* aCurrentOperation = currentOperation();
347 if (theOperation == aCurrentOperation)
348 theOperation->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 // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
353 while(hasOperation()) {
354 ModuleBase_Operation* aCurrentOperation = currentOperation();
355 aCurrentOperation->abort();
356 if(theOperation == aCurrentOperation)
362 void XGUI_OperationMgr::onCommitOperation()
364 ModuleBase_Operation* anOperation = currentOperation();
366 anOperation->commit();
369 void XGUI_OperationMgr::onAbortOperation()
371 ModuleBase_Operation* aCurrentOperation = currentOperation();
372 if (aCurrentOperation && canStopOperation(aCurrentOperation)) {
373 abortOperation(aCurrentOperation);
377 void XGUI_OperationMgr::onOperationStarted()
379 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
380 updateApplyOfOperations(aSenderOperation);
381 emit operationStarted(aSenderOperation);
384 void XGUI_OperationMgr::onOperationAborted()
386 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
387 emit operationAborted(aSenderOperation);
390 void XGUI_OperationMgr::onOperationCommitted()
392 // apply state for all features from the stack of operations should be updated
393 updateApplyOfOperations();
395 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
396 emit operationCommitted(aSenderOperation);
399 void XGUI_OperationMgr::onOperationResumed()
401 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
402 emit operationResumed(aSenderOperation);
405 void XGUI_OperationMgr::onOperationStopped()
407 ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
408 ModuleBase_Operation* aCurrentOperation = currentOperation();
409 if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
412 myOperations.removeAll(aCurrentOperation);
413 aCurrentOperation->deleteLater();
415 emit operationStopped(aCurrentOperation);
417 // get last operation which can be resumed
418 ModuleBase_Operation* aResultOp = 0;
419 QListIterator<ModuleBase_Operation*> anIt(myOperations);
421 while (anIt.hasPrevious()) {
422 ModuleBase_Operation* anOp = anIt.previous();
429 bool isModified = aCurrentOperation->isModified();
430 aResultOp->setIsModified(aResultOp->isModified() || isModified);
431 resumeOperation(aResultOp);
432 onValidateOperation();
436 bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
438 // Let the manager decide what to do with the given key combination.
439 ModuleBase_Operation* anOperation = currentOperation();
440 bool isAccepted = true;
441 switch (theEvent->key()) {
443 case Qt::Key_Enter: {
444 emit keyEnterReleased();
449 bool noModifiers = (theEvent->modifiers() == Qt::NoModifier);
451 ModuleBase_IViewer* aViewer = myWorkshop->viewer();
452 Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
453 if (!aContext.IsNull()) {
454 Handle(V3d_View) aView = aViewer->activeView();
455 if ((theEvent->key() == Qt::Key_N))
456 aContext->HilightNextDetected(aView);
457 else if ((theEvent->key() == Qt::Key_P))
458 aContext->HilightPreviousDetected(aView);
469 // anOperation->keyReleased(theEvent->key());
474 XGUI_Workshop* XGUI_OperationMgr::workshop() const
476 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
477 return aConnector->workshop();