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