]> SALOME platform Git repositories - modules/gui.git/blob - src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx
Salome HOME
PPGP patch: provides "closeStudy" event
[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 Close of the module.
175
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.
179 */
180 void SALOME_PYQT_ModuleLight::onModelClosed()
181 {
182   // call helper
183   myHelper->modelClosed(application()->activeStudy());
184   LightApp_Module::onModelClosed();
185 }
186
187
188 /*!
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()
192 */
193 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
194 {
195   // get list of dockable windows from helper
196   winMap = myHelper->windows();
197 }
198
199 /*!
200   \brief Define the compatible view windows associated with the module.
201   \param viewList output list of view windows types
202   \sa PyModuleHelper::viewManagers()
203 */
204 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
205 {
206   // get list of view types from helper
207   viewList = myHelper->viewManagers();
208 }
209
210 /*!
211   \brief Process study activation.
212   \sa PyModuleHelper::studyActivated()
213 */
214 void SALOME_PYQT_ModuleLight::studyActivated()
215 {
216   // call helper
217   myHelper->studyActivated( application()->activeStudy() );
218 }
219
220 /*!
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()
226 */
227 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context, 
228                                                 QMenu*         menu, 
229                                                 QString&       /*title*/ )
230 {
231   // call helper
232   myHelper->contextMenu( context, menu );
233 }
234
235 /*!
236   \brief Export preferences for the Python module.
237   \sa PyModuleHelper::createPreferences()
238 */
239 void SALOME_PYQT_ModuleLight::createPreferences()
240 {
241   // call helper
242   myHelper->createPreferences();
243 }
244
245 /*!
246   \brief Process module's preferences changing.
247   \param section preference resources section
248   \param parameter preference resources parameter name
249   \sa PyModuleHelper::preferencesChanged()
250 */
251 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
252 {
253   // call helper
254   myHelper->preferencesChanged( section, parameter );
255 }
256
257 /*!
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()
261 */
262 void SALOME_PYQT_ModuleLight::save( QStringList& files )
263 {
264   // call helper
265   myHelper->save( files );
266 }
267
268 /*
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()
273 */
274 bool SALOME_PYQT_ModuleLight::load( const QStringList& files )
275 {
276   // call helper
277   return myHelper->load( files );
278 }
279
280 /*!
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()
285 */
286 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
287 {
288   // call helper
289   myHelper->dumpPython( files );
290 }
291
292 /*!
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()
297 */
298 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
299 {
300   // call helper
301   return myHelper->isDraggable( what );
302 }
303
304 /*!
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()
309 */
310 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
311 {
312   // call helper
313   return myHelper->isDropAccepted( where );
314 }
315
316 /*!
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()
323 */
324 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
325                                            const int row, Qt::DropAction action )
326 {
327   // call helper
328   myHelper->dropObjects( what, where, row, action );
329 }
330
331 /*!
332   \brief Create new empty data object
333   \param parent entry of parent data object
334   \return entry of created data object
335 */
336 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
337 {
338   QString entry;
339   SALOME_PYQT_DataObjectLight* obj = 0;
340
341   if ( !parent.isEmpty() ) {
342     SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
343     if ( parentObj )
344       obj = new SALOME_PYQT_DataObjectLight( parentObj );
345   }
346   else {
347     SALOME_PYQT_DataModelLight* dm =
348       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
349     if ( dm )
350       obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
351   }  
352   if ( obj )
353     entry = obj->entry();
354   return entry;
355 }
356
357 /*!
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
364 */
365 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
366                                                const QString& icon,
367                                                const QString& toolTip,
368                                                const QString& parent )
369 {
370   QString entry = createObject( parent );
371   SALOME_PYQT_DataObjectLight* obj = findObject( entry );
372   if ( obj ) {
373     obj->setName( name);
374     obj->setToolTip( toolTip );
375     obj->setIcon( icon );
376   }
377   return entry;
378 }
379
380 /*!
381   \brief Set data object name
382   \param entry data object entry
383   \param name data object name
384 */
385 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
386 {
387   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
388   if ( dataObj )
389     dataObj->setName( name );
390 }
391
392 /*!
393   \brief Get data object name
394   \param entry data object entry
395   \return data object name
396 */
397 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
398 {
399   QString name;
400   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
401   if ( dataObj )
402     name = dataObj->name();
403   return name;
404 }
405
406 /*!
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)
410 */
411 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
412 {
413   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
414   if ( dataObj )
415     dataObj->setIcon( icon );
416 }
417
418 /*!
419   \brief Set data object tooltip
420   \param entry data object entry
421   \param toolTip data object tooltip
422 */
423 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
424 {
425   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
426   if ( dataObj )
427     dataObj->setToolTip( toolTip );
428 }
429
430 /*!
431   \brief Get data object tooltip
432   \param entry data object entry
433   \return data object tooltip
434 */
435 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
436 {
437   QString toolTip;
438   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
439   if ( dataObj )
440     toolTip = dataObj->toolTip();
441   return toolTip;
442 }
443
444 /*!
445   \brief Set data object color
446   \param entry data object entry
447   \param color data object color
448  */
449 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
450 {
451   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
452   if ( dataObj )
453     dataObj->setColor( color );
454 }
455
456 /*!
457   \brief Get data object color
458   \param entry data object entry
459   \return data object color
460 */
461 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
462 {
463   QColor color;
464   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
465   if ( dataObj )
466     color = dataObj->color( SUIT_DataObject::Foreground );
467   return color;
468 }
469
470 /*!
471   \brief Set reference to another data object
472   \param entry data object entry
473   \param refEntry referenced data object entry
474 */
475 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
476 {
477   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
478   if ( dataObj )
479     dataObj->setRefEntry( refEntry );
480 }
481
482 /*
483   \brief Get entry of the referenced object (if there's any)
484   \param entry data object entry
485   \return referenced data object entry
486 */
487 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
488 {
489   QString refEntry;
490   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
491   if ( dataObj )
492     refEntry = dataObj->refEntry();
493   return refEntry;
494 }
495
496 /*!
497   \brief Remove object by entry
498   \param entry data object entry
499 */
500 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
501 {
502   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
503   if ( dataObj && dataObj->parent() )
504     dataObj->parent()->removeChild( dataObj );
505 }
506
507 /*!
508   \brief Remove all child data objects from specified data object
509   \param entry data object entry
510 */
511 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
512 {
513   SUIT_DataObject* dataObj = 0;
514   if ( !entry.isEmpty() ) {
515     dataObj = findObject( entry );
516   }
517   else {
518     SALOME_PYQT_DataModelLight* dm =
519       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
520     if ( dm ) dataObj = dm->getRoot();
521   }
522   if ( dataObj ) {
523     DataObjectList children;
524     dataObj->children( children );
525     QListIterator<SUIT_DataObject*> it( children );
526     while ( it.hasNext() ) {
527       dataObj->removeChild( it.next() );
528     }
529   }
530 }
531
532 /*!
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
536 */
537 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
538 {
539   QStringList entryList;
540   SUIT_DataObject* dataObj = 0;
541   if ( !entry.isEmpty() ) {
542     dataObj = findObject( entry );
543   }
544   else {
545     SALOME_PYQT_DataModelLight* dm =
546       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
547     if ( dm ) dataObj = dm->getRoot();
548   }
549   if ( dataObj ) {
550     DataObjectList lst;
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() );
556     }
557   }
558   return entryList;
559 }
560
561 /*!
562   \brief Create new instance of data model and return it.
563 */
564 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
565 {
566   return new SALOME_PYQT_DataModelLight( this );
567 }
568
569 /*!
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
573 */
574 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
575 {
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 )
584         obj = curentobj;
585     }
586   }
587   return obj;
588 }