Salome HOME
Merge branch 'master' into cgt/devCEA
[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
26 #include <XGUI_Workshop.h>
27 #include <XGUI_PropertyPanel.h>
28 #include <XGUI_ContextMenuMgr.h>
29 #include <XGUI_ObjectsBrowser.h>
30 #include <XGUI_OperationMgr.h>
31 #include <XGUI_Displayer.h>
32 #include <XGUI_MenuMgr.h>
33
34 #include <ModuleBase_Operation.h>
35 #include <ModuleBase_Preferences.h>
36 #include <ModuleBase_ActionInfo.h>
37 #include <ModuleBase_IModule.h>
38
39 #include <LightApp_Application.h>
40 #include <LightApp_SelectionMgr.h>
41 #include <LightApp_OCCSelector.h>
42 #include <LightApp_Study.h>
43 #include <OCCViewer_ViewModel.h>
44
45 #include <SUIT_Selector.h>
46 #include <SUIT_Desktop.h>
47 #include <SUIT_ViewManager.h>
48 #include <SUIT_ResourceMgr.h>
49 #include <SUIT_DataBrowser.h>
50
51 #include <QtxPopupMgr.h>
52 #include <QtxActionMenuMgr.h>
53 #include <QtxActionToolMgr.h>
54 #include <QtxResourceMgr.h>
55
56 #include <Config_PropManager.h>
57 #include <Config_ModuleReader.h>
58
59 #include <AIS_ListOfInteractive.hxx>
60 #include <AIS_ListIteratorOfListOfInteractive.hxx>
61
62 #include <QDockWidget>
63 #include <QAction>
64 #include <QTimer>
65 #include <QMenu>
66
67 //#define SALOME_PATCH_FOR_CTRL_WHEEL
68
69 extern "C" {
70 SHAPERGUI_EXPORT CAM_Module* createModule()
71 {
72   return new SHAPERGUI();
73 }
74
75 SHAPERGUI_EXPORT char* getModuleVersion()
76 {
77   return (char*)"0.0";
78 }
79 } // extern "C"
80
81 /** 
82 * Class for preferences management
83 */
84 class SHAPERGUI_PrefMgr: public ModuleBase_IPrefMgr
85 {
86 public:
87   /// Constructor
88   /// \param theMgr preferences manager of SALOME
89   /// \param theModName name of the module
90   SHAPERGUI_PrefMgr(LightApp_Preferences* theMgr, const QString& theModName):
91     myMgr(theMgr), myModName(theModName) {}
92
93   virtual int addPreference(const QString& theLbl, int pId,
94                             SUIT_PreferenceMgr::PrefItemType theType,
95                             const QString& theSection, const QString& theName )
96   {
97     return myMgr->addPreference(myModName, theLbl, pId, theType, theSection, theName);
98   }
99
100   virtual void setItemProperty(const QString& thePropName,
101                                const QVariant& theValue,
102                                const int theId = -1)
103   {
104     myMgr->setItemProperty(thePropName, theValue, theId);
105   }
106
107
108   virtual SUIT_PreferenceMgr* prefMgr() const { return myMgr; }
109
110 private:
111   LightApp_Preferences* myMgr;
112   QString myModName;
113 };
114
115
116
117
118 //******************************************************
119 SHAPERGUI::SHAPERGUI()
120     : LightApp_Module("SHAPER"),
121       mySelector(0), myIsOpened(0), myPopupMgr(0)
122 {
123   myWorkshop = new XGUI_Workshop(this);
124   connect(myWorkshop, SIGNAL(commandStatusUpdated()),
125           this, SLOT(onUpdateCommandStatus()));
126
127   myProxyViewer = new SHAPERGUI_SalomeViewer(this);
128
129   ModuleBase_Preferences::setResourceMgr(application()->resourceMgr());
130   ModuleBase_Preferences::loadCustomProps();
131 }
132
133 //******************************************************
134 SHAPERGUI::~SHAPERGUI()
135 {
136 }
137
138 //******************************************************
139 void SHAPERGUI::initialize(CAM_Application* theApp)
140 {
141   LightApp_Module::initialize(theApp);
142
143   myWorkshop->startApplication();
144   LightApp_Application* anApp = dynamic_cast<LightApp_Application*>(theApp);
145   if (anApp)
146   {
147     connect(anApp, SIGNAL(preferenceResetToDefaults()), this, SLOT(onDefaultPreferences()));
148   }
149 }
150
151 //******************************************************
152 void SHAPERGUI::windows(QMap<int, int>& theWndMap) const
153 {
154   theWndMap.insert(LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea);
155 }
156
157 //******************************************************
158 void SHAPERGUI::viewManagers(QStringList& theList) const
159 {
160   theList.append(OCCViewer_Viewer::Type());
161 }
162
163 //******************************************************
164 // We can not create selector in this method because it can be called when
165 // SHAPER module is not active. Take into account that creation of our selector
166 // leads to switching OFF all other selectors
167 //void SHAPERGUI::connectToStudy(CAM_Study* theStudy)
168 //{
169 //  // if there are created viewer managers, we should try to create viewer
170 //  // selector and initialize viewer with it. It sets interactive contect to the
171 //  // proxy viewer. If study is opened, CAM application calls this method before the open()
172 //  // of data model
173 //  // the SHAPER data model is specific and during open(load) redisplay signals are flushed, so
174 //  // we need to connect to the viewer before it. Here,
175 //  // it seems the most appropriate place for this
176 //  // according to SALOME architecture.
177 //  if (!mySelector) {
178 //    ViewManagerList OCCViewManagers;
179 //    application()->viewManagers(OCCViewer_Viewer::Type(), OCCViewManagers);
180 //    if (OCCViewManagers.size() > 0) {
181 //      mySelector = createSelector(OCCViewManagers.first());
182 //    }
183 //  }
184 //  LightApp_Module::connectToStudy(theStudy);
185 //}
186
187 //******************************************************
188 bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
189 {
190   bool isDone = LightApp_Module::activateModule(theStudy);
191   SHAPERGUI_DataModel* aDataModel = dynamic_cast<SHAPERGUI_DataModel*>(dataModel());
192   aDataModel->initRootObject();
193
194   if (isDone) {
195     setMenuShown(true);
196     setToolShown(true);
197
198     QObject* aObj = myWorkshop->objectBrowser()->parent();
199     QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
200     if (aObjDoc) {
201       QAction* aViewAct = aObjDoc->toggleViewAction();
202       aViewAct->setEnabled(true);
203       myWorkshop->objectBrowser()->setVisible(true);
204       aObjDoc->setVisible(true);
205       desktop()->tabifyDockWidget(aObjDoc, myWorkshop->propertyPanel());
206     }
207
208     if (!mySelector) {
209       ViewManagerList OCCViewManagers;
210       application()->viewManagers(OCCViewer_Viewer::Type(), OCCViewManagers);
211       if (OCCViewManagers.size() > 0) {
212         mySelector = createSelector(OCCViewManagers.first());
213       }
214     }
215     // it should be pefromed after the selector creation in order to have AISContext
216     myWorkshop->activateModule();
217     //action(myEraseAll)->setEnabled(false);
218
219     if (myIsOpened) {
220       myWorkshop->objectBrowser()->rebuildDataTree();
221       myWorkshop->updateCommandStatus();
222       myIsOpened = false;
223     }
224     else
225       myWorkshop->updateCommandStatus();
226   }
227   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
228   myIsStorePositions = aResMgr->booleanValue("Study", "store_positions", true);
229   myIsEditEnabled = getApp()->isEditEnabled();
230   getApp()->setEditEnabled(false);
231
232   // this following row is caused by #187 bug.
233   // SALOME saves the dock widget positions before deactivateModule() and
234   // load it after the module activation. So, if the panel is visible before
235   // deactivate, it becomes visible after activate.
236   // In order to avoid the visible property panel, the widget position save is
237   // switch off in this module
238   aResMgr->setValue("Study", "store_positions", false);
239
240   // Synchronize displayed objects
241   Handle(AIS_InteractiveContext) aContext;
242   if (mySelector && mySelector->viewer())
243     aContext = mySelector->viewer()->getAISContext();
244
245   if (!aContext.IsNull()) {
246     XGUI_Displayer* aDisp = myWorkshop->displayer();
247     QObjectPtrList aObjList = aDisp->displayedObjects();
248
249     AIS_ListOfInteractive aList;
250     aContext->DisplayedObjects(aList);
251     AIS_ListIteratorOfListOfInteractive aLIt;
252     Handle(AIS_InteractiveObject) anAISIO;
253     foreach (ObjectPtr aObj, aObjList) {
254       AISObjectPtr aPrs = aDisp->getAISObject(aObj);
255       Handle(AIS_InteractiveObject) aAIS = aPrs->impl<Handle(AIS_InteractiveObject)>();
256       bool aFound = false;
257       for (aLIt.Initialize(aList); aLIt.More(); aLIt.Next()) {
258         anAISIO = aLIt.Value();
259         if (anAISIO.get() == aAIS.get()) {
260           aFound = true;
261           break;
262         }
263       }
264       if (!aFound) {
265         aObj->setDisplayed(false);
266         //aDisp->erase(aObj, false);
267       }
268     }
269     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
270   }
271   myProxyViewer->activateViewer(true);
272
273   // Postrrocessing for LoadScriptId to remove created(if it was created) SALOME Object Browser
274   connect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
275           this, SLOT(onScriptLoaded()));
276   return isDone;
277 }
278
279 //******************************************************
280 bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
281 {
282   myProxyViewer->activateViewer(false);
283   setMenuShown(false);
284   setToolShown(false);
285
286   myWorkshop->deactivateModule();
287
288   QObject* aObj = myWorkshop->objectBrowser()->parent();
289   QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
290   if (aObjDoc) {
291     aObjDoc->setVisible(false);
292     myWorkshop->objectBrowser()->setVisible(false);
293     QAction* aViewAct = aObjDoc->toggleViewAction();
294     aViewAct->setEnabled(false);
295   }
296
297   // the active operation should be stopped for the next activation.
298   // There should not be active operation and visualized preview.
299   // Abort operation should be performed before the selection's remove
300   // because the displayed objects should be removed from the viewer, but
301   // the AIS context is obtained from the selector.
302   ModuleBase_Operation* anOperation = myWorkshop->operationMgr()->currentOperation();
303   while (anOperation) {
304     anOperation->abort();
305     anOperation = myWorkshop->operationMgr()->currentOperation();
306   }
307   // Delete selector because it has to be redefined on next activation
308   if (mySelector) {
309     myProxyViewer->setSelector(0);
310     delete mySelector;
311     mySelector = 0;
312   }
313
314   //myWorkshop->contextMenuMgr()->disconnectViewer();
315
316   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
317   aResMgr->setValue("Study", "store_positions", myIsStorePositions);
318   getApp()->setEditEnabled(myIsEditEnabled);
319
320   // Postrrocessing for LoadScriptId to remove created(if it was created) SALOME Object Browser
321   disconnect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
322              this, SLOT(onScriptLoaded()));
323
324   return LightApp_Module::deactivateModule(theStudy);
325 }
326
327 //******************************************************
328 void SHAPERGUI::onViewManagerAdded(SUIT_ViewManager* theMgr)
329 {
330   if (!mySelector) {
331     mySelector = createSelector(theMgr);
332     myWorkshop->module()->activateSelectionFilters();
333     myWorkshop->synchronizeViewer();
334   }
335 }
336
337 //******************************************************
338 void SHAPERGUI::onViewManagerRemoved(SUIT_ViewManager* theMgr)
339 {
340   if (mySelector) {
341     if (theMgr->getType() == OCCViewer_Viewer::Type()) {
342       OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
343       if (mySelector->viewer() == aViewer) {
344         XGUI_Displayer* aDisp = myWorkshop->displayer();
345         QObjectPtrList aObjects = aDisp->displayedObjects();
346         foreach(ObjectPtr aObj, aObjects)
347           aObj->setDisplayed(false);
348         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
349         myProxyViewer->setSelector(0);
350         delete mySelector;
351         mySelector = 0;
352
353         myWorkshop->module()->clearViewer();
354       }
355     }
356   }
357 }
358
359 //******************************************************
360 QtxPopupMgr* SHAPERGUI::popupMgr()
361 {
362   if (!myPopupMgr)
363     myPopupMgr = new QtxPopupMgr( 0, this );
364   return myPopupMgr;
365 }
366
367 //******************************************************
368 void SHAPERGUI::onDefaultPreferences()
369 {
370   // reset main resources
371   ModuleBase_Preferences::resetResourcePreferences(preferences());
372   // reset plugin's resources
373   ModuleBase_Preferences::resetConfigPropPreferences(preferences());
374
375   myWorkshop->displayer()->redisplayObjects();
376 }
377
378 //******************************************************
379 void SHAPERGUI::onScriptLoaded()
380 {
381   // this slot is called after processing of the LoadScriptId action of SalomeApp Application
382   // Each dumped script contains updateObjBrowser() that creates a new instance of Object
383   // Browser. When SHAPER module is active, this browser should not be used. It might be removed
384   // as hidden by means of updateWindows() of SalomeApp_Application or to remove
385   // it manually (because this method of application is protected)
386   SUIT_DataBrowser* aBrowser = getApp()->objectBrowser();
387   if (aBrowser)
388     delete aBrowser;
389 }
390
391 //******************************************************
392 void SHAPERGUI::onUpdateCommandStatus()
393 {
394   getApp()->updateActions();
395 }
396
397 //******************************************************
398 SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
399 {
400   if (theMgr->getType() == OCCViewer_Viewer::Type()) {
401     OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
402     SHAPERGUI_OCCSelector* aSelector = new SHAPERGUI_OCCSelector(aViewer,
403                                                                  getApp()->selectionMgr());
404 #ifdef SALOME_PATCH_FOR_CTRL_WHEEL
405     aViewer->setUseLocalSelection(true);
406 #endif
407     LightApp_SelectionMgr* aMgr = getApp()->selectionMgr();
408     QList<SUIT_Selector*> aList;
409     aMgr->selectors(aList);
410     foreach(SUIT_Selector* aSel, aList)
411     {
412       aSel->setEnabled(aSel == aSelector);
413     }
414     myProxyViewer->setSelector(aSelector);
415     return aSelector;
416   }
417   return 0;
418 }
419
420 //******************************************************
421 CAM_DataModel* SHAPERGUI::createDataModel()
422 {
423   return new SHAPERGUI_DataModel(this);
424 }
425
426 QAction* SHAPERGUI::addFeature(const QString& theWBName, const ActionInfo& theInfo,
427                                const bool isAddSeparator)
428 {
429   return addFeature(theWBName,
430                     theInfo.id,
431                     theInfo.text,
432                     //Issue #650: in the SALOME mode the tooltip should be same as text
433                     theInfo.text,
434                     theInfo.icon,
435                     theInfo.shortcut,
436                     theInfo.checkable,
437                     isAddSeparator,
438                     theInfo.toolTip);
439 }
440
441 //******************************************************
442 QAction* SHAPERGUI::addFeature(const QString& theWBName, const QString& theId,
443                                const QString& theTitle, const QString& theTip,
444                                const QIcon& theIcon, const QKeySequence& theKeys,
445                                bool isCheckable, const bool isAddSeparator,
446                                const QString& theStatusTip)
447 {
448   static QString aLastTool = "";
449   static int aNb = 0;
450   if (aLastTool.isEmpty())
451     aLastTool = theWBName;
452   else if (theWBName != aLastTool) {
453     aLastTool = theWBName;
454     if (aNb > 20) {
455       desktop()->addToolBarBreak();
456       aNb = 0;
457     }
458   }
459   aNb++;
460
461   int aId = myActionsList.size();
462   myActionsList.append(theId);
463   SUIT_Desktop* aDesk = application()->desktop();
464   int aKeys = 0;
465   for (int i = 0; i < theKeys.count(); i++)
466     aKeys += theKeys[i];
467   QAction* aAction = createAction(aId, theTip, theIcon, theTitle, theTip, aKeys, aDesk,
468                                   isCheckable);
469   aAction->setStatusTip(theStatusTip);
470
471   aAction->setData(theId);
472
473   int aWBMenu = createMenu(theWBName, -1, -1, 30/*10-Window, 1000 - Help*/);
474   int aItemId = createMenu(aId, aWBMenu);
475   if (isAddSeparator)
476     createMenu(separator(), aWBMenu);
477
478   int aWBTool = createTool(theWBName, theWBName);
479   int aToolId = createTool(aId, aWBTool);
480   if (isAddSeparator)
481     createTool(separator(), aWBTool);
482
483   return aAction;
484 }
485
486 bool SHAPERGUI::isFeatureOfNested(const QAction* theAction)
487 {
488   return dynamic_cast<const SHAPERGUI_NestedButton*>(theAction);
489 }
490
491 QAction* SHAPERGUI::addFeatureOfNested(const QString& theWBName,
492                                        const ActionInfo& theInfo,
493                                        const QList<QAction*>& theNestedActions)
494 {
495   myActionsList.append(theInfo.id);
496   SUIT_Desktop* aDesk = application()->desktop();
497   SHAPERGUI_NestedButton* anAction = new SHAPERGUI_NestedButton(aDesk, theNestedActions);
498   anAction->setData(theInfo.id);
499   anAction->setCheckable(theInfo.checkable);
500   anAction->setChecked(theInfo.checked);
501   anAction->setEnabled(theInfo.enabled);
502   anAction->setVisible(theInfo.visible);
503   anAction->setIcon(theInfo.icon);
504   anAction->setText(theInfo.text);
505   anAction->setToolTip(theInfo.toolTip);
506   anAction->setShortcut(theInfo.shortcut);
507   anAction->setFont(theInfo.font);
508
509   int aWBMenu = createMenu(theWBName, -1, -1, 30);
510   int aItemId = createMenu(anAction, aWBMenu);
511   createMenu(separator(), aWBMenu); /// nested action is always separated of others
512
513   int aWBTool = createTool(theWBName, theWBName);
514   int aToolId = createTool(anAction, aWBTool);
515   createTool(separator(), aWBTool); /// nested action is always separated of others
516
517   return anAction;
518 }
519
520
521 //******************************************************
522 QAction* SHAPERGUI::addDesktopCommand(const QString& theId, const QString& theTitle,
523                                            const QString& theTip, const QIcon& theIcon,
524                                            const QKeySequence& theKeys, bool isCheckable,
525                                            const char* theMenuSourceText, const int theMenuPosition)
526 {
527   int aMenu = createMenu(tr(theMenuSourceText), -1, -1);
528
529   int aId = myActionsList.size();
530   myActionsList.append(theId);
531   SUIT_Desktop* aDesk = application()->desktop();
532   int aKeys = 0;
533   for (int i = 0; i < theKeys.count(); i++)
534     aKeys += theKeys[i];
535   QAction* aAction = createAction(aId, theTip, theIcon, theTitle, theTip, aKeys, aDesk,
536                                   isCheckable);
537   aAction->setStatusTip(theTip);
538   aAction->setData(theId);
539   createMenu(aId, aMenu, theMenuPosition);
540   return aAction;
541 }
542
543 //******************************************************
544 void SHAPERGUI::addDesktopMenuSeparator(const char* theMenuSourceText, const int theMenuPosition)
545 {
546   int aMenu = createMenu(tr(theMenuSourceText), -1, -1);
547   createMenu(separator(), aMenu, -1, theMenuPosition);
548 }
549
550 bool SHAPERGUI::addActionInToolbar( QAction* theAction, const QString& theToolBarTitle )
551 {
552   if( !theAction )
553     return false;
554
555   SUIT_Desktop* aDesktop = application()->desktop();
556   if( !aDesktop )
557     return false;
558
559   QtxActionToolMgr* aToolMgr = aDesktop->toolMgr();
560   if( !aToolMgr )
561     return false;
562
563   aToolMgr->append( theAction, theToolBarTitle );
564   return true;
565 }
566
567 //******************************************************
568 QList<QAction*> SHAPERGUI::commandList() const
569 {
570   QList<QAction*> aActions;
571   for (int i = 0; i < myActionsList.size(); i++) {
572     QAction* aCmd = action(i);
573     if (aCmd && myActionsList.contains(aCmd->data().toString()))
574       aActions.append(aCmd);
575   }
576
577   return aActions;
578 }
579
580 //******************************************************
581 QMainWindow* SHAPERGUI::desktop() const
582 {
583   return application()->desktop();
584 }
585
586 void SHAPERGUI::setFeatureInfo(const QString& theFeatureId,
587                                const std::shared_ptr<Config_FeatureMessage>& theMessage)
588 {
589   myFeaturesInfo.insert(theFeatureId, theMessage);
590 }
591
592 std::shared_ptr<Config_FeatureMessage> SHAPERGUI::featureInfo(const QString& theFeatureId)
593 {
594   std::shared_ptr<Config_FeatureMessage> aMessage;
595   if (myFeaturesInfo.contains(theFeatureId))
596     aMessage =  myFeaturesInfo[theFeatureId];
597   return aMessage;
598 }
599
600 //******************************************************
601 void SHAPERGUI::selectionChanged()
602 {
603   LightApp_Module::selectionChanged();
604   myWorkshop->salomeViewerSelectionChanged();
605 }
606
607 //******************************************************
608 void SHAPERGUI::contextMenuPopup(const QString& theClient, QMenu* theMenu, QString& theTitle)
609 {
610   myWorkshop->contextMenuMgr()->updateViewerMenu();
611   myWorkshop->contextMenuMgr()->addViewerMenu(theMenu);
612   LightApp_Module::contextMenuPopup(theClient, theMenu, theTitle);
613 }
614
615
616 //******************************************************
617 void SHAPERGUI::createPreferences()
618 {
619   LightApp_Preferences* pref = preferences();
620   if (!pref)
621     return;
622   ModuleBase_Preferences::updateConfigByResources();
623   QString aModName = moduleName();
624
625   QtxPreferenceItem* item = pref->findItem(aModName, true );
626   if ( item && (!item->isEmpty() )) {
627     item->parentItem()->removeItem(item);
628     delete item;
629   }
630
631   int catId = pref->addPreference(aModName, -1 );
632   if ( catId == -1 )
633     return;
634   SHAPERGUI_PrefMgr aMgr(pref, aModName);
635   ModuleBase_Preferences::createEditContent(&aMgr, catId);
636
637   int viewTab = pref->addItem(tr("Viewer"), catId);
638   // Create other parameters group in viewer tab
639   int otherGroup = pref->addItem(tr("Default selection"), viewTab);
640   pref->setItemProperty("columns", 3, otherGroup);
641   pref->addItem(tr("Faces"), otherGroup,
642                          SUIT_PreferenceMgr::Bool,
643                          ModuleBase_Preferences::VIEWER_SECTION, "face-selection");
644   pref->addItem(tr("Edges"), otherGroup,
645                          SUIT_PreferenceMgr::Bool,
646                          ModuleBase_Preferences::VIEWER_SECTION, "edge-selection");
647   pref->addItem(tr("Vertices"), otherGroup,
648                          SUIT_PreferenceMgr::Bool,
649                          ModuleBase_Preferences::VIEWER_SECTION, "vertex-selection");
650
651   int sensitivityGroup = pref->addItem(tr("Selection sensitivity"), viewTab);
652   pref->setItemProperty("columns", 2, sensitivityGroup);
653   pref->addItem(tr("Vertex"), sensitivityGroup, SUIT_PreferenceMgr::Double,
654                 ModuleBase_Preferences::VIEWER_SECTION, "point-selection-sensitivity");
655   pref->addItem(tr("Edge"), sensitivityGroup, SUIT_PreferenceMgr::Double,
656                 ModuleBase_Preferences::VIEWER_SECTION, "edge-selection-sensitivity");
657   pref->retrieve();
658 }
659
660 //******************************************************
661 void SHAPERGUI::preferencesChanged(const QString& theSection, const QString& theParam)
662 {
663   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
664   QString aVal = aResMgr->stringValue(theSection, theParam);
665   Config_Prop* aProp = Config_PropManager::findProp(theSection.toStdString(),
666                                                     theParam.toStdString());
667   std::string aValue = aVal.toStdString();
668   if (aValue.empty()) {
669     aValue = aProp->defaultValue();
670     aResMgr->setValue(theSection, theParam, QString(aValue.c_str()));
671
672     LightApp_Preferences* pref = preferences();
673     if (pref)
674       pref->retrieve();
675   }
676   aProp->setValue(aValue);
677
678   myWorkshop->displayer()->redisplayObjects();
679 }
680
681 void SHAPERGUI::putInfo(const QString& theInfo, const int theMSecs)
682 {
683   application()->putInfo(theInfo, theMSecs);
684 }
685
686 bool SHAPERGUI::abortAllOperations()
687 {
688   return workshop()->operationMgr()->abortAllOperations();
689 }
690
691 void SHAPERGUI::createFeatureActions()
692 {
693   myWorkshop->menuMgr()->createFeatureActions();
694 }