Salome HOME
Merge branch V7_3_1_BR
[modules/gui.git] / src / SALOME_PYQT / SALOME_PYQT_GUILight / SALOME_PYQT_ModuleLight.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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 #include "LightApp_Application.h"
31 #include "SUIT_DataBrowser.h"
32 #include "sipAPISalomePyQtGUILight.h"
33
34 #ifndef GUI_DISABLE_CORBA
35 #include <Container_init_python.hxx>
36 #endif
37
38 // Py_ssize_t for old Pythons
39 // This code is as recommended by"
40 // http://www.python.org/dev/peps/pep-0353/#conversion-guidelines
41 //#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
42 //typedef int Py_ssize_t;
43 //# define PY_SSIZE_T_MAX INT_MAX
44 //# define PY_SSIZE_T_MIN INT_MIN
45 //#endif
46
47 //
48 // NB: Python requests.
49 // General rule for Python requests created by Python-based GUI modules
50 // (SALOME_PYQT_ModuleLight and other ones):
51 // all requests should be executed SYNCHRONOUSLY within the main GUI thread.
52 // However, it is obligatory that ANY Python call is wrapped with a request object,
53 // so that ALL Python API calls are serialized with PyInterp_Dispatcher.
54 //
55 // NB: Library initialization
56 // Since the SalomePyQtGUILight library is not imported in Python it's initialization function
57 // should be called manually (and only once) in order to initialize global sip data
58 // and to get C API from sip : sipBuildResult for example
59 //
60
61 #define INIT_FUNCTION initSalomePyQtGUILight
62 #if defined(SIP_STATIC_MODULE)
63 extern "C" void INIT_FUNCTION();
64 #else
65 PyMODINIT_FUNC INIT_FUNCTION();
66 #endif
67
68 /*!
69   \fn CAM_Module* createModule()
70   \brief Module factory function.
71   \internal
72   
73   Creates an instance of SALOME_PYQT_Module object by request
74   of an application when the module is loaded and initialized.
75
76   \return new module object
77 */
78
79 extern "C" 
80 {
81   SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule() 
82   {
83     static bool alreadyInitialized = false;
84
85     // make initialization only once (see comment above) !
86     if ( !alreadyInitialized ) {
87       PyLockWrapper lck; // GIL acquisition
88       INIT_FUNCTION();
89       alreadyInitialized = !alreadyInitialized;
90     }
91
92     return new SALOME_PYQT_ModuleLight();
93   }
94 }
95
96 /*!
97   \class SALOME_PYQT_ModuleLight
98   \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
99   Python-based SALOME modules.
100 */
101
102 /*!
103   \brief Constructor
104 */
105 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
106   : LightApp_Module( "noname" ) // name is set explicitly at the module initialization
107 {
108   // initialize helper
109   myHelper = new PyModuleHelper( this );
110 }
111
112 /*!
113   \brief Destructor
114 */
115 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
116 {
117   // as myHelper is a QObject, it should be deleted automatically
118 }
119
120 /*!
121   \brief Initialization of the module.
122   \param app parent application object
123   \sa PyModuleHelper::initialize()
124 */
125 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
126 {
127   // call base implementation
128   LightApp_Module::initialize( app );
129
130   // ... then call helper
131   myHelper->initialize( app );
132   SUIT_DataBrowser* ob = getApp()->objectBrowser();
133   if (ob && ob->model()) {
134     connect( ob->model(), SIGNAL( clicked( SUIT_DataObject*, int ) ),
135              myHelper, SLOT( onObjectBrowserClicked( SUIT_DataObject*, int ) ), Qt::UniqueConnection );
136   }
137 }
138
139 /*!
140   \brief Activation of the module.
141   \param study parent study
142   \return \c true if activation is successful and \c false otherwise
143   \sa PyModuleHelper::activate()
144 */
145 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
146 {
147   // call base implementation and then helper
148   return LightApp_Module::activateModule( study ) && myHelper->activate( study );
149 }
150
151 /*!
152   \brief Deactivation of the module.
153   \param study parent study
154   \return \c true if deactivation is successful and \c false otherwise
155   \sa PyModuleHelper::deactivate()
156 */
157 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
158 {  
159   // call helper
160   bool res = myHelper->deactivate( study );
161     
162   // ... then call base implementation
163   return LightApp_Module::deactivateModule( study ) && res;
164 }
165
166 /*!
167   \brief Close of the module.
168
169   This function is usually used in order to close the module's 
170   specific menus and toolbars and perform other such actions
171   required when the module is closed.
172 */
173 void SALOME_PYQT_ModuleLight::onModelClosed()
174 {
175   // call helper
176   myHelper->modelClosed(application()->activeStudy());
177   LightApp_Module::onModelClosed();
178 }
179
180
181 /*!
182   \brief Get the dockable windows associated with the module.
183   \param winMap output map of dockable windows in form { <window_type> : <dock_area> }
184   \sa PyModuleHelper::windows()
185 */
186 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
187 {
188   // get list of dockable windows from helper
189   winMap = myHelper->windows();
190 }
191
192 /*!
193   \brief Define the compatible view windows associated with the module.
194   \param viewList output list of view windows types
195   \sa PyModuleHelper::viewManagers()
196 */
197 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
198 {
199   // get list of view types from helper
200   viewList = myHelper->viewManagers();
201 }
202
203 /*!
204   \brief Process study activation.
205   \sa PyModuleHelper::studyActivated()
206 */
207 void SALOME_PYQT_ModuleLight::studyActivated()
208 {
209   // call helper
210   myHelper->studyActivated( application()->activeStudy() );
211 }
212
213 /*!
214   \brief Process context popup menu request.
215   \param context popup menu context (e.g. "ObjectBrowser")
216   \param menu popup menu
217   \param title popup menu title (not used)
218   \sa PyModuleHelper::contextMenu()
219 */
220 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context, 
221                                                 QMenu*         menu, 
222                                                 QString&       /*title*/ )
223 {
224   // call helper
225   myHelper->contextMenu( context, menu );
226 }
227
228 /*!
229   \brief Export preferences for the Python module.
230   \sa PyModuleHelper::createPreferences()
231 */
232 void SALOME_PYQT_ModuleLight::createPreferences()
233 {
234   // call helper
235   myHelper->createPreferences();
236 }
237
238 /*!
239   \brief Process module's preferences changing.
240   \param section preference resources section
241   \param parameter preference resources parameter name
242   \sa PyModuleHelper::preferencesChanged()
243 */
244 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
245 {
246   // call helper
247   myHelper->preferencesChanged( section, parameter );
248 }
249
250 /*!
251   \brief Save module data. Called when user saves study.
252   \param files output list of files where module stores data
253   \sa PyModuleHelper::save()
254 */
255 void SALOME_PYQT_ModuleLight::save( QStringList& files )
256 {
257   // call helper
258   myHelper->save( files );
259 }
260
261 /*
262  \brief Load module data. Called when user opens study 
263  and activates module.
264  \param files list of files where module data is stored
265  \sa PyModuleHelper::load()
266 */
267 bool SALOME_PYQT_ModuleLight::load( const QStringList& files )
268 {
269   // call helper
270   return myHelper->load( files );
271 }
272
273 /*!
274   \brief Dump module data to the Python script. 
275   Called when user activates dump study operation.
276   \param files output list of files where module stores python script
277   \sa PyModuleHelper::dumpPython()
278 */
279 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
280 {
281   // call helper
282   myHelper->dumpPython( files );
283 }
284
285 /*!
286   \brief Test if object \a what can be dragged by the user.
287   \param what data object being tested
288   \return \c true if object can be dragged or \c false otherwise
289   \sa PyModuleHelper::isDraggable()
290 */
291 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
292 {
293   // call helper
294   return myHelper->isDraggable( what );
295 }
296
297 /*!
298   \brief Test if drop operation can be done on the \a where object.
299   \param where data object being tested
300   \return \c true if if drop operation is supported by object or \c false otherwise
301   \sa PyModuleHelper::isDropAccepted()
302 */
303 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
304 {
305   // call helper
306   return myHelper->isDropAccepted( where );
307 }
308
309 /*!
310   \brief Perform drop operation
311   \param what list of data objects being dropped
312   \param where target data object for drop operation
313   \param row line (child item index) where drop operation is performed to
314   \param action current drop action (copy or move)
315   \sa PyModuleHelper::dropObjects()
316 */
317 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
318                                            const int row, Qt::DropAction action )
319 {
320   // call helper
321   myHelper->dropObjects( what, where, row, action );
322 }
323
324 /*!
325   \brief Create new empty data object
326   \param parent entry of parent data object
327   \return entry of created data object
328 */
329 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
330 {
331   QString entry;
332   SALOME_PYQT_DataObjectLight* obj = 0;
333
334   if ( !parent.isEmpty() ) {
335     SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
336     if ( parentObj )
337       obj = new SALOME_PYQT_DataObjectLight( parentObj );
338   }
339   else {
340     SALOME_PYQT_DataModelLight* dm =
341       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
342     if ( dm )
343       obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
344   }  
345   if ( obj )
346     entry = obj->entry();
347   return entry;
348 }
349
350 /*!
351  \brief Create new data object with specified name, icon and tooltip
352  \param name data object name
353  \param icon data object icon
354  \param toolTip data object tooltip
355  \param parent entry of parent data object
356  \return entry of created data object
357 */
358 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
359                                                const QString& icon,
360                                                const QString& toolTip,
361                                                const QString& parent )
362 {
363   QString entry = createObject( parent );
364   SALOME_PYQT_DataObjectLight* obj = findObject( entry );
365   if ( obj ) {
366     obj->setName( name);
367     obj->setToolTip( toolTip );
368     obj->setIcon( icon );
369   }
370   return entry;
371 }
372
373 /*!
374   \brief Set data object name
375   \param entry data object entry
376   \param name data object name
377 */
378 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
379 {
380   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
381   if ( dataObj )
382     dataObj->setName( name );
383 }
384
385 /*!
386   \brief Get data object name
387   \param entry data object entry
388   \return data object name
389 */
390 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
391 {
392   QString name;
393   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
394   if ( dataObj )
395     name = dataObj->name();
396   return name;
397 }
398
399 /*!
400   \brief Set data object icon
401   \param entry data object entry
402   \param icon data object icon file name (icon is loaded from module resources)
403 */
404 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
405 {
406   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
407   if ( dataObj )
408     dataObj->setIcon( icon );
409 }
410
411 /*!
412   \brief Set data object tooltip
413   \param entry data object entry
414   \param toolTip data object tooltip
415 */
416 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
417 {
418   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
419   if ( dataObj )
420     dataObj->setToolTip( toolTip );
421 }
422
423 /*!
424   \brief Get data object tooltip
425   \param entry data object entry
426   \return data object tooltip
427 */
428 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
429 {
430   QString toolTip;
431   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
432   if ( dataObj )
433     toolTip = dataObj->toolTip();
434   return toolTip;
435 }
436
437 /*!
438   \brief Set data object color
439   \param entry data object entry
440   \param color data object color
441  */
442 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
443 {
444   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
445   if ( dataObj )
446     dataObj->setColor( color );
447 }
448
449 /*!
450   \brief Get data object color
451   \param entry data object entry
452   \return data object color
453 */
454 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
455 {
456   QColor color;
457   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
458   if ( dataObj )
459     color = dataObj->color( SUIT_DataObject::Foreground );
460   return color;
461 }
462
463 void SALOME_PYQT_ModuleLight::setObjectPosition( const QString& theEntry, int thePos )
464 {
465   SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
466   if ( dataObj )
467     dataObj->setPosition(thePos);
468 }
469
470 int SALOME_PYQT_ModuleLight::getObjectPosition( const QString& theEntry )
471 {
472   SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
473   if ( dataObj )
474     return dataObj->position();
475   return -1;
476 }
477
478
479 /*!
480   \brief Set reference to another data object
481   \param entry data object entry
482   \param refEntry referenced data object entry
483 */
484 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
485 {
486   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
487   if ( dataObj )
488     dataObj->setRefEntry( refEntry );
489 }
490
491 /*
492   \brief Get entry of the referenced object (if there's any)
493   \param entry data object entry
494   \return referenced data object entry
495 */
496 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
497 {
498   QString refEntry;
499   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
500   if ( dataObj )
501     refEntry = dataObj->refEntry();
502   return refEntry;
503 }
504
505 /*!
506   \brief Remove object by entry
507   \param entry data object entry
508 */
509 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
510 {
511   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
512   if ( dataObj && dataObj->parent() )
513     dataObj->parent()->removeChild( dataObj );
514 }
515
516 /*!
517   \brief Remove all child data objects from specified data object
518   \param entry data object entry
519 */
520 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
521 {
522   SUIT_DataObject* dataObj = 0;
523   if ( !entry.isEmpty() ) {
524     dataObj = findObject( entry );
525   }
526   else {
527     SALOME_PYQT_DataModelLight* dm =
528       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
529     if ( dm ) dataObj = dm->getRoot();
530   }
531   if ( dataObj ) {
532     DataObjectList children;
533     dataObj->children( children );
534     QListIterator<SUIT_DataObject*> it( children );
535     while ( it.hasNext() ) {
536       dataObj->removeChild( it.next() );
537     }
538   }
539 }
540
541 /*!
542   \brief Get entries of all child data objects of specified data object
543   \param entry data object entry
544   \param recursive \c true for recursive processing
545 */
546 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
547 {
548   QStringList entryList;
549   SUIT_DataObject* dataObj = 0;
550   if ( !entry.isEmpty() ) {
551     dataObj = findObject( entry );
552   }
553   else {
554     SALOME_PYQT_DataModelLight* dm =
555       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
556     if ( dm ) dataObj = dm->getRoot();
557   }
558   if ( dataObj ) {
559     DataObjectList lst;
560     dataObj->children( lst, recursive );
561     QListIterator<SUIT_DataObject*> it( lst );
562     while ( it.hasNext() ) {
563       SALOME_PYQT_DataObjectLight* sobj = dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.next() );
564       entryList.append( sobj->entry() );
565     }
566   }
567   return entryList;
568 }
569
570 /*!
571   \brief Create new instance of data model and return it.
572 */
573 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
574 {
575   return new SALOME_PYQT_DataModelLight( this );
576 }
577
578 /*!
579   \brief Find data object by its entry
580   \param entry data object entry
581   \return data object with given entry or 0 if object isn't found
582 */
583 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
584 {
585   SALOME_PYQT_DataObjectLight* obj = 0;
586   SALOME_PYQT_DataModelLight* dm =
587     dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
588   if ( !entry.isEmpty() && dm ) {
589     for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current() && !obj; ++it ) { 
590       SALOME_PYQT_DataObjectLight* curentobj =
591         dynamic_cast<SALOME_PYQT_DataObjectLight*>( it.current() );
592       if ( curentobj && curentobj->entry() == entry )
593         obj = curentobj;
594     }
595   }
596   return obj;
597 }