Salome HOME
Angle presentation from NewGEOM_2.0.0. It is moved here to prepare a patch for OCCT...
[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
198   bool isStarted = theOperation->start();
199   if (isStarted)
200     onValidateOperation();
201   return isStarted;
202 }
203
204 bool XGUI_OperationMgr::abortAllOperations()
205 {
206   bool aResult = true;
207   if(!hasOperation())
208     return aResult;
209
210   if (operationsCount() == 1) {
211     ModuleBase_Operation* aCurrentOperation = currentOperation();
212     if (canStopOperation(aCurrentOperation)) {
213       abortOperation(aCurrentOperation);
214     }
215     else
216       aResult = false;
217   }
218   else {
219     aResult = QMessageBox::question(qApp->activeWindow(),
220                                     tr("Abort operation"),
221                                     tr("All active operations will be aborted."),
222                                     QMessageBox::Ok | QMessageBox::Cancel,
223                                     QMessageBox::Cancel) == QMessageBox::Ok;
224     while(aResult && hasOperation()) {
225       abortOperation(currentOperation());
226     }
227   }
228   return aResult;
229 }
230
231 bool XGUI_OperationMgr::commitAllOperations()
232 {
233   bool isCompositeCommitted = false;
234   while (hasOperation()) {
235     ModuleBase_Operation* anOperation = currentOperation();
236     if (workshop()->errorMgr()->isApplyEnabled()) {
237       onCommitOperation();
238     } else {
239       abortOperation(anOperation);
240     }
241     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
242                                                                             (anOperation);
243     if (aFOperation) {
244       FeaturePtr aFeature = aFOperation->feature();
245       CompositeFeaturePtr aComposite = 
246           std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
247       isCompositeCommitted = aComposite.get();
248       if (isCompositeCommitted)
249         break;
250     }
251   }
252   return true;
253 }
254
255 void XGUI_OperationMgr::onValidateOperation()
256 {
257   if (!hasOperation())
258     return;
259   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
260                                                                           (currentOperation());
261   if(aFOperation && aFOperation->feature().get())
262     workshop()->errorMgr()->updateActions(aFOperation->feature());
263 }
264
265 void XGUI_OperationMgr::updateApplyOfOperations(ModuleBase_Operation* theOperation)
266 {
267   XGUI_ErrorMgr* anErrorMgr = workshop()->errorMgr();
268   if (theOperation) {
269     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
270     if (aFOperation)
271       anErrorMgr->updateAcceptAllAction(aFOperation->feature());
272   }
273   else {
274     foreach(ModuleBase_Operation* anOperation, myOperations) {
275       if (anOperation)
276         updateApplyOfOperations(anOperation);
277     }
278   }
279 }
280
281 bool XGUI_OperationMgr::canStopOperation(ModuleBase_Operation* theOperation)
282 {
283   //in case of nested (sketch) operation no confirmation needed
284   if (isGrantedOperation(theOperation->id()))
285     return true;
286   if (theOperation && theOperation->isModified()) {
287     QString aMessage = tr("%1 operation will be aborted.").arg(theOperation->id());
288     int anAnswer = QMessageBox::question(qApp->activeWindow(),
289                                          tr("Abort operation"),
290                                          aMessage,
291                                          QMessageBox::Ok | QMessageBox::Cancel,
292                                          QMessageBox::Cancel);
293     return anAnswer == QMessageBox::Ok;
294   }
295   return true;
296 }
297
298 bool XGUI_OperationMgr::commitOperation()
299 {
300   if (hasOperation() && currentOperation()->isValid()) {
301     onCommitOperation();
302     return true;
303   }
304   return false;
305 }
306
307 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
308 {
309   theOperation->resume();
310 }
311
312 bool XGUI_OperationMgr::isGrantedOperation(const QString& theId)
313 {
314   bool isGranted = false;
315
316   QListIterator<ModuleBase_Operation*> anIt(myOperations);
317   anIt.toBack();
318   ModuleBase_Operation* aPreviousOperation = 0;
319   while (anIt.hasPrevious() && !isGranted) {
320     ModuleBase_Operation* anOp = anIt.previous();
321     if (anOp)
322       isGranted = anOp->isGranted(theId);
323   }
324   return isGranted;
325 }
326
327 void XGUI_OperationMgr::setCurrentFeature(const FeaturePtr& theFeature)
328 {
329   SessionPtr aMgr = ModelAPI_Session::get();
330   DocumentPtr aDoc = aMgr->activeDocument();
331   bool aIsOp = aMgr->isOperation();
332   if (!aIsOp)
333     aMgr->startOperation();
334   aDoc->setCurrentFeature(theFeature, false);
335   if (!aIsOp)
336     aMgr->finishOperation();
337 }
338
339 bool XGUI_OperationMgr::canStartOperation(const QString& theId)
340 {
341   bool aCanStart = true;
342   ModuleBase_Operation* aCurrentOp = currentOperation();
343   if (aCurrentOp) {
344     bool aGranted = aCurrentOp->isGranted(theId);
345     // the started operation is granted for the current one,
346     // e.g. current - Sketch, started - Line
347     if (aGranted) {
348       aCanStart = true;
349     }
350     else {
351       if (!isGrantedOperation(theId)) {
352         // the operation is not granted in the current list of operations
353         // e.g. Edit Parameter when Sketch, Line in Sketch is active.
354         aCanStart = abortAllOperations();
355       }
356       else if (canStopOperation(aCurrentOp)) {
357         // the started operation is granted in the parrent operation,
358         // e.g. current - Line in Sketch, started Circle 
359         if (workshop()->errorMgr()->isApplyEnabled() && aCurrentOp->isModified())
360           aCurrentOp->commit();
361         else
362           abortOperation(aCurrentOp);
363       } else {
364         aCanStart = false;
365       }
366     }
367   }
368   return aCanStart;
369 }
370
371 void XGUI_OperationMgr::abortOperation(ModuleBase_Operation* theOperation)
372 {
373   ModuleBase_Operation* aCurrentOperation = currentOperation();
374   if (theOperation == aCurrentOperation)
375     theOperation->abort();
376   else {
377     // it is possible to trigger upper operation(e.g. sketch, current is sketch line)
378     // all operation from the current to triggered should also be aborted
379     // operations over the parameter one are not aborted(e.g. extrusion cut, sketch abort)
380     while(hasOperation()) {
381       ModuleBase_Operation* aCurrentOperation = currentOperation();
382       aCurrentOperation->abort();
383       if(theOperation == aCurrentOperation)
384         break;
385     }
386   }
387 }
388
389 void XGUI_OperationMgr::onCommitOperation()
390 {
391   ModuleBase_Operation* anOperation = currentOperation();
392   if (anOperation)
393     anOperation->commit();
394 }
395
396 void XGUI_OperationMgr::onAbortOperation()
397 {
398   ModuleBase_Operation* aCurrentOperation = currentOperation();
399   if (aCurrentOperation && canStopOperation(aCurrentOperation)) {
400     abortOperation(aCurrentOperation);
401   }
402 }
403
404 void XGUI_OperationMgr::onBeforeOperationStarted()
405 {
406   ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
407   if (!aCurrentOperation)
408     return;
409
410   /// Set current feature and remeber old current feature
411   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
412   if (aFOperation) {
413     SessionPtr aMgr = ModelAPI_Session::get();
414     DocumentPtr aDoc = aMgr->activeDocument();
415     // the parameter of current feature should be false, we should use all feature, not only visible
416     // in order to correctly save the previous feature of the nested operation, where the
417     // features can be not visible in the tree. The problem case is Edit sketch entitity(line)
418     // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit.
419     // When sketch entity operation started, the sketch should be cashed here as the current.
420     // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch
421     // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
422     // As a result the sketch disappears from the viewer. However after commit it is displayed back.
423     aFOperation->setPreviousCurrentFeature(aDoc->currentFeature(false));
424
425 #ifdef DEBUG_CURRENT_FEATURE
426     FeaturePtr aFeature = aFOperation->feature();
427     QString aKind = aFeature ? aFeature->getKind().c_str() : "";
428     qDebug(QString("onBeforeOperationStarted(), edit operation = %1, feature = %2")
429             .arg(aFOperation->isEditOperation())
430             .arg(ModuleBase_Tools::objectInfo(aFeature)).toStdString().c_str());
431
432     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
433             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
434 #endif
435
436     if (aFOperation->isEditOperation()) // it should be performed by the feature edit only
437       // in create operation, the current feature is changed by addFeature()
438       aDoc->setCurrentFeature(aFOperation->feature(), false);
439
440 #ifdef DEBUG_CURRENT_FEATURE
441     qDebug("\tdocument->setCurrentFeature");
442     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
443             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
444 #endif
445   ModuleBase_IModule* aModule = myWorkshop->module();
446   if (aModule)
447     aModule->beforeOperationStarted(aFOperation);
448   }
449 }
450
451 void XGUI_OperationMgr::onOperationStarted()
452 {
453   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
454   updateApplyOfOperations(aSenderOperation);
455   emit operationStarted(aSenderOperation);
456 }
457
458 void XGUI_OperationMgr::onBeforeOperationAborted()
459 {
460   onBeforeOperationCommitted();
461 }
462
463 void XGUI_OperationMgr::onOperationAborted()
464 {
465   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
466   emit operationAborted(aSenderOperation);
467 }
468
469 void XGUI_OperationMgr::onBeforeOperationCommitted()
470 {
471   ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
472   if (!aCurrentOperation)
473     return;
474
475   /// Restore the previous current feature
476   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
477   if (aFOperation) {
478 #ifdef DEBUG_CURRENT_FEATURE
479     QString aKind = aFOperation->feature()->getKind().c_str();
480     qDebug(QString("onBeforeOperationCommitted(), edit operation = %1, feature = %2")
481             .arg(aFOperation->isEditOperation())
482             .arg(ModuleBase_Tools::objectInfo(aFOperation->feature())).toStdString().c_str());
483
484     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
485             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
486 #endif
487
488     if (aFOperation->isEditOperation()) {
489       /// Restore the previous current feature
490       setCurrentFeature(aFOperation->previousCurrentFeature());
491     }
492     else { // create operation
493       // the Top created feature should stays the current. In nested operations, like Line in the Sketch or
494       // Sketch in ExtrusionCut, a previous feature should be restored on commit. It is performed here
495       // in order to perform it in the current transaction without opening a new one.
496       if (myOperations.front() != aFOperation)
497         setCurrentFeature(aFOperation->previousCurrentFeature());
498     }
499 #ifdef DEBUG_CURRENT_FEATURE
500     qDebug("\tdocument->setCurrentFeature");
501     qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
502             ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
503 #endif
504     ModuleBase_IModule* aModule = myWorkshop->module();
505     if (aModule)
506       aModule->beforeOperationStopped(aFOperation);
507   }
508 }
509
510 void XGUI_OperationMgr::onOperationCommitted()
511 {
512   // apply state for all features from the stack of operations should be updated
513   updateApplyOfOperations();
514
515   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
516   emit operationCommitted(aSenderOperation);
517 }
518
519 void XGUI_OperationMgr::onOperationResumed()
520 {
521   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
522   emit operationResumed(aSenderOperation);
523 }
524
525 void XGUI_OperationMgr::onOperationStopped()
526 {
527   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
528   ModuleBase_Operation* aCurrentOperation = currentOperation();
529   if (!aSenderOperation || !aCurrentOperation || aSenderOperation != aCurrentOperation)
530     return;
531
532   myOperations.removeAll(aCurrentOperation);
533   aCurrentOperation->deleteLater();
534
535   emit operationStopped(aCurrentOperation);
536
537   // get last operation which can be resumed
538   ModuleBase_Operation* aResultOp = 0;
539   QListIterator<ModuleBase_Operation*> anIt(myOperations);
540   anIt.toBack();
541   while (anIt.hasPrevious()) {
542     ModuleBase_Operation* anOp = anIt.previous();
543     if (anOp) {
544       aResultOp = anOp;
545       break;
546     }
547   }
548   if (aResultOp) {
549     bool isModified = aCurrentOperation->isModified();
550     aResultOp->setIsModified(aResultOp->isModified() || isModified);
551     resumeOperation(aResultOp);
552     onValidateOperation();
553   }
554 }
555
556 bool XGUI_OperationMgr::onKeyReleased(QObject *theObject, QKeyEvent* theEvent)
557 {
558   // Let the manager decide what to do with the given key combination.
559   ModuleBase_Operation* anOperation = currentOperation();
560   bool isAccepted = false;
561   switch (theEvent->key()) {
562     case Qt::Key_Return:
563     case Qt::Key_Enter: {
564       isAccepted = onProcessEnter(theObject);
565     }
566     break;
567     case Qt::Key_N:
568     case Qt::Key_P: {
569       bool noModifiers = (theEvent->modifiers() == Qt::NoModifier);
570       if (noModifiers) {
571         ModuleBase_IViewer* aViewer = myWorkshop->viewer();
572         Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
573         if (!aContext.IsNull()) {
574           Handle(V3d_View) aView = aViewer->activeView();
575           if ((theEvent->key() == Qt::Key_N))
576             aContext->HilightNextDetected(aView);
577           else if ((theEvent->key() == Qt::Key_P))
578             aContext->HilightPreviousDetected(aView);
579         }
580       }
581     }
582     break;
583     break;
584     default:
585       isAccepted = false;
586       break;
587   }
588   //if(anOperation) {
589   //  anOperation->keyReleased(theEvent->key());
590   //}
591   return isAccepted;
592 }
593
594 bool XGUI_OperationMgr::onProcessEnter(QObject* theObject)
595 {
596   bool isAccepted = false;
597   ModuleBase_Operation* aOperation = currentOperation();
598   ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
599   // only property panel enter is processed in order to do not process enter in application dialogs
600   bool isPPChild = isChildObject(theObject, aPanel);
601   if (!isPPChild)
602     return isAccepted;
603
604   ModuleBase_ModelWidget* anActiveWgt = aPanel->activeWidget();
605   bool isAborted = false;
606   if (!anActiveWgt) {
607     QWidget* aFocusWidget = aPanel->focusWidget();
608     QToolButton* aCancelBtn = aPanel->findChild<QToolButton*>(PROP_PANEL_CANCEL);
609     if (aFocusWidget && aCancelBtn && aFocusWidget == aCancelBtn) {
610       abortOperation(aOperation);
611       isAccepted = true;
612       isAborted = true;
613     }
614   }
615   if (!isAborted) {
616     isAccepted = anActiveWgt && anActiveWgt->processEnter();
617     if (!isAccepted) {
618       isAccepted = myWorkshop->module()->processEnter(anActiveWgt ? anActiveWgt->attributeID() : "");
619       if (!isAccepted) {
620         /// functionality is similar to Apply click
621         ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(currentOperation());
622         if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty()) {
623           // key released is emitted to apply the current value to the model if it was modified in PP
624           emit keyEnterReleased();
625           commitOperation();
626           isAccepted = true;
627         }
628         else
629           isAccepted = false;
630       }
631     }
632   }
633   return isAccepted;
634 }
635
636 bool XGUI_OperationMgr::onProcessDelete(QObject* theObject)
637 {
638   bool isAccepted = false;
639   ModuleBase_Operation* aOperation = currentOperation();
640   ModuleBase_ModelWidget* anActiveWgt = 0;
641   // firstly the widget should process Delete action
642   ModuleBase_IPropertyPanel* aPanel;
643   bool isPPChildObject = false;
644   if (aOperation) {
645     aPanel = aOperation->propertyPanel();
646     if (aPanel) {
647       isPPChildObject = isChildObject(theObject, aPanel);
648       // process delete in active widget only if delete sender is child of property panel
649       // it is necessary for the case when OB is shown, user perform selection and click Delete
650       if (isPPChildObject) {
651         anActiveWgt = aPanel->activeWidget();
652         if (anActiveWgt) {
653           isAccepted = anActiveWgt->processDelete();
654         }
655       }
656     }
657   }
658   if (!isAccepted) {
659     // after widget, object browser and viewer should process delete
660     /// other widgets such as line edit controls should not lead to
661     /// processing delete by workshop
662     XGUI_ObjectsBrowser* aBrowser = workshop()->objectBrowser();
663     QWidget* aViewPort = myWorkshop->viewer()->activeViewPort();
664     // property panel child object is processed to process delete performed on Apply button of PP
665     if (theObject == aBrowser->treeView() ||
666         isChildObject(theObject, aViewPort) ||
667         isPPChildObject)
668       workshop()->deleteObjects();
669     isAccepted = true;
670   }
671
672   return isAccepted;
673 }
674
675 XGUI_Workshop* XGUI_OperationMgr::workshop() const
676 {
677   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
678   return aConnector->workshop();
679 }
680
681 bool XGUI_OperationMgr::isChildObject(const QObject* theObject, const QObject* theParent)
682 {
683   bool isPPChild = false;
684   if (theParent && theObject) {
685     QObject* aParent = (QObject*)theObject;
686     while (aParent ) {
687       isPPChild = aParent == theParent;
688       if (isPPChild)
689         break;
690       aParent = aParent->parent();
691     }
692   }
693   return isPPChild;
694 }