Salome HOME
Update viewer on activation of PartSet
[modules/shaper.git] / src / PartSet / PartSet_MenuMgr.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "PartSet_MenuMgr.h"
21 #include "PartSet_Module.h"
22 #include "PartSet_SketcherMgr.h"
23 #include "PartSet_Tools.h"
24
25 #include <PartSetPlugin_Part.h>
26
27 #include <GeomAPI_Pnt2d.h>
28 #include <GeomDataAPI_Point2D.h>
29
30 #include <SketchPlugin_ConstraintCoincidence.h>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Circle.h>
33 #include <SketchPlugin_Point.h>
34 #include <SketchPlugin_Sketch.h>
35
36 #include <ModuleBase_ISelection.h>
37 #include <ModuleBase_Operation.h>
38 #include <ModuleBase_OperationFeature.h>
39 #include <ModuleBase_ViewerPrs.h>
40 #include <ModuleBase_IViewer.h>
41 #include <ModuleBase_Tools.h>
42
43 #include <XGUI_ModuleConnector.h>
44 #include <XGUI_Workshop.h>
45 #include <XGUI_Displayer.h>
46 #include <XGUI_DataModel.h>
47 #include <XGUI_OperationMgr.h>
48 #include <XGUI_ObjectsBrowser.h>
49
50 #include <Events_Loop.h>
51 #include <ModelAPI_Events.h>
52 #include <ModelAPI_Session.h>
53 #include <ModelAPI_ResultParameter.h>
54
55 #include <QMainWindow>
56 #include <QAction>
57 #include <QMenu>
58 #include <QEvent>
59
60 #include <TopoDS.hxx>
61 #include <BRep_Tool.hxx>
62
63 PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
64   : QObject(theModule), myModule(theModule), myPrevId(-1)
65 {
66   createActions();
67 }
68
69
70 QAction* PartSet_MenuMgr::action(const QString& theId) const
71 {
72   if (myActions.contains(theId))
73     return myActions[theId];
74   return 0;
75 }
76
77 void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
78 {
79   if (myActions.contains(theId))
80     qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
81   theAction->setData(theId);
82   connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
83   myActions[theId] = theAction;
84 }
85
86 void PartSet_MenuMgr::createActions()
87 {
88   QAction* aAction;
89
90   QWidget* aParent = myModule->workshop()->desktop();
91   aAction = ModuleBase_Tools::createAction(QIcon(), tr("Auxiliary"), aParent);
92   aAction->setCheckable(true);
93   addAction("AUXILIARY_CMD", aAction);
94
95   aAction = ModuleBase_Tools::createAction(QIcon(":icons/activate.png"), tr("Activate"), aParent,
96                                            this, SLOT(onActivatePart(bool)));
97   myActions["ACTIVATE_PART_CMD"] = aAction;
98
99   // Activate PartSet
100   aAction = ModuleBase_Tools::createAction(QIcon(":icons/activate.png"), tr("Activate"), aParent,
101                         this, SLOT(onActivatePartSet(bool)));
102   myActions["ACTIVATE_PARTSET_CMD"] = aAction;
103
104   aAction = ModuleBase_Tools::createAction(QIcon(":icons/edit.png"), tr("Edit..."), aParent,
105                          this, SLOT(onEdit(bool)));
106   myActions["EDIT_CMD"] = aAction;
107 }
108
109
110 void PartSet_MenuMgr::onAction(bool isChecked)
111 {
112   QAction* aAction = static_cast<QAction*>(sender());
113   QString anId = aAction->data().toString();
114
115   if (anId == "AUXILIARY_CMD") {
116     setAuxiliary(isChecked);
117   }
118 }
119
120 bool PartSet_MenuMgr::addViewerMenu(const QMap<QString, QAction*>& theStdActions,
121                                     QWidget* theParent,
122                                     QMap<int, QAction*>& theMenuActions) const
123 {
124   int anIndex = 0;
125
126   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
127   if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
128       !myModule->sketchMgr()->isNestedSketchOperation(anOperation))
129     return false;
130
131   myCoinsideLines.clear();
132   ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
133
134   bool aIsDetach = false;
135   bool hasAttribute = false;
136   bool hasFeature = false;
137
138   QList<ModuleBase_ViewerPrsPtr> aPrsList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
139   if (aPrsList.size() > 1) {
140     hasFeature = true;
141   } else if (aPrsList.size() == 1) {
142     ResultPtr aResult;
143     FeaturePtr aFeature;
144     foreach(ModuleBase_ViewerPrsPtr aPrs, aPrsList) {
145       aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
146       if (aResult.get() != NULL) {
147         const GeomShapePtr& aShape = aPrs->shape();
148         if (aShape.get() && aShape->isEqual(aResult->shape()))
149           hasFeature = true;
150         else
151           hasAttribute = true;
152       } else {
153         aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs->object());
154         hasFeature = (aFeature.get() != NULL);
155       }
156     }
157
158     const GeomShapePtr& aShape = aPrsList.first()->shape();
159     if (aShape.get() && !aShape->isNull() && aShape->shapeType() == GeomAPI_Shape::VERTEX) {
160       // Find 2d coordinates
161       FeaturePtr aSketchFea = myModule->sketchMgr()->activeSketch();
162       if (aSketchFea->getKind() == SketchPlugin_Sketch::ID()) {
163         const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
164         gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aTDShape));
165         std::shared_ptr<GeomAPI_Pnt> aPnt3d(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
166         std::shared_ptr<GeomAPI_Pnt2d> aSelPnt = PartSet_Tools::convertTo2D(aSketchFea, aPnt3d);
167
168         // Find coincident in these coordinates
169         ObjectPtr aObj = aPrsList.first()->object();
170         FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
171         FeaturePtr aCoincident = PartSet_Tools::findFirstCoincidence(aFeature, aSelPnt);
172         // If we have coincidence then add Detach menu
173         if (aCoincident.get() != NULL) {
174           QList<FeaturePtr> aCoins;
175           mySelectedFeature = aCoincident;
176           QList<bool> anIsAttributes;
177           PartSet_Tools::findCoincidences(mySelectedFeature, myCoinsideLines, aCoins,
178                                           SketchPlugin_ConstraintCoincidence::ENTITY_A(),
179                                           anIsAttributes);
180           PartSet_Tools::findCoincidences(mySelectedFeature, myCoinsideLines, aCoins,
181                                           SketchPlugin_ConstraintCoincidence::ENTITY_B(),
182                                           anIsAttributes);
183           if (myCoinsideLines.size() > 0) {
184             aIsDetach = true;
185             QMenu* aSubMenu = new QMenu(tr("Detach"), theParent);
186             theMenuActions[anIndex++] = aSubMenu->menuAction();
187             QAction* aAction;
188             int i = 0;
189             foreach (FeaturePtr aCoins, myCoinsideLines) {
190               QString anItemText = aCoins->data()->name().c_str();
191 #ifdef _DEBUG
192               if (anIsAttributes[i])
193                 anItemText += " [attribute]";
194 #endif
195               aAction = aSubMenu->addAction(anItemText);
196               aAction->setData(QVariant(i));
197               i++;
198             }
199             connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
200             connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
201             connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
202           }
203         }
204       }
205     }
206   }
207   if (!hasAttribute) {
208     bool isAuxiliary;
209     if (canSetAuxiliary(isAuxiliary)) {
210       QAction* anAction = action("AUXILIARY_CMD");
211       theMenuActions[anIndex++] = anAction;
212       anAction->setChecked(isAuxiliary);
213     }
214   }
215
216   if (!aIsDetach && hasFeature) {
217     // Delete item should be the last in the list of actions
218     theMenuActions[1000] = theStdActions["DELETE_CMD"];
219   }
220
221   return true;
222 }
223
224 void PartSet_MenuMgr::updateViewerMenu(const QMap<QString, QAction*>& theStdActions)
225 {
226   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
227
228   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
229                         myModule->sketchMgr()->isNestedSketchOperation(anOperation);
230   if (isActiveSketch) {
231     theStdActions["WIREFRAME_CMD"]->setEnabled(false);
232     theStdActions["SHADING_CMD"]->setEnabled(false);
233     theStdActions["SHOW_ONLY_CMD"]->setEnabled(false);
234     theStdActions["SHOW_CMD"]->setEnabled(false);
235     theStdActions["HIDE_CMD"]->setEnabled(false);
236     theStdActions["HIDEALL_CMD"]->setEnabled(false);
237   }
238 }
239
240
241 void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
242 {
243   if (myPrevId != -1) {
244     // Restore color for previous object
245     setLineColor(myPrevId, myColor, false);
246   }
247   myPrevId = theAction->data().toInt();
248   myColor = setLineColor(myPrevId, Qt::white, true);
249 }
250
251 QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
252 {
253   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
254   XGUI_Workshop* aWorkshop = aConnector->workshop();
255   XGUI_Displayer* aDisplayer = aWorkshop->displayer();
256
257   FeaturePtr aLine = myCoinsideLines.at(myPrevId);
258   std::list<ResultPtr>::const_iterator aIt;
259   const std::list<ResultPtr>& aResults = aLine->results();
260   QColor aColor;
261   for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
262     aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
263   }
264   if (theUpdate)
265     aDisplayer->updateViewer();
266   return aColor;
267 }
268
269
270 void addRefCoincidentFeatures(const std::set<AttributePtr>& theRefList,
271   std::shared_ptr<GeomAPI_Pnt2d>& theRefPnt,
272   QObjectPtrList& theOutList)
273 {
274   std::set<AttributePtr>::const_iterator aIt;
275   for (aIt = theRefList.cbegin(); aIt != theRefList.cend(); ++aIt) {
276     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
277     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
278     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
279       std::shared_ptr<GeomAPI_Pnt2d> aPnt = PartSet_Tools::getCoincedencePoint(aConstrFeature);
280       if (aPnt.get() == NULL)
281         return;
282       gp_Pnt aP = aPnt->impl<gp_Pnt>();
283       if (theRefPnt->isEqual(aPnt) && (!theOutList.contains(aConstrFeature))) {
284         theOutList.append(aConstrFeature);
285       }
286     }
287   }
288 }
289
290 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
291 {
292   int aId = theAction->data().toInt();
293   FeaturePtr aLine = myCoinsideLines.at(aId);
294   std::shared_ptr<GeomAPI_Pnt2d> aOrig = PartSet_Tools::getCoincedencePoint(mySelectedFeature);
295   if (!aOrig.get())
296     return;
297
298   const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
299
300   QObjectPtrList aToDelFeatures;
301
302   addRefCoincidentFeatures(aRefsList, aOrig, aToDelFeatures);
303
304   const std::list<ResultPtr>& aResults = aLine->results();
305   std::list<ResultPtr>::const_iterator aResIt;
306   for (aResIt = aResults.cbegin(); aResIt != aResults.cend(); aResIt++) {
307     ResultPtr aResult = (*aResIt);
308     const std::set<AttributePtr>& aRefList = aResult->data()->refsToMe();
309     addRefCoincidentFeatures(aRefList, aOrig, aToDelFeatures);
310   }
311   if (aToDelFeatures.size() > 0) {
312     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
313     XGUI_Workshop* aWorkshop = aConnector->workshop();
314     ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
315
316     ModuleBase_Operation* anOpAction =
317       new ModuleBase_Operation(tr("Detach %1").arg(aLine->data()->name().c_str()), myModule);
318     bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
319     XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
320     // the active nested sketch operation should be aborted unconditionally
321     // the Delete action should be additionally granted for the Sketch operation
322     // in order to do not abort/commit it
323     bool isCommitted;
324     if (!anOpMgr->canStartOperation(tr("Detach"), isCommitted))
325       return; // the objects are processed but can not be deleted
326
327     anOpMgr->startOperation(anOpAction);
328     aWorkshop->deleteFeatures(aToDelFeatures);
329
330     anOpMgr->commitOperation();
331   }
332   myCoinsideLines.clear();
333 }
334
335
336 void PartSet_MenuMgr::onDetachMenuHide()
337 {
338   if (myPrevId != -1) {
339     // Restore color for previous object
340     setLineColor(myPrevId, myColor, false);
341   }
342   // Clear previous definitions
343   myPrevId = -1;
344 }
345
346
347 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
348 {
349   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
350
351   CompositeFeaturePtr aSketch = myModule->sketchMgr()->activeSketch();
352   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
353                         myModule->sketchMgr()->isNestedSketchOperation(anOperation);
354   if (!isActiveSketch)
355     return;
356
357   QObjectPtrList anObjects;
358   bool isUseTransaction = false;
359   // 1. change auxiliary type of a created feature
360   if (myModule->sketchMgr()->isNestedCreateOperation(anOperation, aSketch) &&
361       PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
362       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
363                                                                (anOperation);
364       if (aFOperation)
365         anObjects.append(aFOperation->feature());
366   }
367   else {
368     isUseTransaction = true;
369     // 2. change auxiliary type of selected sketch entities
370     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
371     anObjects = aSelection->selectedPresentations();
372   }
373
374   QAction* anAction = action("AUXILIARY_CMD");
375   //SessionPtr aMgr = ModelAPI_Session::get();
376   ModuleBase_Operation* anOpAction = 0;
377   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
378   XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
379   if (isUseTransaction) {
380     anOpAction = new ModuleBase_Operation(anAction->text(), myModule);
381     bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
382
383     bool isCommitted;
384     if (!anOpMgr->canStartOperation(anOpAction->id(), isCommitted))
385       return; // the objects are processed but can not be deleted
386
387     anOpMgr->startOperation(anOpAction);
388   }
389   static const Events_ID anVisualEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
390   if (anObjects.size() > 0) {
391     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
392     for (; anIt != aLast; anIt++) {
393       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
394       if (aFeature.get() != NULL) {
395         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
396                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
397         if (aSketchFeature.get() != NULL) {
398           std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
399
400           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
401             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
402             aSketchFeature->data()->attribute(anAttribute));
403           if (anAuxiliaryAttr)
404             anAuxiliaryAttr->setValue(isChecked);
405           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, anVisualEvent);
406         }
407       }
408     }
409   }
410   if (isUseTransaction)
411     anOpMgr->commitOperation();
412
413   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
414   Events_Loop::loop()->flush(anVisualEvent);
415 }
416
417 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
418 {
419   bool anEnabled = false;
420   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
421
422   CompositeFeaturePtr aSketch = myModule->sketchMgr()->activeSketch();
423   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
424                         myModule->sketchMgr()->isNestedSketchOperation(anOperation);
425   if (!isActiveSketch)
426     return anEnabled;
427
428   QObjectPtrList anObjects;
429   // 1. change auxiliary type of a created feature
430   if (myModule->sketchMgr()->isNestedCreateOperation(anOperation, aSketch) &&
431     PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
432     ModuleBase_OperationFeature* aFOperation =
433       dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
434     if (aFOperation)
435       anObjects.append(aFOperation->feature());
436   }
437   else {
438     /// The operation should not be aborted here, because the method does not changed
439     /// the auxilliary state, but checks the possibility to perform this
440     ///if (myModule->sketchMgr()->isNestedSketchOperation(anOperation))
441     ///  anOperation->abort();
442     // 2. change auxiliary type of selected sketch entities
443     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
444     anObjects = aSelection->selectedPresentations();
445   }
446
447   bool isNotAuxiliaryFound = false;
448   if (anObjects.size() > 0) {
449     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
450     for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
451       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
452       if ((aFeature.get() != NULL) && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
453         anEnabled = true;
454         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
455                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
456         if (aSketchFeature.get() != NULL) {
457           std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
458
459           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
460             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
461             aSketchFeature->data()->attribute(anAttribute));
462           if (anAuxiliaryAttr)
463             isNotAuxiliaryFound = !anAuxiliaryAttr->value();
464         }
465       }
466     }
467   }
468   theValue = anObjects.size() && !isNotAuxiliaryFound;
469   return anEnabled;
470 }
471
472 void PartSet_MenuMgr::onActivatePart(bool)
473 {
474   if (myModule->workshop()->currentOperation())
475     return;
476   QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
477   if (aObjects.size() > 0) {
478     ObjectPtr aObj = aObjects.first();
479     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
480     if (!aPart.get()) {
481       FeaturePtr aPartFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
482       if (aPartFeature.get() && (aPartFeature->getKind() == PartSetPlugin_Part::ID())) {
483         aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeature->firstResult());
484       }
485     }
486     if (aPart.get()) {
487       activatePart(aPart);
488       myModule->workshop()->updateCommandStatus();
489     }
490   }
491 }
492
493 void PartSet_MenuMgr::activatePart(ResultPartPtr thePart) const
494 {
495   bool isFirstLoad = !thePart->partDoc().get();
496   thePart->activate();
497   if (isFirstLoad) {
498     XGUI_Workshop* aWorkshop = myModule->getWorkshop();
499     XGUI_ObjectsBrowser* aObjBrowser = aWorkshop->objectBrowser();
500     DocumentPtr aDoc = thePart->partDoc();
501     std::list<bool> aStates;
502     aDoc->restoreNodesState(aStates);
503     aObjBrowser->setStateForDoc(aDoc, aStates);
504   }
505 }
506
507 void PartSet_MenuMgr::onActivatePartSet(bool)
508 {
509   if (myModule->workshop()->currentOperation())
510     return;
511   activatePartSet();
512 }
513
514 void PartSet_MenuMgr::activatePartSet() const
515 {
516   SessionPtr aMgr = ModelAPI_Session::get();
517   bool isNewTransaction = !aMgr->isOperation();
518   // activation may cause changes in current features in document, so it must be in transaction
519   if (isNewTransaction)
520     aMgr->startOperation("Activation");
521   aMgr->setActiveDocument(aMgr->moduleDocument());
522   if (isNewTransaction)
523     aMgr->finishOperation();
524
525   myModule->workshop()->updateCommandStatus();
526   myModule->workshop()->viewer()->update();
527 }
528
529 void PartSet_MenuMgr::grantedOperationIds(ModuleBase_Operation* theOperation,
530                                           QStringList& theIds) const
531 {
532   if (PartSet_SketcherMgr::isSketchOperation(theOperation)) {
533     theIds.append(tr("Detach"));
534     theIds.append(tr("Auxiliary"));
535   }
536 }
537
538 void PartSet_MenuMgr::onEdit(bool)
539 {
540   QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
541   FeaturePtr aFeature;
542   foreach(ObjectPtr aObj, aObjects) {
543     aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
544     if (aFeature.get())
545       break;
546   }
547   if (aFeature.get() == NULL) {
548     ResultParameterPtr aParam;
549     foreach(ObjectPtr aObj, aObjects) {
550       aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObj);
551       if (aParam.get())
552         break;
553     }
554     if (aParam.get() != NULL)
555       aFeature = ModelAPI_Feature::feature(aParam);
556   }
557   if (aFeature.get() != NULL)
558     myModule->editFeature(aFeature);
559 }
560
561 bool PartSet_MenuMgr::eventFilter(QObject* theObj, QEvent* theEvent)
562 {
563   if (theEvent->type() == QEvent::MouseButtonDblClick) {
564     SessionPtr aMgr = ModelAPI_Session::get();
565     if (aMgr->activeDocument() != aMgr->moduleDocument())
566       activatePartSet();
567   }
568   return QObject::eventFilter(theObj, theEvent);
569 }