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());
183 LightApp_Module::onModelClosed();
188 \brief Get the dockable windows associated with the module.
189 \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
190 \sa PyModuleHelper::windows()
192 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
194 // get list of dockable windows from helper
195 winMap = myHelper->windows();
199 \brief Define the compatible view windows associated with the module.
200 \param viewList output list of view windows types
201 \sa PyModuleHelper::viewManagers()
203 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
205 // get list of view types from helper
206 viewList = myHelper->viewManagers();
210 \brief Process study activation.
211 \sa PyModuleHelper::studyActivated()
213 void SALOME_PYQT_ModuleLight::studyActivated()
216 myHelper->studyActivated( application()->activeStudy() );
220 \brief Process context popup menu request.
221 \param context popup menu context (e.g. "ObjectBrowser")
222 \param menu popup menu
223 \param title popup menu title (not used)
224 \sa PyModuleHelper::contextMenu()
226 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context,
231 myHelper->contextMenu( context, menu );
235 \brief Export preferences for the Python module.
236 \sa PyModuleHelper::createPreferences()
238 void SALOME_PYQT_ModuleLight::createPreferences()
241 myHelper->createPreferences();
245 \brief Process module's preferences changing.
246 \param section preference resources section
247 \param parameter preference resources parameter name
248 \sa PyModuleHelper::preferencesChanged()
250 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
253 myHelper->preferencesChanged( section, parameter );
257 \brief Save module data. Called when user saves study.
258 \param files output list of files where module stores data
260 \sa PyModuleHelper::save()
262 void SALOME_PYQT_ModuleLight::save( QStringList& files, const QString& url )
265 myHelper->save( files, url );
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
273 \return \c true if loading has been finished successfully or \c false otherwise
274 \sa PyModuleHelper::load()
276 bool SALOME_PYQT_ModuleLight::load( const QStringList& files, const QString& url )
279 return myHelper->load( files, url );
283 \brief Dump module data to the Python script.
284 Called when user activates dump study operation.
285 \param files output list of files where module stores python script
286 \sa PyModuleHelper::dumpPython()
288 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
291 myHelper->dumpPython( files );
295 \brief Test if object \a what can be dragged by the user.
296 \param what data object being tested
297 \return \c true if object can be dragged or \c false otherwise
298 \sa PyModuleHelper::isDraggable()
300 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
303 return myHelper->isDraggable( what );
307 \brief Test if drop operation can be done on the \a where object.
308 \param where data object being tested
309 \return \c true if if drop operation is supported by object or \c false otherwise
310 \sa PyModuleHelper::isDropAccepted()
312 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
315 return myHelper->isDropAccepted( where );
319 \brief Perform drop operation
320 \param what list of data objects being dropped
321 \param where target data object for drop operation
322 \param row line (child item index) where drop operation is performed to
323 \param action current drop action (copy or move)
324 \sa PyModuleHelper::dropObjects()
326 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
327 const int row, Qt::DropAction action )
330 myHelper->dropObjects( what, where, row, action );
334 \brief Create new empty data object
335 \param parent entry of parent data object
336 \return entry of created data object
338 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
341 SALOME_PYQT_DataObjectLight* obj = 0;
343 if ( !parent.isEmpty() ) {
344 SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
346 obj = new SALOME_PYQT_DataObjectLight( parentObj );
349 SALOME_PYQT_DataModelLight* dm =
350 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
352 obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
355 entry = obj->entry();
360 \brief Create new data object with specified name, icon and tooltip
361 \param name data object name
362 \param icon data object icon
363 \param toolTip data object tooltip
364 \param parent entry of parent data object
365 \return entry of created data object
367 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
369 const QString& toolTip,
370 const QString& parent )
372 QString entry = createObject( parent );
373 SALOME_PYQT_DataObjectLight* obj = findObject( entry );
376 obj->setToolTip( toolTip );
377 obj->setIcon( icon );
383 \brief Set data object name
384 \param entry data object entry
385 \param name data object name
387 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
389 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
391 dataObj->setName( name );
395 \brief Get data object name
396 \param entry data object entry
397 \return data object name
399 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
402 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
404 name = dataObj->name();
409 \brief Set data object icon
410 \param entry data object entry
411 \param icon data object icon file name (icon is loaded from module resources)
413 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
415 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
417 dataObj->setIcon( icon );
421 \brief Set data object tooltip
422 \param entry data object entry
423 \param toolTip data object tooltip
425 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
427 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
429 dataObj->setToolTip( toolTip );
433 \brief Get data object tooltip
434 \param entry data object entry
435 \return data object tooltip
437 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
440 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
442 toolTip = dataObj->toolTip();
447 \brief Set data object color
448 \param entry data object entry
449 \param color data object color
451 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
453 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
455 dataObj->setColor( color );
459 \brief Get data object color
460 \param entry data object entry
461 \return data object color
463 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
466 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
468 color = dataObj->color( SUIT_DataObject::Foreground );
472 void SALOME_PYQT_ModuleLight::setObjectPosition( const QString& theEntry, int thePos )
474 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
476 dataObj->setPosition(thePos);
479 int SALOME_PYQT_ModuleLight::getObjectPosition( const QString& theEntry )
481 SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
483 return dataObj->position();
489 \brief Set reference to another data object
490 \param entry data object entry
491 \param refEntry referenced data object entry
493 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
495 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
497 dataObj->setRefEntry( refEntry );
501 \brief Get entry of the referenced object (if there's any)
502 \param entry data object entry
503 \return referenced data object entry
505 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
508 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
510 refEntry = dataObj->refEntry();
515 \brief Remove object by entry
516 \param entry data object entry
518 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
520 SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
521 if ( dataObj && dataObj->parent() )
522 dataObj->parent()->removeChild( dataObj );
526 \brief Remove all child data objects from specified data object
527 \param entry data object entry
529 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
531 SUIT_DataObject* dataObj = 0;
532 if ( !entry.isEmpty() ) {
533 dataObj = findObject( entry );
536 SALOME_PYQT_DataModelLight* dm =
537 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
538 if ( dm ) dataObj = dm->getRoot();
541 DataObjectList children;
542 dataObj->children( children );
543 QListIterator<SUIT_DataObject*> it( children );
544 while ( it.hasNext() ) {
545 dataObj->removeChild( it.next() );
551 \brief Get entries of all child data objects of specified data object
552 \param entry data object entry
553 \param recursive \c true for recursive processing
555 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
557 QStringList entryList;
558 SUIT_DataObject* dataObj = 0;
559 if ( !entry.isEmpty() ) {
560 dataObj = findObject( entry );
563 SALOME_PYQT_DataModelLight* dm =
564 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
565 if ( dm ) dataObj = dm->getRoot();
569 dataObj->children( lst, recursive );
570 QListIterator<SUIT_DataObject*> it( lst );
571 while ( it.hasNext() ) {
572 SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
573 entryList.append( sobj->entry() );
580 \brief Create new instance of data model and return it.
582 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
584 return new SALOME_PYQT_DataModelLight( this );
588 \brief Find data object by its entry
589 \param entry data object entry
590 \return data object with given entry or 0 if object isn't found
592 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
594 SALOME_PYQT_DataObjectLight* obj = 0;
595 SALOME_PYQT_DataModelLight* dm =
596 dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
597 if ( !entry.isEmpty() && dm ) {
598 for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) {
599 SALOME_PYQT_DataObjectLight* curentobj =
600 dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
601 if ( curentobj && curentobj->entry() == entry )
608 void SALOME_PYQT_ModuleLight::getSelected( DataObjectList& ) const
610 MESSAGE("getSelected");
613 unsigned long SALOME_PYQT_ModuleLight::getModifiedTime() const
615 MESSAGE("getModifiedTime");
620 SUIT_DataObject* SALOME_PYQT_ModuleLight::root() const
627 void SALOME_PYQT_ModuleLight::setSelected( const QStringList& entries, const bool isUnused)
629 MESSAGE("setSelected");
630 return myHelper->selectionUpdated(entries);
634 //void SALOME_PYQT_ModuleLight::selectionChanged()
636 // MESSAGE("signal selectionChanged");
639 void SALOME_PYQT_ModuleLight::setLocalSelected(const QStringList & entries)
641 MESSAGE("setLocalSelected");
644 mySelector = new SALOME_PYQT_Selector(this, this->getApp()->selectionMgr());
646 mySelector->setLocalEntries(entries);
647 emit localSelectionChanged();