Salome HOME
ModuleBase_ViewerPrs is wrapped into shared_ptr.
[modules/shaper.git] / src / XGUI / XGUI_ContextMenuMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #include "XGUI_ContextMenuMgr.h"
4 #include "XGUI_Workshop.h"
5 #include "XGUI_ObjectsBrowser.h"
6 #include "XGUI_SelectionMgr.h"
7 #include "XGUI_Displayer.h"
8 #include "XGUI_ViewerProxy.h"
9 #include "XGUI_Selection.h"
10 #include "XGUI_SalomeConnector.h"
11 #include "XGUI_DataModel.h"
12 #include "XGUI_OperationMgr.h"
13 #include "XGUI_Tools.h"
14
15 #ifndef HAVE_SALOME
16 #include <AppElements_MainWindow.h>
17 #endif
18
19 //#include "PartSetPlugin_Part.h"
20
21 #include <ModelAPI_Data.h>
22 #include <ModelAPI_AttributeDocRef.h>
23 #include <ModelAPI_Object.h>
24 #include <ModelAPI_Session.h>
25 #include <ModelAPI_ResultGroup.h>
26 #include <ModelAPI_ResultParameter.h>
27 #include <ModelAPI_ResultConstruction.h>
28 #include <ModelAPI_ResultBody.h>
29 #include <ModelAPI_Tools.h>
30
31 #include <ModuleBase_IModule.h>
32 #include <ModuleBase_Tools.h>
33 #include <ModuleBase_OperationAction.h>
34
35 #include <QAction>
36 #include <QActionGroup>
37 #include <QContextMenuEvent>
38 #include <QMenu>
39 #include <QMdiArea>
40 #include <QMainWindow>
41
42
43 XGUI_ContextMenuMgr::XGUI_ContextMenuMgr(XGUI_Workshop* theParent)
44     : QObject(theParent),
45       myWorkshop(theParent),
46       mySeparator(0)
47 {
48 }
49
50 XGUI_ContextMenuMgr::~XGUI_ContextMenuMgr()
51 {
52 }
53
54 void XGUI_ContextMenuMgr::createActions()
55 {
56 #ifdef HAVE_SALOME
57   QMainWindow* aDesktop = myWorkshop->salomeConnector()->desktop();
58 #else
59   QMainWindow* aDesktop = myWorkshop->mainWindow();
60 #endif
61
62   QAction* aAction = new QAction(QIcon(":pictures/delete.png"), tr("Delete"), this);
63   aDesktop->addAction(aAction);
64
65   addAction("DELETE_CMD", aAction);
66   aAction->setShortcutContext(Qt::ApplicationShortcut);
67
68   aAction = new QAction(QIcon(":pictures/rename_edit.png"), tr("Rename"), this);
69   addAction("RENAME_CMD", aAction);
70   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRename()));
71
72   aAction = new QAction(QIcon(":pictures/move.png"), XGUI_Workshop::MOVE_TO_END_COMMAND, this);
73   addAction("MOVE_CMD", aAction);
74
75   aAction = new QAction(QIcon(":pictures/clean_history.png"), tr("Clean history"), this);
76   addAction("CLEAN_HISTORY_CMD", aAction);
77
78   aAction = new QAction(QIcon(":pictures/color.png"), tr("Color..."), this);
79   addAction("COLOR_CMD", aAction);
80
81   aAction = new QAction(QIcon(":pictures/eye_pencil.png"), tr("Show"), this);
82   addAction("SHOW_CMD", aAction);
83
84   aAction = new QAction(QIcon(":pictures/eye_pencil.png"), tr("Show only"), this);
85   addAction("SHOW_ONLY_CMD", aAction);
86
87   aAction = new QAction(QIcon(":pictures/eye_pencil_closed.png"), tr("Hide"), this);
88   addAction("HIDE_CMD", aAction);
89
90   aAction = new QAction(QIcon(":pictures/eye_pencil_closed.png"), tr("Hide all"), this);
91   addAction("HIDEALL_CMD", aAction);
92
93   aAction = new QAction(QIcon(":pictures/shading.png"), tr("Shading"), this);
94   addAction("SHADING_CMD", aAction);
95
96   aAction = new QAction(QIcon(":pictures/wireframe.png"), tr("Wireframe"), this);
97   addAction("WIREFRAME_CMD", aAction);
98
99   mySeparator = new QAction(this);
100   mySeparator->setSeparator(true);
101
102   mySelectActions = new QActionGroup(this);
103   mySelectActions->setExclusive(true);
104
105   aAction = new QAction(QIcon(":pictures/vertex.png"), tr("Vertices"), this);
106   aAction->setCheckable(true);
107   addAction("SELECT_VERTEX_CMD", aAction);
108   mySelectActions->addAction(aAction);
109
110   aAction = new QAction(QIcon(":pictures/edge.png"), tr("Edges"), this);
111   aAction->setCheckable(true);
112   addAction("SELECT_EDGE_CMD", aAction);
113   mySelectActions->addAction(aAction);
114
115   aAction = new QAction(QIcon(":pictures/face.png"), tr("Faces"), this);
116   aAction->setCheckable(true);
117   addAction("SELECT_FACE_CMD", aAction);
118   mySelectActions->addAction(aAction);
119
120   aAction = new QAction(QIcon(":pictures/result.png"), tr("Result"), this);
121   aAction->setCheckable(true);
122   addAction("SELECT_RESULT_CMD", aAction);
123   mySelectActions->addAction(aAction);
124
125   aAction->setChecked(true);
126
127   buildObjBrowserMenu();
128   buildViewerMenu();
129 }
130
131 void XGUI_ContextMenuMgr::addAction(const QString& theId, QAction* theAction)
132 {
133   if (myActions.contains(theId))
134     qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
135   theAction->setData(theId);
136   connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
137   myActions[theId] = theAction;
138 }
139
140 QAction* XGUI_ContextMenuMgr::action(const QString& theId) const
141 {
142   if (myActions.contains(theId))
143     return myActions[theId];
144   return 0;
145 }
146
147 QAction* XGUI_ContextMenuMgr::actionByName(const QString& theName) const
148 {
149   foreach(QAction* eachAction, myActions) {
150     if (eachAction->text() == theName) {
151       return eachAction;
152     }
153   }
154   return NULL;
155 }
156
157 QStringList XGUI_ContextMenuMgr::actionIds() const
158 {
159   return myActions.keys();
160 }
161
162 void XGUI_ContextMenuMgr::onAction(bool isChecked)
163 {
164   QAction* aAction = static_cast<QAction*>(sender());
165   emit actionTriggered(aAction->data().toString(), isChecked);
166 }
167
168 void XGUI_ContextMenuMgr::updateCommandsStatus()
169 {
170 }
171
172 void XGUI_ContextMenuMgr::onContextMenuRequest(QContextMenuEvent* theEvent)
173 {
174   QMenu* aMenu = new QMenu();
175   if (sender() == myWorkshop->objectBrowser()) {
176     updateObjectBrowserMenu();
177     addObjBrowserMenu(aMenu);
178   } else if (sender() == myWorkshop->viewer()) {
179     updateViewerMenu();
180     addViewerMenu(aMenu);
181   }
182
183   if (aMenu && (aMenu->actions().size() > 0)) {
184     // it is possible that some objects should do something before and after the popup menu exec
185     // e.g. a sketch manager changes an internal flag on this signals in order to do not hide
186     // a created entity
187     emit beforeContextMenu();
188     aMenu->exec(theEvent->globalPos());
189     emit afterContextMenu();
190     delete aMenu;
191   }
192 }
193
194 void XGUI_ContextMenuMgr::updateObjectBrowserMenu() 
195 {
196   foreach(QAction* aAction, myActions)
197     aAction->setEnabled(false);
198
199   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
200   QObjectPtrList aObjects = aSelMgr->selection()->selectedObjects();
201   int aSelected = aObjects.size();
202   if (aSelected > 0) {
203     SessionPtr aMgr = ModelAPI_Session::get();
204     XGUI_Displayer* aDisplayer = myWorkshop->displayer();
205     bool hasResult = false;
206     bool hasFeature = false;
207     bool hasParameter = false;
208     bool hasSubFeature = false;
209     ModuleBase_Tools::checkObjects(aObjects, hasResult, hasFeature, hasParameter, hasSubFeature);
210
211     //Process Feature
212     if (aSelected == 1) {
213       ObjectPtr aObject = aObjects.first();
214       if (aObject) {
215         if (hasResult && myWorkshop->canBeShaded(aObject)) {
216           XGUI_Displayer::DisplayMode aMode = aDisplayer->displayMode(aObject);
217           if (aMode != XGUI_Displayer::NoMode) {
218             action("WIREFRAME_CMD")->setEnabled(aMode == XGUI_Displayer::Shading);
219             action("SHADING_CMD")->setEnabled(aMode == XGUI_Displayer::Wireframe);
220           } else {
221             action("WIREFRAME_CMD")->setEnabled(true);
222             action("SHADING_CMD")->setEnabled(true);
223           }
224         }
225         if (!hasFeature) {
226           bool aHasSubResults = ModelAPI_Tools::hasSubResults(
227                                             std::dynamic_pointer_cast<ModelAPI_Result>(aObject));
228           if (aHasSubResults) {
229             action("HIDE_CMD")->setEnabled(true);
230             action("SHOW_CMD")->setEnabled(true);
231           }
232           else {
233             if (aObject->isDisplayed()) {
234               action("HIDE_CMD")->setEnabled(true);
235             } else if (hasResult && (!hasParameter)) {
236               action("SHOW_CMD")->setEnabled(true);
237             }
238           }
239           if (!(hasParameter || hasFeature))
240             action("SHOW_ONLY_CMD")->setEnabled(true);
241         }
242         else if (hasFeature && myWorkshop->canMoveFeature())
243           action("MOVE_CMD")->setEnabled(true);
244
245         else if (hasFeature || hasParameter)
246           action("CLEAN_HISTORY_CMD")->setEnabled(!hasSubFeature);
247
248         if( aMgr->activeDocument() == aObject->document() )
249         {
250           action("RENAME_CMD")->setEnabled(true);
251           action("DELETE_CMD")->setEnabled(!hasSubFeature);
252         }
253       }
254     } else {
255       // parameter is commented because the actions are not in the list of result parameter actions
256       if (hasResult /*&& (!hasParameter)*/) {
257         action("SHOW_CMD")->setEnabled(true);
258         action("HIDE_CMD")->setEnabled(true);
259         action("SHOW_ONLY_CMD")->setEnabled(true);
260         action("SHADING_CMD")->setEnabled(true);
261         action("WIREFRAME_CMD")->setEnabled(true);
262       }
263     }
264     bool allActive = true;
265     foreach( ObjectPtr aObject, aObjects )
266       if( aMgr->activeDocument() != aObject->document() )  {
267         allActive = false;
268         break;
269       }
270     if (!hasSubFeature && allActive ) {
271       if (hasFeature || hasParameter)
272         action("DELETE_CMD")->setEnabled(true);
273     }
274     if (!hasSubFeature && allActive && (hasFeature|| hasParameter))
275       action("CLEAN_HISTORY_CMD")->setEnabled(true);
276   }
277
278   // Show/Hide command has to be disabled for objects from non active document
279   bool aDeactivate = false;
280   foreach (ObjectPtr aObj, aObjects) {
281     if (!aObj->document()->isActive()) {
282       if ((aObj->document() != ModelAPI_Session::get()->moduleDocument()) ||
283            aObj->groupName() == ModelAPI_ResultPart::group()) {
284         aDeactivate = true;
285         break;
286       }
287     }
288   }
289   if (aDeactivate) {
290     // If at leas a one objec can not be edited then Show/Hide has to be disabled
291     action("SHOW_CMD")->setEnabled(false);
292     action("HIDE_CMD")->setEnabled(false);
293     action("SHOW_ONLY_CMD")->setEnabled(false);
294   }
295
296   if (myWorkshop->canChangeColor())
297     action("COLOR_CMD")->setEnabled(true);
298
299   ModuleBase_IModule* aModule = myWorkshop->module();
300   if (aModule)
301     aModule->updateObjectBrowserMenu(myActions);
302 }
303
304 void XGUI_ContextMenuMgr::updateViewerMenu()
305 {
306   foreach(QAction* aAction, myActions)
307     aAction->setEnabled(false);
308
309   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
310   XGUI_Displayer* aDisplayer = myWorkshop->displayer();
311   QList<ModuleBase_ViewerPrsPtr> aPrsList = aSelMgr->selection()->getSelected(ModuleBase_ISelection::Viewer);
312   if (aPrsList.size() > 0) {
313     bool isVisible = false;
314     bool isShading = false;
315     bool canBeShaded = false;
316     ObjectPtr aObject;
317     foreach(ModuleBase_ViewerPrsPtr aPrs, aPrsList) {
318       aObject = aPrs->object();
319       ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObject);
320       if (aRes && aRes->isDisplayed()) {
321         isVisible = true;
322         canBeShaded = myWorkshop->displayer()->canBeShaded(aObject);
323         isShading = (myWorkshop->displayer()->displayMode(aObject) == XGUI_Displayer::Shading);      
324         break;
325       }
326     }
327     if (isVisible) {
328       if (canBeShaded) {
329         XGUI_Displayer::DisplayMode aMode = aDisplayer->displayMode(aObject);
330         if (aMode != XGUI_Displayer::NoMode) {
331           action("WIREFRAME_CMD")->setEnabled(aMode == XGUI_Displayer::Shading);
332           action("SHADING_CMD")->setEnabled(aMode == XGUI_Displayer::Wireframe);
333         } else {
334           action("WIREFRAME_CMD")->setEnabled(true);
335           action("SHADING_CMD")->setEnabled(true);
336         }
337       }
338       action("SHOW_ONLY_CMD")->setEnabled(true);
339       action("HIDE_CMD")->setEnabled(true);
340     } else
341       action("SHOW_CMD")->setEnabled(true);
342   }
343   if (myWorkshop->displayer()->objectsCount() > 0)
344     action("HIDEALL_CMD")->setEnabled(true);
345   if (myWorkshop->canChangeColor())
346     action("COLOR_CMD")->setEnabled(true);
347
348   action("DELETE_CMD")->setEnabled(true);
349
350   // Update selection menu
351   QIntList aModes = aDisplayer->activeSelectionModes();
352   if (aModes.count() <= 1) {
353     action("SELECT_VERTEX_CMD")->setEnabled(true);
354     action("SELECT_EDGE_CMD")->setEnabled(true);
355     action("SELECT_FACE_CMD")->setEnabled(true);
356     action("SELECT_RESULT_CMD")->setEnabled(true);
357     if (aModes.count() == 1) {
358       switch (aModes.first()) {
359       case TopAbs_VERTEX: 
360         action("SELECT_VERTEX_CMD")->setChecked(true);
361         break;
362       case TopAbs_EDGE: 
363         action("SELECT_EDGE_CMD")->setChecked(true);
364         break;
365       case TopAbs_FACE:
366         action("SELECT_FACE_CMD")->setChecked(true);
367         break;
368       default:
369         action("SELECT_RESULT_CMD")->setChecked(true);
370       }
371     } else 
372       action("SELECT_RESULT_CMD")->setChecked(true);
373   }
374   ModuleBase_IModule* aModule = myWorkshop->module();
375   if (aModule)
376     aModule->updateViewerMenu(myActions);
377 }
378
379 void XGUI_ContextMenuMgr::connectObjectBrowser()
380 {
381   connect(myWorkshop->objectBrowser(), SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
382           SLOT(onContextMenuRequest(QContextMenuEvent*)));
383 }
384
385 void XGUI_ContextMenuMgr::connectViewer()
386 {
387   connect(myWorkshop->viewer(), SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
388           SLOT(onContextMenuRequest(QContextMenuEvent*)));
389 }
390
391
392 void XGUI_ContextMenuMgr::buildObjBrowserMenu()
393 {
394   QAction* aSeparator = new QAction(this);
395   aSeparator->setSeparator(true);
396
397   QActionsList aList;
398   
399   // Result construction menu
400   aList.append(action("SHOW_CMD"));
401   aList.append(action("HIDE_CMD"));
402   aList.append(action("SHOW_ONLY_CMD"));
403   aList.append(action("COLOR_CMD"));
404   aList.append(mySeparator);
405   aList.append(action("RENAME_CMD"));
406   myObjBrowserMenus[ModelAPI_ResultConstruction::group()] = aList;
407   //-------------------------------------
408   // Result body menu
409   aList.clear();
410   aList.append(action("WIREFRAME_CMD"));
411   aList.append(action("SHADING_CMD"));
412   aList.append(action("COLOR_CMD"));
413   aList.append(mySeparator);
414   aList.append(action("SHOW_CMD"));
415   aList.append(action("HIDE_CMD"));
416   aList.append(action("SHOW_ONLY_CMD"));
417   aList.append(mySeparator);
418   aList.append(action("RENAME_CMD"));
419   myObjBrowserMenus[ModelAPI_ResultBody::group()] = aList;
420   // Group menu
421   myObjBrowserMenus[ModelAPI_ResultGroup::group()] = aList;
422   // Result part menu
423   myObjBrowserMenus[ModelAPI_ResultPart::group()] = aList;
424   //-------------------------------------
425   // Feature menu
426   aList.clear();
427   aList.append(action("DELETE_CMD"));
428   aList.append(action("MOVE_CMD"));
429   aList.append(action("CLEAN_HISTORY_CMD"));
430   aList.append(mySeparator);
431   aList.append(action("RENAME_CMD"));
432   myObjBrowserMenus[ModelAPI_Feature::group()] = aList;
433
434   aList.clear();
435   aList.append(action("DELETE_CMD"));
436   aList.append(action("CLEAN_HISTORY_CMD"));
437   aList.append(mySeparator);
438   aList.append(action("RENAME_CMD"));
439   myObjBrowserMenus[ModelAPI_ResultParameter::group()] = aList;
440   //-------------------------------------
441 }
442
443 void XGUI_ContextMenuMgr::buildViewerMenu()
444 {
445   QActionsList aList;
446   // Result construction menu
447   aList.append(action("HIDE_CMD"));
448   aList.append(action("SHOW_ONLY_CMD"));
449   aList.append(action("COLOR_CMD"));
450   myViewerMenu[ModelAPI_ResultConstruction::group()] = aList;
451   // Result part menu
452   myViewerMenu[ModelAPI_ResultPart::group()] = aList;
453   //-------------------------------------
454   // Result body menu
455   aList.clear();
456   aList.append(action("WIREFRAME_CMD"));
457   aList.append(action("SHADING_CMD"));
458   aList.append(action("COLOR_CMD"));
459   aList.append(mySeparator);
460   aList.append(action("HIDE_CMD"));
461   aList.append(action("SHOW_ONLY_CMD"));
462   myViewerMenu[ModelAPI_ResultBody::group()] = aList;
463   // Group menu
464   myViewerMenu[ModelAPI_ResultGroup::group()] = aList;
465   //-------------------------------------
466
467 }
468
469
470 void XGUI_ContextMenuMgr::addObjBrowserMenu(QMenu* theMenu) const
471 {
472   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
473   QObjectPtrList aObjects = aSelMgr->selection()->selectedObjects();
474   int aSelected = aObjects.size();
475   QActionsList aActions;
476   if (aSelected == 1) {
477     ObjectPtr aObject = aObjects.first();
478     std::string aName = aObject->groupName();
479     if (myObjBrowserMenus.contains(aName))
480       aActions = myObjBrowserMenus[aName];
481   } else if (aSelected > 1) {
482       aActions.append(action("SHADING_CMD"));
483       aActions.append(action("WIREFRAME_CMD"));
484       aActions.append(mySeparator);
485       aActions.append(action("SHOW_CMD"));
486       aActions.append(action("HIDE_CMD"));
487       aActions.append(action("SHOW_ONLY_CMD"));
488       aActions.append(mySeparator);
489       aActions.append(action("DELETE_CMD"));
490       //aActions.append(action("MOVE_CMD"));
491       aActions.append(action("CLEAN_HISTORY_CMD"));
492       aActions.append(action("COLOR_CMD"));
493   }
494   theMenu->addActions(aActions);
495
496   ModuleBase_IModule* aModule = myWorkshop->module();
497   if (aModule) {
498     theMenu->addSeparator();
499     aModule->addObjectBrowserMenu(theMenu);
500   }
501   theMenu->addSeparator();
502   theMenu->addActions(myWorkshop->objectBrowser()->actions());
503 }
504
505 void XGUI_ContextMenuMgr::addViewerMenu(QMenu* theMenu) const
506 {
507   ModuleBase_IModule* aModule = myWorkshop->module();
508   if (aModule) {
509     if (aModule->addViewerMenu(theMenu, myActions))
510       theMenu->addSeparator();
511   }
512   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
513   QList<ModuleBase_ViewerPrsPtr> aPrsList = aSelMgr->selection()->getSelected(ModuleBase_ISelection::Viewer);
514   int aSelected = aPrsList.size();
515   QActionsList aActions;
516
517   // Create selection menu
518   XGUI_OperationMgr* aOpMgr = myWorkshop->operationMgr();
519   QIntList aModes;
520   myWorkshop->module()->activeSelectionModes(aModes);
521   if ((!aOpMgr->hasOperation()) && aModes.isEmpty()) {
522     QMenu* aSelMenu = new QMenu(tr("Selection mode"), theMenu);
523     aSelMenu->addAction(action("SELECT_VERTEX_CMD"));
524     aSelMenu->addAction(action("SELECT_EDGE_CMD"));
525     aSelMenu->addAction(action("SELECT_FACE_CMD"));
526     aSelMenu->addAction(action("SELECT_RESULT_CMD"));
527     theMenu->addMenu(aSelMenu);
528     theMenu->addSeparator();
529   }
530   if (aSelected == 1) {
531     ObjectPtr aObject = aPrsList.first()->object();
532     if (aObject.get() != NULL) {
533       std::string aName = aObject->groupName();
534       if (myViewerMenu.contains(aName))
535         aActions = myViewerMenu[aName];
536     }
537     aActions.append(action("COLOR_CMD"));
538   } else if (aSelected > 1) {
539     aActions.append(action("HIDE_CMD"));
540     aActions.append(action("COLOR_CMD"));
541   }
542   // hide all is shown always even if selection in the viewer is empty
543   aActions.append(action("HIDEALL_CMD"));
544   theMenu->addActions(aActions);
545
546 #ifndef HAVE_SALOME
547   theMenu->addSeparator();
548   QMdiArea* aMDI = myWorkshop->mainWindow()->mdiArea();
549   if (aMDI->actions().size() > 0) {
550     QMenu* aSubMenu = theMenu->addMenu(tr("Windows"));
551     aSubMenu->addActions(aMDI->actions());
552   }
553 #endif
554 }
555
556 QStringList XGUI_ContextMenuMgr::actionObjectGroups(const QString& theName)
557 {
558   QStringList aGroups;
559
560   QMap<std::string, QActionsList>::const_iterator anIt = myObjBrowserMenus.begin(),
561                                                   aLast = myObjBrowserMenus.end();
562   for (; anIt != aLast; anIt++) {
563     QString aGroupName(anIt.key().c_str());
564     if (aGroups.contains(aGroupName))
565       continue;
566     QActionsList anActions = anIt.value();
567     QActionsList::const_iterator anAIt = anActions.begin(), anALast = anActions.end();
568     bool aFound = false;
569     for (; anAIt != anALast && !aFound; anAIt++)
570       aFound = (*anAIt)->data().toString() == theName;
571     if (aFound)
572       aGroups.append(aGroupName);
573   }
574   return aGroups;
575 }
576
577 void XGUI_ContextMenuMgr::onRename()
578 {
579   QObjectPtrList anObjects = myWorkshop->selector()->selection()->selectedObjects();
580   if (!myWorkshop->abortAllOperations())
581     return; 
582   // restore selection in case if dialog box was shown
583   myWorkshop->objectBrowser()->setObjectsSelected(anObjects);
584   myWorkshop->objectBrowser()->onEditItem();
585 }