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