Salome HOME
Issue #1412: Activate selection mode FACES for sketcher only in operations with selector
[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 #include "XGUI_ModuleConnector.h"
9 #include "XGUI_Workshop.h"
10 #include "XGUI_ErrorMgr.h"
11 #include "XGUI_Tools.h"
12 #include "XGUI_ObjectsBrowser.h"
13
14 #include <ModuleBase_IPropertyPanel.h>
15 #include <ModuleBase_ModelWidget.h>
16 #include "ModuleBase_Operation.h"
17 #include "ModuleBase_IWorkshop.h"
18 #include "ModuleBase_IModule.h"
19 #include <ModuleBase_IViewer.h>
20 #include "ModuleBase_OperationDescription.h"
21 #include "ModuleBase_OperationFeature.h"
22 #include "ModuleBase_Tools.h"
23
24 #include "ModelAPI_CompositeFeature.h"
25 #include "ModelAPI_Session.h"
26
27 #include <XGUI_PropertyPanel.h>
28 #include <QToolButton>
29
30 #include <QMessageBox>
31 #include <QApplication>
32 #include <QKeyEvent>
33
34 //#define DEBUG_CURRENT_FEATURE
35
36 /// Processes "Delete" key event of application. This key is used by several application actions.
37 /// There is a logical order of the actions processing. So the key can not be set for actions
38 /// as a shortcut. The class listens the key event and call operation manager processor.
39 class XGUI_ShortCutListener : public QObject
40 {
41 public:
42   /// Constructor
43   /// \param theParent the parent to be deleted when the parent is deleted
44   /// \param theOperationMgr the class to perform deletion
45   XGUI_ShortCutListener(QObject* theParent, XGUI_OperationMgr* theOperationMgr)
46     : QObject(theParent), myOperationMgr(theOperationMgr)
47   {
48     qApp->installEventFilter(this);
49   }
50   ~XGUI_ShortCutListener() {}
51
52   /// Switch on short cut listener
53   void setActive(const bool theIsActive) { myIsActive = theIsActive; }
54
55   /// Redefinition of virtual function to process Delete key release
56   virtual bool eventFilter(QObject *theObject, QEvent *theEvent)
57   {
58     bool isAccepted = false;
59     if (myIsActive && theEvent->type() == QEvent::KeyRelease) {
60       QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
61       if(aKeyEvent) {
62         switch (aKeyEvent->key()) {
63           case Qt::Key_Delete: {
64             isAccepted = myOperationMgr->onProcessDelete(theObject);
65           }
66         }
67       }
68     }
69     if (!isAccepted)
70       isAccepted = QObject::eventFilter(theObject, theEvent);
71     return isAccepted;
72   }
73
74 private:
75   XGUI_OperationMgr* myOperationMgr; /// processor for key event
76   bool myIsActive; /// boolean state whether the event filter perform own signal processing
77 };
78
79 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
80                                      ModuleBase_IWorkshop* theWorkshop)
81 : QObject(theParent), myWorkshop(theWorkshop)
82 {
83   /// we need to install filter to the application in order to react to 'Delete' key button
84   /// this key can not be a short cut for a corresponded action because we need to set
85   /// the actions priority
86   myShortCutListener = new XGUI_ShortCutListener(theParent, this);
87 }
88
89 XGUI_OperationMgr::~XGUI_OperationMgr()
90 {
91 }
92
93 void XGUI_OperationMgr::activate()
94 {
95   myShortCutListener->setActive(true);
96 }
97
98 void XGUI_OperationMgr::deactivate()
99 {
100   myShortCutListener->setActive(false);
101 }
102
103 ModuleBase_Operation* XGUI_OperationMgr::currentOperation() const
104 {
105   return myOperations.count() > 0 ? myOperations.last() : 0;
106 }
107
108 bool XGUI_OperationMgr::isCurrentOperation(ModuleBase_Operation* theOperation)
109 {
110   if(!hasOperation())
111     return false;
112   return currentOperation() == theOperation;
113 }
114
115 bool XGUI_OperationMgr::hasOperation() const
116 {
117   return !myOperations.isEmpty() && (myOperations.last() != NULL);
118 }
119
120 bool XGUI_OperationMgr::hasOperation(const QString& theId) const
121 {
122   foreach(ModuleBase_Operation* aOp, myOperations) {
123     if (aOp->id() == theId)
124       return true;
125   }
126   return false;
127 }
128
129 ModuleBase_Operation* XGUI_OperationMgr::findOperation(const QString& theId) const
130 {
131   foreach(ModuleBase_Operation* aOp, myOperations) {
132     if (aOp->id() == theId)
133       return aOp;
134   }
135   return 0;
136 }
137
138
139 int XGUI_OperationMgr::operationsCount() const
140 {
141   return myOperations.count();
142 }
143
144 QStringList XGUI_OperationMgr::operationList() const
145 {
146   QStringList result;
147   foreach(ModuleBase_Operation* eachOperation, myOperations) {
148     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(eachOperation);
149     if (aFOperation) {
150       FeaturePtr aFeature = aFOperation->feature();
151       if(aFeature) {
152         result << QString::fromStdString(aFeature->getKind());
153       }
154     }
155   }
156   return result;
157 }
158
159 ModuleBase_Operation* XGUI_OperationMgr::previousOperation(ModuleBase_Operation* theOperation) const
160 {
161   int idx = myOperations.lastIndexOf(theOperation);
162   if(idx == -1 || idx == 0) {
163     return NULL;
164   }
165   return myOperations.at(idx - 1);
166 }
167
168 bool XGUI_OperationMgr::eventFilter(QObject *theObject, QEvent *theEvent)
169 {
170   bool isAccepted = false;
171   if (theEvent->type() == QEvent::KeyRelease) {
172     QKeyEvent* aKeyEvent = dynamic_cast<QKeyEvent*>(theEvent);
173     if(aKeyEvent)
174       isAccepted = onKeyReleased(theObject, aKeyEvent);
175   }
176   if (!isAccepted)
177     isAccepted = QObject::eventFilter(theObject, theEvent);
178
179   return isAccepted;
180 }
181
182 bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
183 {
184   if (hasOperation())
185     currentOperation()->postpone();
186   myOperations.append(theOperation);
187
188   connect(theOperation, SIGNAL(beforeStarted()), SLOT(onBeforeOperationStarted()));
189   connect(theOperation, SIGNAL(beforeAborted()), SLOT(onBeforeOperationAborted()));
190   connect(theOperation, SIGNAL(beforeCommitted()), SLOT(onBeforeOperationCommitted()));
191
192   connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
193   connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
194   connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
195
196   connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
197   connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
198
199   bool isStarted = theOperation->start();
200   if (isStarted)
201     onValidateOperation();
202   return isStarted;
203 }
204
205 bool XGUI_OperationMgr::abortAllOperations()
206 {
207   bool aResult = true;
208   if(!hasOperation())
209     return aResult;
210
211   if (operationsCount() == 1) {
212     ModuleBase_Operation* aCurrentOperation = currentOperation();
213     if (canStopOperation(aCurrentOperation)) {
214       abortOperation(aCurrentOperation);
215     }
216     else
217       aResult = false;
218   }
219   else {
220     aResult = QMessageBox::question(qApp->activeWindow(),
221                                     tr("Abort operation"),
222                                     tr("All active operations will be aborted."),
223                                     QMessageBox::Ok | QMessageBox::Cancel,
224                                     QMessageBox::Cancel) == QMessageBox::Ok;
225     while(aResult && hasOperation()) {
226       abortOperation(currentOperation());
227     }
228   }
229   return aResult;
230 }
231
232 bool XGUI_OperationMgr::commitAllOperations()
233 {
234   bool isCompositeCommitted = false, anOperationProcessed = false;
235   while (hasOperation()) {
236     ModuleBase_Operation* anOperation = currentOperation();
237     if (XGUI_Tools::workshop(myWorkshop)->errorMgr()->isApplyEnabled()) {
238       anOperationProcessed = onCommitOperation();
239     } else {
240       abortOperation(anOperation);
241       anOperationProcessed = true;
242     }
243     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
244                                                                             (anOperation);
245     if (aFOperation) {
246       FeaturePtr aFeature = aFOperation->feature();
247       CompositeFeaturePtr aComposite = 
248           std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
249       isCompositeCommitted = aComposite.get();
250       if (isCompositeCommitted)
251         break;
252     }
253     // not processed[committed] operation might be used in composite feature,
254     // so the while will be stopped by the previous check.
255     // this code is not necessary, but logically should be done when the processing will not
256     // be done for not composite feature by some reasons
257     if (!anOperationProcessed)
258       break;
259   }
260   return true;
261 }
262
263 void XGUI_OperationMgr::onValidateOperation()
264 {
265   if (!hasOperation())
266     return;
267   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
268                                                                           (currentOperation());
269   if(aFOperation && aFOperation->feature().get())
270     XGUI_Tools::workshop(myWorkshop)->errorMgr()->updateActions(aFOperation->feature());
271 }
272
273 void XGUI_OperationMgr::updateApplyOfOperations(ModuleBase_Operation* theOperation)
274 {
275   XGUI_ErrorMgr* anErrorMgr = XGUI_Tools::workshop(myWorkshop)->errorMgr();
276   if (theOperation) {
277     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
278     if (aFOperation)
279       anErrorMgr->updateAcceptAllAction(aFOperation->feature());
280   }
281   else {
282     foreach(ModuleBase_Operation* anOperation, myOperations) {
283       if (anOperation)
284         updateApplyOfOperations(anOperation);
285     }
286   }
287   // Apply button of the current operation should also be updated
288   onValidateOperation();
289 }
290
291 bool XGUI_OperationMgr::canStopOperation(ModuleBase_Operation* theOperation)
292 {
293   //in case of nested (sketch) operation no confirmation needed
294   if (isGrantedOperation(theOperation->id()))
295     return true;
296   if (theOperation && theOperation->isModified()) {
297     QString aMessage = tr("%1 operation will be aborted.").arg(theOperation->id());
298     int anAnswer = QMessageBox::question(qApp->activeWindow(),
299                                          tr("Abort operation"),
300                                          aMessage,
301                                          QMessageBox::Ok | QMessageBox::Cancel,
302                                          QMessageBox::Cancel);
303     return anAnswer == QMessageBox::Ok;
304   }
305   return true;
306 }
307
308 bool XGUI_OperationMgr::commitOperation()
309 {
310   //if (hasOperation() && currentOperation()->isValid()) {
311   //  onCommitOperation();
312   //  return true;
313   //}
314   //return false;
315   return onCommitOperation();
316 }
317
318 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
319 {
320   theOperation->resume();
321 }
322
323 bool XGUI_OperationMgr::isGrantedOperation(const QString& theId)
324 {
325   bool isGranted = false;
326
327   QListIterator<ModuleBase_Operation*> anIt(myOperations);
328   anIt.toBack();
329   ModuleBase_Operation* aPreviousOperation = 0;
330   while (anIt.hasPrevious() && !isGranted) {
331     ModuleBase_Operation* anOp = anIt.previous();
332     if (anOp)
333       isGranted = anOp->isGranted(theId);
334   }
335   return isGranted;
336 }
337
338 void XGUI_OperationMgr::setCurrentFeature(const FeaturePtr& theFeature)
339 {
340   SessionPtr aMgr = ModelAPI_Session::get();
341   DocumentPtr aDoc = aMgr->activeDocument();
342   bool aIsOp = aMgr->isOperation();
343   if (!aIsOp)
344     aMgr->startOperation(QString("Set current feature: %1").arg(theFeature->getKind().c_str()).toStdString());
345   aDoc->setCurrentFeature(theFeature, false);
346   if (!aIsOp)
347     aMgr->finishOperation();
348 }
349
350 bool XGUI_OperationMgr::canStartOperation(const QString& theId)
351 {
352   bool aCanStart = true;
353   ModuleBase_Operation* aCurrentOp = currentOperation();
354   if (aCurrentOp) {
355     bool aGranted = aCurrentOp->isGranted(theId);
356     // the started operation is granted for the current one,
357     // e.g. current - Sketch, started - Line
358     if (aGranted) {
359       aCanStart = true;
360     }
361     else {
362       if (!isGrantedOperation(theId)) {
363         // the operation is not granted in the current list of operations
364         // e.g. Edit Parameter when Sketch, Line in Sketch is active.
365         aCanStart = abortAllOperations();
366       }
367       else if (canStopOperation(aCurrentOp)) {
368         // the started operation is granted in the parrent operation,
369         // e.g. current - Line in Sketch, started Circle 
370         if (XGUI_Tools::workshop(myWorkshop)->errorMgr()->isApplyEnabled() && aCurrentOp->isModified())
371           aCurrentOp->commit();
372         else
373           abortOperation(aCurrentOp);
374       } else {
375         aCanStart = false;
376       }
377     }
378   }
379   return aCanStart;
380 }
381
382 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
383 {
384   ModuleBase_Operation* aCurrentOperation = currentOperation();
385   if (theOperation == aCurrentOperation)
386     theOperation->abort();
387   else {
388     // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
389     // all operation from the current to triggered should also be aborted
390     // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
391     while(hasOperation()) {
392       ModuleBase_Operation* aCurrentOperation = currentOperation();
393       aCurrentOperation->abort();
394       if(theOperation == aCurrentOperation)
395         break;
396     }
397   }
398 }
399
400 bool XGUI_OperationMgr::onCommitOperation()
401 {
402   bool isCommitted = false;
403   ModuleBase_Operation* anOperation = currentOperation();
404   if (anOperation && myWorkshop->module()->canCommitOperation())
405     isCommitted = anOperation->commit();
406   return isCommitted;
407 }
408
409 void XGUI_OperationMgr::onAbortOperation()
410 {
411   ModuleBase_Operation* aCurrentOperation = currentOperation();
412   if (aCurrentOperation && canStopOperation(aCurrentOperation)) {
413     abortOperation(aCurrentOperation);
414   }
415 }
416
417 void XGUI_OperationMgr::onBeforeOperationStarted()
418 {
419   ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
420   if (!aCurrentOperation)
421     return;
422
423   /// Set current feature and remeber old current feature
424   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
425   if (aFOperation) {
426     SessionPtr aMgr = ModelAPI_Session::get();
427     DocumentPtr aDoc = aMgr->activeDocument();
428     // the parameter of current feature should be false, we should use all feature, not only visible
429     // in order to correctly save the previous feature of the nested operation, where the
430     // features can be not visible in the tree. The problem case is Edit sketch entitity(line)
431     // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit.
432     // When sketch entity operation started, the sketch should be cashed here as the current.
433     // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch
434     // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
435     // As a result the sketch disappears from the viewer. However after commit it is displayed back.
436     aFOperation->setPreviousCurrentFeature(aDoc->currentFeature(false));
437
438 #ifdef DEBUG_CURRENT_FEATURE
439     FeaturePtr aFeature = aFOperation->feature();
440     QString aKind = aFeature ? aFeature->getKind().c_str() : "";
441     qDebug(QString("onBeforeOperationStarted(), edit operation = %1, feature = %2")
442             .arg(aFOperation->isEditOperation())
443             .arg(ModuleBase_Tools::objectInfo(aFeature)).toStdString().c_str());
444
445     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
446             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
447 #endif
448
449     if (aFOperation->isEditOperation()) {// it should be performed by the feature edit only
450       // in create operation, the current feature is changed by addFeature()
451       aDoc->setCurrentFeature(aFOperation->feature(), false);
452       // this is the only place where flushes must be called after setCurrentFeature for the current
453       // moment: after this the opertion is not finished, so, the ObjectBrowser state may be corrupted
454       // (issue #1457)
455       static Events_Loop* aLoop = Events_Loop::loop();
456       static Events_ID aCreateEvent = aLoop->eventByName(EVENT_OBJECT_CREATED);
457       aLoop->flush(aCreateEvent);
458       static Events_ID aDeleteEvent = aLoop->eventByName(EVENT_OBJECT_DELETED);
459       aLoop->flush(aDeleteEvent);
460     }
461
462 #ifdef DEBUG_CURRENT_FEATURE
463     qDebug("\tdocument->setCurrentFeature");
464     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
465             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
466 #endif
467   ModuleBase_IModule* aModule = myWorkshop->module();
468   if (aModule)
469     aModule->beforeOperationStarted(aFOperation);
470   }
471 }
472
473 void XGUI_OperationMgr::onOperationStarted()
474 {
475   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
476   updateApplyOfOperations(aSenderOperation);
477   emit operationStarted(aSenderOperation);
478 }
479
480 void XGUI_OperationMgr::onBeforeOperationAborted()
481 {
482   onBeforeOperationCommitted();
483 }
484
485 void XGUI_OperationMgr::onOperationAborted()
486 {
487   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
488   emit operationAborted(aSenderOperation);
489 }
490
491 void XGUI_OperationMgr::onBeforeOperationCommitted()
492 {
493   ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
494   if (!aCurrentOperation)
495     return;
496
497   /// Restore the previous current feature
498   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
499   if (aFOperation) {
500 #ifdef DEBUG_CURRENT_FEATURE
501     QString aKind = aFOperation->feature()->getKind().c_str();
502     qDebug(QString("onBeforeOperationCommitted(), edit operation = %1, feature = %2")
503             .arg(aFOperation->isEditOperation())
504             .arg(ModuleBase_Tools::objectInfo(aFOperation->feature())).toStdString().c_str());
505
506     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
507             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
508 #endif
509
510     if (aFOperation->isEditOperation()) {
511       /// Restore the previous current feature
512       setCurrentFeature(aFOperation->previousCurrentFeature());
513     }
514     else { // create operation
515       // the Top created feature should stays the current. In nested operations, like Line in the Sketch or
516       // Sketch in ExtrusionCut, a previous feature should be restored on commit. It is performed here
517       // in order to perform it in the current transaction without opening a new one.
518       if (myOperations.front() != aFOperation)
519         setCurrentFeature(aFOperation->previousCurrentFeature());
520     }
521 #ifdef DEBUG_CURRENT_FEATURE
522     qDebug("\tdocument->setCurrentFeature");
523     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
524             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
525 #endif
526     ModuleBase_IModule* aModule = myWorkshop->module();
527     if (aModule)
528       aModule->beforeOperationStopped(aFOperation);
529   }
530 }
531
532 void XGUI_OperationMgr::onOperationCommitted()
533 {
534   // apply state for all features from the stack of operations should be updated
535   updateApplyOfOperations();
536
537   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
538   emit operationCommitted(aSenderOperation);
539 }
540
541 void XGUI_OperationMgr::onOperationResumed()
542 {
543   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
544   emit operationResumed(aSenderOperation);
545 }
546
547 void XGUI_OperationMgr::onOperationStopped()
548 {
549   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
550   ModuleBase_Operation* aCurrentOperation = currentOperation();
551   if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
552     return;
553
554   myOperations.removeAll(aCurrentOperation);
555   aCurrentOperation->deleteLater();
556
557   emit operationStopped(aCurrentOperation);
558
559   // get last operation which can be resumed
560   ModuleBase_Operation* aResultOp = 0;
561   QListIterator<ModuleBase_Operation*> anIt(myOperations);
562   anIt.toBack();
563   while (anIt.hasPrevious()) {
564     ModuleBase_Operation* anOp = anIt.previous();
565     if (anOp) {
566       aResultOp = anOp;
567       break;
568     }
569   }
570   if (aResultOp) {
571     bool isModified = aCurrentOperation->isModified();
572     aResultOp->setIsModified(aResultOp->isModified() || isModified);
573     resumeOperation(aResultOp);
574     onValidateOperation();
575   }
576 }
577
578 bool XGUI_OperationMgr::onKeyReleased(QObject *theObject, QKeyEvent* theEvent)
579 {
580   // Let the manager decide what to do with the given key combination.
581   ModuleBase_Operation* anOperation = currentOperation();
582   bool isAccepted = false;
583   switch (theEvent->key()) {
584     case Qt::Key_Return:
585     case Qt::Key_Enter: {
586       isAccepted = onProcessEnter(theObject);
587     }
588     break;
589     case Qt::Key_N:
590     case Qt::Key_P: {
591       bool noModifiers = (theEvent->modifiers() == Qt::NoModifier);
592       if (noModifiers) {
593         ModuleBase_IViewer* aViewer = myWorkshop->viewer();
594         Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
595         if (!aContext.IsNull()) {
596           Handle(V3d_View) aView = aViewer->activeView();
597           if ((theEvent->key() == Qt::Key_N))
598             aContext->HilightNextDetected(aView);
599           else if ((theEvent->key() == Qt::Key_P))
600             aContext->HilightPreviousDetected(aView);
601         }
602       }
603     }
604     break;
605     break;
606     default:
607       isAccepted = false;
608       break;
609   }
610   //if(anOperation) {
611   //  anOperation->keyReleased(theEvent->key());
612   //}
613   return isAccepted;
614 }
615
616 bool XGUI_OperationMgr::onProcessEnter(QObject* theObject)
617 {
618   bool isAccepted = false;
619   ModuleBase_Operation* aOperation = currentOperation();
620   // to avoid enter processing when operation has not been started yet
621   if (!aOperation)
622     return isAccepted;
623   ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
624   // only property panel enter is processed in order to do not process enter in application dialogs
625   bool isPPChild = isChildObject(theObject, aPanel);
626   if (!isPPChild)
627     return isAccepted;
628
629   ModuleBase_ModelWidget* anActiveWgt = aPanel->activeWidget();
630   bool isAborted = false;
631   if (!anActiveWgt) {
632     QWidget* aFocusWidget = aPanel->focusWidget();
633     QToolButton* aCancelBtn = dynamic_cast<XGUI_PropertyPanel*>(aPanel)->findButton(PROP_PANEL_CANCEL);
634     if (aFocusWidget && aCancelBtn && aFocusWidget == aCancelBtn) {
635       abortOperation(aOperation);
636       isAccepted = true;
637       isAborted = true;
638     }
639   }
640   if (!isAborted) {
641     isAccepted = anActiveWgt && anActiveWgt->processEnter();
642     if (!isAccepted) {
643       isAccepted = myWorkshop->module()->processEnter(anActiveWgt ? anActiveWgt->attributeID() : "");
644       if (!isAccepted) {
645         /// functionality is similar to Apply click
646         ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(currentOperation());
647         if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty()) {
648           // key released is emitted to apply the current value to the model if it was modified in PP
649           emit keyEnterReleased();
650           commitOperation();
651           isAccepted = true;
652         }
653         else
654           isAccepted = false;
655       }
656     }
657   }
658   return isAccepted;
659 }
660
661 bool XGUI_OperationMgr::onProcessDelete(QObject* theObject)
662 {
663   bool isAccepted = false;
664   ModuleBase_Operation* aOperation = currentOperation();
665   ModuleBase_ModelWidget* anActiveWgt = 0;
666   // firstly the widget should process Delete action
667   ModuleBase_IPropertyPanel* aPanel;
668   bool isPPChildObject = false;
669   if (aOperation) {
670     aPanel = aOperation->propertyPanel();
671     if (aPanel) {
672       isPPChildObject = isChildObject(theObject, aPanel);
673       // process delete in active widget only if delete sender is child of property panel
674       // it is necessary for the case when OB is shown, user perform selection and click Delete
675       if (isPPChildObject) {
676         anActiveWgt = aPanel->activeWidget();
677         if (anActiveWgt) {
678           isAccepted = anActiveWgt->processDelete();
679         }
680       }
681     }
682   }
683   if (!isAccepted) {
684     // after widget, object browser and viewer should process delete
685     /// other widgets such as line edit controls should not lead to
686     /// processing delete by workshop
687     XGUI_ObjectsBrowser* aBrowser = XGUI_Tools::workshop(myWorkshop)->objectBrowser();
688     QWidget* aViewPort = myWorkshop->viewer()->activeViewPort();
689     // property panel child object is processed to process delete performed on Apply button of PP
690     if (theObject == aBrowser->treeView() ||
691         isChildObject(theObject, aViewPort) ||
692         isPPChildObject)
693       XGUI_Tools::workshop(myWorkshop)->deleteObjects();
694     isAccepted = true;
695   }
696
697   return isAccepted;
698 }
699
700 bool XGUI_OperationMgr::isChildObject(const QObject* theObject, const QObject* theParent)
701 {
702   bool isPPChild = false;
703   if (theParent && theObject) {
704     QObject* aParent = (QObject*)theObject;
705     while (aParent ) {
706       isPPChild = aParent == theParent;
707       if (isPPChild)
708         break;
709       aParent = aParent->parent();
710     }
711   }
712   return isPPChild;
713 }