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