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"
31 #include "sipAPISalomePyQtGUILight.h"
33 #ifndef GUI_DISABLE_CORBA
34 #include <Container_init_python.hxx>
37 // Py_ssize_t for old Pythons
38 // This code is as recommended by"
39 // http://www.python.org/dev/peps/pep-0353/#conversion-guidelines
40 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
41 typedef int Py_ssize_t;
42 # define PY_SSIZE_T_MAX INT_MAX
43 # define PY_SSIZE_T_MIN INT_MIN
47 // NB: Python requests.
48 // General rule for Python requests created by Python-based GUI modules
49 // (SALOME_PYQT_ModuleLight and other ones):
50 // all requests should be executed SYNCHRONOUSLY within the main GUI thread.
51 // However, it is obligatory that ANY Python call is wrapped with a request object,
52 // so that ALL Python API calls are serialized with PyInterp_Dispatcher.
54 // NB: Library initialization
55 // Since the SalomePyQtGUILight library is not imported in Python it's initialization function
56 // should be called manually (and only once) in order to initialize global sip data
57 // and to get C API from sip : sipBuildResult for example
60 #define INIT_FUNCTION initSalomePyQtGUILight
61 #if defined(SIP_STATIC_MODULE)
62 extern "C" void INIT_FUNCTION();
64 PyMODINIT_FUNC INIT_FUNCTION();
68 \fn CAM_Module* createModule()
69 \brief Module factory function.
72 Creates an instance of SALOME_PYQT_Module object by request
73 of an application when the module is loaded and initialized.
75 \return new module object
80 SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule()
82 static bool alreadyInitialized = false;
84 // make initialization only once (see comment above) !
85 if ( !alreadyInitialized ) {
86 static PyThreadState* gtstate = 0;
87 #ifndef GUI_DISABLE_CORBA
88 if ( SUIT_PYTHON::initialized )
89 gtstate = SUIT_PYTHON::_gtstate;
91 gtstate = KERNEL_PYTHON::_gtstate;
93 gtstate = SUIT_PYTHON::_gtstate;
95 PyEval_RestoreThread( gtstate );
99 PyEval_ReleaseThread( gtstate );
101 alreadyInitialized = !alreadyInitialized;
104 return new SALOME_PYQT_ModuleLight();
109 \class SALOME_PYQT_ModuleLight
110 \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
111 Python-based SALOME modules.
117 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
118 : LightApp_Module( "noname" ) // name is set explicitly at the module initialization
121 myHelper = new PyModuleHelper( this );
127 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
129 // as myHelper is a QObject, it should be deleted automatically
133 \brief Initialization of the module.
134 \param app parent application object
135 \sa PyModuleHelper::initialize()
137 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
139 // call base implementation
140 LightApp_Module::initialize( app );
142 // ... then call helper
143 myHelper->initialize( app );
147 \brief Activation of the module.
148 \param study parent study
149 \return \c true if activation is successful and \c false otherwise
150 \sa PyModuleHelper::activate()
152 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
154 // call base implementation and then helper
155 return LightApp_Module::activateModule( study ) && myHelper->activate( study );
159 \brief Deactivation of the module.
160 \param study parent study
161 \return \c true if deactivation is successful and \c false otherwise
162 \sa PyModuleHelper::deactivate()
164 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
167 bool res = myHelper->deactivate( study );
169 // ... then call base implementation
170 return LightApp_Module::deactivateModule( study ) && res;
174 \brief Close of the module.
176 This function is usually used in order to close the module's
177 specific menus and toolbars and perform other such actions
178 required when the module is closed.
180 void SALOME_PYQT_ModuleLight::onModelClosed()
183 myHelper->modelClosed(application()->activeStudy());
184 LightApp_Module::onModelClosed();
189 \brief Get the dockable windows associated with the module.
190 \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
191 \sa PyModuleHelper::windows()
193 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
195 // get list of dockable windows from helper
196 winMap = myHelper->windows();
200 \brief Define the compatible view windows associated with the module.
201 \param viewList output list of view windows types
202 \sa PyModuleHelper::viewManagers()
204 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
206 // get list of view types from helper
207 viewList = myHelper->viewManagers();
211 \brief Process study activation.
212 \sa PyModuleHelper::studyActivated()
214 void SALOME_PYQT_ModuleLight::studyActivated()
217 myHelper->studyActivated( application()->activeStudy() );
221 \brief Process context popup menu request.
222 \param context popup menu context (e.g. "ObjectBrowser")
223 \param menu popup menu
224 \param title popup menu title (not used)
225 \sa PyModuleHelper::contextMenu()
227 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context,
232 myHelper->contextMenu( context, menu );
236 \brief Export preferences for the Python module.
237 \sa PyModuleHelper::createPreferences()
239 void SALOME_PYQT_ModuleLight::createPreferences()
242 myHelper->createPreferences();
246 \brief Process module's preferences changing.
247 \param section preference resources section
248 \param parameter preference resources parameter name
249 \sa PyModuleHelper::preferencesChanged()
251 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
254 myHelper->preferencesChanged( section, parameter );
258 \brief Save module data. Called when user saves study.
259 \param files output list of files where module stores data
260 \sa PyModuleHelper::save()
262 void SALOME_PYQT_ModuleLight::save( QStringList& files )
265 myHelper->save( files );
269 \brief Load module data. Called when user opens study
270 and activates module.
271 \param files list of files where module data is stored
272 \sa PyModuleHelper::load()
274 bool SALOME_PYQT_ModuleLight::load( const QStringList& files )
277 return myHelper->load( files );
281 \brief Dump module data to the Python script.
282 Called when user activates dump study operation.
283 \param files output list of files where module stores python script
284 \sa PyModuleHelper::dumpPython()
286 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
289 myHelper->dumpPython( files );
293 \brief Test if object \a what can be dragged by the user.
294 \param what data object being tested
295 \return \c true if object can be dragged or \c false otherwise
296 \sa PyModuleHelper::isDraggable()
298 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
301 return myHelper->isDraggable( what );
305 \brief Test if drop operation can be done on the \a where object.
306 \param where data object being tested
307 \return \c true if if drop operation is supported by object or \c false otherwise
308 \sa PyModuleHelper::isDropAccepted()
310 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
313 return myHelper->isDropAccepted( where );
317 \brief Perform drop operation
318 \param what list of data objects being dropped
319 \param where target data object for drop operation
320 \param row line (child item index) where drop operation is performed to
321 \param action current drop action (copy or move)
322 \sa PyModuleHelper::dropObjects()
324 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
325 const int row, Qt::DropAction action )
328 myHelper->dropObjects( what, where, row, action );
332 \brief Create new empty data object
333 \param parent entry of parent data object
334 \return entry of created data object
336 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
339 SALOME_PYQT_DataObjectLight* obj = 0;
341 if ( !parent.isEmpty() ) {
342 SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
344 obj = new SALOME_PYQT_DataObjectLight( parentObj );
347 SALOME_PYQT_DataModelLight* dm =
348 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
350 obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
353 entry = obj->entry();
358 \brief Create new data object with specified name, icon and tooltip
359 \param name data object name
360 \param icon data object icon
361 \param toolTip data object tooltip
362 \param parent entry of parent data object
363 \return entry of created data object
365 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
367 const QString& toolTip,
368 const QString& parent )
370 QString entry = createObject( parent );
371 SALOME_PYQT_DataObjectLight* obj = findObject( entry );
374 obj->setToolTip( toolTip );
375 obj->setIcon( icon );
381 \brief Set data object name
382 \param entry data object entry
383 \param name data object name
385 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
387 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
389 dataObj->setName( name );
393 \brief Get data object name
394 \param entry data object entry
395 \return data object name
397 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
400 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
402 name = dataObj->name();
407 \brief Set data object icon
408 \param entry data object entry
409 \param icon data object icon file name (icon is loaded from module resources)
411 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
413 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
415 dataObj->setIcon( icon );
419 \brief Set data object tooltip
420 \param entry data object entry
421 \param toolTip data object tooltip
423 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
425 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
427 dataObj->setToolTip( toolTip );
431 \brief Get data object tooltip
432 \param entry data object entry
433 \return data object tooltip
435 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
438 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
440 toolTip = dataObj->toolTip();
445 \brief Set data object color
446 \param entry data object entry
447 \param color data object color
449 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
451 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
453 dataObj->setColor( color );
457 \brief Get data object color
458 \param entry data object entry
459 \return data object color
461 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
464 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
466 color = dataObj->color( SUIT_DataObject::Foreground );
471 \brief Set reference to another data object
472 \param entry data object entry
473 \param refEntry referenced data object entry
475 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
477 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
479 dataObj->setRefEntry( refEntry );
483 \brief Get entry of the referenced object (if there's any)
484 \param entry data object entry
485 \return referenced data object entry
487 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
490 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
492 refEntry = dataObj->refEntry();
497 \brief Remove object by entry
498 \param entry data object entry
500 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
502 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
503 if ( dataObj && dataObj->parent() )
504 dataObj->parent()->removeChild( dataObj );
508 \brief Remove all child data objects from specified data object
509 \param entry data object entry
511 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
513 SUIT_DataObject* dataObj = 0;
514 if ( !entry.isEmpty() ) {
515 dataObj = findObject( entry );
518 SALOME_PYQT_DataModelLight* dm =
519 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
520 if ( dm ) dataObj = dm->getRoot();
523 DataObjectList children;
524 dataObj->children( children );
525 QListIterator<SUIT_DataObject*> it( children );
526 while ( it.hasNext() ) {
527 dataObj->removeChild( it.next() );
533 \brief Get entries of all child data objects of specified data object
534 \param entry data object entry
535 \param recursive \c true for recursive processing
537 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
539 QStringList entryList;
540 SUIT_DataObject* dataObj = 0;
541 if ( !entry.isEmpty() ) {
542 dataObj = findObject( entry );
545 SALOME_PYQT_DataModelLight* dm =
546 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
547 if ( dm ) dataObj = dm->getRoot();
551 dataObj->children( lst, recursive );
552 QListIterator<SUIT_DataObject*> it( lst );
553 while ( it.hasNext() ) {
554 SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
555 entryList.append( sobj->entry() );
562 \brief Create new instance of data model and return it.
564 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
566 return new SALOME_PYQT_DataModelLight( this );
570 \brief Find data object by its entry
571 \param entry data object entry
572 \return data object with given entry or 0 if object isn't found
574 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
576 SALOME_PYQT_DataObjectLight* obj = 0;
577 SALOME_PYQT_DataModelLight* dm =
578 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
579 if ( !entry.isEmpty() && dm ) {
580 for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) {
581 SALOME_PYQT_DataObjectLight* curentobj =
582 dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
583 if ( curentobj && curentobj->entry() == entry )