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