Salome HOME
380beaad9ec228ccccec6a2798e82eea7d7e2a30
[modules/gui.git] / src / GuiHelpers / StandardApp_Module.cxx
1 // Copyright (C) 2011-2021  CEA/DEN, EDF R&D, OPEN CASCADE
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 // Author : Guillaume Boulant (EDF)
20
21 #include "StandardApp_Module.hxx"
22
23 #include "SALOME_GuiServices.hxx"
24
25 #include <SUIT_Desktop.h>
26 #include <SUIT_Study.h>
27 #include <SalomeApp_Application.h>
28 #include <SALOME_LifeCycleCORBA.hxx>
29 #include "QtxPopupMgr.h"
30
31 #include CORBA_CLIENT_HEADER(SALOMEDS)
32 #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes)
33
34 // QT Includes
35 #include <QIcon>
36 #include <QAction>
37
38 #include <Basics_Utils.hxx>
39 #include "QtHelper.hxx"
40
41 // Constructor
42 StandardApp_Module::StandardApp_Module() :
43   SalomeApp_Module( "" )
44 {
45   // Note that it's no use to specify here the moduleName because it's
46   // automatically determined by the name of the GUI library
47   // (lib<moduleName>.so) just before initialize step. If you want
48   // nevertheless to setup the module name you should specified this
49   // name in the initialize function below using the CAM_module
50   // function setModuleName(QString&). You are warn then that the
51   // loading of resource files may be incorect and should be manually
52   // managed. In conclusion, if you don't need a special
53   // configuration, please conform to the standard convention: if
54   // <moduleName> is the name of the module as declared in the GUI
55   // configuration file (SalomeApp.xml), then you just have to provide
56   // a library whose name is lib<moduleName>.so and which contains a
57   // factory "extern C" function 'CAM_Module* createModule()'
58 }
59
60 int StandardApp_Module::ACTIONID_DEFAULT_INIT_VALUE = 910;
61 int StandardApp_Module::ACTIONID_UNDEFINED = -1;
62
63 // Module's initialization
64 void StandardApp_Module::initialize( CAM_Application* app )
65 {
66   //
67   // ----------------------------------------------------------------
68   // Standard initialization
69   // ----------------------------------------------------------------
70   //
71   SalomeApp_Module::initialize( app );
72   _resourceMgr = app->resourceMgr();
73   // Please note that the moduleName() function is inherited from
74   // CAM_module classe, and that its value is determined automatically
75   // from the name specified in the SalomeApp.xml associated to this
76   // module and which corresponds to the name of the GUI library
77   // (lib<moduleName>.so). For XSALOME, see
78   // share/salome/resources/xsalome/SalomeApp.xml in the install
79   // directory.
80   _defaultMenuId = this->createMenu( QCHARSTAR(moduleName()), -1, -1, 30 );
81   _defaultToolbarId = this->createTool ( QCHARSTAR(moduleName()), moduleName() );
82   _actionId_internalCount = StandardApp_Module::ACTIONID_DEFAULT_INIT_VALUE;
83
84   //
85   // ----------------------------------------------------------------
86   // The following initializes the GUI widget and associated actions
87   // ----------------------------------------------------------------
88   // These functions may be redefined in specialized version of this class
89   this->createModuleWidgets();
90   this->createModuleActions();
91 }
92
93 QIcon StandardApp_Module::createIcon(const QString& iconName) {
94   // The icon file is supposed to be available througth the resource
95   // manager, i.e. in the folder containing the XSALOME resources (see
96   // specification in the module file SalomeApp.xml).
97   QPixmap aPixmap = _resourceMgr->loadPixmap( QCHARSTAR(moduleName()), iconName );
98   return QIcon( aPixmap );
99 }
100
101 int StandardApp_Module::newActionId() {
102   _actionId_internalCount++;
103   return _actionId_internalCount;
104 }
105
106 /*!
107  * This function creates an action and connects it to a button in the
108  * toolbar and to an item in the menu associated to this module.  This
109  * function applies a common and standard procedure with a maximum of
110  * default values. If no identifier is specified, then a static
111  * internal counter is used to associate an identifier to the created
112  * action. In any case, the action identifier is returned.
113  *
114  * Note that the action (object of type QAction) can be retrieved
115  * using the method "QAction * action(int identifier)" of the super
116  * class.
117  */
118 int StandardApp_Module::createStandardAction(const QString& label,
119                                              QObject * slotobject,
120                                              const char* slotmember,
121                                              const QString& iconName,
122                                              const QString& tooltip,
123                                              const int identifier)
124 {
125
126   // If the tooltip is not defined, we choose instead the label text.
127   QString effToolTip(tooltip);
128   if ( effToolTip.isEmpty() )
129     effToolTip = label;
130
131   QIcon actionIcon = this->createIcon(iconName);
132
133   // If the identifier is not specified, then we use an internal
134   // counter.
135   int effIdentifier = identifier;
136   if ( effIdentifier == StandardApp_Module::ACTIONID_UNDEFINED ) {
137     effIdentifier=newActionId();
138   }
139
140   // Creating the action
141   this->createAction( effIdentifier, label, actionIcon,
142                       label, effToolTip, 0, getApp()->desktop(),
143                       false, slotobject, slotmember);
144
145   return effIdentifier;
146 }
147
148 /**
149  * Integrate the action in the default toolbar
150  */
151 void StandardApp_Module::addActionInToolbar(int actionId) {
152   this->createTool( actionId, _defaultToolbarId );
153 }
154
155 /**
156  * Integrate action in the specified menu. If the menu is not
157  * specified, then it is integrated into the menu associated to the
158  * SALOME module.
159  */
160 void StandardApp_Module::addActionInMenubar(int actionId, int menuId) {
161   if ( menuId == UNSPECIFIED_INT) {
162     menuId = _defaultMenuId;
163   }
164   this->action( actionId )->setIconVisibleInMenu(true);
165   this->createMenu( actionId, menuId, 10 );
166 }
167
168
169
170 /**
171  * Add the specified action as an item in the popup menu, with the
172  * specified visible rule. The default is "visible for object browser".
173  */
174 void StandardApp_Module::addActionInPopupMenu(int actionId,const QString& menus,const QString& rule) {
175   // _GBO_ for a fine customization of the rule (for example with a
176   // test on the type of the selected object), see the LIGTH module:
177   // implement "LightApp_Selection*    createSelection() const;"
178   int parentId = -1;
179   QtxPopupMgr* mgr = this->popupMgr();
180   this->action( actionId )->setIconVisibleInMenu(true);
181   if (! menus.isEmpty())
182     mgr->insert ( this->action( actionId ), menus, parentId, 0 );
183   else
184     mgr->insert ( this->action( actionId ), parentId, 0 );
185   mgr->setRule( this->action( actionId ), rule, QtxPopupMgr::VisibleRule );
186 }
187
188 /*!
189  * This function can be used to create additionnal widget for this
190  * module GUI (e.g. docked widget). It can be redefined in a
191  * specialized version of this class.
192  */
193 void StandardApp_Module::createModuleWidgets() {
194   // Nothing to do in this default gui
195 }
196
197 /*!
198  * This function can be used to defined the list of actions for this
199  * module GUI.  It can be redefined in a specialized version of this
200  * class.
201  * Depending on wether you use the method "createStandardAction" or
202  * not, the actions will be automatically plugged in the toolbar and
203  * the menu associated to the module.
204  */
205 void StandardApp_Module::createModuleActions() {
206   int actionId = this->createStandardAction("Test", this, SLOT(OnTest()),
207                                             "f1.png", "Run the default test function");
208   this->addActionInToolbar(actionId);
209 }
210
211 // Get compatible dockable windows.
212 void StandardApp_Module::windows( QMap<int, int>& theMap ) const
213 {
214   theMap.clear();
215   theMap.insert( SalomeApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
216 #ifndef DISABLE_PYCONSOLE
217   theMap.insert( SalomeApp_Application::WT_PyConsole,     Qt::BottomDockWidgetArea );
218 #endif
219 }
220
221 // Module's engine IOR
222 QString StandardApp_Module::engineIOR() const
223 {
224   CORBA::String_var anIOR = getApp()->orb()->object_to_string(getEngine());
225   return QString( anIOR.in() );
226 }
227
228 /*!
229  * This specifies the filename for the icon to be used for the study
230  * component associated to the module. Note that this icon could be
231  * different than the module icon which is defined by the
232  * SalomeApp.xml file dedicated to this module (see the shared
233  * resources folder dedicated to the module) and which is used for the
234  * toolbar of the SALOME application.
235  */
236 QString StandardApp_Module::studyIconName()
237 {
238   // By default, we return the module icone name
239   return iconName(); // inherited from CAM_Module
240 }
241
242 /*!
243  * This can be used to switch the layout of main application
244  * dockwidgets to one of the predefined configuration (see enum
245  * DockLayoutType). When a layout is set, the previous layout is
246  * memorized and can be restored using the unsetDockLayout function (1
247  * step undo). It is typically to be used in the functions
248  * activateModule to setup the layout and deactivateModule to unset
249  * the layout, i.e. restore to the previous state.
250  */
251 void StandardApp_Module::setDockLayout(DockLayoutType layoutType) {
252   SUIT_Desktop* desk = getApp()->desktop();
253   _areaAtBottomLeftCorner = desk->corner(Qt::BottomLeftCorner);
254   _areaAtBottomRightCorner = desk->corner(Qt::BottomRightCorner);
255
256   if ( layoutType == DOCKLAYOUT_LEFT_VLARGE ) {
257     desk->setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
258     desk->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
259   } else {
260     desk->setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea);
261     desk->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
262   }
263 }
264
265 /*!
266  * This function restores the layout state that was previously in
267  * place before the last setDockLayout call.
268  */
269 void StandardApp_Module::unsetDockLayout() {
270   SUIT_Desktop* desk = getApp()->desktop();
271   desk->setCorner(Qt::BottomLeftCorner, _areaAtBottomLeftCorner);
272   desk->setCorner(Qt::BottomRightCorner, _areaAtBottomRightCorner);
273 }
274
275 // Module's activation
276 bool StandardApp_Module::activateModule( SUIT_Study* theStudy )
277 {
278   bool bOk = SalomeApp_Module::activateModule( theStudy );
279
280   setMenuShown( true );
281   setToolShown( true );
282
283   if ( this->createStudyComponentAtActivation() ) {
284     this->createStudyComponent();
285   }
286
287   return bOk;
288 }
289
290 /*!
291  * This function should be implemented in a specialized class and must
292  * return true if you want to automatically create a study component
293  * for this module at activation step (when you first load the module
294  * for a given study). The default function return true.
295  */
296 bool StandardApp_Module::createStudyComponentAtActivation() {
297   return true;
298 }
299
300 /*!
301  * This creates a root entry in the active study for this module, i.e
302  * a SComponent with the name of the module and the icon specified for
303  * the module. This component is associated to the engine (return by
304  * getEngine()) if the engine is a SALOMEDS::Driver.
305  */
306 void StandardApp_Module::createStudyComponent() {
307
308   SALOMEDS::Study_var aDSStudy = GUI::getStudyServant();
309
310   SALOMEDS::SComponent_var aFather = aDSStudy->FindComponent(QCHARSTAR(moduleName()));
311   if (aFather->_is_nil())
312     {
313       SALOMEDS::StudyBuilder_var aStudyBuilder = aDSStudy->NewBuilder();
314       aFather = aStudyBuilder->NewComponent(QCHARSTAR(moduleName()));
315       SALOMEDS::GenericAttribute_var anAttr = aStudyBuilder->FindOrCreateAttribute(aFather, "AttributeName");
316       SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow(anAttr);
317       aName->SetValue(QCHARSTAR(moduleName()));
318       aName->Destroy();
319       anAttr = aStudyBuilder->FindOrCreateAttribute(aFather, "AttributePixMap");
320       SALOMEDS::AttributePixMap_var aPixMap = SALOMEDS::AttributePixMap::_narrow(anAttr);
321       aPixMap->SetPixMap(QCHARSTAR(studyIconName()));
322
323       // WARN: The engine should be associated to the SComponent IF
324       // AND ONLY IF it is a SALOMEDS::Driver. Otherwise, there is no
325       // need to do that, and it could even lead to exception
326       // raising (eh, you work on SALOME isn't it?)
327       SALOMEDS::Driver_var driver = SALOMEDS::Driver::_narrow(this->getEngine());
328       if ( ! driver->_is_nil() ) {
329         STDLOG("Associate the SComponent to the engine");
330         aStudyBuilder->DefineComponentInstance(aFather, this->getEngine());
331       }
332     }
333
334 }
335
336 // Module's deactivation
337 bool StandardApp_Module::deactivateModule( SUIT_Study* theStudy )
338 {
339   setMenuShown( false );
340   setToolShown( false );
341
342   return SalomeApp_Module::deactivateModule( theStudy );
343 }
344
345 void StandardApp_Module::OnTest()
346 {
347   // Just for test
348   STDLOG("OnTest: engine IOR = "<<QCHARSTAR(engineIOR()));
349 }
350