Salome HOME
Merge branch 'occ/shaper2smesh'
[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 #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 aFeature = ModelAPI_Feature::feature(aObj);
177         FeaturePtr aCoincident = PartSet_Tools::findFirstCoincidence(aFeature, 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 aCoins, myCoinsideLines) {
196               QString anItemText = aCoins->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       gp_Pnt aP = aPnt->impl<gp_Pnt>();
289       if (theRefPnt->isEqual(aPnt) && (!theOutList.contains(aConstrFeature))) {
290         theOutList.append(aConstrFeature);
291       }
292     }
293   }
294 }
295
296 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
297 {
298   int aId = theAction->data().toInt();
299   FeaturePtr aLine = myCoinsideLines.at(aId);
300   std::shared_ptr<GeomAPI_Pnt2d> aOrig = PartSet_Tools::getCoincedencePoint(mySelectedFeature);
301   if (!aOrig.get())
302     return;
303
304   const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
305
306   QObjectPtrList aToDelFeatures;
307
308   addRefCoincidentFeatures(aRefsList, aOrig, aToDelFeatures);
309
310   const std::list<ResultPtr>& aResults = aLine->results();
311   std::list<ResultPtr>::const_iterator aResIt;
312   for (aResIt = aResults.cbegin(); aResIt != aResults.cend(); aResIt++) {
313     ResultPtr aResult = (*aResIt);
314     const std::set<AttributePtr>& aRefList = aResult->data()->refsToMe();
315     addRefCoincidentFeatures(aRefList, aOrig, aToDelFeatures);
316   }
317   if (aToDelFeatures.size() > 0) {
318     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
319     XGUI_Workshop* aWorkshop = aConnector->workshop();
320     ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
321
322     ModuleBase_Operation* anOpAction =
323       new ModuleBase_Operation(tr("Detach %1").arg(aLine->data()->name().c_str()), myModule);
324     bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
325     XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
326     // the active nested sketch operation should be aborted unconditionally
327     // the Delete action should be additionally granted for the Sketch operation
328     // in order to do not abort/commit it
329     bool isCommitted;
330     if (!anOpMgr->canStartOperation(tr("Detach"), isCommitted))
331       return; // the objects are processed but can not be deleted
332
333     anOpMgr->startOperation(anOpAction);
334     aWorkshop->deleteFeatures(aToDelFeatures);
335
336     anOpMgr->commitOperation();
337   }
338   myCoinsideLines.clear();
339 }
340
341
342 void PartSet_MenuMgr::onDetachMenuHide()
343 {
344   if (myPrevId != -1) {
345     // Restore color for previous object
346     setLineColor(myPrevId, myColor, false);
347   }
348   // Clear previous definitions
349   myPrevId = -1;
350 }
351
352
353 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
354 {
355   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
356
357   CompositeFeaturePtr aSketch = myModule->sketchMgr()->activeSketch();
358   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
359                         myModule->sketchMgr()->isNestedSketchOperation(anOperation);
360   if (!isActiveSketch)
361     return;
362
363   QObjectPtrList anObjects;
364   bool isUseTransaction = false;
365   // 1. change auxiliary type of a created feature
366   if (myModule->sketchMgr()->isNestedCreateOperation(anOperation, aSketch) &&
367       PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
368       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
369                                                                (anOperation);
370       if (aFOperation)
371         anObjects.append(aFOperation->feature());
372   }
373   else {
374     isUseTransaction = true;
375     // 2. change auxiliary type of selected sketch entities
376     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
377     anObjects = aSelection->selectedPresentations();
378   }
379
380   QAction* anAction = action("AUXILIARY_CMD");
381   //SessionPtr aMgr = ModelAPI_Session::get();
382   ModuleBase_Operation* anOpAction = 0;
383   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
384   XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
385   if (isUseTransaction) {
386     anOpAction = new ModuleBase_Operation(anAction->text(), myModule);
387     bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
388
389     bool isCommitted;
390     if (!anOpMgr->canStartOperation(anOpAction->id(), isCommitted))
391       return; // the objects are processed but can not be deleted
392
393     anOpMgr->startOperation(anOpAction);
394   }
395   static const Events_ID anVisualEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
396   if (anObjects.size() > 0) {
397     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
398     for (; anIt != aLast; anIt++) {
399       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
400       if (aFeature.get() != NULL) {
401         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
402                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
403         if (aSketchFeature.get() != NULL) {
404           std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
405
406           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
407             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
408             aSketchFeature->data()->attribute(anAttribute));
409           if (anAuxiliaryAttr)
410             anAuxiliaryAttr->setValue(isChecked);
411           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, anVisualEvent);
412         }
413       }
414     }
415   }
416   if (isUseTransaction)
417     anOpMgr->commitOperation();
418
419   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
420   Events_Loop::loop()->flush(anVisualEvent);
421 }
422
423 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
424 {
425   bool anEnabled = false;
426   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
427
428   CompositeFeaturePtr aSketch = myModule->sketchMgr()->activeSketch();
429   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
430                         myModule->sketchMgr()->isNestedSketchOperation(anOperation);
431   if (!isActiveSketch)
432     return anEnabled;
433
434   QObjectPtrList anObjects;
435   // 1. change auxiliary type of a created feature
436   if (myModule->sketchMgr()->isNestedCreateOperation(anOperation, aSketch) &&
437     PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
438     ModuleBase_OperationFeature* aFOperation =
439       dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
440     if (aFOperation)
441       anObjects.append(aFOperation->feature());
442   }
443   else {
444     /// The operation should not be aborted here, because the method does not changed
445     /// the auxilliary state, but checks the possibility to perform this
446     ///if (myModule->sketchMgr()->isNestedSketchOperation(anOperation))
447     ///  anOperation->abort();
448     // 2. change auxiliary type of selected sketch entities
449     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
450     anObjects = aSelection->selectedPresentations();
451   }
452
453   bool isNotAuxiliaryFound = false;
454   if (anObjects.size() > 0) {
455     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
456     for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
457       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
458       if ((aFeature.get() != NULL) && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
459         anEnabled = true;
460         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
461                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
462         if (aSketchFeature.get() != NULL) {
463           std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
464
465           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
466             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
467             aSketchFeature->data()->attribute(anAttribute));
468           if (anAuxiliaryAttr)
469             isNotAuxiliaryFound = !anAuxiliaryAttr->value();
470         }
471       }
472     }
473   }
474   theValue = anObjects.size() && !isNotAuxiliaryFound;
475   return anEnabled;
476 }
477
478 void PartSet_MenuMgr::onActivatePart(bool)
479 {
480   if (myModule->workshop()->currentOperation())
481     return;
482   QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
483   if (aObjects.size() > 0) {
484     ObjectPtr aObj = aObjects.first();
485     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
486     if (!aPart.get()) {
487       FeaturePtr aPartFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
488       if (aPartFeature.get() && (aPartFeature->getKind() == PartSetPlugin_Part::ID())) {
489         aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeature->firstResult());
490       }
491     }
492     if (aPart.get()) {
493       activatePart(aPart);
494       myModule->workshop()->updateCommandStatus();
495     }
496   }
497 }
498
499 void PartSet_MenuMgr::activatePart(ResultPartPtr thePart) const
500 {
501   bool isFirstLoad = !thePart->partDoc().get();
502   thePart->activate();
503   if (isFirstLoad) {
504     XGUI_Workshop* aWorkshop = myModule->getWorkshop();
505     XGUI_ObjectsBrowser* aObjBrowser = aWorkshop->objectBrowser();
506     DocumentPtr aDoc = thePart->partDoc();
507     std::list<bool> aStates;
508     aDoc->restoreNodesState(aStates);
509     aObjBrowser->setStateForDoc(aDoc, aStates);
510   }
511 }
512
513 void PartSet_MenuMgr::onActivateAllParts()
514 {
515   SessionPtr aMgr = ModelAPI_Session::get();
516   if (aMgr->isOperation())
517     return;
518
519   DocumentPtr aDoc = aMgr->moduleDocument();
520   int aNbParts = aDoc->size(ModelAPI_ResultPart::group());
521   bool isActivated = false;
522   QList<ResultPartPtr> aPartsToLoad;
523   for (int i = 0; i < aNbParts; i++) {
524     ObjectPtr aObj = aDoc->object(ModelAPI_ResultPart::group(), i);
525     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
526     if (!aPartRes->partDoc().get())
527       aPartsToLoad.append(aPartRes);
528   }
529   if (!aPartsToLoad.isEmpty()) {
530     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
531     aMgr->startOperation("All Parts loading");
532     foreach(ResultPartPtr aPartRes, aPartsToLoad) {
533       aPartRes->loadPart();
534     }
535     aMgr->finishOperation();
536
537     XGUI_Workshop* aWorkshop = myModule->getWorkshop();
538     XGUI_ObjectsBrowser* aObjBrowser = aWorkshop->objectBrowser();
539     aObjBrowser->update();
540     aWorkshop->viewer()->update();
541     aWorkshop->updateCommandStatus();
542     QApplication::restoreOverrideCursor();
543   }
544 }
545
546 void PartSet_MenuMgr::onActivatePartSet(bool)
547 {
548   if (myModule->workshop()->currentOperation())
549     return;
550   activatePartSet();
551 }
552
553 void PartSet_MenuMgr::activatePartSet() const
554 {
555   SessionPtr aMgr = ModelAPI_Session::get();
556   bool isNewTransaction = !aMgr->isOperation();
557   // activation may cause changes in current features in document, so it must be in transaction
558   if (isNewTransaction)
559     aMgr->startOperation("Activation");
560   aMgr->setActiveDocument(aMgr->moduleDocument());
561   if (isNewTransaction)
562     aMgr->finishOperation();
563
564   myModule->workshop()->updateCommandStatus();
565   myModule->workshop()->viewer()->update();
566 }
567
568 void PartSet_MenuMgr::grantedOperationIds(ModuleBase_Operation* theOperation,
569                                           QStringList& theIds) const
570 {
571   if (PartSet_SketcherMgr::isSketchOperation(theOperation)) {
572     theIds.append(tr("Detach"));
573     theIds.append(tr("Auxiliary"));
574   }
575 }
576
577 void PartSet_MenuMgr::onEdit(bool)
578 {
579   QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
580   FeaturePtr aFeature;
581   foreach(ObjectPtr aObj, aObjects) {
582     aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
583     if (aFeature.get())
584       break;
585   }
586   if (aFeature.get() == NULL) {
587     ResultParameterPtr aParam;
588     foreach(ObjectPtr aObj, aObjects) {
589       aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObj);
590       if (aParam.get())
591         break;
592     }
593     if (aParam.get() != NULL)
594       aFeature = ModelAPI_Feature::feature(aParam);
595   }
596   if (aFeature.get() != NULL)
597     myModule->editFeature(aFeature);
598 }
599
600 bool PartSet_MenuMgr::eventFilter(QObject* theObj, QEvent* theEvent)
601 {
602   if (theEvent->type() == QEvent::MouseButtonDblClick) {
603     SessionPtr aMgr = ModelAPI_Session::get();
604     if (aMgr->activeDocument() != aMgr->moduleDocument())
605       activatePartSet();
606   }
607   return QObject::eventFilter(theObj, theEvent);
608 }