Salome HOME
Merge from V6_main 01/04/2013
[modules/gui.git] / src / SALOME_PYQT / SALOME_PYQT_GUILight / SALOME_PYQT_ModuleLight.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : SALOME_PYQT_ModuleLight.cxx
21 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
22
23 #include "SALOME_PYQT_DataModelLight.h"
24 #include "SALOME_PYQT_ModuleLight.h"
25 #include "SALOME_PYQT_PyModule.h"
26
27 #include "CAM_Application.h"
28 #include "SUITApp_init_python.hxx"
29 #include "SUIT_DataObjectIterator.h"
30
31 #include "sipAPISalomePyQtGUILight.h"
32
33 #ifndef GUI_DISABLE_CORBA
34 #include <Container_init_python.hxx>
35 #endif
36
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
44 #endif
45
46 //
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.
53 //
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
58 //
59
60 #define INIT_FUNCTION initSalomePyQtGUILight
61 #if defined(SIP_STATIC_MODULE)
62 extern "C" void INIT_FUNCTION();
63 #else
64 PyMODINIT_FUNC INIT_FUNCTION();
65 #endif
66
67 /*!
68   \fn CAM_Module* createModule()
69   \brief Module factory function.
70   \internal
71   
72   Creates an instance of SALOME_PYQT_Module object by request
73   of an application when the module is loaded and initialized.
74
75   \return new module object
76 */
77
78 extern "C" 
79 {
80   SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule() 
81   {
82     static bool alreadyInitialized = false;
83
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;
90       else
91         gtstate = KERNEL_PYTHON::_gtstate;
92 #else
93       gtstate = SUIT_PYTHON::_gtstate;
94 #endif
95       PyEval_RestoreThread( gtstate );
96
97       INIT_FUNCTION();
98
99       PyEval_ReleaseThread( gtstate );
100
101       alreadyInitialized = !alreadyInitialized;
102     }
103
104     return new SALOME_PYQT_ModuleLight();
105   }
106 }
107
108 /*!
109   \class SALOME_PYQT_ModuleLight
110   \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
111   Python-based SALOME modules.
112 */
113
114 /*!
115   \brief Constructor
116 */
117 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
118   : LightApp_Module( "noname" ) // name is set explicitly at the module initialization
119 {
120   // initialize helper
121   myHelper = new PyModuleHelper( this );
122 }
123
124 /*!
125   \brief Destructor
126 */
127 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
128 {
129   // as myHelper is a QObject, it should be deleted automatically
130 }
131
132 /*!
133   \brief Initialization of the module.
134   \param app parent application object
135   \sa PyModuleHelper::initialize()
136 */
137 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
138 {
139   // call base implementation
140   LightApp_Module::initialize( app );
141
142   // ... then call helper
143   myHelper->initialize( app );
144 }
145
146 /*!
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()
151 */
152 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
153 {
154   // call base implementation and then helper
155   return LightApp_Module::activateModule( study ) && myHelper->activate( study );
156 }
157
158 /*!
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()
163 */
164 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
165 {
166   // call helper
167   bool res = myHelper->deactivate( study );
168     
169   // ... then call base implementation
170   return LightApp_Module::deactivateModule( study ) && res;
171 }
172
173 /*!
174   \brief Get the dockable windows associated with the module.
175   \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
176   \sa PyModuleHelper::windows()
177 */
178 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
179 {
180   // get list of dockable windows from helper
181   winMap = myHelper->windows();
182 }
183
184 /*!
185   \brief Define the compatible view windows associated with the module.
186   \param viewList output list of view windows types
187   \sa PyModuleHelper::viewManagers()
188 */
189 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
190 {
191   // get list of view types from helper
192   viewList = myHelper->viewManagers();
193 }
194
195 /*!
196   \brief Process study activation.
197   \sa PyModuleHelper::studyActivated()
198 */
199 void SALOME_PYQT_ModuleLight::studyActivated()
200 {
201   // call helper
202   myHelper->studyActivated( application()->activeStudy() );
203 }
204
205 /*!
206   \brief Process context popup menu request.
207   \param context popup menu context (e.g. "ObjectBrowser")
208   \param menu popup menu
209   \param title popup menu title (not used)
210   \sa PyModuleHelper::contextMenu()
211 */
212 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context, 
213                                                 QMenu*         menu, 
214                                                 QString&       /*title*/ )
215 {
216   // call helper
217   myHelper->contextMenu( context, menu );
218 }
219
220 /*!
221   \brief Export preferences for the Python module.
222   \sa PyModuleHelper::createPreferences()
223 */
224 void SALOME_PYQT_ModuleLight::createPreferences()
225 {
226   // call helper
227   myHelper->createPreferences();
228 }
229
230 /*!
231   \brief Process module's preferences changing.
232   \param section preference resources section
233   \param parameter preference resources parameter name
234   \sa PyModuleHelper::preferencesChanged()
235 */
236 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
237 {
238   // call helper
239   myHelper->preferencesChanged( section, parameter );
240 }
241
242 /*!
243   \brief Save module data. Called when user saves study.
244   \param files output list of files where module stores data
245   \sa PyModuleHelper::save()
246 */
247 void SALOME_PYQT_ModuleLight::save( QStringList& files )
248 {
249   // call helper
250   myHelper->save( files );
251 }
252
253 /*
254  \brief Load module data. Called when user opens study 
255  and activates module.
256  \param files list of files where module data is stored
257  \sa PyModuleHelper::load()
258 */
259 bool SALOME_PYQT_ModuleLight::load( const QStringList& files )
260 {
261   // call helper
262   return myHelper->load( files );
263 }
264
265 /*!
266   \brief Dump module data to the Python script. 
267   Called when user activates dump study operation.
268   \param files output list of files where module stores python script
269   \sa PyModuleHelper::dumpPython()
270 */
271 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
272 {
273   // call helper
274   myHelper->dumpPython( files );
275 }
276
277 /*!
278   \brief Test if object \a what can be dragged by the user.
279   \param what data object being tested
280   \return \c true if object can be dragged or \c false otherwise
281   \sa PyModuleHelper::isDraggable()
282 */
283 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
284 {
285   // call helper
286   return myHelper->isDraggable( what );
287 }
288
289 /*!
290   \brief Test if drop operation can be done on the \a where object.
291   \param where data object being tested
292   \return \c true if if drop operation is supported by object or \c false otherwise
293   \sa PyModuleHelper::isDropAccepted()
294 */
295 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
296 {
297   // call helper
298   return myHelper->isDropAccepted( where );
299 }
300
301 /*!
302   \brief Perform drop operation
303   \param what list of data objects being dropped
304   \param where target data object for drop operation
305   \param row line (child item index) where drop operation is performed to
306   \param action current drop action (copy or move)
307   \sa PyModuleHelper::dropObjects()
308 */
309 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
310                                            const int row, Qt::DropAction action )
311 {
312   // call helper
313   myHelper->dropObjects( what, where, row, action );
314 }
315
316 /*!
317   \brief Create new empty data object
318   \param parent entry of parent data object
319   \return entry of created data object
320 */
321 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
322 {
323   QString entry;
324   SALOME_PYQT_DataObjectLight* obj = 0;
325
326   if ( !parent.isEmpty() ) {
327     SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
328     if ( parentObj )
329       obj = new SALOME_PYQT_DataObjectLight( parentObj );
330   }
331   else {
332     SALOME_PYQT_DataModelLight* dm =
333       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
334     if ( dm )
335       obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
336   }  
337   if ( obj )
338     entry = obj->entry();
339   return entry;
340 }
341
342 /*!
343  \brief Create new data object with specified name, icon and tooltip
344  \param name data object name
345  \param icon data object icon
346  \param toolTip data object tooltip
347  \param parent entry of parent data object
348  \return entry of created data object
349 */
350 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
351                                                const QString& icon,
352                                                const QString& toolTip,
353                                                const QString& parent )
354 {
355   QString entry = createObject( parent );
356   SALOME_PYQT_DataObjectLight* obj = findObject( entry );
357   if ( obj ) {
358     obj->setName( name);
359     obj->setToolTip( toolTip );
360     obj->setIcon( icon );
361   }
362   return entry;
363 }
364
365 /*!
366   \brief Set data object name
367   \param entry data object entry
368   \param name data object name
369 */
370 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
371 {
372   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
373   if ( dataObj )
374     dataObj->setName( name );
375 }
376
377 /*!
378   \brief Get data object name
379   \param entry data object entry
380   \return data object name
381 */
382 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
383 {
384   QString name;
385   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
386   if ( dataObj )
387     name = dataObj->name();
388   return name;
389 }
390
391 /*!
392   \brief Set data object icon
393   \param entry data object entry
394   \param icon data object icon file name (icon is loaded from module resources)
395 */
396 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
397 {
398   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
399   if ( dataObj )
400     dataObj->setIcon( icon );
401 }
402
403 /*!
404   \brief Set data object tooltip
405   \param entry data object entry
406   \param toolTip data object tooltip
407 */
408 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
409 {
410   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
411   if ( dataObj )
412     dataObj->setToolTip( toolTip );
413 }
414
415 /*!
416   \brief Get data object tooltip
417   \param entry data object entry
418   \return data object tooltip
419 */
420 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
421 {
422   QString toolTip;
423   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
424   if ( dataObj )
425     toolTip = dataObj->toolTip();
426   return toolTip;
427 }
428
429 /*!
430   \brief Set data object color
431   \param entry data object entry
432   \param color data object color
433  */
434 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
435 {
436   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
437   if ( dataObj )
438     dataObj->setColor( color );
439 }
440
441 /*!
442   \brief Get data object color
443   \param entry data object entry
444   \return data object color
445 */
446 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
447 {
448   QColor color;
449   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
450   if ( dataObj )
451     color = dataObj->color( SUIT_DataObject::Foreground );
452   return color;
453 }
454
455 /*!
456   \brief Set reference to another data object
457   \param entry data object entry
458   \param refEntry referenced data object entry
459 */
460 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
461 {
462   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
463   if ( dataObj )
464     dataObj->setRefEntry( refEntry );
465 }
466
467 /*
468   \brief Get entry of the referenced object (if there's any)
469   \param entry data object entry
470   \return referenced data object entry
471 */
472 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
473 {
474   QString refEntry;
475   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
476   if ( dataObj )
477     refEntry = dataObj->refEntry();
478   return refEntry;
479 }
480
481 /*!
482   \brief Remove object by entry
483   \param entry data object entry
484 */
485 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
486 {
487   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
488   if ( dataObj && dataObj->parent() )
489     dataObj->parent()->removeChild( dataObj );
490 }
491
492 /*!
493   \brief Remove all child data objects from specified data object
494   \param entry data object entry
495 */
496 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
497 {
498   SUIT_DataObject* dataObj = 0;
499   if ( !entry.isEmpty() ) {
500     dataObj = findObject( entry );
501   }
502   else {
503     SALOME_PYQT_DataModelLight* dm =
504       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
505     if ( dm ) dataObj = dm->getRoot();
506   }
507   if ( dataObj ) {
508     DataObjectList children;
509     dataObj->children( children );
510     QListIterator<SUIT_DataObject*> it( children );
511     while ( it.hasNext() ) {
512       dataObj->removeChild( it.next() );
513     }
514   }
515 }
516
517 /*!
518   \brief Get entries of all child data objects of specified data object
519   \param entry data object entry
520   \param recursive \c true for recursive processing
521 */
522 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
523 {
524   QStringList entryList;
525   SUIT_DataObject* dataObj = 0;
526   if ( !entry.isEmpty() ) {
527     dataObj = findObject( entry );
528   }
529   else {
530     SALOME_PYQT_DataModelLight* dm =
531       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
532     if ( dm ) dataObj = dm->getRoot();
533   }
534   if ( dataObj ) {
535     DataObjectList lst;
536     dataObj->children( lst, recursive );
537     QListIterator<SUIT_DataObject*> it( lst );
538     while ( it.hasNext() ) {
539       SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
540       entryList.append( sobj->entry() );
541     }
542   }
543   return entryList;
544 }
545
546 /*!
547   \brief Create new instance of data model and return it.
548 */
549 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
550 {
551   return new SALOME_PYQT_DataModelLight( this );
552 }
553
554 /*!
555   \brief Find data object by its entry
556   \param entry data object entry
557   \return data object with given entry or 0 if object isn't found
558 */
559 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
560 {
561   SALOME_PYQT_DataObjectLight* obj = 0;
562   SALOME_PYQT_DataModelLight* dm =
563     dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
564   if ( !entry.isEmpty() && dm ) {
565     for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) { 
566       SALOME_PYQT_DataObjectLight* curentobj =
567         dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
568       if ( curentobj && curentobj->entry() == entry )
569         obj = curentobj;
570     }
571   }
572   return obj;
573 }