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