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