Salome HOME
[bos #32216][CEA] GUI ergonomic. Fixed scaling of Sketcher symbols because of using...
[modules/shaper.git] / src / SHAPERGUI / SHAPERGUI.cpp
1 // Copyright (C) 2014-2024  CEA, EDF
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 "SHAPERGUI.h"
21 #include "SHAPERGUI_DataModel.h"
22 #include "SHAPERGUI_OCCSelector.h"
23 #include "SHAPERGUI_NestedButton.h"
24 #include "SHAPERGUI_ToolbarsMgr.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_DataModel.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 #include <XGUI_ViewerProxy.h>
38
39 #include <ModuleBase_Operation.h>
40 #include <ModuleBase_Preferences.h>
41 #include <ModuleBase_ActionInfo.h>
42 #include <ModuleBase_IModule.h>
43 #include <ModuleBase_ITreeNode.h>
44
45 #include <ModelAPI_Tools.h>
46
47 #include <LightApp_Application.h>
48 #include <LightApp_SelectionMgr.h>
49 #include <LightApp_OCCSelector.h>
50 #include <LightApp_Study.h>
51
52 #include <OCCViewer_ViewModel.h>
53 #include <OCCViewer_ViewPort3d.h>
54 #include <OCCViewer_ViewManager.h>
55
56 #include <SUIT_Selector.h>
57 #include <SUIT_Desktop.h>
58 #include <SUIT_ViewManager.h>
59 #include <SUIT_ViewWindow.h>
60 #include <SUIT_ResourceMgr.h>
61 #include <SUIT_DataBrowser.h>
62
63 #include <QtxPopupMgr.h>
64 #include <QtxActionMenuMgr.h>
65 #include <QtxActionToolMgr.h>
66 #include <QtxResourceMgr.h>
67 #include <QtxInfoPanel.h>
68
69 #include <Config_PropManager.h>
70 #include <Config_ModuleReader.h>
71
72 #include <AIS_ListOfInteractive.hxx>
73 #include <AIS_ListIteratorOfListOfInteractive.hxx>
74 #include <Standard_Version.hxx>
75
76 #include <QDockWidget>
77 #include <QAction>
78 #include <QTimer>
79 #include <QMenu>
80 #include <QToolBar>
81
82 #include <ModelAPI_Session.h>
83 #include <Events_MessageBool.h>
84
85 #if OCC_VERSION_HEX < 0x070400
86   #define SALOME_PATCH_FOR_CTRL_WHEEL
87 #endif
88
89 extern "C" {
90 SHAPERGUI_EXPORT CAM_Module* createModule()
91 {
92   return new SHAPERGUI();
93 }
94
95 SHAPERGUI_EXPORT char* getModuleVersion()
96 {
97   return (char*)"0.0";
98 }
99 } // extern "C"
100
101
102 static const QString ToolbarsSection("SHAPER_Toolbars");
103 static const QString FreeCommandsParam("OutOFToolbars");
104 static const std::string PARTROOT_NODE_NAME = "PartRoot";
105
106
107 /**
108 * Class for preferences management
109 */
110 class SHAPERGUI_PrefMgr: public ModuleBase_IPrefMgr
111 {
112 public:
113   /// Constructor
114   /// \param theMgr preferences manager of SALOME
115   /// \param theModName name of the module
116   SHAPERGUI_PrefMgr(LightApp_Preferences* theMgr, const QString& theModName):
117     myMgr(theMgr), myModName(theModName) {}
118
119   virtual int addPreference(const QString& theLbl, int pId,
120                             SUIT_PreferenceMgr::PrefItemType theType,
121                             const QString& theSection, const QString& theName )
122   {
123     return myMgr->addPreference(myModName, theLbl, pId, theType, theSection, theName);
124   }
125
126   virtual void setItemProperty(const QString& thePropName,
127                                const QVariant& theValue,
128                                const int theId = -1)
129   {
130     myMgr->setItemProperty(thePropName, theValue, theId);
131   }
132
133
134   virtual SUIT_PreferenceMgr* prefMgr() const { return myMgr; }
135
136 private:
137   LightApp_Preferences* myMgr;
138   QString myModName;
139 };
140
141
142
143
144 //******************************************************
145 SHAPERGUI::SHAPERGUI()
146     : LightApp_Module("SHAPER"),
147       mySelector(0), myIsOpened(0), myPopupMgr(0), myIsInspectionVisible(false),
148   myInspectionPanel(0), myIsFacesPanelVisible(false), myIsToolbarsModified(false),
149   myAxisArrowRate(-1)
150 {
151   myWorkshop = new XGUI_Workshop(this);
152   connect(myWorkshop, SIGNAL(commandStatusUpdated()),
153           this, SLOT(onUpdateCommandStatus()));
154
155   myProxyViewer = new SHAPERGUI_SalomeViewer(this);
156
157   ModuleBase_Preferences::setResourceMgr(application()->resourceMgr());
158
159   // It will be called in XGUI_Workshop::startApplication
160   // ModuleBase_Preferences::loadCustomProps();
161 }
162
163 //******************************************************
164 SHAPERGUI::~SHAPERGUI()
165 {
166   delete myWorkshop;
167   delete myProxyViewer;
168 }
169
170 //******************************************************
171 void SHAPERGUI::initialize(CAM_Application* theApp)
172 {
173   LightApp_Module::initialize(theApp);
174
175   myWorkshop->startApplication();
176   LightApp_Application* anApp = dynamic_cast<LightApp_Application*>(theApp);
177   if (anApp)
178   {
179     connect(anApp, SIGNAL(preferenceResetToDefaults()), this, SLOT(onDefaultPreferences()));
180   }
181
182   int aMenu = createMenu(tr("Inspection"), -1, -1, 30);
183
184   int aId = getNextCommandId();
185   myActionsList.append(aId);
186   SUIT_Desktop* aDesk = application()->desktop();
187   QString aTip = tr("Show inspection window");
188   myWhatIsAction = createAction(aId, aTip, QIcon(":pictures/whatis.png"), tr("What Is"),
189     aTip, QKeySequence(), aDesk, true, this, SLOT(onWhatIs(bool)));
190   myWhatIsAction->setStatusTip(aTip);
191   myWhatIsAction->setData("INSPECTION_CMD");
192   createMenu(aId, aMenu, 0);
193
194   QString aToolName = tr("Inspection");
195   int aTool = createTool(aToolName);
196 #ifdef _DEBUG
197   int aToolId =
198 #endif
199     createTool(myWhatIsAction, aTool);
200   registerCommandToolbar(aToolName, aId);
201
202   // Define Edit toolbars command
203   aId = getNextCommandId();
204   //myActionsList.append(aId); Do not use it for editing of toolbars
205   aTip = tr("Edit toolbars of the module");
206 #ifdef _DEBUG
207   QAction* aAction =
208 #endif
209     createAction(aId, aTip, QIcon(":pictures/configure_toolbars.png"),
210     tr("Edit toolbars..."), aTip, QKeySequence(), aDesk, false, this, SLOT(onEditToolbars()));
211   int aEditMenu = createMenu(tr("MEN_DESK_EDIT"), -1, -1, -1);
212 #ifdef _DEBUG
213   int aEditItem =
214 #endif
215     createMenu(aId, aEditMenu);
216
217   if (!myInspectionPanel) {
218     myInspectionPanel = myWorkshop->inspectionPanel();
219     connect(myInspectionPanel->toggleViewAction(), SIGNAL(toggled(bool)),
220       this, SLOT(onWhatIs(bool)));
221   }
222   hideInternalWindows();
223
224   // Initialize viewer proxy if OCC viewer is already exist
225   ViewManagerList aOCCViewManagers;
226   application()->viewManagers(OCCViewer_Viewer::Type(), aOCCViewManagers);
227   if (aOCCViewManagers.size() > 0) {
228     SUIT_ViewManager* aMgr = aOCCViewManagers.first();
229     SUIT_ViewWindow* aWnd = aMgr->getActiveView();
230     if (aWnd) {
231       OCCViewer_ViewWindow* aOccWnd = static_cast<OCCViewer_ViewWindow*>(aWnd);
232       OCCViewer_ViewPort3d* aViewPort = aOccWnd->getViewPort();
233       if (aViewPort) {
234         XGUI_ViewerProxy* aViewer = myWorkshop->viewer();
235         aViewPort->installEventFilter(aViewer);
236         Handle(V3d_View) aView = aViewPort->getView();
237         aViewer->SetScale(aView, aView->Camera()->Scale());
238         // We can not create selector here because other modules will be deactivated later
239         //onViewManagerAdded(aMgr);
240       }
241     }
242   }
243   SHAPERGUI_DataModel* aDataModel = dynamic_cast<SHAPERGUI_DataModel*>(dataModel());
244   aDataModel->initRootObject();
245 }
246
247 //******************************************************
248 void SHAPERGUI::windows(QMap<int, int>& theWndMap) const
249 {
250   theWndMap.insert(LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea);
251   theWndMap.insert(LightApp_Application::WT_InfoPanel, Qt::RightDockWidgetArea);
252 }
253
254 //******************************************************
255 void SHAPERGUI::viewManagers(QStringList& theList) const
256 {
257   theList.append(OCCViewer_Viewer::Type());
258 }
259
260 //******************************************************
261 // We can not create selector in this method because it can be called when
262 // SHAPER module is not active. Take into account that creation of our selector
263 // leads to switching OFF all other selectors
264 //void SHAPERGUI::connectToStudy(CAM_Study* theStudy)
265 //{
266 //  // if there are created viewer managers, we should try to create viewer
267 //  // selector and initialize viewer with it. It sets interactive context to the
268 //  // proxy viewer. If study is opened, CAM application calls this method before the open()
269 //  // of data model
270 //  // the SHAPER data model is specific and during open(load) redisplay signals are flushed, so
271 //  // we need to connect to the viewer before it. Here,
272 //  // it seems the most appropriate place for this
273 //  // according to SALOME architecture.
274 //  if (!mySelector) {
275 //    ViewManagerList OCCViewManagers;
276 //    application()->viewManagers(OCCViewer_Viewer::Type(), OCCViewManagers);
277 //    if (OCCViewManagers.size() > 0) {
278 //      mySelector = createSelector(OCCViewManagers.first());
279 //    }
280 //  }
281 //  LightApp_Module::connectToStudy(theStudy);
282 //}
283
284 //******************************************************
285 bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
286 {
287   ModelAPI_Session::get()->moduleDocument(); // initialize a root document if not done yet
288
289   // this must be done in the initialization and in activation (on the second activation
290   // initialization in not called, so SComponent must be added anyway
291   SHAPERGUI_DataModel* aDataModel = dynamic_cast<SHAPERGUI_DataModel*>(dataModel());
292   aDataModel->initRootObject();
293
294
295   bool isDone = LightApp_Module::activateModule(theStudy);
296   loadToolbarsConfig();
297
298   if (isDone) {
299     setMenuShown(true);
300     setToolShown(true);
301
302     QObject* aObj = myWorkshop->objectBrowser()->parent();
303     QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
304     if (aObjDoc) {
305       myWorkshop->objectBrowser()->setVisible(true);
306       aObjDoc->setVisible(true);
307       desktop()->tabifyDockWidget(aObjDoc, myWorkshop->propertyPanel());
308       aObjDoc->toggleViewAction()->setVisible(true);
309     }
310
311     myInspectionPanel->toggleViewAction()->setVisible(true);
312
313     myWorkshop->facesPanel()->toggleViewAction()->setVisible(true);
314     if (myIsFacesPanelVisible)
315       myWorkshop->facesPanel()->show();
316     myWorkshop->propertyPanel()->toggleViewAction()->setVisible(true);
317
318     if (!mySelector) {
319       ViewManagerList OCCViewManagers;
320       application()->viewManagers(OCCViewer_Viewer::Type(), OCCViewManagers);
321       if (OCCViewManagers.size() > 0) {
322         onViewManagerAdded(OCCViewManagers.first());
323       }
324     }
325     // it should be performed after the selector creation in order to have AISContext
326     myWorkshop->activateModule();
327     //action(myEraseAll)->setEnabled(false);
328
329     if (myIsOpened) {
330       myWorkshop->objectBrowser()->rebuildDataTree();
331       myWorkshop->updateCommandStatus();
332       myIsOpened = false;
333     }
334     else
335     {
336       myWorkshop->updateCommandStatus();
337     }
338
339     //bos #40645 [CEA] Automatically expand tree in Object Browser
340     XGUI_DataTree* aTreeView = myWorkshop->objectBrowser()->treeView();
341     XGUI_DataModel* aDataModel = myWorkshop->objectBrowser()->dataModel();
342     QModelIndex aRootIdx = aDataModel->documentRootIndex(ModelAPI_Session::get()->moduleDocument());
343     int aNbChild = aDataModel->rowCount(aRootIdx);
344     for (int i = 0; i < aNbChild; i++)
345     {
346       QModelIndex aIdx = aDataModel->index(i, 0, aRootIdx);
347       ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)aIdx.internalPointer();
348       std::string aType = aNode->type();
349       if(aType == PARTROOT_NODE_NAME)
350       {
351         if(!aTreeView->isExpanded(aIdx))
352           aTreeView->setExpanded(aIdx, true);
353       }
354     }
355   }
356   myIsEditEnabled = getApp()->isEditEnabled();
357   getApp()->setEditEnabled(false);
358
359   // Synchronize displayed objects
360   Handle(AIS_InteractiveContext) aContext;
361   if (mySelector && mySelector->viewer())
362     aContext = mySelector->viewer()->getAISContext();
363
364   if (!aContext.IsNull()) {
365     XGUI_Displayer* aDisp = myWorkshop->displayer();
366     QObjectPtrList aObjList = aDisp->displayedObjects();
367
368     if (myOldSelectionColor.size() == 0)
369       myOldSelectionColor = aDisp->selectionColor();
370
371     AIS_ListOfInteractive aList;
372     aContext->DisplayedObjects(aList);
373     AIS_ListIteratorOfListOfInteractive aLIt;
374     Handle(AIS_InteractiveObject) anAISIO;
375     foreach (ObjectPtr aObj, aObjList) {
376       AISObjectPtr aPrs = aDisp->getAISObject(aObj);
377       Handle(AIS_InteractiveObject) aAIS = aPrs->impl<Handle(AIS_InteractiveObject)>();
378       bool aFound = false;
379       for (aLIt.Initialize(aList); aLIt.More(); aLIt.Next()) {
380         anAISIO = aLIt.Value();
381         if (anAISIO.get() == aAIS.get()) {
382           aFound = true;
383           break;
384         }
385       }
386       if (!aFound) {
387         aObj->setDisplayed(false);
388         //aDisp->erase(aObj, false);
389       }
390     }
391     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
392   }
393   myProxyViewer->activateViewer(true);
394
395   // Post-processing for LoadScriptId to remove created(if it was created) SALOME Object Browser
396   connect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
397           this, SLOT(onScriptLoaded()));
398
399   disconnect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
400              getApp(), SLOT(onSaveDoc()));
401   disconnect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
402              getApp(), SLOT(onSaveAsDoc()));
403
404   connect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
405           this, SLOT(onSaveDocByShaper()));
406   connect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
407           this, SLOT(onSaveAsDocByShaper()));
408   updateInfoPanel();
409
410   //connect(myWorkshop->operationMgr(), SIGNAL(operationResumed(ModuleBase_Operation*)),
411   //        this, SLOT(onOperationResumed(ModuleBase_Operation*)));
412   //connect(myWorkshop->operationMgr(), SIGNAL(operationStopped(ModuleBase_Operation*)),
413   //        this, SLOT(onOperationStopped(ModuleBase_Operation*)));
414   connect(myWorkshop->operationMgr(), SIGNAL(operationCommitted(ModuleBase_Operation*)),
415           this, SLOT(onOperationCommitted(ModuleBase_Operation*)));
416   connect(myWorkshop->operationMgr(), SIGNAL(operationAborted(ModuleBase_Operation*)),
417           this, SLOT(onOperationAborted(ModuleBase_Operation*)));
418
419   return isDone;
420 }
421
422 //******************************************************
423 void SHAPERGUI::hideInternalWindows()
424 {
425   myProxyViewer->activateViewer(false);
426   setMenuShown(false);
427   setToolShown(false);
428
429   QObject* aObj = myWorkshop->objectBrowser()->parent();
430   QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
431   if (aObjDoc) {
432     aObjDoc->setVisible(false);
433     myWorkshop->objectBrowser()->setVisible(false);
434     aObjDoc->toggleViewAction()->setVisible(false);
435   }
436
437   myInspectionPanel->hide();
438   myInspectionPanel->toggleViewAction()->setVisible(false);
439
440   myWorkshop->facesPanel()->hide();
441   myWorkshop->facesPanel()->toggleViewAction()->setVisible(false);
442
443   myWorkshop->propertyPanel()->hide();
444   myWorkshop->propertyPanel()->toggleViewAction()->setVisible(false);
445
446   myWorkshop->hidePanel(myWorkshop->facesPanel());
447 }
448
449
450 //******************************************************
451 bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
452 {
453   saveToolbarsConfig();
454   myWorkshop->deactivateModule();
455
456   myIsInspectionVisible = myInspectionPanel->isVisible();
457   myIsFacesPanelVisible = myWorkshop->facesPanel()->isVisible();
458   hideInternalWindows();
459
460
461   // the active operation should be stopped for the next activation.
462   // There should not be active operation and visualized preview.
463   // Abort operation should be performed before the selection's remove
464   // because the displayed objects should be removed from the viewer, but
465   // the AIS context is obtained from the selector.
466   ModuleBase_Operation* anOperation = myWorkshop->operationMgr()->currentOperation();
467   while (anOperation) {
468     anOperation->abort();
469     anOperation = myWorkshop->operationMgr()->currentOperation();
470   }
471   // Delete selector because it has to be redefined on next activation
472   if (mySelector) {
473     // Restore size of arrows of trihedron
474     if (myAxisArrowRate > 0) {
475       Handle(AIS_Trihedron) aTrihedron = mySelector->viewer()->getTrihedron();
476       Handle(Prs3d_DatumAspect) aDatumAspect = aTrihedron->Attributes()->DatumAspect();
477       aDatumAspect->SetAttribute(Prs3d_DP_ShadingConeLengthPercent, myAxisArrowRate);
478       Handle(AIS_InteractiveContext) aContext = mySelector->viewer()->getAISContext();
479       aContext->Redisplay(aTrihedron, false);
480     }
481     myWorkshop->displayer()->setSelectionColor(myOldSelectionColor);
482     myProxyViewer->setSelector(0);
483
484     LightApp_SelectionMgr* aMgr = getApp()->selectionMgr();
485     QList<SUIT_Selector*> aList;
486     aMgr->selectors(aList);
487     foreach(SUIT_Selector* aSel, aList) {
488       aSel->setEnabled(aSel != mySelector);
489     }
490
491     delete mySelector;
492     mySelector = 0;
493   }
494
495   //myWorkshop->contextMenuMgr()->disconnectViewer();
496
497   getApp()->setEditEnabled(myIsEditEnabled);
498
499   myOldSelectionColor.clear();
500
501   // Post-processing for LoadScriptId to remove created(if it was created) SALOME Object Browser
502   disconnect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
503              this, SLOT(onScriptLoaded()));
504
505   disconnect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
506              this, SLOT(onSaveDocByShaper()));
507   disconnect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
508              this, SLOT(onSaveAsDocByShaper()));
509
510   connect(getApp()->action(LightApp_Application::FileSaveId), SIGNAL(triggered(bool)),
511           getApp(), SLOT(onSaveDoc()));
512   connect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
513           getApp(), SLOT(onSaveAsDoc()));
514
515   publishToStudy();
516
517   return LightApp_Module::deactivateModule(theStudy);
518 }
519
520 //******************************************************
521 void SHAPERGUI::logShaperGUIEvent()
522 {
523   QAction* anAction = static_cast<QAction*>(sender());
524   if ( !anAction )
525     return;
526   const QString anId = anAction->data().toString();
527   const QString section = anId.contains("Sketch") ? "sketcher" : "";
528
529   CAM_Application::logStructuredUserEvent( moduleName(),
530                                            section,
531                                            anAction->text(),
532                                            "activated" );
533 }
534
535 //******************************************************
536 static void onOperationGeneric( ModuleBase_Operation* theOperation,
537                                 const QString moduleName,
538                                 const QString &event )
539 {
540   QString anId = theOperation->id();
541   QString section = "";
542
543   if (anId.contains("Sketch"))
544   {
545     section = "sketcher";
546     anId.remove("Sketch");
547   }
548
549   CAM_Application::logStructuredUserEvent( moduleName,
550                                            section,
551                                            anId,
552                                            event );
553 }
554
555 //******************************************************
556 void SHAPERGUI::onOperationCommitted(ModuleBase_Operation* theOperation)
557 {
558   onOperationGeneric(theOperation, moduleName(), "committed");
559 }
560
561 //******************************************************
562 void SHAPERGUI::onOperationAborted(ModuleBase_Operation* theOperation)
563 {
564   onOperationGeneric(theOperation, moduleName(), "aborted");
565 }
566
567 //******************************************************
568 void SHAPERGUI::onViewManagerAdded(SUIT_ViewManager* theMgr)
569 {
570   if (!mySelector) {
571     mySelector = createSelector(theMgr);
572     myWorkshop->selectionActivate()->updateSelectionFilters();
573     myWorkshop->selectionActivate()->updateSelectionModes();
574     myWorkshop->synchronizeViewer();
575   }
576   if (theMgr->getType() == OCCViewer_Viewer::Type()) {
577     // Set the auto rotate flag in the new viewer based on the current preference
578     OCCViewer_ViewManager *aVM = (OCCViewer_ViewManager*)theMgr;
579     bool aAutoRotation = Config_PropManager::boolean("Visualization", "use_auto_rotation");
580     aVM->setAutoRotation(aAutoRotation);
581
582     connect(theMgr, SIGNAL(viewCreated(SUIT_ViewWindow*)),
583             myProxyViewer, SLOT(onViewCreated(SUIT_ViewWindow*)));
584   }
585 }
586
587 //******************************************************
588 void SHAPERGUI::onViewManagerRemoved(SUIT_ViewManager* theMgr)
589 {
590   if (mySelector) {
591     if (theMgr->getType() == OCCViewer_Viewer::Type()) {
592       OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
593       if (mySelector->viewer() == aViewer) {
594         XGUI_Displayer* aDisp = myWorkshop->displayer();
595         QObjectPtrList aObjects = aDisp->displayedObjects();
596         ResultPtr aRes;
597         foreach(ObjectPtr aObj, aObjects) {
598           aObj->setDisplayed(false);
599           aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
600           if (aRes.get()) {
601             while (aRes = ModelAPI_Tools::bodyOwner(aRes)) {
602               aRes->setDisplayed(false);
603             }
604           }
605         }
606         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
607         myProxyViewer->setSelector(0);
608         delete mySelector;
609         mySelector = 0;
610
611         myWorkshop->module()->clearViewer();
612       }
613     }
614   }
615 }
616
617 //******************************************************
618 QtxPopupMgr* SHAPERGUI::popupMgr()
619 {
620   if (!myPopupMgr)
621     myPopupMgr = new QtxPopupMgr( 0, this );
622   return myPopupMgr;
623 }
624
625 //******************************************************
626 void SHAPERGUI::onDefaultPreferences()
627 {
628   // reset main resources
629   ModuleBase_Preferences::resetResourcePreferences(preferences());
630   // reset plugin's resources
631   ModuleBase_Preferences::resetConfigPropPreferences(preferences());
632
633   myWorkshop->displayer()->redisplayObjects();
634 }
635
636 //******************************************************
637 void SHAPERGUI::onScriptLoaded()
638 {
639   // this slot is called after processing of the LoadScriptId action of SalomeApp Application
640   // Each dumped script contains updateObjBrowser() that creates a new instance of Object
641   // Browser. When SHAPER module is active, this browser should not be used. It might be removed
642   // as hidden by means of updateWindows() of SalomeApp_Application or to remove
643   // it manually (because this method of application is protected)
644   SUIT_DataBrowser* aBrowser = getApp()->objectBrowser();
645   if (aBrowser)
646     delete aBrowser;
647   myWorkshop->displayer()->updateViewer();
648   myWorkshop->updateCommandStatus();
649 }
650
651 //******************************************************
652 void SHAPERGUI::onSaveDocByShaper()
653 {
654   if(!workshop()->operationMgr()->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
655     return;
656
657   getApp()->onSaveDoc();
658 }
659
660 //******************************************************
661 void SHAPERGUI::onSaveAsDocByShaper()
662 {
663   if(!workshop()->operationMgr()->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
664     return;
665
666   getApp()->onSaveAsDoc();
667 }
668
669 //******************************************************
670 void SHAPERGUI::onUpdateCommandStatus()
671 {
672   getApp()->updateActions();
673
674   LightApp_Application* aApp = dynamic_cast<LightApp_Application*>(application());
675   QtxInfoPanel* aInfoPanel = aApp->infoPanel();
676   if (aInfoPanel->isVisible())
677     updateInfoPanel();
678 }
679
680 //******************************************************
681 SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
682 {
683   if (theMgr->getType() == OCCViewer_Viewer::Type()) {
684     OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
685
686     // Remember current length of arrow of axis
687     Handle(AIS_Trihedron) aTrihedron = aViewer->getTrihedron();
688     Handle(Prs3d_DatumAspect) aDatumAspect = aTrihedron->Attributes()->DatumAspect();
689     myAxisArrowRate = aDatumAspect->Attribute(Prs3d_DP_ShadingConeLengthPercent);
690
691     SHAPERGUI_OCCSelector* aSelector = new SHAPERGUI_OCCSelector(aViewer,
692                                                                  getApp()->selectionMgr());
693 #ifdef SALOME_PATCH_FOR_CTRL_WHEEL
694     aViewer->setUseLocalSelection(true);
695 #endif
696     LightApp_SelectionMgr* aMgr = getApp()->selectionMgr();
697     QList<SUIT_Selector*> aList;
698     aMgr->selectors(aList);
699     foreach(SUIT_Selector* aSel, aList)
700     {
701       aSel->setEnabled(aSel == aSelector);
702     }
703     myProxyViewer->setSelector(aSelector);
704
705     if (myOldSelectionColor.size() == 0)
706       myOldSelectionColor = myWorkshop->displayer()->selectionColor();
707
708     std::vector<int> aColor = Config_PropManager::color("Visualization", "selection_color");
709     myWorkshop->displayer()->setSelectionColor(aColor);
710
711     // Cause scaling of arrows of axis and dimensions
712     myWorkshop->module()->onViewTransformed();
713
714     return aSelector;
715   }
716   return 0;
717 }
718
719 //******************************************************
720 CAM_DataModel* SHAPERGUI::createDataModel()
721 {
722   return new SHAPERGUI_DataModel(this);
723 }
724
725 QAction* SHAPERGUI::addFeature(const QString& theWBName, const ActionInfo& theInfo,
726                                const bool isAddSeparator)
727 {
728   return addFeature(theWBName,
729                     theInfo.toolBar,
730                     theInfo.id,
731                     theInfo.text,
732                     //Issue #650: in the SALOME mode the tooltip should be same as text
733                     theInfo.text,
734                     theInfo.icon,
735                     theInfo.shortcut,
736                     theInfo.checkable,
737                     isAddSeparator,
738                     theInfo.toolTip);
739 }
740
741 //******************************************************
742 QAction* SHAPERGUI::addFeature(const QString& theWBName, const QString& theTBName,
743                                const QString& theId, const QString& theTitle, const QString& theTip,
744                                const QIcon& theIcon, const QKeySequence& theKeys,
745                                bool isCheckable, const bool isAddSeparator,
746                                const QString& theStatusTip)
747 {
748   static QString aLastTool = "";
749   static int aNb = 0;
750   if (aLastTool.isEmpty())
751     aLastTool = theWBName;
752   else if (theWBName != aLastTool) {
753     aLastTool = theWBName;
754     if (aNb > 20) {
755       desktop()->addToolBarBreak();
756       aNb = 0;
757     }
758   }
759   aNb++;
760
761   int aId = getNextCommandId();
762   myActionsList.append(aId);
763   SUIT_Desktop* aDesk = application()->desktop();
764   int aKeys = 0;
765   for (int i = 0; i < theKeys.count(); i++)
766     aKeys += theKeys[i];
767
768   QAction* aAction = createAction(aId, theTip, theIcon, theTitle, theTip, aKeys, aDesk,
769                                   isCheckable, nullptr, nullptr, theId);
770   aAction->setStatusTip(theStatusTip);
771
772   aAction->setData(theId);
773
774   int aWBMenu = createMenu(theWBName, -1, -1, 30/*10-Window, 1000 - Help*/);
775
776   if( theId == "PointCoordinates" )
777     createMenu(separator(), aWBMenu);
778
779 #ifdef _DEBUG
780   int aItemId =
781 #endif
782     createMenu(aId, aWBMenu);
783
784   if (isAddSeparator)
785     createMenu(separator(), aWBMenu);
786
787   int aWBTool = createTool(theTBName, theTBName);
788 #ifdef _DEBUG
789   int aToolId =
790 #endif
791     createTool(aId, aWBTool);
792   registerCommandToolbar(theTBName, aId);
793   if (isAddSeparator) {
794     createTool(separator(), aWBTool);
795     registerCommandToolbar(theTBName, -1);
796   }
797   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(logShaperGUIEvent()));
798   return aAction;
799 }
800
801 bool SHAPERGUI::isFeatureOfNested(const QAction* theAction)
802 {
803   return dynamic_cast<const SHAPERGUI_NestedButton*>(theAction);
804 }
805
806 QAction* SHAPERGUI::addFeatureOfNested(const QString& theWBName,
807                                        const ActionInfo& theInfo,
808                                        const QList<QAction*>& theNestedActions)
809 {
810   SUIT_Desktop* aDesk = application()->desktop();
811   SHAPERGUI_NestedButton* anAction = new SHAPERGUI_NestedButton(aDesk, makeActionID(theInfo.id), theNestedActions);
812   anAction->setData(theInfo.id);
813   anAction->setCheckable(theInfo.checkable);
814   anAction->setChecked(theInfo.checked);
815   anAction->setEnabled(theInfo.enabled);
816   anAction->setVisible(theInfo.visible);
817   anAction->setIcon(theInfo.icon);
818   anAction->setText(theInfo.text);
819   anAction->setToolTip(theInfo.toolTip);
820   anAction->setShortcut(theInfo.shortcut);
821   anAction->setFont(theInfo.font);
822
823   int aWBMenu = createMenu(theWBName, -1, -1, 30);
824   int aItemId = createMenu(anAction, aWBMenu);
825   myActionsList.append(aItemId);
826   createMenu(separator(), aWBMenu); /// nested action is always separated of others
827
828   int aWBTool = createTool(theWBName, theWBName);
829 #ifdef _DEBUG
830   int aToolId =
831 #endif
832     createTool(anAction, aWBTool);
833   registerCommandToolbar(theWBName, aItemId);
834   createTool(separator(), aWBTool); /// nested action is always separated of others
835   registerCommandToolbar(theWBName, -1);
836
837   connect(anAction, SIGNAL(triggered(bool)), this, SLOT(logShaperGUIEvent()));
838
839   return anAction;
840 }
841
842
843 //******************************************************
844 QAction* SHAPERGUI::addDesktopCommand(const QString& theId, const QString& theTitle,
845                                            const QString& theTip, const QIcon& theIcon,
846                                            const QKeySequence& theKeys, bool isCheckable,
847                                            const char* theMenuSourceText,
848                                            const QString& theSubMenu,
849                                            const int theMenuPosition,
850                                            const int theSubMenuPosition)
851 {
852   int aMenu = createMenu(tr(theMenuSourceText), -1, -1);
853   if (!theSubMenu.isNull())
854     aMenu = createMenu(theSubMenu, aMenu, -1, theSubMenuPosition);
855
856   int aId = getNextCommandId();
857   myActionsList.append(aId);
858   SUIT_Desktop* aDesk = application()->desktop();
859   int aKeys = 0;
860   for (int i = 0; i < theKeys.count(); i++)
861     aKeys += theKeys[i];
862   QAction* aAction = createAction(aId, theTip, theIcon, theTitle, theTip, aKeys, aDesk,
863                                   isCheckable, nullptr, nullptr, theId);
864   aAction->setStatusTip(theTip);
865   aAction->setData(theId);
866   createMenu(aId, aMenu, theMenuPosition);
867
868   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(logShaperGUIEvent()));
869
870   return aAction;
871 }
872
873 //******************************************************
874 void SHAPERGUI::addDesktopMenuSeparator(const char* theMenuSourceText, const int theMenuPosition)
875 {
876   int aMenu = createMenu(tr(theMenuSourceText), -1, -1);
877   createMenu(separator(), aMenu, -1, theMenuPosition);
878 }
879
880 //******************************************************
881 bool SHAPERGUI::addActionInToolbar( QAction* theAction, const QString& theToolBarTitle )
882 {
883   if( !theAction )
884     return false;
885
886   SUIT_Desktop* aDesktop = application()->desktop();
887   if( !aDesktop )
888     return false;
889
890   QtxActionToolMgr* aToolMgr = aDesktop->toolMgr();
891   if( !aToolMgr )
892     return false;
893
894   aToolMgr->append( theAction, theToolBarTitle );
895   return true;
896 }
897
898 //******************************************************
899 QList<QAction*> SHAPERGUI::commandList() const
900 {
901   QList<QAction*> aActions;
902   foreach (int aId, myActionsList) {
903     QAction* aCmd = action(aId);
904     if (aCmd)
905       aActions.append(aCmd);
906   }
907
908   return aActions;
909 }
910
911 //******************************************************
912 QMainWindow* SHAPERGUI::desktop() const
913 {
914   return application()->desktop();
915 }
916
917 void SHAPERGUI::setFeatureInfo(const QString& theFeatureId,
918                                const std::shared_ptr<Config_FeatureMessage>& theMessage)
919 {
920   myFeaturesInfo.insert(theFeatureId, theMessage);
921 }
922
923 std::shared_ptr<Config_FeatureMessage> SHAPERGUI::featureInfo(const QString& theFeatureId)
924 {
925   std::shared_ptr<Config_FeatureMessage> aMessage;
926   if (myFeaturesInfo.contains(theFeatureId))
927     aMessage =  myFeaturesInfo[theFeatureId];
928   return aMessage;
929 }
930
931 //******************************************************
932 void SHAPERGUI::selectionChanged()
933 {
934   LightApp_Module::selectionChanged();
935   myWorkshop->salomeViewerSelectionChanged();
936 }
937
938 //******************************************************
939 void SHAPERGUI::contextMenuPopup(const QString& theClient, QMenu* theMenu, QString& theTitle)
940 {
941   myWorkshop->contextMenuMgr()->updateViewerMenu();
942   myWorkshop->contextMenuMgr()->addViewerMenu(theMenu);
943   LightApp_Module::contextMenuPopup(theClient, theMenu, theTitle);
944 }
945
946
947 //******************************************************
948 void SHAPERGUI::createPreferences()
949 {
950   LightApp_Preferences* aPref = preferences();
951   if (!aPref)
952     return;
953   ModuleBase_Preferences::updateConfigByResources();
954   QString aModName = moduleName();
955
956   QtxPreferenceItem* item = aPref->findItem(aModName, true );
957   if ( item && (!item->isEmpty() )) {
958     item->parentItem()->removeItem(item);
959     delete item;
960   }
961
962   int catId = aPref->addPreference(aModName, -1 );
963   if ( catId == -1 )
964     return;
965   SHAPERGUI_PrefMgr aMgr(aPref, aModName);
966   ModuleBase_Preferences::createEditContent(&aMgr, catId);
967
968   int viewTab = aPref->addItem(tr("Viewer"), catId);
969   // Create other parameters group in viewer tab
970   int otherGroup = aPref->addItem(tr("Default selection"), viewTab);
971   aPref->setItemProperty("columns", 3, otherGroup);
972   aPref->addItem(tr("Faces"), otherGroup,
973                          SUIT_PreferenceMgr::Bool,
974                          ModuleBase_Preferences::VIEWER_SECTION, "face-selection");
975   aPref->addItem(tr("Edges"), otherGroup,
976                          SUIT_PreferenceMgr::Bool,
977                          ModuleBase_Preferences::VIEWER_SECTION, "edge-selection");
978   aPref->addItem(tr("Vertices"), otherGroup,
979                          SUIT_PreferenceMgr::Bool,
980                          ModuleBase_Preferences::VIEWER_SECTION, "vertex-selection");
981
982   int sensitivityGroup = aPref->addItem(tr("Selection sensitivity"), viewTab);
983   aPref->setItemProperty("columns", 2, sensitivityGroup);
984   aPref->addItem(tr("Vertex"), sensitivityGroup, SUIT_PreferenceMgr::DblSpin,
985                 ModuleBase_Preferences::VIEWER_SECTION, "point-selection-sensitivity");
986   aPref->addItem(tr("Edge"), sensitivityGroup, SUIT_PreferenceMgr::DblSpin,
987                 ModuleBase_Preferences::VIEWER_SECTION, "edge-selection-sensitivity");
988
989   int highlightGroup = aPref->addItem(tr("Additional highlighting"), viewTab);
990   aPref->setItemProperty("columns", 2, highlightGroup);
991   aPref->addItem(tr("In 3d mode"), highlightGroup,
992     SUIT_PreferenceMgr::Bool, ModuleBase_Preferences::VIEWER_SECTION, "highlighting-3d");
993   aPref->addItem(tr("In 2d mode"), highlightGroup,
994     SUIT_PreferenceMgr::Bool, ModuleBase_Preferences::VIEWER_SECTION, "highlighting-2d");
995
996   int colorScaleGroup = aPref->addItem(tr("Color scale"), viewTab);
997   aPref->setItemProperty("columns", 4, colorScaleGroup);
998   int aItem = aMgr.addPreference(tr("X position"), colorScaleGroup,
999     SUIT_PreferenceMgr::Double, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_x_position");
1000   aPref->setItemProperty("min", 0, aItem);
1001   aPref->setItemProperty("max", 1, aItem);
1002   aItem = aMgr.addPreference(tr("Y position"), colorScaleGroup,
1003     SUIT_PreferenceMgr::Double, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_y_position");
1004   aPref->setItemProperty("min", 0, aItem);
1005   aPref->setItemProperty("max", 1, aItem);
1006   aItem = aMgr.addPreference(tr("Width"), colorScaleGroup,
1007     SUIT_PreferenceMgr::Double, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_width");
1008   aPref->setItemProperty("min", 0, aItem);
1009   aPref->setItemProperty("max", 1, aItem);
1010   aItem = aMgr.addPreference(tr("Height"), colorScaleGroup,
1011     SUIT_PreferenceMgr::Double, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_height");
1012   aPref->setItemProperty("min", 0, aItem);
1013   aPref->setItemProperty("max", 1, aItem);
1014   aItem = aMgr.addPreference(tr("Intervals number"), colorScaleGroup,
1015     SUIT_PreferenceMgr::Integer, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_nb_intervals");
1016   aPref->setItemProperty("min", 0, aItem);
1017   aPref->setItemProperty("max", 100, aItem);
1018   aItem = aMgr.addPreference(tr("Text height"), colorScaleGroup,
1019     SUIT_PreferenceMgr::Integer, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_text_height");
1020   aPref->setItemProperty("min", 0, aItem);
1021   aPref->setItemProperty("max", 100, aItem);
1022   aItem = aMgr.addPreference(tr("Text color"), colorScaleGroup,
1023     SUIT_PreferenceMgr::Color, ModuleBase_Preferences::VIEWER_SECTION, "scalar_bar_text_color");
1024
1025   int aGroupNamesGroup = aMgr.addPreference(tr("Group names display"), viewTab,
1026     SUIT_PreferenceMgr::GroupBox , ModuleBase_Preferences::VIEWER_SECTION, "group_names_display");
1027   aPref->setItemProperty("columns", 3, aGroupNamesGroup);
1028   aMgr.addPreference(tr("Text font"), aGroupNamesGroup,
1029     SUIT_PreferenceMgr::String, ModuleBase_Preferences::VIEWER_SECTION, "group_names_font");
1030   aItem = aMgr.addPreference(tr("Text size"), aGroupNamesGroup,
1031     SUIT_PreferenceMgr::Integer, ModuleBase_Preferences::VIEWER_SECTION, "group_names_size");
1032   aPref->setItemProperty("min", 8, aItem);
1033   aPref->setItemProperty("max", 100, aItem);
1034   aItem = aMgr.addPreference(tr("Text color"), aGroupNamesGroup,
1035     SUIT_PreferenceMgr::Color, ModuleBase_Preferences::VIEWER_SECTION, "group_names_color");
1036
1037   aPref->retrieve();
1038 }
1039
1040 //******************************************************
1041 void SHAPERGUI::preferencesChanged(const QString& theSection, const QString& theParam)
1042 {
1043   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
1044   QString aVal = aResMgr->stringValue(theSection, theParam);
1045   Config_Prop* aProp = Config_PropManager::findProp(theSection.toStdString(),
1046                                                     theParam.toStdString());
1047   if (!aProp)
1048     return; // invalid case, the property default value must be registered in XML file
1049   std::string aValue = aVal.toStdString();
1050   if (aValue.empty()) {
1051     aValue = aProp->defaultValue();
1052     aResMgr->setValue(theSection, theParam, QString(aValue.c_str()));
1053
1054     LightApp_Preferences* aPref = preferences();
1055     if (aPref)
1056       aPref->retrieve();
1057   }
1058   aProp->setValue(aValue);
1059
1060   if (theSection == "Visualization") {
1061     if (theParam == "selection_color") {
1062       std::vector<int> aColor = Config_PropManager::color("Visualization", "selection_color");
1063       myWorkshop->displayer()->setSelectionColor(aColor);
1064     }
1065     if ((theParam == "zoom_trihedron_arrows") || (theParam == "axis_arrow_size")) {
1066       if (mySelector) {
1067         Handle(AIS_Trihedron) aTrihedron = mySelector->viewer()->getTrihedron();
1068         if (!aTrihedron.IsNull()) {
1069           bool aZoom = Config_PropManager::boolean("Visualization", "zoom_trihedron_arrows");
1070           Handle(AIS_InteractiveContext) aContext = mySelector->viewer()->getAISContext();
1071
1072           ModuleBase_IViewer* aViewer = myWorkshop->viewer();
1073           Handle(V3d_View) aView = aViewer->activeView();
1074           if (aZoom) {
1075             double aAxLen =
1076               aView->Convert(Config_PropManager::integer("Visualization", "axis_arrow_size"));
1077             Handle(Prs3d_DatumAspect) aDatumAspect = aTrihedron->Attributes()->DatumAspect();
1078             double aAxisLen = aDatumAspect->AxisLength(Prs3d_DP_XAxis);
1079             myAxisArrowRate = aDatumAspect->Attribute(Prs3d_DP_ShadingConeLengthPercent);
1080             aDatumAspect->SetAttribute(Prs3d_DP_ShadingConeLengthPercent, aAxLen / aAxisLen);
1081             aTrihedron->Attributes()->SetDatumAspect(aDatumAspect);
1082             aContext->Redisplay(aTrihedron, true);
1083
1084           }
1085           else if (myAxisArrowRate > 0) {
1086             Handle(Prs3d_DatumAspect) aDatumAspect = aTrihedron->Attributes()->DatumAspect();
1087             aDatumAspect->SetAttribute(Prs3d_DP_ShadingConeLengthPercent, myAxisArrowRate);
1088             aContext->Redisplay(aTrihedron, true);
1089           }
1090         }
1091       }
1092     }
1093     if (theParam == "use_auto_rotation") {
1094       bool aAutoRotation = Config_PropManager::boolean("Visualization", "use_auto_rotation");
1095       // Update the auto rotation flag in all OCC 3D view windows
1096       ViewManagerList lst;
1097       getApp()->viewManagers(OCCViewer_Viewer::Type(), lst);
1098       for ( auto it = lst.begin(); it != lst.end(); ++it )
1099       {
1100         OCCViewer_ViewManager *aVMgr = dynamic_cast<OCCViewer_ViewManager*>(*it);
1101         if (aVMgr) {
1102           aVMgr->setAutoRotation(aAutoRotation);
1103         }
1104       }
1105     }
1106   }
1107   else if (theSection == ModuleBase_Preferences::GENERAL_SECTION && theParam == "create_init_part") {
1108     bool aCreate = ModuleBase_Preferences::resourceMgr()->booleanValue(
1109       ModuleBase_Preferences::GENERAL_SECTION, "create_init_part", true);
1110     Events_MessageBool aCreateMsg(Events_Loop::eventByName(EVENT_CREATE_PART_ON_START), aCreate);
1111     aCreateMsg.send();
1112   }
1113   else if (theSection == ModuleBase_Preferences::VIEWER_SECTION &&
1114            theParam.startsWith("group_names_"))
1115   { // one of the group names parameter changed, so, update the groups names vizualization
1116     myWorkshop->updateGroupsText();
1117     myWorkshop->displayer()->updateViewer();
1118   }
1119   myWorkshop->displayer()->redisplayObjects();
1120 }
1121
1122 void SHAPERGUI::putInfo(const QString& theInfo, const int theMSecs)
1123 {
1124   application()->putInfo(theInfo, theMSecs);
1125 }
1126
1127 bool SHAPERGUI::abortAllOperations()
1128 {
1129   return workshop()->operationMgr()->abortAllOperations();
1130 }
1131
1132 void SHAPERGUI::createFeatureActions()
1133 {
1134   myWorkshop->menuMgr()->createFeatureActions();
1135 }
1136
1137 void SHAPERGUI::onWhatIs(bool isToggled)
1138 {
1139   if (sender() == myWhatIsAction) {
1140     QAction* aViewAct = myInspectionPanel->toggleViewAction();
1141     aViewAct->blockSignals(true);
1142     aViewAct->setChecked(isToggled);
1143     aViewAct->blockSignals(false);
1144     myInspectionPanel->setVisible(isToggled);
1145   }
1146   else {
1147     myWhatIsAction->blockSignals(true);
1148     myWhatIsAction->setChecked(isToggled);
1149     myWhatIsAction->blockSignals(false);
1150     myInspectionPanel->setVisible(isToggled);
1151   }
1152 }
1153
1154 void SHAPERGUI::updateModuleVisibilityState()
1155 {
1156   LightApp_Module::updateModuleVisibilityState();
1157   onWhatIs(myIsInspectionVisible);
1158
1159   // the following code is caused by #187 bug.
1160   // SALOME saves the dock widget positions before deactivateModule() and
1161   // load it after the module activation. So, if the panel is visible before
1162   // deactivate, it becomes visible after activate.
1163   // In order to avoid the visible property panel, we hide it here
1164   ModuleBase_Operation* anOperation = myWorkshop->module()->currentOperation();
1165   if (!anOperation) {
1166     myWorkshop->hidePanel(myWorkshop->propertyPanel());
1167   }
1168 }
1169
1170 void SHAPERGUI::onEditToolbars()
1171 {
1172   SHAPERGUI_ToolbarsDlg aDlg(this);
1173   if (aDlg.exec() == QDialog::Accepted) {
1174     if (aDlg.isReset())
1175       resetToolbars();
1176     else
1177       updateToolbars(aDlg.result());
1178   }
1179 }
1180
1181 void SHAPERGUI::registerCommandToolbar(const QString& theToolName, int theCommandId)
1182 {
1183   if (!myToolbars.contains(theToolName))
1184     myToolbars[theToolName] = QList<int>();
1185   myToolbars[theToolName].append(theCommandId);
1186 }
1187
1188 int SHAPERGUI::getNextCommandId() const
1189 {
1190   QtxActionMenuMgr* aMenuMgr = menuMgr();
1191   QIntList aIds = aMenuMgr->idList();
1192   int aId = aIds.count();
1193   while (action(aId) || myActionsList.contains(aId))
1194     aId++;
1195   return aId;
1196 }
1197
1198 void SHAPERGUI::updateToolbars(const QMap<QString, QIntList>& theNewToolbars)
1199 {
1200   // Store default toolbars
1201   if (myDefaultToolbars.size() == 0)
1202     myDefaultToolbars = myToolbars;
1203
1204   QtxActionToolMgr* aMgr = toolMgr();
1205   QStringList aToolbars = theNewToolbars.keys();
1206   QIntList aCommands, aOldCmd;
1207   int aToolbarId;
1208   QAction* aAction;
1209   int aActionId;
1210   foreach(QString aName, aToolbars) {
1211     aCommands = theNewToolbars[aName];
1212     // Find or create toolbar
1213     if (aMgr->hasToolBar(aName)) {
1214       aToolbarId = aMgr->find(aMgr->toolBar(aName));
1215       aOldCmd = myToolbars[aName];
1216     }
1217     else {
1218       aToolbarId = aMgr->createToolBar(aName);
1219     }
1220     int aPos = 0;
1221     foreach(int aCmd, aCommands) {
1222       // Find action
1223       if (aCmd == -1)
1224         aAction = separator();
1225       else
1226         aAction = action(aCmd);
1227       aActionId = aMgr->actionId(aAction);
1228       if (aActionId == -1) {
1229         // Add new action
1230         aMgr->insert(aAction, aToolbarId, aPos);
1231       }
1232       else {
1233         // Change position of action
1234         if (aMgr->index(aActionId, aToolbarId) != aPos) {
1235           if (aMgr->containsAction(aActionId, aToolbarId))
1236             aMgr->remove(aActionId, aToolbarId);
1237           aMgr->insert(aActionId, aToolbarId, aPos);
1238         }
1239       }
1240       aOldCmd.removeAll(aCmd);
1241       aPos++;
1242     }
1243     // remove extra actions
1244     foreach(int aCmd, aOldCmd) {
1245       aAction = action(aCmd);
1246       aActionId = aMgr->actionId(aAction);
1247       aMgr->remove(aActionId, aToolbarId);
1248     }
1249     myToolbars.remove(aName);
1250   }
1251   // Remove extra toolbars
1252   aToolbars = myToolbars.keys();
1253   foreach(QString aName, aToolbars) {
1254     aMgr->removeToolBar(aName);
1255   }
1256   // Set new toolbars structure
1257   myToolbars = theNewToolbars;
1258   myIsToolbarsModified = true;
1259 }
1260
1261 void SHAPERGUI::saveToolbarsConfig()
1262 {
1263   if (!myIsToolbarsModified)
1264     return;
1265   // Save toolbars configuration into map
1266   QMap<QString, QStringList> aToolbarsConfig;
1267 #ifdef _DEBUG
1268   QtxActionToolMgr* aMgr =
1269 #endif
1270     toolMgr();
1271   QStringList aToolbars = myToolbars.keys();
1272   QIntList aActionsIds;
1273   foreach(QString aName, aToolbars) {
1274     aActionsIds = myToolbars[aName];
1275     QStringList aContent;
1276     foreach(int aId, aActionsIds) {
1277       if (aId == -1)
1278         aContent.append("");
1279       else
1280         aContent.append(action(aId)->data().toString());
1281     }
1282     aToolbarsConfig[aName] = aContent;
1283   }
1284   // Store the configuration into resources
1285   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
1286   QStringList aNames = aToolbarsConfig.keys();
1287   QStringList aValues;
1288   foreach(QString aToolbar, aNames) {
1289     aResMgr->setValue(ToolbarsSection, aToolbar, aToolbarsConfig[aToolbar].join(","));
1290   }
1291   // Remove obsolete parameters from resources
1292   QStringList aOldParams = aResMgr->parameters(ToolbarsSection);
1293   foreach(QString aName, aOldParams) {
1294     if (!aToolbars.contains(aName))
1295       aResMgr->remove(ToolbarsSection, aName);
1296   }
1297   // Store current list of free commands
1298   QIntList aFreeCommands = getFreeCommands();
1299   QStringList aFreeList;
1300   foreach(int aId, aFreeCommands) {
1301     aFreeList.append(action(aId)->data().toString());
1302   }
1303   if (aFreeList.size() > 0)
1304     aResMgr->setValue(ToolbarsSection, FreeCommandsParam, aFreeList.join(","));
1305
1306   myIsToolbarsModified = false;
1307 }
1308
1309 void SHAPERGUI::loadToolbarsConfig()
1310 {
1311   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
1312   QStringList aToolbarNames = aResMgr->parameters(ToolbarsSection);
1313   if (aToolbarNames.size() == 0)
1314     return;
1315
1316   // Create commands map
1317   QMap<QString, int> aCommandsMap;
1318   QString aCmdIdStr;
1319   foreach(int aId, myActionsList) {
1320     aCmdIdStr = action(aId)->data().toString();
1321     aCommandsMap[aCmdIdStr] = aId;
1322   }
1323
1324   // Create new toolbars structure
1325   QMap<QString, QIntList> aToolbars;
1326   QStringList aCommands;
1327   QIntList aKnownCommands;
1328   QList<QAction*> aActions;
1329   foreach(QString aName, aToolbarNames) {
1330     aCommands = aResMgr->stringValue(ToolbarsSection, aName).split(",");
1331     if (aName == FreeCommandsParam) {
1332       // The value is a list of free commands
1333       foreach(QString aCommand, aCommands) {
1334         aKnownCommands.append(aCommandsMap[aCommand]);
1335       }
1336     }
1337     else {
1338       aToolbars[aName] = QIntList();
1339       if (aCommands.size() > 0) {
1340         foreach(QString aCommand, aCommands) {
1341           if (aCommand.isEmpty())
1342             aToolbars[aName].append(-1);
1343           else if (aCommandsMap.contains(aCommand)) {
1344             int aId = aCommandsMap[aCommand];
1345             aToolbars[aName].append(aId);
1346             aKnownCommands.append(aId);
1347           }
1348         }
1349       }
1350     }
1351   }
1352   // Find new and obsolete commands
1353   QIntList aNewCommands = myActionsList;
1354   foreach(int aId, myActionsList) {
1355     if (aKnownCommands.contains(aId)) {
1356       aKnownCommands.removeAll(aId);
1357       aNewCommands.removeAll(aId);
1358     }
1359   }
1360   if (aNewCommands.size() > 0) {
1361     // Add new commands to toolbars structure
1362     QStringList aKeys = myToolbars.keys();
1363     foreach(int aNewId, aNewCommands) {
1364       foreach(QString aName, aKeys) {
1365         if (myToolbars[aName].contains(aNewId)) {
1366           if (!aToolbars.contains(aName)) {
1367             aToolbars[aName] = QIntList();
1368           }
1369           aToolbars[aName].append(aNewId);
1370         }
1371       }
1372     }
1373   }
1374   if (aKnownCommands.size() > 0) {
1375     // Remove obsolete commands from the toolbars structure
1376     QStringList aKeys = aToolbars.keys();
1377     foreach(int aOldId, aKnownCommands) {
1378       foreach(QString aName, aKeys) {
1379         if (aToolbars[aName].contains(aOldId)) {
1380           aToolbars[aName].removeAll(aOldId);
1381           if (aToolbars[aName].size() == 0)
1382             aToolbars.remove(aName);
1383         }
1384       }
1385     }
1386   }
1387   updateToolbars(aToolbars);
1388   myIsToolbarsModified = false;
1389 }
1390
1391
1392 QIntList SHAPERGUI::getFreeCommands() const
1393 {
1394   QIntList aFreeCommands;
1395   QtxActionToolMgr* aMgr = toolMgr();
1396   QAction* anAction;
1397   int aId;
1398   QMap<QString, QIntList>::const_iterator aIt;
1399   QIntList aShaperActions = shaperActions();
1400   foreach(int aCmd, aShaperActions) {
1401     anAction = action(aCmd);
1402     aId = aMgr->actionId(anAction);
1403     if (!aMgr->containsAction(aId))
1404       aFreeCommands.append(aCmd);
1405   }
1406   return aFreeCommands;
1407 }
1408
1409 void SHAPERGUI::resetToolbars()
1410 {
1411   if (!myDefaultToolbars.isEmpty())
1412     updateToolbars(myDefaultToolbars);
1413   myIsToolbarsModified = false;
1414   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
1415   aResMgr->remove(ToolbarsSection);
1416 }
1417
1418 void SHAPERGUI::publishToStudy()
1419 {
1420   if (isActiveModule() && ModelAPI_Session::get()->hasModuleDocument()) {
1421     myWorkshop->module()->launchOperation("PublishToStudy", false);
1422
1423     // update SHAPERSTUDY objects in OCC and VTK viewers
1424     QStringList aVMList;
1425     aVMList << "OCCViewer" << "VTKViewer";
1426     getApp()->updatePresentations("SHAPERSTUDY", aVMList);
1427   }
1428 }
1429
1430 void SHAPERGUI::fillPartSetInfoPanel(QtxInfoPanel* theInfoPanel)
1431 {
1432   QIntList aShaperActions = shaperActions();
1433   theInfoPanel->addLabel(tr("Current mode: Part set mode"));
1434
1435   addActionsToInfoGroup(theInfoPanel, tr("Parts management"),
1436     { "Part", "Duplicate", "Remove" });
1437   addActionsToInfoGroup(theInfoPanel, tr("Import operations"),
1438     { "OPEN_CMD", "IMPORT_PART_CMD", "IMPORT_SHAPE_CMD" });
1439   addActionsToInfoGroup(theInfoPanel, tr("Export operations"),
1440     { "SAVEAS_CMD", "EXPORT_PART_CMD", "EXPORT_SHAPE_CMD" });
1441   addActionsToInfoGroup(theInfoPanel, tr("Arrangement of parts"),
1442     { "Placement", "Translation", "Rotation" });
1443 }
1444
1445 void SHAPERGUI::fillPartInfoPanel(QtxInfoPanel* theInfoPanel)
1446 {
1447   QIntList aShaperActions = shaperActions();
1448   theInfoPanel->addLabel(tr("Current mode: Part mode"));
1449
1450   addActionsToInfoGroup(theInfoPanel, tr("Primitives"),
1451     { "Box", "Cylinder", "Sphere" });
1452   addActionsToInfoGroup(theInfoPanel, tr("Geometry"),
1453     { "Vertex", "Edge", "Wire", "Face" });
1454   addActionsToInfoGroup(theInfoPanel, tr("Features"),
1455     { "Extrusion", "Revolution", "Cut", "Fuse", "Fillet" });
1456 }
1457
1458 void SHAPERGUI::fillSketcherInfoPanel(QtxInfoPanel* theInfoPanel)
1459 {
1460   QIntList aShaperActions = shaperActions();
1461   theInfoPanel->addLabel(tr("Current mode: Sketcher mode"));
1462
1463   addActionsToInfoGroup(theInfoPanel, tr("Primitives"),
1464     { "SketchPoint", "SketchLine", "SketchCircle", "SketchRectangle" });
1465   addActionsToInfoGroup(theInfoPanel, tr("Dimensions"),
1466     { "SketchConstraintLength", "SketchConstraintRadius", "SketchConstraintAngle" });
1467   addActionsToInfoGroup(theInfoPanel, tr("Constraints"),
1468     { "SketchConstraintParallel", "SketchConstraintPerpendicular",
1469     "SketchConstraintEqual", "SketchConstraintCoincidence" });
1470 }
1471
1472 void SHAPERGUI::addActionsToInfoGroup(QtxInfoPanel* theInfoPanel,
1473   const QString& theGroup, const QSet<QString>& theActions)
1474 {
1475   QIntList aShaperActions = shaperActions();
1476
1477   int aGroup = theInfoPanel->addGroup(theGroup);
1478   int aCount = 0;
1479   foreach(int aCmd, aShaperActions) {
1480     QAction* aAction = action(aCmd);
1481     if (theActions.contains(aAction->data().toString()))
1482     {
1483       theInfoPanel->addAction(aAction, aGroup);
1484       aCount++;
1485     }
1486     if (aCount >= theActions.size())
1487       break;
1488   }
1489 }
1490
1491 void SHAPERGUI::updateInfoPanel()
1492 {
1493   LightApp_Application* aApp = dynamic_cast<LightApp_Application*>(application());
1494   QtxInfoPanel* aInfoPanel = aApp->infoPanel();
1495   aInfoPanel->clear();
1496   aInfoPanel->setTitle(tr("Welcome to SHAPER"));
1497
1498   SessionPtr aMgr = ModelAPI_Session::get();
1499   QList<DocumentPtr> aDocs;
1500   DocumentPtr aActiveDoc = aMgr->activeDocument();
1501   DocumentPtr aModuleDoc = aMgr->moduleDocument();
1502
1503   XGUI_OperationMgr* aOpMgr = myWorkshop->operationMgr();
1504   QStringList aOpList = aOpMgr->operationList();
1505   bool isSketcher = false;
1506   if (aOpList.size() > 0)
1507     isSketcher = (aOpList.first() == "Sketch");
1508
1509   if (isSketcher) // Sketcher mode
1510     fillSketcherInfoPanel(aInfoPanel);
1511   else if (aActiveDoc == aModuleDoc) // Part set mode
1512     fillPartSetInfoPanel(aInfoPanel);
1513   else
1514     fillPartInfoPanel(aInfoPanel);
1515 }