Salome HOME
6b17d8d0941d806d97dde44c3d35790ec99bc504
[modules/gui.git] / src / SALOME_PYQT / SALOME_PYQT_GUILight / SALOME_PYQT_ModuleLight.cxx
1 // Copyright (C) 2007-2016  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 #include "SALOME_PYQT_Selector.h"
27
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"
35
36 #ifndef GUI_DISABLE_CORBA
37 #include <Container_init_python.hxx>
38 #endif
39
40 #include <QCoreApplication>
41 #include <utilities.h>
42
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
50 //#endif
51
52 //
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.
59 //
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
64 //
65
66 #define INIT_FUNCTION initSalomePyQtGUILight
67 #if defined(SIP_STATIC_MODULE)
68 extern "C" void INIT_FUNCTION();
69 #else
70 PyMODINIT_FUNC INIT_FUNCTION();
71 #endif
72
73 /*!
74   \fn CAM_Module* createModule()
75   \brief Module factory function.
76   \internal
77   
78   Creates an instance of SALOME_PYQT_Module object by request
79   of an application when the module is loaded and initialized.
80
81   \return new module object
82 */
83
84 extern "C" 
85 {
86   SALOME_PYQT_LIGHT_EXPORT CAM_Module* createModule() 
87   {
88     QCoreApplication* app = QCoreApplication::instance();
89     bool alreadyInitialized = app && app->property( "salome_pyqt_gui_light_initialized" ).toBool();
90
91     // make initialization only once (see comment above) !
92     if ( !alreadyInitialized ) {
93       PyLockWrapper lck; // GIL acquisition
94       INIT_FUNCTION();
95       if ( app ) app->setProperty( "salome_pyqt_gui_light_initialized", true );
96     }
97
98     return new SALOME_PYQT_ModuleLight();
99   }
100 }
101
102 /*!
103   \class SALOME_PYQT_ModuleLight
104   \brief This class implements GUI module for "light-weight" (no-CORBA-engine)
105   Python-based SALOME modules.
106 */
107
108 /*!
109   \brief Constructor
110 */
111 SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight()
112   : LightApp_Module( "noname" ), mySelector(0) // name is set explicitly at the module initialization
113 {
114   // initialize helper
115   myHelper = new PyModuleHelper( this );
116 }
117
118 /*!
119   \brief Destructor
120 */
121 SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight()
122 {
123   // as myHelper is a QObject, it should be deleted automatically
124 }
125
126 /*!
127   \brief Initialization of the module.
128   \param app parent application object
129   \sa PyModuleHelper::initialize()
130 */
131 void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app )
132 {
133   // call base implementation
134   LightApp_Module::initialize( app );
135
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 );
142   }
143 }
144
145 /*!
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()
150 */
151 bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* study )
152 {
153   // call base implementation and then helper
154   return LightApp_Module::activateModule( study ) && myHelper->activate( study );
155 }
156
157 /*!
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()
162 */
163 bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* study )
164 {  
165   // call helper
166   bool res = myHelper->deactivate( study );
167     
168   // ... then call base implementation
169   return LightApp_Module::deactivateModule( study ) && res;
170 }
171
172 /*!
173   \brief Close of the module.
174
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.
178 */
179 void SALOME_PYQT_ModuleLight::onModelClosed()
180 {
181   // call helper
182   myHelper->modelClosed(application()->activeStudy());
183   LightApp_Module::onModelClosed();
184 }
185
186
187 /*!
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()
191 */
192 void SALOME_PYQT_ModuleLight::windows( QMap<int, int>& winMap ) const
193 {
194   // get list of dockable windows from helper
195   winMap = myHelper->windows();
196 }
197
198 /*!
199   \brief Define the compatible view windows associated with the module.
200   \param viewList output list of view windows types
201   \sa PyModuleHelper::viewManagers()
202 */
203 void SALOME_PYQT_ModuleLight::viewManagers( QStringList& viewList ) const
204 {
205   // get list of view types from helper
206   viewList = myHelper->viewManagers();
207 }
208
209 /*!
210   \brief Process study activation.
211   \sa PyModuleHelper::studyActivated()
212 */
213 void SALOME_PYQT_ModuleLight::studyActivated()
214 {
215   // call helper
216   myHelper->studyActivated( application()->activeStudy() );
217 }
218
219 /*!
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()
225 */
226 void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& context, 
227                                                 QMenu*         menu, 
228                                                 QString&       /*title*/ )
229 {
230   // call helper
231   myHelper->contextMenu( context, menu );
232 }
233
234 /*!
235   \brief Export preferences for the Python module.
236   \sa PyModuleHelper::createPreferences()
237 */
238 void SALOME_PYQT_ModuleLight::createPreferences()
239 {
240   // call helper
241   myHelper->createPreferences();
242 }
243
244 /*!
245   \brief Process module's preferences changing.
246   \param section preference resources section
247   \param parameter preference resources parameter name
248   \sa PyModuleHelper::preferencesChanged()
249 */
250 void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& parameter )
251 {
252   // call helper
253   myHelper->preferencesChanged( section, parameter );
254 }
255
256 /*!
257   \brief Save module data. Called when user saves study.
258   \param files output list of files where module stores data
259   \param url study URL
260   \sa PyModuleHelper::save()
261 */
262 void SALOME_PYQT_ModuleLight::save( QStringList& files, const QString& url )
263 {
264   // call helper
265   myHelper->save( files, url );
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   \param url study URL
273   \return \c true if loading has been finished successfully or \c false otherwise
274   \sa PyModuleHelper::load()
275 */
276 bool SALOME_PYQT_ModuleLight::load( const QStringList& files, const QString& url )
277 {
278   // call helper
279   return myHelper->load( files, url );
280 }
281
282 /*!
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()
287 */
288 void SALOME_PYQT_ModuleLight::dumpPython( QStringList& files )
289 {
290   // call helper
291   myHelper->dumpPython( files );
292 }
293
294 /*!
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()
299 */
300 bool SALOME_PYQT_ModuleLight::isDraggable( const SUIT_DataObject* what ) const
301 {
302   // call helper
303   return myHelper->isDraggable( what );
304 }
305
306 /*!
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()
311 */
312 bool SALOME_PYQT_ModuleLight::isDropAccepted( const SUIT_DataObject* where ) const
313 {
314   // call helper
315   return myHelper->isDropAccepted( where );
316 }
317
318 /*!
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()
325 */
326 void SALOME_PYQT_ModuleLight::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
327                                            const int row, Qt::DropAction action )
328 {
329   // call helper
330   myHelper->dropObjects( what, where, row, action );
331 }
332
333 /*!
334   \brief Create new empty data object
335   \param parent entry of parent data object
336   \return entry of created data object
337 */
338 QString SALOME_PYQT_ModuleLight::createObject( const QString& parent )
339 {
340   QString entry;
341   SALOME_PYQT_DataObjectLight* obj = 0;
342
343   if ( !parent.isEmpty() ) {
344     SALOME_PYQT_DataObjectLight* parentObj = findObject( parent );
345     if ( parentObj )
346       obj = new SALOME_PYQT_DataObjectLight( parentObj );
347   }
348   else {
349     SALOME_PYQT_DataModelLight* dm =
350       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
351     if ( dm )
352       obj = new SALOME_PYQT_DataObjectLight( dm->getRoot() );
353   }  
354   if ( obj )
355     entry = obj->entry();
356   return entry;
357 }
358
359 /*!
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
366 */
367 QString SALOME_PYQT_ModuleLight::createObject( const QString& name,
368                                                const QString& icon,
369                                                const QString& toolTip,
370                                                const QString& parent )
371 {
372   QString entry = createObject( parent );
373   SALOME_PYQT_DataObjectLight* obj = findObject( entry );
374   if ( obj ) {
375     obj->setName( name);
376     obj->setToolTip( toolTip );
377     obj->setIcon( icon );
378   }
379   return entry;
380 }
381
382 /*!
383   \brief Set data object name
384   \param entry data object entry
385   \param name data object name
386 */
387 void SALOME_PYQT_ModuleLight::setName( const QString& entry, const QString& name )
388 {
389   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
390   if ( dataObj )
391     dataObj->setName( name );
392 }
393
394 /*!
395   \brief Get data object name
396   \param entry data object entry
397   \return data object name
398 */
399 QString SALOME_PYQT_ModuleLight::getName( const QString& entry ) const
400 {
401   QString name;
402   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
403   if ( dataObj )
404     name = dataObj->name();
405   return name;
406 }
407
408 /*!
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)
412 */
413 void SALOME_PYQT_ModuleLight::setIcon( const QString& entry, const QString& icon )
414 {
415   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
416   if ( dataObj )
417     dataObj->setIcon( icon );
418 }
419
420 /*!
421   \brief Set data object tooltip
422   \param entry data object entry
423   \param toolTip data object tooltip
424 */
425 void SALOME_PYQT_ModuleLight::setToolTip( const QString& entry, const QString& toolTip )
426 {
427   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
428   if ( dataObj )
429     dataObj->setToolTip( toolTip );
430 }
431
432 /*!
433   \brief Get data object tooltip
434   \param entry data object entry
435   \return data object tooltip
436 */
437 QString SALOME_PYQT_ModuleLight::getToolTip( const QString& entry ) const
438 {
439   QString toolTip;
440   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
441   if ( dataObj )
442     toolTip = dataObj->toolTip();
443   return toolTip;
444 }
445
446 /*!
447   \brief Set data object color
448   \param entry data object entry
449   \param color data object color
450  */
451 void SALOME_PYQT_ModuleLight::setColor( const QString& entry, const QColor& color )
452 {
453   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
454   if ( dataObj )
455     dataObj->setColor( color );
456 }
457
458 /*!
459   \brief Get data object color
460   \param entry data object entry
461   \return data object color
462 */
463 QColor SALOME_PYQT_ModuleLight::getColor( const QString& entry ) const
464 {
465   QColor color;
466   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
467   if ( dataObj )
468     color = dataObj->color( SUIT_DataObject::Foreground );
469   return color;
470 }
471
472 void SALOME_PYQT_ModuleLight::setObjectPosition( const QString& theEntry, int thePos )
473 {
474   SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
475   if ( dataObj )
476     dataObj->setPosition(thePos);
477 }
478
479 int SALOME_PYQT_ModuleLight::getObjectPosition( const QString& theEntry )
480 {
481   SALOME_PYQT_DataObjectLight* dataObj = findObject( theEntry );
482   if ( dataObj )
483     return dataObj->position();
484   return -1;
485 }
486
487
488 /*!
489   \brief Set reference to another data object
490   \param entry data object entry
491   \param refEntry referenced data object entry
492 */
493 void SALOME_PYQT_ModuleLight::setReference( const QString& entry, const QString& refEntry )
494 {
495   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
496   if ( dataObj )
497     dataObj->setRefEntry( refEntry );
498 }
499
500 /*
501   \brief Get entry of the referenced object (if there's any)
502   \param entry data object entry
503   \return referenced data object entry
504 */
505 QString SALOME_PYQT_ModuleLight::getReference( const QString& entry ) const
506 {
507   QString refEntry;
508   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
509   if ( dataObj )
510     refEntry = dataObj->refEntry();
511   return refEntry;
512 }
513
514 /*!
515   \brief Remove object by entry
516   \param entry data object entry
517 */
518 void SALOME_PYQT_ModuleLight::removeObject( const QString& entry )
519 {
520   SALOME_PYQT_DataObjectLight* dataObj = findObject( entry );
521   if ( dataObj && dataObj->parent() )
522     dataObj->parent()->removeChild( dataObj );
523 }
524
525 /*!
526   \brief Remove all child data objects from specified data object
527   \param entry data object entry
528 */
529 void SALOME_PYQT_ModuleLight::removeChildren( const QString& entry )
530 {
531   SUIT_DataObject* dataObj = 0;
532   if ( !entry.isEmpty() ) {
533     dataObj = findObject( entry );
534   }
535   else {
536     SALOME_PYQT_DataModelLight* dm =
537       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
538     if ( dm ) dataObj = dm->getRoot();
539   }
540   if ( dataObj ) {
541     DataObjectList children;
542     dataObj->children( children );
543     QListIterator<SUIT_DataObject*> it( children );
544     while ( it.hasNext() ) {
545       dataObj->removeChild( it.next() );
546     }
547   }
548 }
549
550 /*!
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
554 */
555 QStringList SALOME_PYQT_ModuleLight::getChildren( const QString& entry, const bool recursive ) const
556 {
557   QStringList entryList;
558   SUIT_DataObject* dataObj = 0;
559   if ( !entry.isEmpty() ) {
560     dataObj = findObject( entry );
561   }
562   else {
563     SALOME_PYQT_DataModelLight* dm =
564       dynamic_cast<SALOME_PYQT_DataModelLight*>( dataModel() );
565     if ( dm ) dataObj = dm->getRoot();
566   }
567   if ( dataObj ) {
568     DataObjectList lst;
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() );
574     }
575   }
576   return entryList;
577 }
578
579 /*!
580   \brief Create new instance of data model and return it.
581 */
582 CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel()
583 {
584   return new SALOME_PYQT_DataModelLight( this );
585 }
586
587 /*!
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
591 */
592 SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject( const QString& entry ) const
593 {
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 )
602         obj = curentobj;
603     }
604   }
605   return obj;
606 }
607
608 void SALOME_PYQT_ModuleLight::getSelected( DataObjectList& ) const
609 {
610   MESSAGE("getSelected");
611 }
612
613 unsigned long SALOME_PYQT_ModuleLight::getModifiedTime() const
614 {
615   MESSAGE("getModifiedTime");
616
617 }
618
619
620 SUIT_DataObject* SALOME_PYQT_ModuleLight::root() const
621 {
622   MESSAGE("root");
623
624 }
625
626
627 void SALOME_PYQT_ModuleLight::setSelected( const QStringList& entries, const bool isUnused)
628 {
629   MESSAGE("setSelected");
630   return myHelper->selectionUpdated(entries);
631 }
632
633 void SALOME_PYQT_ModuleLight::setLocalSelected(const QStringList & entries)
634 {
635   MESSAGE("setLocalSelected");
636   if (!mySelector)
637     {
638        mySelector = new SALOME_PYQT_Selector(this, this->getApp()->selectionMgr());
639     }
640   mySelector->setLocalEntries(entries);
641   emit localSelectionChanged();
642 }
643