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"
26 #include "SALOME_PYQT_Selector.h"
28 #include "CAM_Application.h"
29 #include "SUITApp_init_python.hxx"
30 #include "SUIT_DataObjectIterator.h"
31 #include "LightApp_Application.h"
32 #include "LightApp_SelectionMgr.h"
33 #include "SUIT_DataBrowser.h"
34 #include "sipAPISalomePyQtGUILight.h"
36 #ifndef GUI_DISABLE_CORBA
37 #include <Container_init_python.hxx>
40 #include <QCoreApplication>
41 #include <utilities.h>
43 // Py_ssize_t for old Pythons
44 // This code is as recommended by"
45 // http://www.python.org/dev/peps/pep-0353/#conversion-guidelines
46 //#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
47 //typedef int Py_ssize_t;
48 //# define PY_SSIZE_T_MAX INT_MAX
49 //# define PY_SSIZE_T_MIN INT_MIN
53 // NB: Python requests.
54 // General rule for Python requests created by Python-based GUI modules
55 // (SALOME_PYQT_ModuleLight and other ones):
56 // all requests should be executed SYNCHRONOUSLY within the main GUI thread.
57 // However, it is obligatory that ANY Python call is wrapped with a request object,
58 // so that ALL Python API calls are serialized with PyInterp_Dispatcher.
60 // NB: Library initialization
61 // Since the SalomePyQtGUILight library is not imported in Python it's initialization function
62 // should be called manually (and only once) in order to initialize global sip data
63 // and to get C API from sip : sipBuildResult for example
66 #define INIT_FUNCTION initSalomePyQtGUILight
67 #if defined(SIP_STATIC_MODULE)
68 extern "C" void INIT_FUNCTION();
70 PyMODINIT_FUNC INIT_FUNCTION();
74 \fn CAM_Module* createModule()
75 \brief Module factory function.
78 Creates an instance of SALOME_PYQT_Module object by request
79 of an application when the module is loaded and initialized.
81 \return new module object
86 SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule()
88 QCoreApplication* app = QCoreApplication::instance();
89 bool alreadyInitialized = app && app->property( "salome_pyqt_gui_light_initialized" ).toBool();
91 // make initialization only once (see comment above) !
92 if ( !alreadyInitialized ) {
93 PyLockWrapper lck; // GIL acquisition
95 if ( app ) app->setProperty( "salome_pyqt_gui_light_initialized", true );
98 return new SALOME_PYQT_ModuleLight();
103 \class SALOME_PYQT_ModuleLight
104 \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
105 Python-based SALOME modules.
111 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
112 : LightApp_Module( "noname" ), mySelector(0) // name is set explicitly at the module initialization
115 myHelper = new PyModuleHelper( this );
121 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
123 // as myHelper is a QObject, it should be deleted automatically
127 \brief Initialization of the module.
128 \param app parent application object
129 \sa PyModuleHelper::initialize()
131 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
133 // call base implementation
134 LightApp_Module::initialize( app );
136 // ... then call helper
137 myHelper->initialize( app );
138 SUIT_DataBrowser* ob = getApp()->objectBrowser();
139 if (ob && ob->model()) {
140 connect( ob->model(), SIGNAL( clicked( SUIT_DataObject*, int ) ),
141 myHelper, SLOT( onObjectBrowserClicked( SUIT_DataObject*, int ) ), Qt::UniqueConnection );
146 \brief Activation of the module.
147 \param study parent study
148 \return \c true if activation is successful and \c false otherwise
149 \sa PyModuleHelper::activate()
151 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
153 // call base implementation and then helper
154 return LightApp_Module::activateModule( study ) && myHelper->activate( study );
158 \brief Deactivation of the module.
159 \param study parent study
160 \return \c true if deactivation is successful and \c false otherwise
161 \sa PyModuleHelper::deactivate()
163 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
166 bool res = myHelper->deactivate( study );
168 // ... then call base implementation
169 return LightApp_Module::deactivateModule( study ) && res;
173 \brief Close of the module.
175 This function is usually used in order to close the module's
176 specific menus and toolbars and perform other such actions
177 required when the module is closed.
179 void SALOME_PYQT_ModuleLight::onModelClosed()
182 myHelper->modelClosed(application()->activeStudy());
185 LightApp_Module::onModelClosed();
190 \brief Get the dockable windows associated with the module.
191 \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
192 \sa PyModuleHelper::windows()
194 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
196 // get list of dockable windows from helper
197 winMap = myHelper->windows();
201 \brief Define the compatible view windows associated with the module.
202 \param viewList output list of view windows types
203 \sa PyModuleHelper::viewManagers()
205 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
207 // get list of view types from helper
208 viewList = myHelper->viewManagers();
212 \brief Process study activation.
213 \sa PyModuleHelper::studyActivated()
215 void SALOME_PYQT_ModuleLight::studyActivated()
218 myHelper->studyActivated( application()->activeStudy() );
222 \brief Process context popup menu request.
223 \param context popup menu context (e.g. "ObjectBrowser")
224 \param menu popup menu
225 \param title popup menu title (not used)
226 \sa PyModuleHelper::contextMenu()
228 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context,
233 myHelper->contextMenu( context, menu );
237 \brief Export preferences for the Python module.
238 \sa PyModuleHelper::createPreferences()
240 void SALOME_PYQT_ModuleLight::createPreferences()
243 myHelper->createPreferences();
247 \brief Process module's preferences changing.
248 \param section preference resources section
249 \param parameter preference resources parameter name
250 \sa PyModuleHelper::preferencesChanged()
252 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
255 myHelper->preferencesChanged( section, parameter );
259 \brief Save module data. Called when user saves study.
260 \param files output list of files where module stores data
262 \sa PyModuleHelper::save()
264 void SALOME_PYQT_ModuleLight::save( QStringList& files, const QString& url )
267 myHelper->save( files, url );
271 \brief Load module data. Called when user opens study
272 and activates module.
273 \param files list of files where module data is stored
275 \return \c true if loading has been finished successfully or \c false otherwise
276 \sa PyModuleHelper::load()
278 bool SALOME_PYQT_ModuleLight::load( const QStringList& files, const QString& url )
281 return myHelper->load( files, url );
285 \brief Dump module data to the Python script.
286 Called when user activates dump study operation.
287 \param files output list of files where module stores python script
288 \sa PyModuleHelper::dumpPython()
290 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
293 myHelper->dumpPython( files );
297 \brief Test if object \a what can be dragged by the user.
298 \param what data object being tested
299 \return \c true if object can be dragged or \c false otherwise
300 \sa PyModuleHelper::isDraggable()
302 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
305 return myHelper->isDraggable( what );
309 \brief Test if drop operation can be done on the \a where object.
310 \param where data object being tested
311 \return \c true if if drop operation is supported by object or \c false otherwise
312 \sa PyModuleHelper::isDropAccepted()
314 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
317 return myHelper->isDropAccepted( where );
321 \brief Perform drop operation
322 \param what list of data objects being dropped
323 \param where target data object for drop operation
324 \param row line (child item index) where drop operation is performed to
325 \param action current drop action (copy or move)
326 \sa PyModuleHelper::dropObjects()
328 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
329 const int row, Qt::DropAction action )
332 myHelper->dropObjects( what, where, row, action );
336 \brief Create new empty data object
337 \param parent entry of parent data object
338 \return entry of created data object
340 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
343 SALOME_PYQT_DataObjectLight* obj = 0;
345 if ( !parent.isEmpty() ) {
346 SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
348 obj = new SALOME_PYQT_DataObjectLight( parentObj );
351 SALOME_PYQT_DataModelLight* dm =
352 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
354 obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
357 entry = obj->entry();
362 \brief Create new data object with specified name, icon and tooltip
363 \param name data object name
364 \param icon data object icon
365 \param toolTip data object tooltip
366 \param parent entry of parent data object
367 \return entry of created data object
369 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
371 const QString& toolTip,
372 const QString& parent )
374 QString entry = createObject( parent );
375 SALOME_PYQT_DataObjectLight* obj = findObject( entry );
378 obj->setToolTip( toolTip );
379 obj->setIcon( icon );
385 \brief Set data object name
386 \param entry data object entry
387 \param name data object name
389 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
391 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
393 dataObj->setName( name );
397 \brief Get data object name
398 \param entry data object entry
399 \return data object name
401 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
404 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
406 name = dataObj->name();
411 \brief Set data object icon
412 \param entry data object entry
413 \param icon data object icon file name (icon is loaded from module resources)
415 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
417 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
419 dataObj->setIcon( icon );
423 \brief Set data object tooltip
424 \param entry data object entry
425 \param toolTip data object tooltip
427 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
429 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
431 dataObj->setToolTip( toolTip );
435 \brief Get data object tooltip
436 \param entry data object entry
437 \return data object tooltip
439 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
442 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
444 toolTip = dataObj->toolTip();
449 \brief Set data object color
450 \param entry data object entry
451 \param color data object color
453 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
455 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
457 dataObj->setColor( color );
461 \brief Get data object color
462 \param entry data object entry
463 \return data object color
465 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
468 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
470 color = dataObj->color( SUIT_DataObject::Foreground );
474 void SALOME_PYQT_ModuleLight::setObjectPosition( const QString& theEntry, int thePos )
476 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
478 dataObj->setPosition(thePos);
481 int SALOME_PYQT_ModuleLight::getObjectPosition( const QString& theEntry )
483 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
485 return dataObj->position();
491 \brief Set reference to another data object
492 \param entry data object entry
493 \param refEntry referenced data object entry
495 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
497 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
499 dataObj->setRefEntry( refEntry );
503 \brief Get entry of the referenced object (if there's any)
504 \param entry data object entry
505 \return referenced data object entry
507 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
510 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
512 refEntry = dataObj->refEntry();
517 \brief Remove object by entry
518 \param entry data object entry
520 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
522 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
523 if ( dataObj && dataObj->parent() )
524 dataObj->parent()->removeChild( dataObj );
528 \brief Remove all child data objects from specified data object
529 \param entry data object entry
531 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
533 SUIT_DataObject* dataObj = 0;
534 if ( !entry.isEmpty() ) {
535 dataObj = findObject( entry );
538 SALOME_PYQT_DataModelLight* dm =
539 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
540 if ( dm ) dataObj = dm->getRoot();
543 DataObjectList children;
544 dataObj->children( children );
545 QListIterator<SUIT_DataObject*> it( children );
546 while ( it.hasNext() ) {
547 dataObj->removeChild( it.next() );
553 \brief Get entries of all child data objects of specified data object
554 \param entry data object entry
555 \param recursive \c true for recursive processing
557 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
559 QStringList entryList;
560 SUIT_DataObject* dataObj = 0;
561 if ( !entry.isEmpty() ) {
562 dataObj = findObject( entry );
565 SALOME_PYQT_DataModelLight* dm =
566 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
567 if ( dm ) dataObj = dm->getRoot();
571 dataObj->children( lst, recursive );
572 QListIterator<SUIT_DataObject*> it( lst );
573 while ( it.hasNext() ) {
574 SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
575 entryList.append( sobj->entry() );
582 \brief Create new instance of data model and return it.
584 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
586 return new SALOME_PYQT_DataModelLight( this );
590 \brief Find data object by its entry
591 \param entry data object entry
592 \return data object with given entry or 0 if object isn't found
594 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
596 SALOME_PYQT_DataObjectLight* obj = 0;
597 SALOME_PYQT_DataModelLight* dm =
598 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
599 if ( !entry.isEmpty() && dm ) {
600 for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) {
601 SALOME_PYQT_DataObjectLight* curentobj =
602 dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
603 if ( curentobj && curentobj->entry() == entry )
613 void SALOME_PYQT_ModuleLight::getSelected( DataObjectList& ) const
615 MESSAGE("getSelected");
621 //unsigned long SALOME_PYQT_ModuleLight::getModifiedTime() const
623 // MESSAGE("getModifiedTime");
630 //SUIT_DataObject* SALOME_PYQT_ModuleLight::root() const
637 \brief Used to notify a Python light module of a modification of selection in study (propagation of a remote selection)
638 \param list of study entries
640 void SALOME_PYQT_ModuleLight::setSelected( const QStringList& entries, const bool isUnused)
642 MESSAGE("setSelected");
643 return myHelper->selectionUpdated(entries);
647 \brief called by Python module to notify a list of study entries locally selected (for selection propagation)
648 \param list of study entries
650 void SALOME_PYQT_ModuleLight::setLocalSelected(const QStringList & entries)
652 MESSAGE("setLocalSelected");
655 mySelector = new SALOME_PYQT_Selector(this, this->getApp()->selectionMgr());
657 mySelector->setLocalEntries(entries);
658 emit localSelectionChanged();
661 void SALOME_PYQT_ModuleLight::enableSelector()
663 MESSAGE("enableSelector");
666 mySelector = new SALOME_PYQT_Selector(this, this->getApp()->selectionMgr());
668 mySelector->setEnabled(true);
671 void SALOME_PYQT_ModuleLight::disableSelector()
673 MESSAGE("disableSelector");
675 mySelector->setEnabled(false);