]> SALOME platform Git repositories - modules/shaper.git/blob - src/SHAPERGUI/SHAPERGUI.cpp
Salome HOME
53c7fcbbf83d608f45ca3f0cce196a810aeb3e1e
[modules/shaper.git] / src / SHAPERGUI / SHAPERGUI.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "SHAPERGUI.h"
22 #include "SHAPERGUI_DataModel.h"
23 #include "SHAPERGUI_OCCSelector.h"
24 #include "SHAPERGUI_NestedButton.h"
25 #include "SHAPERGUI_ToolbarsMgr.h"
26
27 #include <XGUI_Workshop.h>
28 #include <XGUI_PropertyPanel.h>
29 #include <XGUI_ContextMenuMgr.h>
30 #include <XGUI_ObjectsBrowser.h>
31 #include <XGUI_OperationMgr.h>
32 #include <XGUI_Displayer.h>
33 #include <XGUI_MenuMgr.h>
34 #include <XGUI_FacesPanel.h>
35 #include <XGUI_SelectionActivate.h>
36 #include <XGUI_InspectionPanel.h>
37
38 #include <ModuleBase_Operation.h>
39 #include <ModuleBase_Preferences.h>
40 #include <ModuleBase_ActionInfo.h>
41 #include <ModuleBase_IModule.h>
42
43 #include <LightApp_Application.h>
44 #include <LightApp_SelectionMgr.h>
45 #include <LightApp_OCCSelector.h>
46 #include <LightApp_Study.h>
47 #include <OCCViewer_ViewModel.h>
48
49 #include <SUIT_Selector.h>
50 #include <SUIT_Desktop.h>
51 #include <SUIT_ViewManager.h>
52 #include <SUIT_ResourceMgr.h>
53 #include <SUIT_DataBrowser.h>
54
55 #include <QtxPopupMgr.h>
56 #include <QtxActionMenuMgr.h>
57 #include <QtxActionToolMgr.h>
58 #include <QtxResourceMgr.h>
59
60 #include <Config_PropManager.h>
61 #include <Config_ModuleReader.h>
62
63 #include <AIS_ListOfInteractive.hxx>
64 #include <AIS_ListIteratorOfListOfInteractive.hxx>
65
66 #include <QDockWidget>
67 #include <QAction>
68 #include <QTimer>
69 #include <QMenu>
70 #include <QToolBar>
71
72 #define SALOME_PATCH_FOR_CTRL_WHEEL
73
74 extern "C" {
75 SHAPERGUI_EXPORT CAM_Module* createModule()
76 {
77   return new SHAPERGUI();
78 }
79
80 SHAPERGUI_EXPORT char* getModuleVersion()
81 {
82   return (char*)"0.0";
83 }
84 } // extern "C"
85
86 /** 
87 * Class for preferences management
88 */
89 class SHAPERGUI_PrefMgr: public ModuleBase_IPrefMgr
90 {
91 public:
92   /// Constructor
93   /// \param theMgr preferences manager of SALOME
94   /// \param theModName name of the module
95   SHAPERGUI_PrefMgr(LightApp_Preferences* theMgr, const QString& theModName):
96     myMgr(theMgr), myModName(theModName) {}
97
98   virtual int addPreference(const QString& theLbl, int pId,
99                             SUIT_PreferenceMgr::PrefItemType theType,
100                             const QString& theSection, const QString& theName )
101   {
102     return myMgr->addPreference(myModName, theLbl, pId, theType, theSection, theName);
103   }
104
105   virtual void setItemProperty(const QString& thePropName,
106                                const QVariant& theValue,
107                                const int theId = -1)
108   {
109     myMgr->setItemProperty(thePropName, theValue, theId);
110   }
111
112
113   virtual SUIT_PreferenceMgr* prefMgr() const { return myMgr; }
114
115 private:
116   LightApp_Preferences* myMgr;
117   QString myModName;
118 };
119
120
121
122
123 //******************************************************
124 SHAPERGUI::SHAPERGUI()
125     : LightApp_Module("SHAPER"),
126       mySelector(0), myIsOpened(0), myPopupMgr(0), myIsInspectionVisible(false),
127   myInspectionPanel(0)
128 {
129   myWorkshop = new XGUI_Workshop(this);
130   connect(myWorkshop, SIGNAL(commandStatusUpdated()),
131           this, SLOT(onUpdateCommandStatus()));
132
133   myProxyViewer = new SHAPERGUI_SalomeViewer(this);
134
135   ModuleBase_Preferences::setResourceMgr(application()->resourceMgr());
136   ModuleBase_Preferences::loadCustomProps();
137 }
138
139 //******************************************************
140 SHAPERGUI::~SHAPERGUI()
141 {
142   delete myWorkshop;
143   delete myProxyViewer;
144 }
145
146 //******************************************************
147 void SHAPERGUI::initialize(CAM_Application* theApp)
148 {
149   LightApp_Module::initialize(theApp);
150
151   myWorkshop->startApplication();
152   LightApp_Application* anApp = dynamic_cast<LightApp_Application*>(theApp);
153   if (anApp)
154   {
155     connect(anApp, SIGNAL(preferenceResetToDefaults()), this, SLOT(onDefaultPreferences()));
156   }
157
158   int aMenu = createMenu(tr("Inspection"), -1, -1, 30);
159   int aSubMenu = createMenu(tr("Information"), aMenu);
160
161   int aId = getNextCommandId();
162   myActionsList.append(aId);
163   SUIT_Desktop* aDesk = application()->desktop();
164   QString aTip = tr("Show inspection window");
165   myWhatIsAction = createAction(aId, aTip, QIcon(":pictures/whatis.png"), tr("What Is"),
166     aTip, QKeySequence(), aDesk, true, this, SLOT(onWhatIs(bool)));
167   myWhatIsAction->setStatusTip(aTip);
168   myWhatIsAction->setData("INSPECTION_CMD");
169   createMenu(aId, aSubMenu, 0);
170
171   QString aToolName = tr("Inspection tool");
172   int aTool = createTool(aToolName);
173   int aToolId = createTool(myWhatIsAction, aTool);
174   registerCommandToolbar(aToolName, aId);
175
176   // Define Edit toolbars command
177   aId = getNextCommandId();
178   myActionsList.append(aId);
179   aTip = tr("Edit toolbars of the module");
180   QAction* aAction = createAction(aId, aTip, QIcon(), tr("Edit toolbars..."),
181     aTip, QKeySequence(), aDesk, false, this, SLOT(onEditToolbars()));
182   int aEditMenu = createMenu(tr("MEN_DESK_EDIT"), -1, -1, 30);
183   int aEditItem = createMenu(aId, aEditMenu);
184 }
185
186 //******************************************************
187 void SHAPERGUI::windows(QMap<int, int>& theWndMap) const
188 {
189   theWndMap.insert(LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea);
190 }
191
192 //******************************************************
193 void SHAPERGUI::viewManagers(QStringList& theList) const
194 {
195   theList.append(OCCViewer_Viewer::Type());
196 }
197
198 //******************************************************
199 // We can not create selector in this method because it can be called when
200 // SHAPER module is not active. Take into account that creation of our selector
201 // leads to switching OFF all other selectors
202 //void SHAPERGUI::connectToStudy(CAM_Study* theStudy)
203 //{
204 //  // if there are created viewer managers, we should try to create viewer
205 //  // selector and initialize viewer with it. It sets interactive contect to the
206 //  // proxy viewer. If study is opened, CAM application calls this method before the open()
207 //  // of data model
208 //  // the SHAPER data model is specific and during open(load) redisplay signals are flushed, so
209 //  // we need to connect to the viewer before it. Here,
210 //  // it seems the most appropriate place for this
211 //  // according to SALOME architecture.
212 //  if (!mySelector) {
213 //    ViewManagerList OCCViewManagers;
214 //    application()->viewManagers(OCCViewer_Viewer::Type(), OCCViewManagers);
215 //    if (OCCViewManagers.size() > 0) {
216 //      mySelector = createSelector(OCCViewManagers.first());
217 //    }
218 //  }
219 //  LightApp_Module::connectToStudy(theStudy);
220 //}
221
222 //******************************************************
223 bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
224 {
225   bool isDone = LightApp_Module::activateModule(theStudy);
226   SHAPERGUI_DataModel* aDataModel = dynamic_cast<SHAPERGUI_DataModel*>(dataModel());
227   aDataModel->initRootObject();
228
229   if (isDone) {
230     setMenuShown(true);
231     setToolShown(true);
232
233     QObject* aObj = myWorkshop->objectBrowser()->parent();
234     QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
235     if (aObjDoc) {
236       QAction* aViewAct = aObjDoc->toggleViewAction();
237       aViewAct->setEnabled(true);
238       myWorkshop->objectBrowser()->setVisible(true);
239       aObjDoc->setVisible(true);
240       desktop()->tabifyDockWidget(aObjDoc, myWorkshop->propertyPanel());
241     }
242
243     if (!myInspectionPanel) {
244       myInspectionPanel = myWorkshop->inspectionPanel();
245       QAction* aViewAct = myInspectionPanel->toggleViewAction();
246       connect(aViewAct, SIGNAL(toggled(bool)), this, SLOT(onWhatIs(bool)));
247     }
248     myInspectionPanel->toggleViewAction()->setEnabled(true);
249
250     if (!mySelector) {
251       ViewManagerList OCCViewManagers;
252       application()->viewManagers(OCCViewer_Viewer::Type(), OCCViewManagers);
253       if (OCCViewManagers.size() > 0) {
254         mySelector = createSelector(OCCViewManagers.first());
255       }
256     }
257     // it should be pefromed after the selector creation in order to have AISContext
258     myWorkshop->activateModule();
259     //action(myEraseAll)->setEnabled(false);
260
261     if (myIsOpened) {
262       myWorkshop->objectBrowser()->rebuildDataTree();
263       myWorkshop->updateCommandStatus();
264       myIsOpened = false;
265     }
266     else
267       myWorkshop->updateCommandStatus();
268   }
269   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
270   myIsStorePositions = aResMgr->booleanValue("Study", "store_positions", true);
271   myIsEditEnabled = getApp()->isEditEnabled();
272   getApp()->setEditEnabled(false);
273
274   // this following row is caused by #187 bug.
275   // SALOME saves the dock widget positions before deactivateModule() and
276   // load it after the module activation. So, if the panel is visible before
277   // deactivate, it becomes visible after activate.
278   // In order to avoid the visible property panel, the widget position save is
279   // switch off in this module
280   aResMgr->setValue("Study", "store_positions", false);
281
282   // Synchronize displayed objects
283   Handle(AIS_InteractiveContext) aContext;
284   if (mySelector && mySelector->viewer())
285     aContext = mySelector->viewer()->getAISContext();
286
287   if (!aContext.IsNull()) {
288     XGUI_Displayer* aDisp = myWorkshop->displayer();
289     QObjectPtrList aObjList = aDisp->displayedObjects();
290
291     AIS_ListOfInteractive aList;
292     aContext->DisplayedObjects(aList);
293     AIS_ListIteratorOfListOfInteractive aLIt;
294     Handle(AIS_InteractiveObject) anAISIO;
295     foreach (ObjectPtr aObj, aObjList) {
296       AISObjectPtr aPrs = aDisp->getAISObject(aObj);
297       Handle(AIS_InteractiveObject) aAIS = aPrs->impl<Handle(AIS_InteractiveObject)>();
298       bool aFound = false;
299       for (aLIt.Initialize(aList); aLIt.More(); aLIt.Next()) {
300         anAISIO = aLIt.Value();
301         if (anAISIO.get() == aAIS.get()) {
302           aFound = true;
303           break;
304         }
305       }
306       if (!aFound) {
307         aObj->setDisplayed(false);
308         //aDisp->erase(aObj, false);
309       }
310     }
311     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
312   }
313   myProxyViewer->activateViewer(true);
314
315   // Postrrocessing for LoadScriptId to remove created(if it was created) SALOME Object Browser
316   connect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
317           this, SLOT(onScriptLoaded()));
318
319   disconnect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
320              getApp(), SLOT(onSaveDoc()));
321   disconnect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
322              getApp(), SLOT(onSaveAsDoc()));
323
324   connect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
325           this, SLOT(onSaveDocByShaper()));
326   connect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
327           this, SLOT(onSaveAsDocByShaper()));
328
329   return isDone;
330 }
331
332 //******************************************************
333 bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
334 {
335   myProxyViewer->activateViewer(false);
336   setMenuShown(false);
337   setToolShown(false);
338
339   myWorkshop->deactivateModule();
340
341   QObject* aObj = myWorkshop->objectBrowser()->parent();
342   QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
343   if (aObjDoc) {
344     aObjDoc->setVisible(false);
345     myWorkshop->objectBrowser()->setVisible(false);
346     QAction* aViewAct = aObjDoc->toggleViewAction();
347     aViewAct->setEnabled(false);
348   }
349
350   myIsInspectionVisible = myInspectionPanel->isVisible();
351   myInspectionPanel->hide();
352   QAction* aViewAct = myInspectionPanel->toggleViewAction();
353   aViewAct->setEnabled(false);
354
355   // the active operation should be stopped for the next activation.
356   // There should not be active operation and visualized preview.
357   // Abort operation should be performed before the selection's remove
358   // because the displayed objects should be removed from the viewer, but
359   // the AIS context is obtained from the selector.
360   ModuleBase_Operation* anOperation = myWorkshop->operationMgr()->currentOperation();
361   while (anOperation) {
362     anOperation->abort();
363     anOperation = myWorkshop->operationMgr()->currentOperation();
364   }
365   // Delete selector because it has to be redefined on next activation
366   if (mySelector) {
367     myProxyViewer->setSelector(0);
368     delete mySelector;
369     mySelector = 0;
370   }
371
372   myWorkshop->hidePanel(myWorkshop->facesPanel());
373   //myWorkshop->contextMenuMgr()->disconnectViewer();
374
375   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
376   aResMgr->setValue("Study", "store_positions", myIsStorePositions);
377   getApp()->setEditEnabled(myIsEditEnabled);
378
379   // Postrrocessing for LoadScriptId to remove created(if it was created) SALOME Object Browser
380   disconnect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
381              this, SLOT(onScriptLoaded()));
382
383   disconnect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
384              this, SLOT(onSaveDocByShaper()));
385   disconnect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
386              this, SLOT(onSaveAsDocByShaper()));
387
388   connect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
389           getApp(), SLOT(onSaveDoc()));
390   connect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
391           getApp(), SLOT(onSaveAsDoc()));
392
393
394   return LightApp_Module::deactivateModule(theStudy);
395 }
396
397 //******************************************************
398 void SHAPERGUI::onViewManagerAdded(SUIT_ViewManager* theMgr)
399 {
400   if (!mySelector) {
401     mySelector = createSelector(theMgr);
402     myWorkshop->selectionActivate()->updateSelectionFilters();
403     myWorkshop->selectionActivate()->updateSelectionModes();
404     myWorkshop->synchronizeViewer();
405   }
406 }
407
408 //******************************************************
409 void SHAPERGUI::onViewManagerRemoved(SUIT_ViewManager* theMgr)
410 {
411   if (mySelector) {
412     if (theMgr->getType() == OCCViewer_Viewer::Type()) {
413       OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
414       if (mySelector->viewer() == aViewer) {
415         XGUI_Displayer* aDisp = myWorkshop->displayer();
416         QObjectPtrList aObjects = aDisp->displayedObjects();
417         foreach(ObjectPtr aObj, aObjects)
418           aObj->setDisplayed(false);
419         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
420         myProxyViewer->setSelector(0);
421         delete mySelector;
422         mySelector = 0;
423
424         myWorkshop->module()->clearViewer();
425       }
426     }
427   }
428 }
429
430 //******************************************************
431 QtxPopupMgr* SHAPERGUI::popupMgr()
432 {
433   if (!myPopupMgr)
434     myPopupMgr = new QtxPopupMgr( 0, this );
435   return myPopupMgr;
436 }
437
438 //******************************************************
439 void SHAPERGUI::onDefaultPreferences()
440 {
441   // reset main resources
442   ModuleBase_Preferences::resetResourcePreferences(preferences());
443   // reset plugin's resources
444   ModuleBase_Preferences::resetConfigPropPreferences(preferences());
445
446   myWorkshop->displayer()->redisplayObjects();
447 }
448
449 //******************************************************
450 void SHAPERGUI::onScriptLoaded()
451 {
452   // this slot is called after processing of the LoadScriptId action of SalomeApp Application
453   // Each dumped script contains updateObjBrowser() that creates a new instance of Object
454   // Browser. When SHAPER module is active, this browser should not be used. It might be removed
455   // as hidden by means of updateWindows() of SalomeApp_Application or to remove
456   // it manually (because this method of application is protected)
457   SUIT_DataBrowser* aBrowser = getApp()->objectBrowser();
458   if (aBrowser)
459     delete aBrowser;
460 }
461
462 //******************************************************
463 void SHAPERGUI::onSaveDocByShaper()
464 {
465   if(!workshop()->operationMgr()->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
466     return;
467
468   getApp()->onSaveDoc();
469 }
470
471 //******************************************************
472 void SHAPERGUI::onSaveAsDocByShaper()
473 {
474   if(!workshop()->operationMgr()->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
475     return;
476
477   getApp()->onSaveAsDoc();
478 }
479
480 //******************************************************
481 void SHAPERGUI::onUpdateCommandStatus()
482 {
483   getApp()->updateActions();
484 }
485
486 //******************************************************
487 SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
488 {
489   if (theMgr->getType() == OCCViewer_Viewer::Type()) {
490     OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
491     SHAPERGUI_OCCSelector* aSelector = new SHAPERGUI_OCCSelector(aViewer,
492                                                                  getApp()->selectionMgr());
493 #ifdef SALOME_PATCH_FOR_CTRL_WHEEL
494     aViewer->setUseLocalSelection(true);
495 #endif
496     LightApp_SelectionMgr* aMgr = getApp()->selectionMgr();
497     QList<SUIT_Selector*> aList;
498     aMgr->selectors(aList);
499     foreach(SUIT_Selector* aSel, aList)
500     {
501       aSel->setEnabled(aSel == aSelector);
502     }
503     myProxyViewer->setSelector(aSelector);
504     return aSelector;
505   }
506   return 0;
507 }
508
509 //******************************************************
510 CAM_DataModel* SHAPERGUI::createDataModel()
511 {
512   return new SHAPERGUI_DataModel(this);
513 }
514
515 QAction* SHAPERGUI::addFeature(const QString& theWBName, const ActionInfo& theInfo,
516                                const bool isAddSeparator)
517 {
518   return addFeature(theWBName,
519                     theInfo.toolBar,
520                     theInfo.id,
521                     theInfo.text,
522                     //Issue #650: in the SALOME mode the tooltip should be same as text
523                     theInfo.text,
524                     theInfo.icon,
525                     theInfo.shortcut,
526                     theInfo.checkable,
527                     isAddSeparator,
528                     theInfo.toolTip);
529 }
530
531 //******************************************************
532 QAction* SHAPERGUI::addFeature(const QString& theWBName, const QString& theTBName,
533                                const QString& theId, const QString& theTitle, const QString& theTip,
534                                const QIcon& theIcon, const QKeySequence& theKeys,
535                                bool isCheckable, const bool isAddSeparator,
536                                const QString& theStatusTip)
537 {
538   static QString aLastTool = "";
539   static int aNb = 0;
540   if (aLastTool.isEmpty())
541     aLastTool = theWBName;
542   else if (theWBName != aLastTool) {
543     aLastTool = theWBName;
544     if (aNb > 20) {
545       desktop()->addToolBarBreak();
546       aNb = 0;
547     }
548   }
549   aNb++;
550
551   int aId = getNextCommandId();
552   myActionsList.append(aId);
553   SUIT_Desktop* aDesk = application()->desktop();
554   int aKeys = 0;
555   for (int i = 0; i < theKeys.count(); i++)
556     aKeys += theKeys[i];
557   QAction* aAction = createAction(aId, theTip, theIcon, theTitle, theTip, aKeys, aDesk,
558                                   isCheckable);
559   aAction->setStatusTip(theStatusTip);
560
561   aAction->setData(theId);
562
563   int aWBMenu = createMenu(theWBName, -1, -1, 30/*10-Window, 1000 - Help*/);
564   int aItemId = createMenu(aId, aWBMenu);
565   if (isAddSeparator)
566     createMenu(separator(), aWBMenu);
567
568   int aWBTool = createTool(theTBName, theTBName);
569   int aToolId = createTool(aId, aWBTool);
570   registerCommandToolbar(theTBName, aId);
571   if (isAddSeparator) {
572     createTool(separator(), aWBTool);
573     registerCommandToolbar(theTBName, -1);
574   }
575   return aAction;
576 }
577
578 bool SHAPERGUI::isFeatureOfNested(const QAction* theAction)
579 {
580   return dynamic_cast<const SHAPERGUI_NestedButton*>(theAction);
581 }
582
583 QAction* SHAPERGUI::addFeatureOfNested(const QString& theWBName,
584                                        const ActionInfo& theInfo,
585                                        const QList<QAction*>& theNestedActions)
586 {
587   SUIT_Desktop* aDesk = application()->desktop();
588   SHAPERGUI_NestedButton* anAction = new SHAPERGUI_NestedButton(aDesk, theNestedActions);
589   anAction->setData(theInfo.id);
590   anAction->setCheckable(theInfo.checkable);
591   anAction->setChecked(theInfo.checked);
592   anAction->setEnabled(theInfo.enabled);
593   anAction->setVisible(theInfo.visible);
594   anAction->setIcon(theInfo.icon);
595   anAction->setText(theInfo.text);
596   anAction->setToolTip(theInfo.toolTip);
597   anAction->setShortcut(theInfo.shortcut);
598   anAction->setFont(theInfo.font);
599
600   int aWBMenu = createMenu(theWBName, -1, -1, 30);
601   int aItemId = createMenu(anAction, aWBMenu);
602   myActionsList.append(aItemId);
603   createMenu(separator(), aWBMenu); /// nested action is always separated of others
604
605   int aWBTool = createTool(theWBName, theWBName);
606   int aToolId = createTool(anAction, aWBTool);
607   registerCommandToolbar(theWBName, aItemId);
608   createTool(separator(), aWBTool); /// nested action is always separated of others
609   registerCommandToolbar(theWBName, -1);
610
611   return anAction;
612 }
613
614
615 //******************************************************
616 QAction* SHAPERGUI::addDesktopCommand(const QString& theId, const QString& theTitle,
617                                            const QString& theTip, const QIcon& theIcon,
618                                            const QKeySequence& theKeys, bool isCheckable,
619                                            const char* theMenuSourceText, const int theMenuPosition)
620 {
621   int aMenu = createMenu(tr(theMenuSourceText), -1, -1);
622
623   int aId = getNextCommandId();
624   myActionsList.append(aId);
625   SUIT_Desktop* aDesk = application()->desktop();
626   int aKeys = 0;
627   for (int i = 0; i < theKeys.count(); i++)
628     aKeys += theKeys[i];
629   QAction* aAction = createAction(aId, theTip, theIcon, theTitle, theTip, aKeys, aDesk,
630                                   isCheckable);
631   aAction->setStatusTip(theTip);
632   aAction->setData(theId);
633   createMenu(aId, aMenu, theMenuPosition);
634   return aAction;
635 }
636
637 //******************************************************
638 void SHAPERGUI::addDesktopMenuSeparator(const char* theMenuSourceText, const int theMenuPosition)
639 {
640   int aMenu = createMenu(tr(theMenuSourceText), -1, -1);
641   createMenu(separator(), aMenu, -1, theMenuPosition);
642 }
643
644 //******************************************************
645 bool SHAPERGUI::addActionInToolbar( QAction* theAction, const QString& theToolBarTitle )
646 {
647   if( !theAction )
648     return false;
649
650   SUIT_Desktop* aDesktop = application()->desktop();
651   if( !aDesktop )
652     return false;
653
654   QtxActionToolMgr* aToolMgr = aDesktop->toolMgr();
655   if( !aToolMgr )
656     return false;
657
658   aToolMgr->append( theAction, theToolBarTitle );
659   return true;
660 }
661
662 //******************************************************
663 QList<QAction*> SHAPERGUI::commandList() const
664 {
665   QList<QAction*> aActions;
666   foreach (int aId, myActionsList) {
667     QAction* aCmd = action(aId);
668     if (aCmd)
669       aActions.append(aCmd);
670   }
671
672   return aActions;
673 }
674
675 //******************************************************
676 QMainWindow* SHAPERGUI::desktop() const
677 {
678   return application()->desktop();
679 }
680
681 void SHAPERGUI::setFeatureInfo(const QString& theFeatureId,
682                                const std::shared_ptr<Config_FeatureMessage>& theMessage)
683 {
684   myFeaturesInfo.insert(theFeatureId, theMessage);
685 }
686
687 std::shared_ptr<Config_FeatureMessage> SHAPERGUI::featureInfo(const QString& theFeatureId)
688 {
689   std::shared_ptr<Config_FeatureMessage> aMessage;
690   if (myFeaturesInfo.contains(theFeatureId))
691     aMessage =  myFeaturesInfo[theFeatureId];
692   return aMessage;
693 }
694
695 //******************************************************
696 void SHAPERGUI::selectionChanged()
697 {
698   LightApp_Module::selectionChanged();
699   myWorkshop->salomeViewerSelectionChanged();
700 }
701
702 //******************************************************
703 void SHAPERGUI::contextMenuPopup(const QString& theClient, QMenu* theMenu, QString& theTitle)
704 {
705   myWorkshop->contextMenuMgr()->updateViewerMenu();
706   myWorkshop->contextMenuMgr()->addViewerMenu(theMenu);
707   LightApp_Module::contextMenuPopup(theClient, theMenu, theTitle);
708 }
709
710
711 //******************************************************
712 void SHAPERGUI::createPreferences()
713 {
714   LightApp_Preferences* pref = preferences();
715   if (!pref)
716     return;
717   ModuleBase_Preferences::updateConfigByResources();
718   QString aModName = moduleName();
719
720   QtxPreferenceItem* item = pref->findItem(aModName, true );
721   if ( item && (!item->isEmpty() )) {
722     item->parentItem()->removeItem(item);
723     delete item;
724   }
725
726   int catId = pref->addPreference(aModName, -1 );
727   if ( catId == -1 )
728     return;
729   SHAPERGUI_PrefMgr aMgr(pref, aModName);
730   ModuleBase_Preferences::createEditContent(&aMgr, catId);
731
732   int viewTab = pref->addItem(tr("Viewer"), catId);
733   // Create other parameters group in viewer tab
734   int otherGroup = pref->addItem(tr("Default selection"), viewTab);
735   pref->setItemProperty("columns", 3, otherGroup);
736   pref->addItem(tr("Faces"), otherGroup,
737                          SUIT_PreferenceMgr::Bool,
738                          ModuleBase_Preferences::VIEWER_SECTION, "face-selection");
739   pref->addItem(tr("Edges"), otherGroup,
740                          SUIT_PreferenceMgr::Bool,
741                          ModuleBase_Preferences::VIEWER_SECTION, "edge-selection");
742   pref->addItem(tr("Vertices"), otherGroup,
743                          SUIT_PreferenceMgr::Bool,
744                          ModuleBase_Preferences::VIEWER_SECTION, "vertex-selection");
745
746   int sensitivityGroup = pref->addItem(tr("Selection sensitivity"), viewTab);
747   pref->setItemProperty("columns", 2, sensitivityGroup);
748   pref->addItem(tr("Vertex"), sensitivityGroup, SUIT_PreferenceMgr::DblSpin,
749                 ModuleBase_Preferences::VIEWER_SECTION, "point-selection-sensitivity");
750   pref->addItem(tr("Edge"), sensitivityGroup, SUIT_PreferenceMgr::DblSpin,
751                 ModuleBase_Preferences::VIEWER_SECTION, "edge-selection-sensitivity");
752   pref->retrieve();
753 }
754
755 //******************************************************
756 void SHAPERGUI::preferencesChanged(const QString& theSection, const QString& theParam)
757 {
758   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
759   QString aVal = aResMgr->stringValue(theSection, theParam);
760   Config_Prop* aProp = Config_PropManager::findProp(theSection.toStdString(),
761                                                     theParam.toStdString());
762   std::string aValue = aVal.toStdString();
763   if (aValue.empty()) {
764     aValue = aProp->defaultValue();
765     aResMgr->setValue(theSection, theParam, QString(aValue.c_str()));
766
767     LightApp_Preferences* pref = preferences();
768     if (pref)
769       pref->retrieve();
770   }
771   aProp->setValue(aValue);
772
773   myWorkshop->displayer()->redisplayObjects();
774 }
775
776 void SHAPERGUI::putInfo(const QString& theInfo, const int theMSecs)
777 {
778   application()->putInfo(theInfo, theMSecs);
779 }
780
781 bool SHAPERGUI::abortAllOperations()
782 {
783   return workshop()->operationMgr()->abortAllOperations();
784 }
785
786 void SHAPERGUI::createFeatureActions()
787 {
788   myWorkshop->menuMgr()->createFeatureActions();
789 }
790
791 void SHAPERGUI::onWhatIs(bool isToggled)
792 {
793   if (sender() == myWhatIsAction) {
794     QAction* aViewAct = myInspectionPanel->toggleViewAction();
795     aViewAct->blockSignals(true);
796     aViewAct->setChecked(isToggled);
797     aViewAct->blockSignals(false);
798     myInspectionPanel->setVisible(isToggled);
799   }
800   else {
801     myWhatIsAction->blockSignals(true);
802     myWhatIsAction->setChecked(isToggled);
803     myWhatIsAction->blockSignals(false);
804     myInspectionPanel->setVisible(isToggled);
805   }
806 }
807
808 void SHAPERGUI::updateModuleVisibilityState()
809 {
810   LightApp_Module::updateModuleVisibilityState();
811   onWhatIs(myIsInspectionVisible);
812 }
813
814 void SHAPERGUI::onEditToolbars()
815 {
816   SHAPERGUI_ToolbarsDlg aDlg(this);
817   if (aDlg.exec() == QDialog::Accepted) {
818     updateToolbars(aDlg.result());
819   }
820 }
821
822 void SHAPERGUI::registerCommandToolbar(const QString& theToolName, int theCommandId)
823 {
824   if (!myToolbars.contains(theToolName))
825     myToolbars[theToolName] = QList<int>();
826   myToolbars[theToolName].append(theCommandId);
827 }
828
829 int SHAPERGUI::getNextCommandId() const
830 {
831   QtxActionMenuMgr* aMenuMgr = menuMgr();
832   QIntList aIds = aMenuMgr->idList();
833   int aId = aIds.count();
834   while (action(aId) || myActionsList.contains(aId))
835     aId++;
836   return aId;
837 }
838
839 void SHAPERGUI::updateToolbars(const QMap<QString, QIntList>& theNewToolbars)
840 {
841   QtxActionToolMgr* aMgr = toolMgr();
842   QStringList aToolbars = theNewToolbars.keys();
843   QIntList aCommands, aOldCmd;
844   int aToolbarId;
845   QAction* aAction;
846   int aActionId;
847   foreach(QString aName, aToolbars) {
848     aCommands = theNewToolbars[aName];
849     // Find or create toolbar
850     if (aMgr->hasToolBar(aName)) {
851       aToolbarId = aMgr->find(aMgr->toolBar(aName));
852       aOldCmd = myToolbars[aName];
853     }
854     else {
855       aToolbarId = aMgr->createToolBar(aName);
856     }
857     int aPos = 0;
858     foreach (int aCmd, aCommands) {
859       // Find action
860       if (aCmd == -1)
861         aAction = separator();
862       else
863         aAction = action(aCmd);
864       aActionId = aMgr->actionId(aAction);
865       if (aActionId == -1) {
866         // Add new action
867         aMgr->insert(aAction, aToolbarId, aPos);
868       }
869       else {
870         // Change position of action
871         if (aMgr->index(aActionId, aToolbarId) != aPos) {
872           if (aMgr->containsAction(aActionId, aToolbarId))
873             aMgr->remove(aActionId, aToolbarId);
874           aMgr->insert(aActionId, aToolbarId, aPos);
875         }
876       }
877       aOldCmd.removeAll(aCmd);
878       aPos++;
879     }
880     // remove extra actions
881     foreach(int aCmd, aOldCmd) {
882       aAction = action(aCmd);
883       aActionId = aMgr->actionId(aAction);
884       aMgr->remove(aActionId, aToolbarId);
885     }
886     myToolbars.remove(aName);
887   }
888   // Remove extra toolbars
889   aToolbars = myToolbars.keys();
890   QToolBar* aToolbar = 0;
891   QList<QAction*> aActionList;
892   foreach(QString aName, aToolbars) {
893     aMgr->removeToolBar(aName);
894   }
895   // Set new toolbars structure
896   myToolbars = theNewToolbars;
897 }