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