Salome HOME
bos #29480 Merge branch 'CR29480'
[modules/shaper.git] / src / XGUI / XGUI_ContextMenuMgr.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 "XGUI_ContextMenuMgr.h"
21 #include "XGUI_Workshop.h"
22 #include "XGUI_ObjectsBrowser.h"
23 #include "XGUI_SelectionMgr.h"
24 #include "XGUI_Displayer.h"
25 #include "XGUI_ViewerProxy.h"
26 #include "XGUI_SalomeConnector.h"
27 #include "XGUI_Selection.h"
28 #include "XGUI_SelectionActivate.h"
29 #include "XGUI_DataModel.h"
30 #include "XGUI_OperationMgr.h"
31 #include "XGUI_Tools.h"
32 #include "XGUI_ActionsMgr.h"
33
34 #ifndef HAVE_SALOME
35 #include <AppElements_MainWindow.h>
36 #endif
37
38 //#include "PartSetPlugin_Part.h"
39
40 #include <ModelAPI_Data.h>
41 #include <ModelAPI_AttributeDocRef.h>
42 #include <ModelAPI_Object.h>
43 #include <ModelAPI_Session.h>
44 #include <ModelAPI_ResultGroup.h>
45 #include <ModelAPI_ResultParameter.h>
46 #include <ModelAPI_ResultConstruction.h>
47 #include <ModelAPI_ResultBody.h>
48 #include <ModelAPI_Tools.h>
49 #include <ModelAPI_ResultField.h>
50 #include <ModelAPI_Folder.h>
51 #include <ModelAPI_AttributeReference.h>
52 #include <ModelAPI_ResultField.h>
53
54 #include <Config_DataModelReader.h>
55
56 #include <ModuleBase_IModule.h>
57 #include <ModuleBase_Tools.h>
58 #include <ModuleBase_Operation.h>
59 #include <ModuleBase_ViewerPrs.h>
60
61 #include <QAction>
62 #include <QActionGroup>
63 #include <QContextMenuEvent>
64 #include <QMenu>
65 #include <QMdiArea>
66 #include <QMainWindow>
67 #include <QModelIndex>
68
69 #ifdef WIN32
70 #pragma warning(disable : 4456) // for nested foreach
71 #endif
72
73 XGUI_ContextMenuMgr::XGUI_ContextMenuMgr(XGUI_Workshop* theParent)
74     : QObject(theParent),
75       myWorkshop(theParent),
76       mySeparator1(0), mySeparator2(0), mySeparator3(0)
77 {
78 }
79
80 XGUI_ContextMenuMgr::~XGUI_ContextMenuMgr()
81 {
82 }
83
84 void XGUI_ContextMenuMgr::createActions()
85 {
86 #ifdef HAVE_SALOME
87   QMainWindow* aDesktop = myWorkshop->salomeConnector()->desktop();
88 #else
89   QMainWindow* aDesktop = myWorkshop->mainWindow();
90 #endif
91
92   QAction* anAction = ModuleBase_Tools::createAction(QIcon(":pictures/delete.png"), tr("Delete"),
93                                                     aDesktop);
94   aDesktop->addAction(anAction);
95
96   addAction("DELETE_CMD", anAction);
97   anAction->setShortcutContext(Qt::ApplicationShortcut);
98
99   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/rename_edit.png"), tr("Rename"),
100                                            aDesktop, this, SLOT(onRename()));
101   anAction->setShortcut(Qt::Key_F2);
102   addAction("RENAME_CMD", anAction);
103
104 #ifdef HAVE_SALOME
105   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_to_end.png"),
106                                            XGUI_Workshop::MOVE_TO_END_COMMAND, this);
107   addAction("MOVE_CMD", anAction);
108
109   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_to_end_split.png"),
110     XGUI_Workshop::MOVE_TO_END_SPLIT_COMMAND, this);
111   addAction("MOVE_SPLIT_CMD", anAction);
112 #endif
113
114   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/recover.png"),
115     tr("Recover"), this);
116   addAction("RECOVER_CMD", anAction);
117
118   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/clean_history.png"),
119                                            tr("Clean history"), aDesktop);
120   addAction("CLEAN_HISTORY_CMD", anAction);
121
122   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/color.png"), tr("Color..."), aDesktop);
123   addAction("COLOR_CMD", anAction);
124
125   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/autocolor.png"),
126                                                   tr("Auto color"), aDesktop);
127   addAction("AUTOCOLOR_CMD", anAction);
128
129   anAction = ModuleBase_Tools::createAction(QIcon(""), tr("Deflection..."), aDesktop);
130   addAction("DEFLECTION_CMD", anAction);
131
132   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/transparency.png"),
133                                            tr("Transparency..."), aDesktop);
134   addAction("TRANSPARENCY_CMD", anAction);
135
136   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/eye_pencil.png"),
137                                                   tr("Show"), aDesktop);
138   addAction("SHOW_CMD", anAction);
139
140   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/eye_pencil.png"),
141                                             tr("Show only"), aDesktop);
142   addAction("SHOW_ONLY_CMD", anAction);
143
144   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/eye_pencil_closed.png"), tr("Hide"),
145                                            aDesktop);
146   addAction("HIDE_CMD", anAction);
147
148   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/eye_pencil_closed.png"),
149                                             tr("Hide all"), aDesktop);
150   addAction("HIDEALL_CMD", anAction);
151
152   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/shading.png"),
153                                             tr("Shading"), aDesktop);
154   addAction("SHADING_CMD", anAction);
155
156   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/wireframe.png"), tr("Wireframe"),
157                                            aDesktop);
158   addAction("WIREFRAME_CMD", anAction);
159
160   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/iso_lines.png"), tr("Define Isos..."),
161                                            aDesktop);
162   addAction("ISOLINES_CMD", anAction);
163
164   anAction = ModuleBase_Tools::createAction(QIcon(), tr("Show Isos"), aDesktop);
165   anAction->setCheckable(true);
166   addAction("SHOW_ISOLINES_CMD", anAction);
167
168   mySeparator1 = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
169   mySeparator1->setSeparator(true);
170
171   mySeparator2 = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
172   mySeparator2->setSeparator(true);
173
174   mySeparator3 = ModuleBase_Tools::createAction(QIcon(), "", aDesktop);
175   mySeparator3->setSeparator(true);
176
177   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/vertex.png"), tr("Vertices"), aDesktop,
178                                            this, SLOT(onShapeSelection(bool)));
179   anAction->setCheckable(true);
180   addAction("SELECT_VERTEX_CMD", anAction);
181
182   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/edge.png"), tr("Edges"), aDesktop,
183                                            this, SLOT(onShapeSelection(bool)));
184   anAction->setCheckable(true);
185   addAction("SELECT_EDGE_CMD", anAction);
186
187   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/face.png"), tr("Faces"), aDesktop,
188                                            this, SLOT(onShapeSelection(bool)));
189   anAction->setCheckable(true);
190   addAction("SELECT_FACE_CMD", anAction);
191
192   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/result.png"), tr("Results"), aDesktop,
193                                            this, SLOT(onResultSelection(bool)));
194   anAction->setCheckable(true);
195   addAction("SELECT_RESULT_CMD", anAction);
196
197   anAction->setChecked(true);
198
199   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/find_result.png"),
200                                            tr("Select results"), aDesktop);
201   addAction("SHOW_RESULTS_CMD", anAction);
202
203   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/find_result.png"),
204                                            tr("Select parent feature"), aDesktop);
205   addAction("SHOW_FEATURE_CMD", anAction);
206
207 #ifdef TINSPECTOR
208   anAction = ModuleBase_Tools::createAction(QIcon(), tr("TInspector"), aDesktop);
209   addAction("TINSPECTOR_VIEW", anAction);
210 #endif
211
212   // Features folders actions
213   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/create_folder.png"),
214                                            tr("Insert a folder before"), aDesktop);
215   addAction("INSERT_FOLDER_CMD", anAction);
216
217   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/insert_folder_before.png"),
218                                            tr("Move into the previous folder"), aDesktop);
219   addAction("ADD_TO_FOLDER_BEFORE_CMD", anAction);
220
221   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/insert_folder_after.png"),
222                                            tr("Move into the next folder"), aDesktop);
223   addAction("ADD_TO_FOLDER_AFTER_CMD", anAction);
224
225   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_out_before.png"),
226                                            tr("Move out before the folder"), aDesktop);
227   addAction("ADD_OUT_FOLDER_BEFORE_CMD", anAction);
228
229   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/move_out_after.png"),
230                                            tr("Move out after the folder"), aDesktop);
231   addAction("ADD_OUT_FOLDER_AFTER_CMD", anAction);
232
233   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/normal-view-inversed.png"),
234                                            tr("Set view by inverted normal to face"), aDesktop);
235   addAction("SET_VIEW_INVERTEDNORMAL_CMD", anAction);
236
237   anAction = ModuleBase_Tools::createAction(QIcon(":pictures/normal-view.png"),
238                                            tr("Set view by normal to face"), aDesktop);
239   addAction("SET_VIEW_NORMAL_CMD", anAction);
240
241   buildObjBrowserMenu();
242   buildViewerMenu();
243 }
244
245 void XGUI_ContextMenuMgr::addAction(const QString& theId, QAction* theAction)
246 {
247   if (myActions.contains(theId))
248     qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
249   theAction->setData(theId);
250   connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
251   myActions[theId] = theAction;
252 }
253
254 QAction* XGUI_ContextMenuMgr::action(const QString& theId) const
255 {
256   if (myActions.contains(theId))
257     return myActions[theId];
258   return 0;
259 }
260
261 QAction* XGUI_ContextMenuMgr::actionByName(const QString& theName) const
262 {
263   foreach(QAction* eachAction, myActions) {
264     if (eachAction->text() == theName) {
265       return eachAction;
266     }
267   }
268   return NULL;
269 }
270
271 QStringList XGUI_ContextMenuMgr::actionIds() const
272 {
273   return myActions.keys();
274 }
275
276 void XGUI_ContextMenuMgr::onAction(bool isChecked)
277 {
278   QAction* anAction = static_cast<QAction*>(sender());
279   emit actionTriggered(anAction->data().toString(), isChecked);
280 }
281
282 void XGUI_ContextMenuMgr::updateCommandsStatus()
283 {
284 }
285
286 void XGUI_ContextMenuMgr::onContextMenuRequest(QContextMenuEvent* theEvent)
287 {
288   QMenu* aMenu = new QMenu();
289   if (sender() == myWorkshop->objectBrowser()) {
290     updateObjectBrowserMenu();
291     addObjBrowserMenu(aMenu);
292   } else if (sender() == myWorkshop->viewer()) {
293     updateViewerMenu();
294     addViewerMenu(aMenu);
295   }
296
297   if (aMenu && (aMenu->actions().size() > 0)) {
298     // it is possible that some objects should do something before and after the popup menu exec
299     // e.g. a sketch manager changes an internal flag on this signals in order to do not hide
300     // a created entity
301     emit beforeContextMenu();
302     aMenu->exec(theEvent->globalPos());
303     emit afterContextMenu();
304     delete aMenu;
305   }
306 }
307
308 void XGUI_ContextMenuMgr::updateObjectBrowserMenu()
309 {
310   foreach(QAction* anAction, myActions)
311     anAction->setEnabled(false);
312
313   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
314   QObjectPtrList aObjects = aSelMgr->selection()->selectedObjects();
315   int aSelected = aObjects.size();
316   if (aSelected > 0) {
317     SessionPtr aMgr = ModelAPI_Session::get();
318     XGUI_Displayer* aDisplayer = myWorkshop->displayer();
319     bool hasResult = false;
320     bool hasFeature = false;
321     bool hasParameter = false;
322     bool hasCompositeOwner = false;
323     bool hasResultInHistory = false;
324     bool hasFolder = false;
325     ModuleBase_Tools::checkObjects(aObjects, hasResult, hasFeature, hasParameter,
326                                    hasCompositeOwner, hasResultInHistory, hasFolder);
327     //Process Feature
328     if (aSelected == 1) { // single selection
329       ObjectPtr aObject = aObjects.first();
330       ResultPtr aResult;
331       if (hasResult)
332         aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObject);
333       if (aObject) {
334         if (hasResult && myWorkshop->canBeShaded(aObject)) {
335           XGUI_Displayer::DisplayMode aMode = aDisplayer->displayMode(aObject);
336           if (aMode != XGUI_Displayer::NoMode) {
337             action("WIREFRAME_CMD")->setEnabled(aMode == XGUI_Displayer::Shading);
338             action("SHADING_CMD")->setEnabled(aMode == XGUI_Displayer::Wireframe);
339           } else {
340             action("WIREFRAME_CMD")->setEnabled(true);
341             action("SHADING_CMD")->setEnabled(true);
342           }
343           action("SHOW_ISOLINES_CMD")->setEnabled(true);
344           action("SHOW_ISOLINES_CMD")->setChecked(ModelAPI_Tools::isShownIsoLines(aResult));
345           action("ISOLINES_CMD")->setEnabled(true);
346         }
347         if (!hasFeature) {
348           bool aHasSubResults = ModelAPI_Tools::hasSubResults(aResult);
349           if (aHasSubResults) {
350             action("HIDE_CMD")->setEnabled(true);
351             action("SHOW_CMD")->setEnabled(true);
352           }
353           else {
354             if (aObject->isDisplayed()) {
355               action("HIDE_CMD")->setEnabled(true);
356             } else if (hasResult && (!hasParameter)) {
357               action("SHOW_CMD")->setEnabled(true);
358             }
359           }
360           if (!(hasParameter || hasFeature))
361             action("SHOW_ONLY_CMD")->setEnabled(true);
362         }
363 #ifdef HAVE_SALOME
364         else if (hasFeature && myWorkshop->canMoveFeature()) {
365           action("MOVE_CMD")->setEnabled(true);
366           action("MOVE_SPLIT_CMD")->setEnabled(true);
367         }
368 #endif
369         if (hasFeature && aObject->document() != aMgr->moduleDocument() &&
370             aObject->document() == aMgr->activeDocument())
371         {
372           XGUI_OperationMgr* anOperationMgr = myWorkshop->operationMgr();
373           if (!anOperationMgr->hasOperation()) {
374             FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
375             std::list<std::shared_ptr<ModelAPI_Result> > aResults;
376             ModelAPI_Tools::getConcealedResults(aFeature, aResults);
377             if (!aResults.empty()) // check the feature conceals at least one result
378               action("RECOVER_CMD")->setEnabled(true);
379           }
380         }
381
382         if( aMgr->activeDocument() == aObject->document() )
383         {
384           action("RENAME_CMD")->setEnabled(true);
385           action("DELETE_CMD")->setEnabled(!hasCompositeOwner);
386           action("CLEAN_HISTORY_CMD")->setEnabled(!hasCompositeOwner &&
387                                                   (hasFeature || hasParameter));
388         }
389       }
390       // end single selection
391     } else { // multi-selection
392       // parameter is commented because the actions are not in the list of result parameter actions
393       if (hasResult /*&& (!hasParameter)*/) {
394         action("SHOW_CMD")->setEnabled(true);
395         action("HIDE_CMD")->setEnabled(true);
396         action("SHOW_ONLY_CMD")->setEnabled(true);
397         action("SHADING_CMD")->setEnabled(true);
398         action("WIREFRAME_CMD")->setEnabled(true);
399         action("SHOW_ISOLINES_CMD")->setEnabled(true);
400         action("ISOLINES_CMD")->setEnabled(true);
401       }
402       if (hasFeature && myWorkshop->canMoveFeature()) {
403         action("MOVE_CMD")->setEnabled(true);
404         action("MOVE_SPLIT_CMD")->setEnabled(true);
405       }
406     } // end multi-selection
407
408     // Check folder management commands state if only features are selected
409     if ((!hasResult) && hasFeature && (!hasParameter) && (!hasCompositeOwner) &&
410       (!hasResultInHistory) && (!hasFolder)) {
411       std::list<FeaturePtr> aFeatures = aSelMgr->getSelectedFeatures();
412       if (aFeatures.size() > 0) { // Check that features do not include Parts
413         QModelIndexList aIndexes = aSelMgr->selection()->selectedIndexes();
414         QModelIndex aFirstIdx = aIndexes.first();
415         QModelIndex aLastIdx = aIndexes.last();
416         QModelIndex aParentIdx = aFirstIdx.parent();
417
418         // if all selected are from the same level
419         bool isSameParent = true;
420         foreach(QModelIndex aIdx, aIndexes) {
421           if (aIdx.parent() != aParentIdx) {
422             isSameParent = false;
423             break;
424           }
425         }
426         if (isSameParent) {
427           // Check is selection continuous
428           XGUI_DataModel* aModel = myWorkshop->objectBrowser()->dataModel();
429           DocumentPtr aDoc = aMgr->activeDocument();
430
431           bool isContinuos = true;
432           if (aSelected > 1) {
433             int aId = -1;
434             foreach(FeaturePtr aF, aFeatures) {
435               if (aId == -1)
436                 aId = aDoc->index(aF);
437               else {
438                 aId++;
439                 if (aId != aDoc->index(aF)) {
440                   isContinuos = false;
441                   break;
442                 }
443               }
444             }
445           }
446           if (isContinuos) {
447             ObjectPtr aDataObj = aModel->object(aParentIdx);
448
449             ObjectPtr aPrevObj;
450             if (aFirstIdx.row() > 0) {
451               QModelIndex aPrevIdx = aFirstIdx.sibling(aFirstIdx.row() - 1, 0);
452               aPrevObj = aModel->object(aPrevIdx);
453             }
454
455             ObjectPtr aNextObj;
456             if (aLastIdx.row() < (aModel->rowCount(aParentIdx) - 1)) {
457               QModelIndex aNextIdx = aFirstIdx.sibling(aLastIdx.row() + 1, 0);
458               aNextObj = aModel->object(aNextIdx);
459             }
460
461             bool isPrevFolder = (aPrevObj.get() &&
462               (aPrevObj->groupName() == ModelAPI_Folder::group()));
463             bool isNextFolder = (aNextObj.get() &&
464               (aNextObj->groupName() == ModelAPI_Folder::group()));
465             bool isInFolder = (aDataObj.get() &&
466               (aDataObj->groupName() == ModelAPI_Folder::group()));
467             bool isOutsideFolder = !isInFolder;
468
469             bool hasFirst = false;
470             bool hasLast = false;
471             if (isInFolder) {
472               FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aDataObj);
473               FeaturePtr aFirstFeatureInFolder;
474               AttributeReferencePtr aFirstFeatAttr =
475                   aFolder->data()->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
476               if (aFirstFeatAttr)
477                 aFirstFeatureInFolder = ModelAPI_Feature::feature(aFirstFeatAttr->value());
478               hasFirst = (aFirstFeatureInFolder == aFeatures.front());
479
480               FeaturePtr aLastFeatureInFolder;
481               AttributeReferencePtr aLastFeatAttr =
482                   aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID());
483               if (aLastFeatAttr)
484                 aLastFeatureInFolder = ModelAPI_Feature::feature(aLastFeatAttr->value());
485               hasLast = (aLastFeatureInFolder == aFeatures.back());
486             }
487             action("INSERT_FOLDER_CMD")->setEnabled(isOutsideFolder);
488             action("ADD_TO_FOLDER_BEFORE_CMD")->setEnabled(isOutsideFolder && isPrevFolder);
489             action("ADD_TO_FOLDER_AFTER_CMD")->setEnabled(isOutsideFolder && isNextFolder);
490             action("ADD_OUT_FOLDER_BEFORE_CMD")->setEnabled(isInFolder && hasFirst);
491             action("ADD_OUT_FOLDER_AFTER_CMD")->setEnabled(isInFolder && hasLast);
492           }
493         }
494       }
495     } // end folder management commands
496
497     bool allActive = true;
498     foreach( ObjectPtr aObject, aObjects )
499       if( aMgr->activeDocument() != aObject->document() )  {
500         allActive = false;
501         break;
502       }
503     if (!hasCompositeOwner && allActive ) {
504       if (hasResult || hasFeature || hasParameter) // #2924 results can be erased
505         action("DELETE_CMD")->setEnabled(true);
506     }
507     if (!hasCompositeOwner && allActive && (hasFeature|| hasParameter))
508       action("CLEAN_HISTORY_CMD")->setEnabled(true);
509
510     action("SHOW_RESULTS_CMD")->setEnabled(hasFeature);
511     action("SHOW_FEATURE_CMD")->setEnabled(hasResult && hasResultInHistory);
512   } // end selection processing
513
514   // Show/Hide command has to be disabled for objects from non active document
515   bool aDeactivate = false;
516   foreach (ObjectPtr aObj, aObjects) {
517     if (!aObj->document()->isActive()) {
518       if ((aObj->document() != ModelAPI_Session::get()->moduleDocument()) ||
519            aObj->groupName() == ModelAPI_ResultPart::group()) {
520         aDeactivate = true;
521         break;
522       }
523     }
524   }
525   if (aDeactivate) {
526     // If at leas a one object can not be edited then Show/Hide has to be disabled
527     action("SHOW_CMD")->setEnabled(false);
528     action("HIDE_CMD")->setEnabled(false);
529     action("SHOW_ONLY_CMD")->setEnabled(false);
530   }
531
532   action("COLOR_CMD")->setEnabled(myWorkshop->canChangeProperty("COLOR_CMD"));
533   action("DEFLECTION_CMD")->setEnabled(myWorkshop->canChangeProperty("DEFLECTION_CMD"));
534   action("TRANSPARENCY_CMD")->setEnabled(myWorkshop->canChangeProperty("TRANSPARENCY_CMD"));
535   action("AUTOCOLOR_CMD")->setEnabled(myWorkshop->canChangeProperty("AUTOCOLOR_CMD"));
536
537   #ifdef _DEBUG
538     #ifdef TINSPECTOR
539       action("TINSPECTOR_VIEW")->setEnabled(true);
540     #endif
541   #endif
542
543
544   ModuleBase_IModule* aModule = myWorkshop->module();
545   if (aModule)
546     aModule->updateObjectBrowserMenu(myActions);
547 }
548
549 void XGUI_ContextMenuMgr::updateViewerMenu()
550 {
551   foreach(QAction* anAction, myActions)
552     anAction->setEnabled(false);
553
554   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
555   XGUI_Displayer* aDisplayer = myWorkshop->displayer();
556   QList<ModuleBase_ViewerPrsPtr> aPrsList =
557     aSelMgr->selection()->getSelected(ModuleBase_ISelection::Viewer);
558   if (aPrsList.size() > 0) {
559     bool isVisible = false;
560     bool canBeShaded = false;
561     bool hasPlanar = false;
562     ObjectPtr aObject;
563     foreach(ModuleBase_ViewerPrsPtr aPrs, aPrsList) {
564       aObject = aPrs->object();
565       if (!aObject.get())
566         continue;
567       GeomShapePtr aShape = aPrs->shape();
568       if (aObject->isDisplayed()) {
569         isVisible = true;
570         canBeShaded = aDisplayer->canBeShaded(aObject);
571       }
572       if (aShape.get()) {
573         hasPlanar = (aShape->isFace() && aShape->isPlanar());
574       }
575     }
576     if (isVisible) {
577       if (canBeShaded) {
578         XGUI_Displayer::DisplayMode aMode = aDisplayer->displayMode(aObject);
579         if (aMode != XGUI_Displayer::NoMode) {
580           action("WIREFRAME_CMD")->setEnabled(aMode == XGUI_Displayer::Shading);
581           action("SHADING_CMD")->setEnabled(aMode == XGUI_Displayer::Wireframe);
582         } else {
583           action("WIREFRAME_CMD")->setEnabled(true);
584           action("SHADING_CMD")->setEnabled(true);
585         }
586         action("ISOLINES_CMD")->setEnabled(true);
587
588         if (aPrsList.size() == 1) {
589           ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObject);
590           if (aResult.get()) {
591             action("SHOW_ISOLINES_CMD")->setEnabled(true);
592             action("SHOW_ISOLINES_CMD")->setChecked(ModelAPI_Tools::isShownIsoLines(aResult));
593           }
594         }
595       }
596       action("SHOW_ONLY_CMD")->setEnabled(true);
597       action("HIDE_CMD")->setEnabled(true);
598     } else
599       action("SHOW_CMD")->setEnabled(true);
600
601     action("SET_VIEW_NORMAL_CMD")->setEnabled(hasPlanar);
602     action("SET_VIEW_INVERTEDNORMAL_CMD")->setEnabled(hasPlanar);
603   }
604   //issue #2159 Hide all incomplete behavior
605 #ifdef HAVE_SALOME
606     action("HIDEALL_CMD")->setEnabled(true);
607 #else
608   if (myWorkshop->displayer()->objectsCount() > 0)
609     action("HIDEALL_CMD")->setEnabled(true);
610 #endif
611
612   // Update selection menu
613   QIntList aModes = myWorkshop->selectionActivate()->activeSelectionModes();
614   action("SELECT_VERTEX_CMD")->setEnabled(true);
615   action("SELECT_EDGE_CMD")->setEnabled(true);
616   action("SELECT_FACE_CMD")->setEnabled(true);
617   action("SELECT_RESULT_CMD")->setEnabled(true);
618
619   action("SELECT_RESULT_CMD")->setChecked(false);
620   action("SELECT_VERTEX_CMD")->setChecked(false);
621   action("SELECT_EDGE_CMD")->setChecked(false);
622   action("SELECT_FACE_CMD")->setChecked(false);
623   action("SELECT_RESULT_CMD")->setChecked(false);
624   if (aModes.count() == 0) {
625     action("SELECT_RESULT_CMD")->setChecked(true);
626   } else {
627     foreach(int aMode, aModes) {
628       switch (aMode) {
629       case TopAbs_VERTEX:
630         action("SELECT_VERTEX_CMD")->setChecked(true);
631         break;
632       case TopAbs_EDGE:
633         action("SELECT_EDGE_CMD")->setChecked(true);
634         break;
635       case TopAbs_FACE:
636         action("SELECT_FACE_CMD")->setChecked(true);
637         break;
638       default:
639         action("SELECT_RESULT_CMD")->setChecked(true);
640       }
641     }
642   }
643
644   ModuleBase_IModule* aModule = myWorkshop->module();
645   if (aModule)
646     aModule->updateViewerMenu(myActions);
647
648   if (myWorkshop->canChangeProperty("COLOR_CMD"))
649     action("COLOR_CMD")->setEnabled(true);
650
651   if (myWorkshop->canChangeProperty("DEFLECTION_CMD"))
652     action("DEFLECTION_CMD")->setEnabled(true);
653
654   if (myWorkshop->canChangeProperty("TRANSPARENCY_CMD"))
655     action("TRANSPARENCY_CMD")->setEnabled(true);
656
657   action("DELETE_CMD")->setEnabled(true);
658 }
659
660 void XGUI_ContextMenuMgr::connectObjectBrowser()
661 {
662   connect(myWorkshop->objectBrowser(), SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
663           SLOT(onContextMenuRequest(QContextMenuEvent*)));
664 }
665
666 void XGUI_ContextMenuMgr::connectViewer()
667 {
668   connect(myWorkshop->viewer(), SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
669           SLOT(onContextMenuRequest(QContextMenuEvent*)));
670 }
671
672
673 void XGUI_ContextMenuMgr::buildObjBrowserMenu()
674 {
675   QAction* aSeparator = ModuleBase_Tools::createAction(QIcon(), "", myWorkshop->desktop());
676   aSeparator->setSeparator(true);
677
678   QActionsList aList;
679
680   // Result construction menu
681   aList.append(action("SHOW_CMD"));
682   aList.append(action("HIDE_CMD"));
683   aList.append(action("SHOW_ONLY_CMD"));
684   aList.append(mySeparator1);
685   aList.append(action("RENAME_CMD"));
686   aList.append(action("COLOR_CMD"));
687   aList.append(action("DEFLECTION_CMD"));
688   aList.append(action("TRANSPARENCY_CMD"));
689   aList.append(action("SHOW_FEATURE_CMD"));
690   aList.append(mySeparator2);
691   aList.append(action("DELETE_CMD"));
692   myObjBrowserMenus[ModelAPI_ResultConstruction::group()] = aList;
693
694   //-------------------------------------
695   // Result body menu
696   aList.clear();
697   aList.append(action("WIREFRAME_CMD"));
698   aList.append(action("SHADING_CMD"));
699   aList.append(mySeparator1); // this separator is not shown as this action is added after show only
700   // qt list container contains only one instance of the same action
701   aList.append(action("SHOW_CMD"));
702   aList.append(action("HIDE_CMD"));
703   aList.append(action("SHOW_ONLY_CMD"));
704   aList.append(mySeparator2);
705   aList.append(action("RENAME_CMD"));
706   aList.append(action("COLOR_CMD"));
707   aList.append(action("DEFLECTION_CMD"));
708   aList.append(action("TRANSPARENCY_CMD"));
709   aList.append(action("SHOW_ISOLINES_CMD"));
710   aList.append(action("ISOLINES_CMD"));
711   aList.append(action("SHOW_FEATURE_CMD"));
712   aList.append(mySeparator3);
713   aList.append(action("DELETE_CMD"));
714   myObjBrowserMenus[ModelAPI_ResultBody::group()] = aList;
715   // Group menu
716   myObjBrowserMenus[ModelAPI_ResultField::group()] = aList;
717   // Result part menu
718   myObjBrowserMenus[ModelAPI_ResultPart::group()] = aList;
719
720   aList.clear();
721   aList.append(action("WIREFRAME_CMD"));
722   aList.append(action("SHADING_CMD"));
723   aList.append(mySeparator1); // this separator is not shown as this action is added after show only
724   // qt list container contains only one instance of the same action
725   aList.append(action("SHOW_CMD"));
726   aList.append(action("HIDE_CMD"));
727   aList.append(action("SHOW_ONLY_CMD"));
728   aList.append(mySeparator2);
729   aList.append(action("AUTOCOLOR_CMD"));
730   aList.append(action("RENAME_CMD"));
731   aList.append(action("COLOR_CMD"));
732   aList.append(action("DEFLECTION_CMD"));
733   aList.append(action("TRANSPARENCY_CMD"));
734   aList.append(action("SHOW_ISOLINES_CMD"));
735   aList.append(action("ISOLINES_CMD"));
736   aList.append(action("SHOW_FEATURE_CMD"));
737   aList.append(mySeparator3);
738   aList.append(action("DELETE_CMD"));
739   // Group menu
740   myObjBrowserMenus[ModelAPI_ResultGroup::group()] = aList;
741   //-------------------------------------
742   // Feature menu
743   aList.clear();
744   aList.append(action("RENAME_CMD"));
745   aList.append(action("SHOW_RESULTS_CMD"));
746   aList.append(action("MOVE_CMD"));
747   aList.append(action("MOVE_SPLIT_CMD"));
748   aList.append(action("RECOVER_CMD"));
749   aList.append(mySeparator1);
750   aList.append(action("INSERT_FOLDER_CMD"));
751   aList.append(action("ADD_TO_FOLDER_BEFORE_CMD"));
752   aList.append(action("ADD_TO_FOLDER_AFTER_CMD"));
753   aList.append(mySeparator2);
754   aList.append(action("ADD_OUT_FOLDER_BEFORE_CMD"));
755   aList.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
756   aList.append(mySeparator3);
757   aList.append(action("CLEAN_HISTORY_CMD"));
758   aList.append(action("DELETE_CMD"));
759   myObjBrowserMenus[ModelAPI_Feature::group()] = aList;
760
761   aList.clear();
762   aList.append(action("RENAME_CMD"));
763   aList.append(mySeparator1);
764   aList.append(action("CLEAN_HISTORY_CMD"));
765   aList.append(action("DELETE_CMD"));
766   myObjBrowserMenus[ModelAPI_ResultParameter::group()] = aList;
767   //-------------------------------------
768
769   aList.clear();
770   aList.append(action("RENAME_CMD"));
771   aList.append(action("DELETE_CMD"));
772   myObjBrowserMenus[ModelAPI_Folder::group()] = aList;
773
774   //---------------------------------------
775   // Step objects menu
776   aList.clear();
777   aList.append(action("SHOW_CMD"));
778   aList.append(action("HIDE_CMD"));
779   aList.append(action("SHOW_ONLY_CMD"));
780   myObjBrowserMenus[ModelAPI_ResultField::ModelAPI_FieldStep::group()] = aList;
781 }
782
783 void XGUI_ContextMenuMgr::buildViewerMenu()
784 {
785   QActionsList aList;
786   // Result construction menu
787   aList.append(action("COLOR_CMD"));
788   aList.append(action("DEFLECTION_CMD"));
789   aList.append(action("TRANSPARENCY_CMD"));
790   aList.append(mySeparator3);
791   aList.append(action("SET_VIEW_NORMAL_CMD"));
792   aList.append(action("SET_VIEW_INVERTEDNORMAL_CMD"));
793   aList.append(mySeparator1);
794   aList.append(action("SHOW_ONLY_CMD"));
795   aList.append(action("HIDE_CMD"));
796   myViewerMenu[ModelAPI_ResultConstruction::group()] = aList;
797   // Result part menu
798   myViewerMenu[ModelAPI_ResultPart::group()] = aList;
799   //-------------------------------------
800   // Result body menu
801   aList.clear();
802   aList.append(action("WIREFRAME_CMD"));
803   aList.append(action("SHADING_CMD"));
804   aList.append(mySeparator2);
805   aList.append(action("COLOR_CMD"));
806   aList.append(action("DEFLECTION_CMD"));
807   aList.append(action("TRANSPARENCY_CMD"));
808   aList.append(action("SHOW_ISOLINES_CMD"));
809   aList.append(action("ISOLINES_CMD"));
810   aList.append(mySeparator3);
811   aList.append(action("SET_VIEW_NORMAL_CMD"));
812   aList.append(action("SET_VIEW_INVERTEDNORMAL_CMD"));
813   aList.append(mySeparator1);
814   aList.append(action("SHOW_ONLY_CMD"));
815   aList.append(action("HIDE_CMD"));
816   myViewerMenu[ModelAPI_ResultBody::group()] = aList;
817   // Group menu
818   myViewerMenu[ModelAPI_ResultGroup::group()] = aList;
819   myViewerMenu[ModelAPI_ResultField::group()] = aList;
820   //-------------------------------------
821   // Step objects menu
822   aList.clear();
823   aList.append(action("HIDE_CMD"));
824   myViewerMenu[ModelAPI_ResultField::ModelAPI_FieldStep::group()] = aList;
825 }
826
827
828 void XGUI_ContextMenuMgr::addObjBrowserMenu(QMenu* theMenu) const
829 {
830   ModuleBase_IModule* aModule = myWorkshop->module();
831   if (aModule) {
832     theMenu->addSeparator();
833     aModule->addObjectBrowserMenu(theMenu);
834   }
835
836   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
837   QObjectPtrList aObjects = aSelMgr->selection()->selectedObjects();
838   int aSelected = aObjects.size();
839   QActionsList anActions;
840   if (aSelected == 1) {
841     ObjectPtr aObject = aObjects.first();
842     std::string aName = aObject->groupName();
843     if (myObjBrowserMenus.contains(aName))
844       anActions = myObjBrowserMenus[aName];
845   } else if (aSelected > 1) {
846       anActions.append(action("WIREFRAME_CMD"));
847       anActions.append(action("SHADING_CMD"));
848       anActions.append(mySeparator1);
849       anActions.append(action("SHOW_CMD"));
850       anActions.append(action("HIDE_CMD"));
851       anActions.append(action("SHOW_ONLY_CMD"));
852       anActions.append(mySeparator2);
853       anActions.append(action("ADD_TO_FOLDER_BEFORE_CMD"));
854       anActions.append(action("ADD_TO_FOLDER_AFTER_CMD"));
855       anActions.append(action("ADD_OUT_FOLDER_BEFORE_CMD"));
856       anActions.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
857       anActions.append(mySeparator3);
858       anActions.append(action("MOVE_CMD"));
859       anActions.append(action("MOVE_SPLIT_CMD"));
860       anActions.append(action("COLOR_CMD"));
861       anActions.append(action("DEFLECTION_CMD"));
862       anActions.append(action("TRANSPARENCY_CMD"));
863       anActions.append(action("SHOW_ISOLINES_CMD"));
864       anActions.append(action("ISOLINES_CMD"));
865       anActions.append(action("CLEAN_HISTORY_CMD"));
866       anActions.append(action("DELETE_CMD"));
867   }
868 #ifdef _DEBUG
869   if (aSelected == 0) {
870     #ifdef TINSPECTOR
871     anActions.append(action("TINSPECTOR_VIEW"));
872     #endif
873   }
874 #endif
875   theMenu->addActions(anActions);
876   addFeatures(theMenu);
877
878   // It is commented out because Object Browser does not have actions
879   //theMenu->addSeparator();
880   //theMenu->addActions(myWorkshop->objectBrowser()->actions());
881 }
882
883 void XGUI_ContextMenuMgr::addViewerMenu(QMenu* theMenu) const
884 {
885   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
886   QList<ModuleBase_ViewerPrsPtr> aPrsList =
887     aSelMgr->selection()->getSelected(ModuleBase_ISelection::Viewer);
888   int aSelected = aPrsList.size();
889   QActionsList anActions;
890
891   // Create selection menu
892   XGUI_OperationMgr* aOpMgr = myWorkshop->operationMgr();
893   if (!aOpMgr->hasOperation() &&
894       myWorkshop->selectionActivate()->activeSelectionPlace() == XGUI_SelectionActivate::Workshop) {
895     QMenu* aSelMenu = new QMenu(tr("Selection mode"), theMenu);
896     aSelMenu->addAction(action("SELECT_VERTEX_CMD"));
897     aSelMenu->addAction(action("SELECT_EDGE_CMD"));
898     aSelMenu->addAction(action("SELECT_FACE_CMD"));
899     //IMP: an attempt to use result selection with other selection modes
900     //aSelMenu->addSeparator();
901     aSelMenu->addAction(action("SELECT_RESULT_CMD"));
902     theMenu->addMenu(aSelMenu);
903     theMenu->addSeparator();
904   }
905   if (aSelected == 1) {
906     ObjectPtr aObject = aPrsList.first()->object();
907     if (aObject.get() != NULL) {
908       std::string aName = aObject->groupName();
909       if (myViewerMenu.contains(aName))
910         anActions = myViewerMenu[aName];
911     }
912   } else if (aSelected > 1) {
913     anActions.append(action("COLOR_CMD"));
914     anActions.append(action("DEFLECTION_CMD"));
915     anActions.append(action("TRANSPARENCY_CMD"));
916     anActions.append(mySeparator1);
917     anActions.append(action("SHOW_ONLY_CMD"));
918     anActions.append(action("HIDE_CMD"));
919   }
920   // hide all is shown always even if selection in the viewer is empty
921   anActions.append(action("HIDEALL_CMD"));
922   theMenu->addActions(anActions);
923
924   QMap<int, QAction*> aMenuActions;
925   ModuleBase_IModule* aModule = myWorkshop->module();
926   if (aModule) {
927     if (aModule->addViewerMenu(myActions, theMenu, aMenuActions))
928       theMenu->addSeparator();
929   }
930
931   // insert the module menu items on specific positions in the popup menu: some actions should be
932   // in the begin of the list, Delete action should be the last by #1343 issue
933   QList<QAction*> anActionsList = theMenu->actions();
934   int anActionsListSize = anActionsList.size();
935   QAction* aFirstAction = anActionsList[0];
936   QMap<int, QAction*>::const_iterator anIt = aMenuActions.begin(), aLast = aMenuActions.end();
937   for (; anIt != aLast; anIt++) {
938     if (anIt.key() > anActionsListSize)
939       theMenu->addAction(anIt.value());
940     else
941       theMenu->insertAction(aFirstAction, *anIt);
942   }
943
944 #ifndef HAVE_SALOME
945   theMenu->addSeparator();
946   QMdiArea* aMDI = myWorkshop->mainWindow()->mdiArea();
947   if (aMDI->actions().size() > 0) {
948     QMenu* aSubMenu = theMenu->addMenu(tr("Windows"));
949     aSubMenu->addActions(aMDI->actions());
950   }
951 #endif
952 }
953
954 QStringList XGUI_ContextMenuMgr::actionObjectGroups(const QString& theName)
955 {
956   QStringList aGroups;
957
958   QMap<std::string, QActionsList>::const_iterator anIt = myObjBrowserMenus.begin(),
959                                                   aLast = myObjBrowserMenus.end();
960   for (; anIt != aLast; anIt++) {
961     QString aGroupName(anIt.key().c_str());
962     if (aGroups.contains(aGroupName))
963       continue;
964     QActionsList anActions = anIt.value();
965     QActionsList::const_iterator anAIt = anActions.begin(), anALast = anActions.end();
966     bool aFound = false;
967     for (; anAIt != anALast && !aFound; anAIt++)
968       aFound = (*anAIt)->data().toString() == theName;
969     if (aFound)
970       aGroups.append(aGroupName);
971   }
972   return aGroups;
973 }
974
975 void XGUI_ContextMenuMgr::onRename()
976 {
977   QObjectPtrList anObjects = myWorkshop->selector()->selection()->selectedObjects();
978   if (!myWorkshop->abortAllOperations())
979     return;
980   // restore selection in case if dialog box was shown
981   myWorkshop->objectBrowser()->setObjectsSelected(anObjects);
982   myWorkshop->objectBrowser()->onEditItem();
983 }
984
985 void XGUI_ContextMenuMgr::addFeatures(QMenu* theMenu) const
986 {
987   SessionPtr aMgr = ModelAPI_Session::get();
988   DocumentPtr anActiveDoc = aMgr->activeDocument();
989
990   XGUI_SelectionMgr* aSelMgr = myWorkshop->selector();
991   XGUI_ActionsMgr* anActionMgr = myWorkshop->actionsMgr();
992   const Config_DataModelReader* aDataModelXML = myWorkshop->dataModelXMLReader();
993   QModelIndexList aSelectedIndexes = aSelMgr->selection()->selectedIndexes();
994
995   QString aName;
996   int aLen = 0;
997   bool aIsRoot = false;
998   foreach(QModelIndex aIdx, aSelectedIndexes) {
999     // Process only first column
1000     if (aIdx.column() == 1) {
1001       aIsRoot = !aIdx.parent().isValid();
1002       // Exit if the selected index belongs to non active document
1003       if (aIsRoot && (anActiveDoc != aMgr->moduleDocument()))
1004         return;
1005
1006       // Get name of the selected index
1007       aName = aIdx.data().toString();
1008       aLen = aName.indexOf('(');
1009       if (aLen != -1) {
1010         aName = aName.left(--aLen);
1011       }
1012       std::string aFeaturesStr = aIsRoot?
1013         aDataModelXML->rootFolderFeatures(aName.toStdString()) :
1014         aDataModelXML->subFolderFeatures(aName.toStdString());
1015         if (aFeaturesStr.length() > 0) {
1016           QStringList aFeturesList =
1017             QString(aFeaturesStr.c_str()).split(",", QString::SkipEmptyParts);
1018           foreach(QString aFea, aFeturesList) {
1019             QAction* anAction = anActionMgr->action(aFea);
1020             if (anAction)
1021               theMenu->addAction(anAction);
1022           }
1023         }
1024     }
1025   }
1026 }
1027
1028 #define UNCHECK_ACTION(NAME) \
1029 { QAction* anAction = action(NAME); \
1030 bool isBlock = anAction->signalsBlocked(); \
1031 anAction->blockSignals(true); \
1032 anAction->setChecked(false); \
1033   anAction->blockSignals(isBlock); }
1034
1035
1036 void XGUI_ContextMenuMgr::onResultSelection(bool theChecked)
1037 {
1038   UNCHECK_ACTION("SELECT_VERTEX_CMD");
1039   UNCHECK_ACTION("SELECT_EDGE_CMD");
1040   UNCHECK_ACTION("SELECT_FACE_CMD");
1041 }
1042
1043 void XGUI_ContextMenuMgr::onShapeSelection(bool theChecked)
1044 {
1045   UNCHECK_ACTION("SHOW_RESULTS_CMD");
1046 }