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