1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File : SALOME_PYQT_ModuleLight.cxx
21 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
23 #include "SALOME_PYQT_DataModelLight.h"
24 #include "SALOME_PYQT_ModuleLight.h"
25 #include "SALOME_PYQT_PyModule.h"
27 #include "CAM_Application.h"
28 #include "SUITApp_init_python.hxx"
29 #include "SUIT_DataObjectIterator.h"
30 #include "LightApp_Application.h"
31 #include "SUIT_DataBrowser.h"
32 #include "sipAPISalomePyQtGUILight.h"
34 #ifndef GUI_DISABLE_CORBA
35 #include <Container_init_python.hxx>
38 #include <QCoreApplication>
40 // Py_ssize_t for old Pythons
41 // This code is as recommended by"
42 // http://www.python.org/dev/peps/pep-0353/#conversion-guidelines
43 //#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
44 //typedef int Py_ssize_t;
45 //# define PY_SSIZE_T_MAX INT_MAX
46 //# define PY_SSIZE_T_MIN INT_MIN
50 // NB: Python requests.
51 // General rule for Python requests created by Python-based GUI modules
52 // (SALOME_PYQT_ModuleLight and other ones):
53 // all requests should be executed SYNCHRONOUSLY within the main GUI thread.
54 // However, it is obligatory that ANY Python call is wrapped with a request object,
55 // so that ALL Python API calls are serialized with PyInterp_Dispatcher.
57 // NB: Library initialization
58 // Since the SalomePyQtGUILight library is not imported in Python it's initialization function
59 // should be called manually (and only once) in order to initialize global sip data
60 // and to get C API from sip : sipBuildResult for example
63 #define INIT_FUNCTION initSalomePyQtGUILight
64 #if defined(SIP_STATIC_MODULE)
65 extern "C" void INIT_FUNCTION();
67 PyMODINIT_FUNC INIT_FUNCTION();
71 \fn CAM_Module* createModule()
72 \brief Module factory function.
75 Creates an instance of SALOME_PYQT_Module object by request
76 of an application when the module is loaded and initialized.
78 \return new module object
83 SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule()
85 QCoreApplication* app = QCoreApplication::instance();
86 bool alreadyInitialized = app && app->property( "salome_pyqt_gui_light_initialized" ).toBool();
88 // make initialization only once (see comment above) !
89 if ( !alreadyInitialized ) {
90 PyLockWrapper lck; // GIL acquisition
92 if ( app ) app->setProperty( "salome_pyqt_gui_light_initialized", true );
95 return new SALOME_PYQT_ModuleLight();
100 \class SALOME_PYQT_ModuleLight
101 \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
102 Python-based SALOME modules.
108 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
109 : LightApp_Module( "noname" ) // name is set explicitly at the module initialization
112 myHelper = new PyModuleHelper( this );
118 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
120 // as myHelper is a QObject, it should be deleted automatically
124 \brief Initialization of the module.
125 \param app parent application object
126 \sa PyModuleHelper::initialize()
128 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
130 // call base implementation
131 LightApp_Module::initialize( app );
133 // ... then call helper
134 myHelper->initialize( app );
135 SUIT_DataBrowser* ob = getApp()->objectBrowser();
136 if (ob && ob->model()) {
137 connect( ob->model(), SIGNAL( clicked( SUIT_DataObject*, int ) ),
138 myHelper, SLOT( onObjectBrowserClicked( SUIT_DataObject*, int ) ), Qt::UniqueConnection );
143 \brief Activation of the module.
144 \param study parent study
145 \return \c true if activation is successful and \c false otherwise
146 \sa PyModuleHelper::activate()
148 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
150 // call base implementation and then helper
151 return LightApp_Module::activateModule( study ) && myHelper->activate( study );
155 \brief Deactivation of the module.
156 \param study parent study
157 \return \c true if deactivation is successful and \c false otherwise
158 \sa PyModuleHelper::deactivate()
160 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
163 bool res = myHelper->deactivate( study );
165 // ... then call base implementation
166 return LightApp_Module::deactivateModule( study ) && res;
170 \brief Close of the module.
172 This function is usually used in order to close the module's
173 specific menus and toolbars and perform other such actions
174 required when the module is closed.
176 void SALOME_PYQT_ModuleLight::onModelClosed()
179 myHelper->modelClosed(application()->activeStudy());
180 LightApp_Module::onModelClosed();
185 \brief Get the dockable windows associated with the module.
186 \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
187 \sa PyModuleHelper::windows()
189 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
191 // get list of dockable windows from helper
192 winMap = myHelper->windows();
196 \brief Define the compatible view windows associated with the module.
197 \param viewList output list of view windows types
198 \sa PyModuleHelper::viewManagers()
200 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
202 // get list of view types from helper
203 viewList = myHelper->viewManagers();
207 \brief Process study activation.
208 \sa PyModuleHelper::studyActivated()
210 void SALOME_PYQT_ModuleLight::studyActivated()
213 myHelper->studyActivated( application()->activeStudy() );
217 \brief Process context popup menu request.
218 \param context popup menu context (e.g. "ObjectBrowser")
219 \param menu popup menu
220 \param title popup menu title (not used)
221 \sa PyModuleHelper::contextMenu()
223 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context,
228 myHelper->contextMenu( context, menu );
232 \brief Export preferences for the Python module.
233 \sa PyModuleHelper::createPreferences()
235 void SALOME_PYQT_ModuleLight::createPreferences()
238 myHelper->createPreferences();
242 \brief Process module's preferences changing.
243 \param section preference resources section
244 \param parameter preference resources parameter name
245 \sa PyModuleHelper::preferencesChanged()
247 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
250 myHelper->preferencesChanged( section, parameter );
254 \brief Save module data. Called when user saves study.
255 \param files output list of files where module stores data
257 \sa PyModuleHelper::save()
259 void SALOME_PYQT_ModuleLight::save( QStringList& files, const QString& url )
262 myHelper->save( files, url );
266 \brief Load module data. Called when user opens study
267 and activates module.
268 \param files list of files where module data is stored
270 \return \c true if loading has been finished successfully or \c false otherwise
271 \sa PyModuleHelper::load()
273 bool SALOME_PYQT_ModuleLight::load( const QStringList& files, const QString& url )
276 return myHelper->load( files, url );
280 \brief Dump module data to the Python script.
281 Called when user activates dump study operation.
282 \param files output list of files where module stores python script
283 \sa PyModuleHelper::dumpPython()
285 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
288 myHelper->dumpPython( files );
292 \brief Test if object \a what can be dragged by the user.
293 \param what data object being tested
294 \return \c true if object can be dragged or \c false otherwise
295 \sa PyModuleHelper::isDraggable()
297 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
300 return myHelper->isDraggable( what );
304 \brief Test if drop operation can be done on the \a where object.
305 \param where data object being tested
306 \return \c true if if drop operation is supported by object or \c false otherwise
307 \sa PyModuleHelper::isDropAccepted()
309 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
312 return myHelper->isDropAccepted( where );
316 \brief Perform drop operation
317 \param what list of data objects being dropped
318 \param where target data object for drop operation
319 \param row line (child item index) where drop operation is performed to
320 \param action current drop action (copy or move)
321 \sa PyModuleHelper::dropObjects()
323 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
324 const int row, Qt::DropAction action )
327 myHelper->dropObjects( what, where, row, action );
331 \brief Create new empty data object
332 \param parent entry of parent data object
333 \return entry of created data object
335 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
338 SALOME_PYQT_DataObjectLight* obj = 0;
340 if ( !parent.isEmpty() ) {
341 SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
343 obj = new SALOME_PYQT_DataObjectLight( parentObj );
346 SALOME_PYQT_DataModelLight* dm =
347 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
349 obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
352 entry = obj->entry();
357 \brief Create new data object with specified name, icon and tooltip
358 \param name data object name
359 \param icon data object icon
360 \param toolTip data object tooltip
361 \param parent entry of parent data object
362 \return entry of created data object
364 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
366 const QString& toolTip,
367 const QString& parent )
369 QString entry = createObject( parent );
370 SALOME_PYQT_DataObjectLight* obj = findObject( entry );
373 obj->setToolTip( toolTip );
374 obj->setIcon( icon );
380 \brief Set data object name
381 \param entry data object entry
382 \param name data object name
384 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
386 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
388 dataObj->setName( name );
392 \brief Get data object name
393 \param entry data object entry
394 \return data object name
396 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
399 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
401 name = dataObj->name();
406 \brief Set data object icon
407 \param entry data object entry
408 \param icon data object icon file name (icon is loaded from module resources)
410 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
412 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
414 dataObj->setIcon( icon );
418 \brief Set data object tooltip
419 \param entry data object entry
420 \param toolTip data object tooltip
422 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
424 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
426 dataObj->setToolTip( toolTip );
430 \brief Get data object tooltip
431 \param entry data object entry
432 \return data object tooltip
434 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
437 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
439 toolTip = dataObj->toolTip();
444 \brief Set data object color
445 \param entry data object entry
446 \param color data object color
448 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
450 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
452 dataObj->setColor( color );
456 \brief Get data object color
457 \param entry data object entry
458 \return data object color
460 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
463 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
465 color = dataObj->color( SUIT_DataObject::Foreground );
469 void SALOME_PYQT_ModuleLight::setObjectPosition( const QString& theEntry, int thePos )
471 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
473 dataObj->setPosition(thePos);
476 int SALOME_PYQT_ModuleLight::getObjectPosition( const QString& theEntry )
478 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
480 return dataObj->position();
486 \brief Set reference to another data object
487 \param entry data object entry
488 \param refEntry referenced data object entry
490 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
492 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
494 dataObj->setRefEntry( refEntry );
498 \brief Get entry of the referenced object (if there's any)
499 \param entry data object entry
500 \return referenced data object entry
502 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
505 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
507 refEntry = dataObj->refEntry();
512 \brief Remove object by entry
513 \param entry data object entry
515 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
517 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
518 if ( dataObj && dataObj->parent() )
519 dataObj->parent()->removeChild( dataObj );
523 \brief Remove all child data objects from specified data object
524 \param entry data object entry
526 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
528 SUIT_DataObject* dataObj = 0;
529 if ( !entry.isEmpty() ) {
530 dataObj = findObject( entry );
533 SALOME_PYQT_DataModelLight* dm =
534 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
535 if ( dm ) dataObj = dm->getRoot();
538 DataObjectList children;
539 dataObj->children( children );
540 QListIterator<SUIT_DataObject*> it( children );
541 while ( it.hasNext() ) {
542 dataObj->removeChild( it.next() );
548 \brief Get entries of all child data objects of specified data object
549 \param entry data object entry
550 \param recursive \c true for recursive processing
552 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
554 QStringList entryList;
555 SUIT_DataObject* dataObj = 0;
556 if ( !entry.isEmpty() ) {
557 dataObj = findObject( entry );
560 SALOME_PYQT_DataModelLight* dm =
561 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
562 if ( dm ) dataObj = dm->getRoot();
566 dataObj->children( lst, recursive );
567 QListIterator<SUIT_DataObject*> it( lst );
568 while ( it.hasNext() ) {
569 SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
570 entryList.append( sobj->entry() );
577 \brief Create new instance of data model and return it.
579 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
581 return new SALOME_PYQT_DataModelLight( this );
585 \brief Find data object by its entry
586 \param entry data object entry
587 \return data object with given entry or 0 if object isn't found
589 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
591 SALOME_PYQT_DataObjectLight* obj = 0;
592 SALOME_PYQT_DataModelLight* dm =
593 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
594 if ( !entry.isEmpty() && dm ) {
595 for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) {
596 SALOME_PYQT_DataObjectLight* curentobj =
597 dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
598 if ( curentobj && curentobj->entry() == entry )