1 // Copyright (C) 2007-2013 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.
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 // Py_ssize_t for old Pythons
39 // This code is as recommended by"
40 // http://www.python.org/dev/peps/pep-0353/#conversion-guidelines
41 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
42 typedef int Py_ssize_t;
43 # define PY_SSIZE_T_MAX INT_MAX
44 # define PY_SSIZE_T_MIN INT_MIN
48 // NB: Python requests.
49 // General rule for Python requests created by Python-based GUI modules
50 // (SALOME_PYQT_ModuleLight and other ones):
51 // all requests should be executed SYNCHRONOUSLY within the main GUI thread.
52 // However, it is obligatory that ANY Python call is wrapped with a request object,
53 // so that ALL Python API calls are serialized with PyInterp_Dispatcher.
55 // NB: Library initialization
56 // Since the SalomePyQtGUILight library is not imported in Python it's initialization function
57 // should be called manually (and only once) in order to initialize global sip data
58 // and to get C API from sip : sipBuildResult for example
61 #define INIT_FUNCTION initSalomePyQtGUILight
62 #if defined(SIP_STATIC_MODULE)
63 extern "C" void INIT_FUNCTION();
65 PyMODINIT_FUNC INIT_FUNCTION();
69 \fn CAM_Module* createModule()
70 \brief Module factory function.
73 Creates an instance of SALOME_PYQT_Module object by request
74 of an application when the module is loaded and initialized.
76 \return new module object
81 SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule()
83 static bool alreadyInitialized = false;
85 // make initialization only once (see comment above) !
86 if ( !alreadyInitialized ) {
87 static PyThreadState* gtstate = 0;
88 #ifndef GUI_DISABLE_CORBA
89 if ( SUIT_PYTHON::initialized )
90 gtstate = SUIT_PYTHON::_gtstate;
92 gtstate = KERNEL_PYTHON::_gtstate;
94 gtstate = SUIT_PYTHON::_gtstate;
96 PyEval_RestoreThread( gtstate );
100 PyEval_ReleaseThread( gtstate );
102 alreadyInitialized = !alreadyInitialized;
105 return new SALOME_PYQT_ModuleLight();
110 \class SALOME_PYQT_ModuleLight
111 \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
112 Python-based SALOME modules.
118 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
119 : LightApp_Module( "noname" ) // name is set explicitly at the module initialization
122 myHelper = new PyModuleHelper( this );
128 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
130 // as myHelper is a QObject, it should be deleted automatically
134 \brief Initialization of the module.
135 \param app parent application object
136 \sa PyModuleHelper::initialize()
138 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
140 // call base implementation
141 LightApp_Module::initialize( app );
143 // ... then call helper
144 myHelper->initialize( app );
145 SUIT_DataBrowser* ob = getApp()->objectBrowser();
146 if (ob && ob->model()) {
147 connect( ob->model(), SIGNAL( clicked( SUIT_DataObject*, int ) ),
148 myHelper, SLOT( onObjectBrowserClicked( SUIT_DataObject*, int ) ), Qt::UniqueConnection );
153 \brief Activation of the module.
154 \param study parent study
155 \return \c true if activation is successful and \c false otherwise
156 \sa PyModuleHelper::activate()
158 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
160 // call base implementation and then helper
161 return LightApp_Module::activateModule( study ) && myHelper->activate( study );
165 \brief Deactivation of the module.
166 \param study parent study
167 \return \c true if deactivation is successful and \c false otherwise
168 \sa PyModuleHelper::deactivate()
170 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
173 bool res = myHelper->deactivate( study );
175 // ... then call base implementation
176 return LightApp_Module::deactivateModule( study ) && res;
180 \brief Close of the module.
182 This function is usually used in order to close the module's
183 specific menus and toolbars and perform other such actions
184 required when the module is closed.
186 void SALOME_PYQT_ModuleLight::onModelClosed()
189 myHelper->modelClosed(application()->activeStudy());
190 LightApp_Module::onModelClosed();
195 \brief Get the dockable windows associated with the module.
196 \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
197 \sa PyModuleHelper::windows()
199 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
201 // get list of dockable windows from helper
202 winMap = myHelper->windows();
206 \brief Define the compatible view windows associated with the module.
207 \param viewList output list of view windows types
208 \sa PyModuleHelper::viewManagers()
210 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
212 // get list of view types from helper
213 viewList = myHelper->viewManagers();
217 \brief Process study activation.
218 \sa PyModuleHelper::studyActivated()
220 void SALOME_PYQT_ModuleLight::studyActivated()
223 myHelper->studyActivated( application()->activeStudy() );
227 \brief Process context popup menu request.
228 \param context popup menu context (e.g. "ObjectBrowser")
229 \param menu popup menu
230 \param title popup menu title (not used)
231 \sa PyModuleHelper::contextMenu()
233 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context,
238 myHelper->contextMenu( context, menu );
242 \brief Export preferences for the Python module.
243 \sa PyModuleHelper::createPreferences()
245 void SALOME_PYQT_ModuleLight::createPreferences()
248 myHelper->createPreferences();
252 \brief Process module's preferences changing.
253 \param section preference resources section
254 \param parameter preference resources parameter name
255 \sa PyModuleHelper::preferencesChanged()
257 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
260 myHelper->preferencesChanged( section, parameter );
264 \brief Save module data. Called when user saves study.
265 \param files output list of files where module stores data
266 \sa PyModuleHelper::save()
268 void SALOME_PYQT_ModuleLight::save( QStringList& files )
271 myHelper->save( files );
275 \brief Load module data. Called when user opens study
276 and activates module.
277 \param files list of files where module data is stored
278 \sa PyModuleHelper::load()
280 bool SALOME_PYQT_ModuleLight::load( const QStringList& files )
283 return myHelper->load( files );
287 \brief Dump module data to the Python script.
288 Called when user activates dump study operation.
289 \param files output list of files where module stores python script
290 \sa PyModuleHelper::dumpPython()
292 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
295 myHelper->dumpPython( files );
299 \brief Test if object \a what can be dragged by the user.
300 \param what data object being tested
301 \return \c true if object can be dragged or \c false otherwise
302 \sa PyModuleHelper::isDraggable()
304 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
307 return myHelper->isDraggable( what );
311 \brief Test if drop operation can be done on the \a where object.
312 \param where data object being tested
313 \return \c true if if drop operation is supported by object or \c false otherwise
314 \sa PyModuleHelper::isDropAccepted()
316 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
319 return myHelper->isDropAccepted( where );
323 \brief Perform drop operation
324 \param what list of data objects being dropped
325 \param where target data object for drop operation
326 \param row line (child item index) where drop operation is performed to
327 \param action current drop action (copy or move)
328 \sa PyModuleHelper::dropObjects()
330 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
331 const int row, Qt::DropAction action )
334 myHelper->dropObjects( what, where, row, action );
338 \brief Create new empty data object
339 \param parent entry of parent data object
340 \return entry of created data object
342 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
345 SALOME_PYQT_DataObjectLight* obj = 0;
347 if ( !parent.isEmpty() ) {
348 SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
350 obj = new SALOME_PYQT_DataObjectLight( parentObj );
353 SALOME_PYQT_DataModelLight* dm =
354 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
356 obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
359 entry = obj->entry();
364 \brief Create new data object with specified name, icon and tooltip
365 \param name data object name
366 \param icon data object icon
367 \param toolTip data object tooltip
368 \param parent entry of parent data object
369 \return entry of created data object
371 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
373 const QString& toolTip,
374 const QString& parent )
376 QString entry = createObject( parent );
377 SALOME_PYQT_DataObjectLight* obj = findObject( entry );
380 obj->setToolTip( toolTip );
381 obj->setIcon( icon );
387 \brief Set data object name
388 \param entry data object entry
389 \param name data object name
391 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
393 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
395 dataObj->setName( name );
399 \brief Get data object name
400 \param entry data object entry
401 \return data object name
403 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
406 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
408 name = dataObj->name();
413 \brief Set data object icon
414 \param entry data object entry
415 \param icon data object icon file name (icon is loaded from module resources)
417 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
419 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
421 dataObj->setIcon( icon );
425 \brief Set data object tooltip
426 \param entry data object entry
427 \param toolTip data object tooltip
429 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
431 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
433 dataObj->setToolTip( toolTip );
437 \brief Get data object tooltip
438 \param entry data object entry
439 \return data object tooltip
441 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
444 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
446 toolTip = dataObj->toolTip();
451 \brief Set data object color
452 \param entry data object entry
453 \param color data object color
455 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
457 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
459 dataObj->setColor( color );
463 \brief Get data object color
464 \param entry data object entry
465 \return data object color
467 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
470 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
472 color = dataObj->color( SUIT_DataObject::Foreground );
476 void SALOME_PYQT_ModuleLight::setObjectPosition( const QString& theEntry, int thePos )
478 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
480 dataObj->setPosition(thePos);
483 int SALOME_PYQT_ModuleLight::getObjectPosition( const QString& theEntry )
485 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
487 return dataObj->position();
493 \brief Set reference to another data object
494 \param entry data object entry
495 \param refEntry referenced data object entry
497 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
499 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
501 dataObj->setRefEntry( refEntry );
505 \brief Get entry of the referenced object (if there's any)
506 \param entry data object entry
507 \return referenced data object entry
509 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
512 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
514 refEntry = dataObj->refEntry();
519 \brief Remove object by entry
520 \param entry data object entry
522 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
524 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
525 if ( dataObj && dataObj->parent() )
526 dataObj->parent()->removeChild( dataObj );
530 \brief Remove all child data objects from specified data object
531 \param entry data object entry
533 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
535 SUIT_DataObject* dataObj = 0;
536 if ( !entry.isEmpty() ) {
537 dataObj = findObject( entry );
540 SALOME_PYQT_DataModelLight* dm =
541 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
542 if ( dm ) dataObj = dm->getRoot();
545 DataObjectList children;
546 dataObj->children( children );
547 QListIterator<SUIT_DataObject*> it( children );
548 while ( it.hasNext() ) {
549 dataObj->removeChild( it.next() );
555 \brief Get entries of all child data objects of specified data object
556 \param entry data object entry
557 \param recursive \c true for recursive processing
559 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
561 QStringList entryList;
562 SUIT_DataObject* dataObj = 0;
563 if ( !entry.isEmpty() ) {
564 dataObj = findObject( entry );
567 SALOME_PYQT_DataModelLight* dm =
568 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
569 if ( dm ) dataObj = dm->getRoot();
573 dataObj->children( lst, recursive );
574 QListIterator<SUIT_DataObject*> it( lst );
575 while ( it.hasNext() ) {
576 SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
577 entryList.append( sobj->entry() );
584 \brief Create new instance of data model and return it.
586 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
588 return new SALOME_PYQT_DataModelLight( this );
592 \brief Find data object by its entry
593 \param entry data object entry
594 \return data object with given entry or 0 if object isn't found
596 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
598 SALOME_PYQT_DataObjectLight* obj = 0;
599 SALOME_PYQT_DataModelLight* dm =
600 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
601 if ( !entry.isEmpty() && dm ) {
602 for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) {
603 SALOME_PYQT_DataObjectLight* curentobj =
604 dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
605 if ( curentobj && curentobj->entry() == entry )