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