From: rnv Date: Fri, 17 Apr 2009 10:54:04 +0000 (+0000) Subject: Implementation of the issue 0020151 (SALOME: Light Python module) X-Git-Tag: V5_1_2rc1~31 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=4e2294c020232787c468924cd5fb7170e6fc61e1;p=modules%2Fgui.git Implementation of the issue 0020151 (SALOME: Light Python module) --- diff --git a/adm_local/unix/make_conclude.in b/adm_local/unix/make_conclude.in index 69822e437..a21a3b28e 100644 --- a/adm_local/unix/make_conclude.in +++ b/adm_local/unix/make_conclude.in @@ -37,25 +37,25 @@ ifneq ($(GUI_DISABLE_CORBA),yes) # transform idl reference in appropriate obj file LIB_CLIENT_SRC = $(LIB_CLIENT_IDL:%.idl=%$(IDL_CLN_CXX)) LIB_SERVER_SRC = $(LIB_SERVER_IDL:%.idl=%$(IDL_SRV_CXX)) -LIB_SWIG_SRC = $(SWIG_DEF:%.i=%_wrap.cxx) else LIB_CLIENT_SRC = LIB_SERVER_SRC = LIB_SWIG_SRC = endif +LIB_SWIG_SRC = $(SWIG_DEF:%.i=%_wrap.cxx) LIB_MOC_SRC = $(LIB_MOC:%.h=%_moc.cxx) LIB_SRC+=$(LIB_MOC_SRC) LIB_DEP= $(LIB_SRC) $(LIB_CLIENT_SRC) $(LIB_SERVER_SRC) $(LIB_SWIG_SRC) - + +LIB_SWIG_OBJ = $(LIB_SWIG_SRC:%.cxx=%.lo) + ifneq ($(GUI_DISABLE_CORBA),yes) LIB_CLIENT_OBJ = $(LIB_CLIENT_IDL:%.idl=%$(IDL_CLN_OBJ)) LIB_SERVER_OBJ = $(LIB_SERVER_IDL:%.idl=%$(IDL_SRV_OBJ)) -LIB_SWIG_OBJ = $(LIB_SWIG_SRC:%.cxx=%.lo) else LIB_CLIENT_OBJ = LIB_SERVER_OBJ = -LIB_SWIG_OBJ = endif # transform c file in appropriate libtool obj file (.c, .cc and .cxx) @@ -73,14 +73,10 @@ LIB_BUILD_A = $(patsubst %.a, $(top_builddir)/lib@LIB_LOCATION_SUFFIX@/salome/%. LIB_BUILD_SO = $(patsubst %.so, $(top_builddir)/lib@LIB_LOCATION_SUFFIX@/salome/%.so, $(filter %.so, $(LIB))) ifneq ($(findstring cmodule.la,$(filter %.la, $(LIB))),) -ifneq ($(GUI_DISABLE_CORBA),yes) LIB_SWIG = $(patsubst %cmodule.la,%.so, $(filter %.la, $(LIB))) else LIB_SWIG = endif -else -LIB_SWIG = -endif lib: $(LIB_BUILD) $(LIB_BUILD_SO) $(LIB_CLIENT_PY) # we don't build static library ! diff --git a/configure.ac b/configure.ac index 7214f91b7..77cd2e02a 100644 --- a/configure.ac +++ b/configure.ac @@ -226,6 +226,16 @@ echo CHECK_PYTHON +echo +echo --------------------------------------------- +echo testing swig +echo --------------------------------------------- +echo + +AM_PATH_PYTHON(2.3) +CHECK_SWIG + + dnl echo dnl echo --------------------------------------------- dnl echo testing java @@ -243,18 +253,6 @@ echo CHECK_DISABLE_CORBA echo "GUI_DISABLE_CORBA = "$GUI_DISABLE_CORBA -if test "x${GUI_DISABLE_CORBA}" != "xyes" ; then - -echo -echo --------------------------------------------- -echo testing swig -echo --------------------------------------------- -echo - -AM_PATH_PYTHON(2.3) -CHECK_SWIG -fi - echo echo --------------------------------------------- echo testing threads @@ -649,6 +647,7 @@ AC_OUTPUT([ \ ./src/SALOME_PY/Makefile \ ./src/SALOME_PYQT/Makefile \ ./src/SALOME_PYQT/SALOME_PYQT_GUI/Makefile \ + ./src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile \ ./src/SALOME_PYQT/SalomePyQt/Makefile \ ./resources/Makefile \ ./idl/Makefile \ diff --git a/src/LightApp/LightApp_Application.cxx b/src/LightApp/LightApp_Application.cxx index 5b8541c17..bbcdd88f3 100644 --- a/src/LightApp/LightApp_Application.cxx +++ b/src/LightApp/LightApp_Application.cxx @@ -24,7 +24,7 @@ // Author: Natalia Donis // #ifndef DISABLE_PYCONSOLE - #include // WARNING! This include must be the first! + #include // WARNING! This include must be the first! #include #endif @@ -1606,7 +1606,7 @@ QWidget* LightApp_Application::createWindow( const int flag ) #ifndef DISABLE_PYCONSOLE else if ( flag == WT_PyConsole ) { - PyConsole_Console* pyCons = new PyConsole_Console( desktop() ); + PyConsole_Console* pyCons = new PyConsole_Console( desktop(),new LightApp_PyInterp()); pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) ); wid = pyCons; pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) ); @@ -2887,6 +2887,7 @@ bool LightApp_Application::isLibExists( const QString& moduleTitle ) const //abd: changed libSalomePyQtGUI to SalomePyQtGUI for WIN32 bool isPythonModule = lib.contains("SalomePyQtGUI"); + bool isPythonLightModule = lib.contains("libSalomePyQtGUILight"); QStringList paths; #ifdef WIN32 @@ -2915,10 +2916,10 @@ bool LightApp_Application::isLibExists( const QString& moduleTitle ) const << "* Module " << moduleTitle.toLatin1().constData() << " will not be available in GUI mode" << std::endl << "****************************************************************" << std::endl ); } - else if ( !isPythonModule ) + else if ( !isPythonModule && !isPythonLightModule) return true; - if ( isPythonModule ) + if ( isPythonModule || isPythonLightModule) { QString pylib = moduleName( moduleTitle ) + QString(".py"); QString pylibgui = moduleName( moduleTitle ) + QString("GUI.py"); @@ -2936,13 +2937,14 @@ bool LightApp_Application::isLibExists( const QString& moduleTitle ) const QFileInfo inf( Qtx::addSlash( *anIt ) + pylib ); QFileInfo infgui( Qtx::addSlash( *anIt ) + pylibgui ); - if( !isPyLib && inf.exists() ) - isPyLib = true; + if(!isPythonLightModule) + if( !isPyLib && inf.exists() ) + isPyLib = true; if( !isPyGuiLib && infgui.exists() ) isPyGuiLib = true; - if ( isPyLib && isPyGuiLib && isLibFound) + if ((isPyLib || isPythonLightModule ) && isPyGuiLib && isLibFound) return true; } diff --git a/src/LightApp/LightApp_EventFilter.cxx b/src/LightApp/LightApp_EventFilter.cxx index b452b018b..30ea24f79 100644 --- a/src/LightApp/LightApp_EventFilter.cxx +++ b/src/LightApp/LightApp_EventFilter.cxx @@ -25,6 +25,8 @@ #include +#include + LightApp_EventFilter* LightApp_EventFilter::myFilter = NULL; /*!Constructor.*/ @@ -61,10 +63,26 @@ bool LightApp_EventFilter::eventFilter( QObject* o, QEvent* e ) if ( aDesktop ) aDesktop->emitActivated(); } + + else if(e->type() == SALOME_EVENT) + { + SALOME_Event* aSE = (SALOME_Event*)((SALOME_CustomEvent*)e)->data(); + processEvent(aSE); + ((SALOME_CustomEvent*)e)->setData( 0 ); + return true; + } return QObject::eventFilter( o, e ); } +/*!Process event.*/ +void LightApp_EventFilter::processEvent( SALOME_Event* theEvent ) +{ + if(theEvent) + theEvent->ExecutePostedEvent(); +} + + /*!Create new instance of LightApp_EventFilter*/ void LightApp_EventFilter::Init() { diff --git a/src/LightApp/LightApp_EventFilter.h b/src/LightApp/LightApp_EventFilter.h index 3b98fbc58..de59af6c2 100644 --- a/src/LightApp/LightApp_EventFilter.h +++ b/src/LightApp/LightApp_EventFilter.h @@ -30,6 +30,9 @@ #pragma warning( disable: 4251 ) #endif + +class SALOME_Event; + /*! Class provide event filter. */ @@ -46,6 +49,7 @@ protected: private: /*! global event filter for qapplication */ virtual bool eventFilter( QObject* o, QEvent* e ); + void processEvent( SALOME_Event* ); private: static LightApp_EventFilter* myFilter; diff --git a/src/LightApp/LightApp_PyInterp.cxx b/src/LightApp/LightApp_PyInterp.cxx new file mode 100644 index 000000000..8e4a751ce --- /dev/null +++ b/src/LightApp/LightApp_PyInterp.cxx @@ -0,0 +1,104 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + +#include "LightApp_PyInterp.h" + +#include +#include + +#include + +/*! + * constructor : multi Python interpreter, one per SALOME study. + * calls initialize method defined in base class, which calls virtual methods + * initstate & initcontext redefined here. + */ +LightApp_PyInterp::LightApp_PyInterp(): PyConsole_Interp() +{ +} + +/*! + * Destructor. + */ +LightApp_PyInterp::~LightApp_PyInterp() +{ +} + +/*!\class LightApp_PyInterp + * EDF-CCAR + * When SALOME uses multi Python interpreter feature, + * Every study has its own interpreter and thread state (_tstate = Py_NewInterpreter()) + * This is fine because every study has its own modules (sys.modules) stdout and stderr + * BUT some Python modules must be imported only once. In multi interpreter context Python + * modules (*.py) are imported several times. + * The pyqt module must be imported only once because it registers classes in a C module. + * It's quite the same with omniorb modules (internals and generated with omniidl) + * This problem is handled with "shared modules" defined in salome_shared_modules.py + * These "shared modules" are imported only once and only copied in all the other interpreters + * BUT it's not the only problem. Every interpreter has its own __builtin__ module. That's fine + * but if we have copied some modules and imported others problems may arise with operations that + * are not allowed in restricted execution environment. So we must impose that all interpreters + * have identical __builtin__ module. + * That's all, for the moment ... + */ + + +bool LightApp_PyInterp::initContext() +{ + /*! + * The GIL is assumed to be held + * It is the caller responsability caller to acquire the GIL + * It will still be held on initContext output + */ + if ( !PyConsole_Interp::initContext() ) + return false; + + //Import special module to change the import mechanism + PyObjWrapper m1( PyImport_ImportModule( "import_hook" ) ); + if ( !m1 ) + { + PyErr_Print(); + return false; + } + + // Call init_shared_modules to initialize the shared import mechanism for modules + //that must not be imported twice + PyObjWrapper m2( PyObject_CallMethod( m1, "init_shared_modules", "O", SUIT_PYTHON::salome_shared_modules_module ) ); + if ( !m2 ) + { + PyErr_Print(); + return false; + } + return true; +} + +/*! + Do nothing + The initialization has been done in main + */ +void LightApp_PyInterp::initPython() +{ + _gtstate=SUIT_PYTHON::_gtstate; // initialisation in main + _interp=SUIT_PYTHON::_interp; +} diff --git a/src/LightApp/LightApp_PyInterp.h b/src/LightApp/LightApp_PyInterp.h new file mode 100644 index 000000000..cbbff1325 --- /dev/null +++ b/src/LightApp/LightApp_PyInterp.h @@ -0,0 +1,41 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + +#ifndef _LIGHTAPP_PYINTERP_H_ +#define _LIGHTAPP_PYINTERP_H_ + +#include // this include must be first (see PyInterp_base.h)! + +class LightApp_PyInterp : public PyConsole_Interp +{ +public: + LightApp_PyInterp(); + virtual ~LightApp_PyInterp(); + +protected: + virtual void initPython(); + virtual bool initContext(); +}; + +#endif //_LIGHTAPP_PYINTERP_H_ diff --git a/src/LightApp/Makefile.am b/src/LightApp/Makefile.am index 1d3892a19..f6d8edd1f 100755 --- a/src/LightApp/Makefile.am +++ b/src/LightApp/Makefile.am @@ -56,6 +56,10 @@ salomeinclude_HEADERS = \ LightApp_PreferencesDlg.h \ LightApp_UpdateFlags.h +if ENABLE_PYCONSOLE + salomeinclude_HEADERS += LightApp_PyInterp.h +endif + # LightApp_OBFilter.h if ENABLE_VTKVIEWER @@ -99,6 +103,10 @@ dist_libLightApp_la_SOURCES = \ LightApp_Preferences.cxx \ LightApp_PreferencesDlg.cxx +if ENABLE_PYCONSOLE + dist_libLightApp_la_SOURCES += LightApp_PyInterp.cxx +endif + # LightApp_OBFilter.cxx if ENABLE_VTKVIEWER @@ -188,7 +196,8 @@ else !ENABLE_OCCVIEWER libLightApp_la_CPPFLAGS += -DDISABLE_OCCVIEWER endif if ENABLE_PYCONSOLE - libLightApp_la_CPPFLAGS += $(PYTHON_INCLUDES) -I$(srcdir)/../PyConsole -I$(srcdir)/../PyInterp + libLightApp_la_CPPFLAGS += $(PYTHON_INCLUDES) -I$(srcdir)/../PyConsole -I$(srcdir)/../PyInterp \ + -I$(srcdir)/../SUITApp libLightApp_la_LDFLAGS += $(PYTHON_LIBS) else !ENABLE_PYCONSOLE libLightApp_la_CPPFLAGS += -DDISABLE_PYCONSOLE @@ -256,9 +265,12 @@ if ENABLE_SALOMEOBJECT libLightApp_la_LIBADD += ../SPlot2d/libSPlot2d.la endif endif + if ENABLE_PYCONSOLE - libLightApp_la_LIBADD += ../PyInterp/libPyInterp.la ../PyConsole/libPyConsole.la + libLightApp_la_LIBADD += ../PyInterp/libPyInterp.la ../PyConsole/libPyConsole.la \ + ../SUITApp/libSUITApp.la endif + if ENABLE_SUPERVGRAPHVIEWER libLightApp_la_LIBADD += ../SUPERVGraph/libSUPERVGraph.la endif diff --git a/src/LightApp/resources/LightApp.xml b/src/LightApp/resources/LightApp.xml index d4e62d9ef..4178c9c07 100644 --- a/src/LightApp/resources/LightApp.xml +++ b/src/LightApp/resources/LightApp.xml @@ -29,7 +29,7 @@ - +
diff --git a/src/Makefile.am b/src/Makefile.am index e49a83136..a1801ad6d 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,7 +64,11 @@ endif SUBDIRS += QxScene LightApp ResExporter if GUI_ENABLE_CORBA - SUBDIRS += TOOLSGUI Session SalomeApp SALOME_SWIG SALOME_PY SALOME_PYQT + SUBDIRS += TOOLSGUI Session SalomeApp +endif + +if ENABLE_PYCONSOLE + SUBDIRS += SALOME_SWIG SALOME_PY SALOME_PYQT endif DIST_SUBDIRS = CASCatch Qtx Style DDS QDS ObjBrowser SUIT SUITApp STD CAF CAM LogWindow Prs Event \ diff --git a/src/SALOME_PY/Makefile.am b/src/SALOME_PY/Makefile.am index 0b47543d3..f91fcc7be 100755 --- a/src/SALOME_PY/Makefile.am +++ b/src/SALOME_PY/Makefile.am @@ -32,12 +32,12 @@ dist_libSalomePy_la_SOURCES = SalomePy.cxx libSalomePy_la_CPPFLAGS = $(QT_INCLUDES) $(PYTHON_INCLUDES) $(VTK_INCLUDES) \ $(OGL_INCLUDES) $(CAS_CXXFLAGS) $(BOOST_CPPFLAGS) @KERNEL_CXXFLAGS@ \ - -DHAVE_CONFIG_H -I$(srcdir)/../SalomeApp -I$(srcdir)/../LightApp \ + -DHAVE_CONFIG_H -I$(srcdir)/../LightApp \ -I$(srcdir)/../Event -I$(srcdir)/../Session -I$(srcdir)/../SVTK \ -I$(srcdir)/../Qtx -I$(srcdir)/../SUIT -I$(srcdir)/../CAM \ -I$(srcdir)/../STD -I$(srcdir)/../VTKViewer -I$(srcdir)/../OBJECT \ - @CAS_CPPFLAGS@ \ - -I$(top_builddir)/salome_adm/unix @CORBA_CXXFLAGS@ @CORBA_INCLUDES@ + @CAS_CPPFLAGS@ + libSalomePy_la_LDFLAGS = $(PYTHON_LIBS) $(QT_MT_LIBS) $(VTK_LIBS) $(OGL_LIBS) \ - ../SalomeApp/libSalomeApp.la \ + ../LightApp/libLightApp.la \ -lvtkCommonPythonD -lvtkGraphicsPythonD -lvtkImagingPythonD diff --git a/src/SALOME_PY/SalomePy.cxx b/src/SALOME_PY/SalomePy.cxx index d2812e856..a2493af84 100755 --- a/src/SALOME_PY/SalomePy.cxx +++ b/src/SALOME_PY/SalomePy.cxx @@ -34,8 +34,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -97,7 +97,7 @@ static PyObject* GetPyClass( const char* theClassName ) PyObject* aPyClass = 0; if( !aVTKModule ) { if ( VTK_MAJOR_VERSION > 3 ) - aVTKModule = PyImport_ImportModule( "libvtkRenderingPython" ); + aVTKModule = PyImport_ImportModule( "vtk.libvtkRenderingPython" ); else aVTKModule = PyImport_ImportModule( "libVTKGraphicsPython" ); if( PyErr_Occurred() ) { @@ -130,10 +130,10 @@ static SVTK_ViewWindow* GetVTKViewWindow( int toCreate = __FindOrCreate ) { SVTK_ViewWindow* aVW = 0; if ( SUIT_Session::session() ) { // get application - SalomeApp_Application* anApp = dynamic_cast( SUIT_Session::session()->activeApplication() ); + LightApp_Application* anApp = dynamic_cast( SUIT_Session::session()->activeApplication() ); if ( anApp ) { // get active study - SalomeApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); + LightApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); if ( aStudy ) { // find or create VTK view manager if ( toCreate == __Create ) { diff --git a/src/SALOME_PYQT/Makefile.am b/src/SALOME_PYQT/Makefile.am index 8ef190431..58b394846 100755 --- a/src/SALOME_PYQT/Makefile.am +++ b/src/SALOME_PYQT/Makefile.am @@ -26,4 +26,8 @@ # include $(top_srcdir)/adm_local/unix/make_common_starter.am -SUBDIRS = SALOME_PYQT_GUI SalomePyQt +SUBDIRS = SALOME_PYQT_GUILight SalomePyQt + +if GUI_ENABLE_CORBA + SUBDIRS += SALOME_PYQT_GUI +endif diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUI/Makefile.am b/src/SALOME_PYQT/SALOME_PYQT_GUI/Makefile.am index a1561d992..750b0bc67 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/Makefile.am +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/Makefile.am @@ -30,33 +30,19 @@ include $(top_srcdir)/adm_local/unix/make_common_starter.am # library target lib_LTLIBRARIES = libSalomePyQtGUI.la -# extra source files (generated by sip) -SIP_SRC = sipAPISalomePyQtGUI.h \ - sipSalomePyQtGUIcmodule.cc - -# Sip definition file -SIP_FILES = SALOME_PYQT_GUI.sip - -# extra dist files -EXTRA_DIST += $(SIP_FILES) - -# extra clean files -CLEANFILES = $(SIP_SRC) - # moc files (generated my moc) MOC_FILES = SALOME_PYQT_Module_moc.cxx # exported header files -salomeinclude_HEADERS = \ - SALOME_PYQT_GUI.h \ - SALOME_PYQT_PyInterp.h \ - SALOME_PYQT_Module.h +salomeinclude_HEADERS = \ + SALOME_PYQT_GUI.h \ + SALOME_PYQT_Module.h # library sources dist_libSalomePyQtGUI_la_SOURCES = \ - SALOME_PYQT_PyInterp.cxx \ - SALOME_PYQT_Module.cxx -nodist_libSalomePyQtGUI_la_SOURCES = $(MOC_FILES) $(SIP_SRC) + SALOME_PYQT_Module.cxx + +nodist_libSalomePyQtGUI_la_SOURCES = $(MOC_FILES) # compilation flags libSalomePyQtGUI_la_CPPFLAGS = $(QT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INCLUDES) \ @@ -64,6 +50,7 @@ libSalomePyQtGUI_la_CPPFLAGS = $(QT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INCLUDES) -DHAVE_CONFIG_H @KERNEL_CXXFLAGS@ -DCALL_OLD_METHODS \ -I@builddir@ -I$(srcdir)/../../PyInterp -I$(srcdir)/../../SalomeApp \ -I$(srcdir)/../../SUIT -I$(srcdir)/../../Qtx -I$(srcdir)/../../LightApp \ + -I$(srcdir)/../SALOME_PYQT_GUILight \ -I$(srcdir)/../../Plot2d -I$(srcdir)/../../OCCViewer \ -I$(srcdir)/../../SalomeApp -I$(srcdir)/../../CAM -I$(srcdir)/../../STD \ -I$(top_builddir)/salome_adm/unix @CORBA_CXXFLAGS@ @CORBA_INCLUDES@ @@ -71,12 +58,5 @@ libSalomePyQtGUI_la_CPPFLAGS = $(QT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INCLUDES) # linkage flags libSalomePyQtGUI_la_LIBADD = $(PYTHON_LIBS) $(SIP_LIBS) $(PYQT_LIBS) $(VTK_LIBS) \ $(OGL_LIBS) ../../PyInterp/libPyInterp.la ../../SalomeApp/libSalomeApp.la \ - ../../OCCViewer/libOCCViewer.la ../../Plot2d/libPlot2d.la - -# Custom build step: generate C++ wrapping according to $(SIP_FILES) -$(SIP_SRC): $(SIP_FILES) - $(SIP) $(PYQT_SIPFLAGS) $< - -# extra dependency (SALOME_PYQT_Module.cxx depends on header files generated by sip) -$(dist_libSalomePyQtGUI_la_SOURCES): $(SIP_SRC) - + ../../OCCViewer/libOCCViewer.la ../../Plot2d/libPlot2d.la \ + ../SALOME_PYQT_GUILight/libSalomePyQtGUILight.la diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx index 0c86c7ae1..267f5fb51 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx @@ -24,136 +24,22 @@ // #include "SALOME_PYQT_Module.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include +#include "SalomeApp_Application.h" +#include "SALOME_PYQT_ModuleLight.h" #include #include +#include -#include -#include -#include -#include -#include -#include -#include - -#include "sipAPISalomePyQtGUI.h" - -#include -#if SIP_VERSION < 0x040700 -#include "sipQtGuiQWidget.h" -#include "sipQtGuiQMenu.h" -#endif - -/*! - \brief Default name of the module, replaced at the moment - of module creation. - \internal -*/ -const char* DEFAULT_NAME = "SALOME_PYQT_Module"; - -/*! - \brief Default menu group number. - \internal -*/ -const int DEFAULT_GROUP = 40; - -/*! - \var IsCallOldMethods - \brief Allow calling obsolete callback methods. - \internal - - If the macro CALL_OLD_METHODS is not defined, the invoking - of obsolete Python module's methods like setSetting(), definePopup(), - etc. is blocked. - - CALL_OLD_METHODS macro can be defined for example by adding - -DCALL_OLD_METHODS compilation option to the Makefile. -*/ -#ifdef CALL_OLD_METHODS -const bool IsCallOldMethods = true; -#else -const bool IsCallOldMethods = false; -#endif - -/* Py_ssize_t for old Pythons */ -/* This code is as recommended by: */ -/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -#endif - -// -// NB: Python requests. -// General rule for Python requests created by SALOME_PYQT_Module: -// all requests should be executed SYNCHRONOUSLY within the main GUI thread. -// However, it is obligatory that ANY Python call is wrapped with a request object, -// so that ALL Python API calls are serialized with PyInterp_Dispatcher. -// - -/*! - \class SALOME_PYQT_Module::XmlHandler - \brief XML resource files parser. - \internal - - This class is used to provide backward compatibility with - existing Python modules in which obsolete menu definition system - (via XML files) is used. -*/ - -class SALOME_PYQT_Module::XmlHandler -{ -public: - XmlHandler( SALOME_PYQT_Module* module, const QString& fileName ); - void createActions(); - void createPopup ( QMenu* menu, - const QString& context, - const QString& parent, - const QString& object ); - void activateMenus( bool ); - -protected: - void createToolBar ( QDomNode& parentNode ); - void createMenu ( QDomNode& parentNode, - const int parentMenuId = -1, - QMenu* parentPopup = 0 ); - - void insertPopupItems( QDomNode& parentNode, - QMenu* menu ); - -private: - SALOME_PYQT_Module* myModule; - QDomDocument myDoc; - QList myMenuItems; -}; // // NB: Library initialization -// Since the SalomePyQtGUI library is not imported in Python it's initialization function +// Since the SalomePyQtGUILight library is not imported in Python it's initialization function // should be called manually (and only once) in order to initialize global sip data // and to get C API from sip : sipBuildResult for example // -#define INIT_FUNCTION initSalomePyQtGUI + +#define INIT_FUNCTION initSalomePyQtGUILight #if defined(SIP_STATIC_MODULE) extern "C" void INIT_FUNCTION(); #else @@ -173,325 +59,90 @@ PyMODINIT_FUNC INIT_FUNCTION(); extern "C" { SALOME_PYQT_EXPORT CAM_Module* createModule() { + static bool alreadyInitialized = false; if ( !alreadyInitialized ) { // call only once (see comment above) ! - PyEval_RestoreThread( KERNEL_PYTHON::_gtstate ); + + PyEval_RestoreThread( KERNEL_PYTHON::_gtstate); INIT_FUNCTION(); - PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate ); + PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate); alreadyInitialized = !alreadyInitialized; } return new SALOME_PYQT_Module(); } } -/*! - \class FuncMsg - \brief Function call in/out tracer. - \internal -*/ - -class FuncMsg -{ -public: - FuncMsg( const QString& funcName ) - { - myName = funcName; - MESSAGE( myName.toLatin1().constData() << " [ begin ]" ); - } - ~FuncMsg() - { - MESSAGE( myName.toLatin1().constData() << " [ end ]" ); - } - void message( const QString& msg ) - { - MESSAGE( myName.toLatin1().constData() << " : " << msg.toLatin1().constData() ); - } -private: - QString myName; -}; - -/*! - \class SALOME_PYQT_Module - \brief This class implements module API for all the Python-based - SALOME modules. -*/ - -// -// Static variables definition -// -SALOME_PYQT_Module::InterpMap SALOME_PYQT_Module::myInterpMap; -SALOME_PYQT_Module* SALOME_PYQT_Module::myInitModule = 0; /*! - \brief Get the module being initialized. - - This is a little trick :) needed to provide an access from Python - (SalomePyQt) to the module being currently activated. The problem - that during the process of module initialization (initialize() - function) it is not yet available via application->activeModule() - call. - - This method returns valid pointer only if called in scope of - initialize() function. - - \return the module being currently initialized + \var __DEFAULT_NAME__ - Default name of the module, replaced at the moment of module creation */ -SALOME_PYQT_Module* SALOME_PYQT_Module::getInitModule() -{ - return myInitModule; -} +const char* __DEFAULT_NAME__ = "SALOME_PYQT_Module"; /*! - \brief Constructor -*/ + * Constructor + */ SALOME_PYQT_Module::SALOME_PYQT_Module() -: SalomeApp_Module( DEFAULT_NAME ), - myInterp( 0 ), - myModule( 0 ), - myXmlHandler ( 0 ), - myLastActivateStatus( true ) + : SalomeApp_Module(__DEFAULT_NAME__), + LightApp_Module(__DEFAULT_NAME__), + SALOME_PYQT_ModuleLight() { } /*! - \brief Destructor -*/ + * Destructor + */ SALOME_PYQT_Module::~SALOME_PYQT_Module() { - if ( myXmlHandler ) - delete myXmlHandler; } /*! - \brief Initialization of the module. - - This method can be used for creation of the menus, toolbars and - other such staff. - - There are two ways to do this: - - for obsolete modules this method first tries to read - _.xml resource file which contains a menu, - toolbars and popup menus description; - - new modules can create menus by direct calling of the - corresponding methods of SalomePyQt Python API in the Python - module's initialize() method which is called from here. - - NOTE: SALOME supports two modes of modules loading: - - immediate (all the modules are created and initialized - immediately when the application object is created; - - postponed modules loading (used currently); in this mode - the module is loaded only be request. - If postponed modules loading is not used, the active - study might be not yet defined at this stage, so initialize() - method should not perform any study-based initialization. - - \param app parent application object -*/ -void SALOME_PYQT_Module::initialize( CAM_Application* app ) + * Get module engine, returns nil var if engine is not found in LifeCycleCORBA + */ +Engines::Component_var SALOME_PYQT_Module::getEngine() const { - FuncMsg fmsg( "SALOME_PYQT_Module::initialize()" ); - - // call base implementation - SalomeApp_Module::initialize( app ); - - // try to get XML resource file name - SUIT_ResourceMgr* aResMgr = getApp()->resourceMgr(); - if ( !myXmlHandler && aResMgr ) { - // get current language - QString aLang = aResMgr->stringValue( "language", "language", QString() ); - if ( aLang.isEmpty() ) - aLang = "en"; - // define resource file name - QString aFileName = name() + "_" + aLang + ".xml"; - aFileName = aResMgr->path( "resources", name(), aFileName ); - // create XML handler instance - if ( !aFileName.isEmpty() && QFile::exists( aFileName ) ) - myXmlHandler = new SALOME_PYQT_Module::XmlHandler( this, aFileName ); - // create menus & toolbars from XML file if required - if ( myXmlHandler ) - myXmlHandler->createActions(); + Engines::Component_var comp; + // temporary solution + try { + comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServerPy", name().toLatin1() ); } - - // perform internal initialization and call module's initialize() funtion - // InitializeReq: request class for internal init() operation - class InitializeReq : public PyInterp_Request - { - public: - InitializeReq( CAM_Application* _app, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myApp( _app ), - myObj( _obj ) {} - - protected: - virtual void execute() - { - myObj->init( myApp ); - } - - private: - CAM_Application* myApp; - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new InitializeReq( app, this ) ); + catch (CORBA::Exception&) { + } + return comp; } /*! - \brief Activation of the module. - - This function is usually used in order to show the module's - specific menus and toolbars, update actions state and perform - other such actions required when the module is activated. - - Note, that returning \c false in this function prevents the - module activation. - - \param theStudy parent study - \return \c true if activation is successful and \c false otherwise -*/ -bool SALOME_PYQT_Module::activateModule( SUIT_Study* theStudy ) + * Get module engine IOR, returns empty string if engine is not found in LifeCycleCORBA + */ +QString SALOME_PYQT_Module::engineIOR() const { - FuncMsg fmsg( "SALOME_PYQT_Module::activateModule()" ); - - // call base implementation - bool res = SalomeApp_Module::activateModule( theStudy ); - - if ( !res ) - return res; - - // reset the activation status to the default value - myLastActivateStatus = true; - - // perform internal activation - // ActivateReq: request class for internal activate() operation - class ActivateReq : public PyInterp_Request - { - public: - ActivateReq( SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->activate( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new ActivateReq( theStudy, this ) ); - - // check activation status (set by activate()) - if ( !lastActivationStatus() ) - return false; - - // activate menus, toolbars, etc - if ( myXmlHandler ) myXmlHandler->activateMenus( true ); - setMenuShown( true ); - setToolShown( true ); - - // connect preferences changing signal - connect( getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), - this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); - - // perform custom activation actions - // CustomizeReq: request class for internal customize() operation - class CustomizeReq : public PyInterp_Request - { - public: - CustomizeReq( SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->customize( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new CustomizeReq( theStudy, this ) ); + if ( !CORBA::is_nil( getEngine() ) ) + return QString( getApp()->orb()->object_to_string( getEngine() ) ); + return QString( "" ); +} - return true; +CAM_DataModel* SALOME_PYQT_Module::createDataModel() +{ + MESSAGE( "SALOME_PYQT_Module::createDataModel()" ); + CAM_DataModel * dm = SalomeApp_Module::createDataModel(); + return dm; } /*! - \brief Deactivation of the module. - - This function is usually used in order to hide the module's - specific menus and toolbars and perform other such actions - required when the module is deactivated. - - \param theStudy parent study - \return \c true if deactivation is successful and \c false otherwise + \brief Process GUI action (from main menu, toolbar or + context popup menu action). */ -bool SALOME_PYQT_Module::deactivateModule( SUIT_Study* theStudy ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::deactivateModule()" ); - - // disconnect preferences changing signal - disconnect( getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), - this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); - - // perform internal deactivation - // DeactivateReq: request class for internal deactivate() operation - class DeactivateReq : public PyInterp_LockRequest - { - public: - DeactivateReq( PyInterp_Interp* _py_interp, - SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->deactivate( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, theStudy, this ) ); - - // deactivate menus, toolbars, etc - if ( myXmlHandler ) myXmlHandler->activateMenus( false ); - setMenuShown( false ); - setToolShown( false ); - - // call base implementation - return SalomeApp_Module::deactivateModule( theStudy ); +void SALOME_PYQT_Module::onGUIEvent(){ + SALOME_PYQT_ModuleLight::onGUIEvent(); } /*! - \brief Get last activation status. - \return status of last module activation operation - \sa activateModule() + \brief Signal handler closing(SUIT_ViewWindow*) of a view + \param pview view being closed */ -bool SALOME_PYQT_Module::lastActivationStatus() const +void SALOME_PYQT_Module::onViewClosed( SUIT_ViewWindow* pview ) { - return myLastActivateStatus; + SALOME_PYQT_ModuleLight::onViewClosed( pview ); } /*! @@ -503,1841 +154,27 @@ bool SALOME_PYQT_Module::lastActivationStatus() const \param section preference resource file section \param setting preference resource name */ -void SALOME_PYQT_Module::preferenceChanged( const QString& module, +void SALOME_PYQT_ModuleLight::preferenceChanged( const QString& module, const QString& section, const QString& setting ) { - FuncMsg fmsg( "SALOME_PYQT_Module::preferenceChanged()" ); - - // perform synchronous request to Python event dispatcher - class Event : public PyInterp_LockRequest - { - public: - Event( PyInterp_Interp* _py_interp, - SALOME_PYQT_Module* _obj, - const QString& _section, - const QString& _setting ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj ( _obj ), - mySection( _section ), - mySetting( _setting ) {} - - protected: - virtual void execute() - { - myObj->prefChanged( mySection, mySetting ); - } - - private: - SALOME_PYQT_Module* myObj; - QString mySection, mySetting; - }; - - if ( module != moduleName() ) { - // module's own preferences are processed by preferencesChanged() method - // ... - // post the request only if dispatcher is not busy! - // execute request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this, section, setting ) ); - } -} - -/*! - \brief Process study activation. - - Called when study desktop is activated. Used for notifying the Python - module about changing of the active study. -*/ -void SALOME_PYQT_Module::studyActivated() -{ - FuncMsg fmsg( "SALOME_PYQT_Module::studyActivated()" ); - - // StudyChangedReq: request class for internal studyChanged() operation - class StudyChangedReq : public PyInterp_Request - { - public: - StudyChangedReq( SUIT_Study* _study, - SALOME_PYQT_Module* _obj ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myStudy ( _study ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->studyChanged( myStudy ); - } - - private: - SUIT_Study* myStudy; - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new StudyChangedReq( application()->activeStudy(), this ) ); -} - -/*! - \brief Process GUI action (from main menu, toolbar or - context popup menu action). -*/ -void SALOME_PYQT_Module::onGUIEvent() -{ - FuncMsg fmsg( "SALOME_PYQT_Module::onGUIEvent()" ); - - // get sender action - QAction* action = qobject_cast( sender() ); - if ( !action ) - return; - - // get action ID - int id = actionId( action ); - fmsg.message( QString( "action id = %1" ).arg( id ) ); - - // perform synchronous request to Python event dispatcher - class GUIEvent : public PyInterp_LockRequest - { - public: - GUIEvent( PyInterp_Interp* _py_interp, - SALOME_PYQT_Module* _obj, - int _id ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myId ( _id ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->guiEvent( myId ); - } - - private: - int myId; - SALOME_PYQT_Module* myObj; - }; - - // post request - PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) ); -} - -/*! - \brief Process context popup menu request. - - Called when user activates popup menu in some window - (view, object browser, etc). - - \param theContext popup menu context (e.g. "ObjectBrowser") - \param thePopupMenu popup menu - \param title popup menu title (not used) -*/ -void SALOME_PYQT_Module::contextMenuPopup( const QString& theContext, - QMenu* thePopupMenu, - QString& /*title*/ ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::contextMenuPopup()" ); - fmsg.message( QString( "context: %1" ).arg( theContext ) ); - - // perform synchronous request to Python event dispatcher - class PopupMenuEvent : public PyInterp_LockRequest - { - public: - PopupMenuEvent( PyInterp_Interp* _py_interp, - SALOME_PYQT_Module* _obj, - const QString& _context, - QMenu* _popup ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myContext( _context ), - myPopup ( _popup ), - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->contextMenu( myContext, myPopup ); - } - - private: - SALOME_PYQT_Module* myObj; - QString myContext; - QMenu* myPopup; - }; - - // post request only if dispatcher is not busy! - // execute request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new PopupMenuEvent( myInterp, this, theContext, thePopupMenu ) ); -} - -/*! - \brief Export preferences for the Python module. - - Called only once when the first instance of the module is created. -*/ -void SALOME_PYQT_Module::createPreferences() -{ - FuncMsg fmsg( "SALOME_PYQT_Module::createPreferences()" ); - - // perform synchronous request to Python event dispatcher - class Event : public PyInterp_LockRequest - { - public: - Event( PyInterp_Interp* _py_interp, - SALOME_PYQT_Module* _obj ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj ( _obj ) {} - - protected: - virtual void execute() - { - myObj->initPreferences(); - } - - private: - SALOME_PYQT_Module* myObj; - }; - - // post request only if dispatcher is not busy! - // execute request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this ) ); -} - -/*! - \brief Define the dockable windows associated with the module. - - To fill the list of windows the correspondind Python module's windows() - method is called from SALOME_PYQT_Module::init() method. - - By default, ObjectBrowser, PythonConsole and LogWindow windows are - associated to the module. - - Allowed dockable windows: - - SalomeApp_Application::WT_ObjectBrowser : object browser - - SalomeApp_Application::WT_PyConsole : python console - - SalomeApp_Application::WT_LogWindow : log messages output window - - Dock area is defined by Qt::DockWidgetArea enumeration: - - Qt::TopDockWidgetArea : top dock area - - Qt::BottomDockWidgetArea : bottom dock area - - Qt::LeftDockWidgetArea : left dock area - - Qt::RightDockWidgetArea : right dock area - - \param mappa map of dockable windows: { : } -*/ -void SALOME_PYQT_Module::windows( QMap& mappa ) const -{ - FuncMsg fmsg( "SALOME_PYQT_Module::windows()" ); - - mappa = myWindowsMap; -} - -/*! - \brief Define the compatible view windows associated with the module. - - The associated view windows are opened automatically when the module - is activated. - - To fill the list of views the correspondind Python module's views() - method is called from SALOME_PYQT_Module::init() method. - By default, the list is empty. - - \param listik list of view windows types -*/ -void SALOME_PYQT_Module::viewManagers( QStringList& lst ) const -{ - FuncMsg fmsg( "SALOME_PYQT_Module::viewManagers()" ); - - lst = myViewMgrList; -} - -/*! - \brief Process module's preferences changing. - - Called when the module's preferences are changed. - - \param section setting section - \param setting setting name -*/ -void SALOME_PYQT_Module::preferencesChanged( const QString& section, const QString& setting ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::preferencesChanged()" ); - - // perform synchronous request to Python event dispatcher - class Event : public PyInterp_LockRequest - { - public: - Event( PyInterp_Interp* _py_interp, - SALOME_PYQT_Module* _obj, - const QString& _section, - const QString& _setting ) - : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myObj ( _obj ), - mySection( _section ), - mySetting( _setting ) {} - - protected: - virtual void execute() - { - myObj->prefChanged( mySection, mySetting ); - } - - private: - SALOME_PYQT_Module* myObj; - QString mySection, mySetting; - }; - - // post request only if dispatcher is not busy! - // execut request synchronously - if ( !PyInterp_Dispatcher::Get()->IsBusy() ) - PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this, section, setting ) ); -} - -/*! - \brief Internal module initialization: - - Performs the following actions: - - initialize or get the Python interpreter (one per study) - - import the Python module - - pass the workspace widget to the Python module - - call Python module's initialize() method - - call Python module's windows() method - - call Python module's views() method - - \param app parent application object -*/ -void SALOME_PYQT_Module::init( CAM_Application* app ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::init()" ); - - // reset interpreter to NULL - myInterp = NULL; - - // get study Id - SalomeApp_Application* anApp = dynamic_cast( app ); - if ( !anApp ) - return; - SalomeApp_Study* aStudy = dynamic_cast( app->activeStudy() ); - if ( !aStudy ) - return; - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - // this module is being activated now! - myInitModule = this; - - // then call Python module's initialize() method - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - // ... (the Python module is already imported) - // ... finally call Python module's initialize() method - if ( PyObject_HasAttrString( myModule , "initialize" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "initialize", "" ) ); - if ( !res ) { - PyErr_Print(); - } - } - - // get required dockable windows list from the Python module - // by calling windows() method - // ... first put default values - myWindowsMap.insert( SalomeApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea ); - myWindowsMap.insert( SalomeApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea ); - myWindowsMap.insert( SalomeApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea ); - - if ( PyObject_HasAttrString( myModule , "windows" ) ) { - PyObjWrapper res1( PyObject_CallMethod( myModule, "windows", "" ) ); - if ( !res1 ) { - PyErr_Print(); - } - else { - myWindowsMap.clear(); - if ( PyDict_Check( res1 ) ) { - PyObject* key; - PyObject* value; - Py_ssize_t pos = 0; - while ( PyDict_Next( res1, &pos, &key, &value ) ) { - // parse the return value - // it should be a map: {integer:integer} - int aKey, aValue; - if( key && PyInt_Check( key ) && value && PyInt_Check( value ) ) { - aKey = PyInt_AsLong( key ); - aValue = PyInt_AsLong( value ); - myWindowsMap[ aKey ] = aValue; - } - } - } - } - } - - // get compatible view windows types from the Python module - // by calling views() method - if ( PyObject_HasAttrString( myModule , "views" ) ) { - PyObjWrapper res2( PyObject_CallMethod( myModule, "views", "" ) ); - if ( !res2 ) { - PyErr_Print(); - } - else { - // parse the return value - // result can be one string... - if ( PyString_Check( res2 ) ) { - myViewMgrList.append( PyString_AsString( res2 ) ); - } - // ... or list of strings - else if ( PyList_Check( res2 ) ) { - int size = PyList_Size( res2 ); - for ( int i = 0; i < size; i++ ) { - PyObject* value = PyList_GetItem( res2, i ); - if( value && PyString_Check( value ) ) { - myViewMgrList.append( PyString_AsString( value ) ); - } - } - } - } - } - // module is already activated! - myInitModule = 0; + SALOME_PYQT_ModuleLight::preferenceChanged(module,section,setting); } /*! - \brief Internal activation: - - Performs the following actions: - - initialize or get the Python interpreter (one per study) - - import the Python GUI module - - call Python module's activate() method - - \param theStudy parent study object + \brief Signal handler windowActivated(SUIT_ViewWindow*) of SUIT_Desktop + \param pview view being activated */ -void SALOME_PYQT_Module::activate( SUIT_Study* theStudy ) +void SALOME_PYQT_Module::onActiveViewChanged( SUIT_ViewWindow* pview ) { - FuncMsg fmsg( "SALOME_PYQT_Module::activate()" ); - - // get study Id - SalomeApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - // call Python module's activate() method (for the new modules) - if ( PyObject_HasAttrString( myModule , "activate" ) ) { - PyObject* res1 = PyObject_CallMethod( myModule, "activate", "" ); - if ( !res1 || !PyBool_Check( res1 ) ) { - PyErr_Print(); - // always true for old modules (no return value) - myLastActivateStatus = true; - } - else { - // detect return status - myLastActivateStatus = PyObject_IsTrue( res1 ); - } - } - - // Connect the SUIT_Desktop signal windowActivated() to this->onActiveViewChanged() - SUIT_Desktop* aDesk = theStudy->application()->desktop(); - if ( aDesk ) - { - connect( aDesk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), - this, SLOT( onActiveViewChanged( SUIT_ViewWindow* ) ) ); - // If a active window exists send activeViewChanged - // If a getActiveView() in SalomePyQt available we no longer need this - SUIT_ViewWindow* aView = aDesk->activeWindow(); - if ( aView ) - activeViewChanged( aView ); - - // get all view currently opened in the study and connect their signals to - // the corresponding slots of the class. - QList wndList = aDesk->windows(); - SUIT_ViewWindow* wnd; - foreach ( wnd, wndList ) - connectView( wnd ); - } + SALOME_PYQT_ModuleLight::onActiveViewChanged(pview); } /*! - \brief Additional customization after module is activated: - - Performs the following actions: - - get the Python interpreter (one per study) - - import the Python GUI module - - call Python module's setSettings() method (obsolete function, - used for compatibility with old code) - - \param theStudy parent study object + \brief Signal handler cloneView() of OCCViewer_ViewWindow + \param pview view being cloned */ -void SALOME_PYQT_Module::customize( SUIT_Study* theStudy ) +void SALOME_PYQT_Module::onViewCloned( SUIT_ViewWindow* pview ) { - FuncMsg fmsg( "SALOME_PYQT_Module::customize()" ); - - // get study Id - SalomeApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - if ( IsCallOldMethods ) { - // call Python module's setWorkspace() method - setWorkSpace(); - } - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - if ( IsCallOldMethods ) { - // call Python module's setSettings() method (obsolete) - if ( PyObject_HasAttrString( myModule , "setSettings" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "setSettings", "" ) ); - if( !res ) { - PyErr_Print(); - } - } - } -} - -/*! - \brief Internal deactivation: - - Performs the following actions: - - call Python module's deactivate() method - - \param theStudy parent study object -*/ -void SALOME_PYQT_Module::deactivate( SUIT_Study* theStudy ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::deactivate()" ); - - // check if the subinterpreter is initialized and Python module is imported - if ( !myInterp || !myModule ) { - // Error! Python subinterpreter should be initialized and module should be imported first! - return; - } - // then call Python module's deactivate() method - if ( PyObject_HasAttrString( myModule , "deactivate" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "deactivate", "" ) ); - if( !res ) { - PyErr_Print(); - } - } - - // Disconnect the SUIT_Desktop signal windowActivated() - SUIT_Desktop* aDesk = theStudy->application()->desktop(); - if ( aDesk ) - { - disconnect( aDesk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), - this, SLOT( onActiveViewChanged( SUIT_ViewWindow* ) ) ); - } -} - -/*! - \brief Perform internal actions when active study is changed. - - Called when active the study is actived (user brings its - desktop to top): - - initialize or get the Python interpreter (one per study) - - import the Python GUI module - - call Python module's activeStudyChanged() method - - \param theStudy study being activated -*/ -void SALOME_PYQT_Module::studyChanged( SUIT_Study* theStudy ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::studyChanged()" ); - - // get study Id - SalomeApp_Study* aStudy = dynamic_cast( theStudy ); - int aStudyId = aStudy ? aStudy->studyDS()->StudyId() : 0; - - // initialize Python subinterpreter (on per study) and put it in variable - initInterp( aStudyId ); - if ( !myInterp ) - return; // Error - - // import Python GUI module - importModule(); - if ( !myModule ) - return; // Error - - if ( IsCallOldMethods ) { - // call Python module's setWorkspace() method - setWorkSpace(); - } - - // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - // call Python module's activeStudyChanged() method - if ( PyObject_HasAttrString( myModule , "activeStudyChanged" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "activeStudyChanged", "i", aStudyId ) ); - if( !res ) { - PyErr_Print(); - } - } -} - -/*! - \brief Get module engine. - - Returns nil var if engine is not found in LifeCycleCORBA. - - \return module's engine reference -*/ -Engines::Component_var SALOME_PYQT_Module::getEngine() const -{ - FuncMsg fmsg( "SALOME_PYQT_Module::getEngine()" ); - - Engines::Component_var comp; - try { - comp = getApp()->lcc()->FindOrLoad_Component( "FactoryServerPy", name().toLatin1() ); - } - catch ( CORBA::Exception& ) { - } - return comp; -} - -/*! - \birief Get module engine IOR. - - Returns empty string if engine is not found in LifeCycleCORBA. - - \return module's engine IOR -*/ -QString SALOME_PYQT_Module::engineIOR() const -{ - FuncMsg fmsg( "SALOME_PYQT_Module::engineIOR()" ); - - QString anIOR = ""; - if ( !CORBA::is_nil( getEngine() ) ) - anIOR = getApp()->orb()->object_to_string( getEngine() ); - return anIOR; -} - -/*! - \brief Process (internally) context popup menu request. - - Performs the following actions: - - calls Python module's definePopup(...) method (obsolete function, - used for compatibility with old code) to define the popup menu context - - parses XML resourses file (if exists) and fills the popup menu with the items) - - calls Python module's customPopup(...) method (obsolete function, - used for compatibility with old code) to allow module to customize the popup menu - - for new modules calls createPopupMenu() function to allow the - modules to build the popup menu by using insertItem(...) Qt functions. - - \param theContext popup menu context - \param thePopupMenu popup menu -*/ -void SALOME_PYQT_Module::contextMenu( const QString& theContext, QMenu* thePopupMenu ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::contextMenu()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - QString aContext( "" ), aObject( "" ), aParent( theContext ); - - if ( IsCallOldMethods && PyObject_HasAttrString( myModule , "definePopup" ) ) { - // call definePopup() Python module's function - // this is obsolete function, used only for compatibility reasons - PyObjWrapper res( PyObject_CallMethod( myModule, - "definePopup", - "sss", - aContext.toLatin1().constData(), - aObject.toLatin1().constData(), - aParent.toLatin1().constData() ) ); - if( !res ) { - PyErr_Print(); - } - else { - // parse return value - char *co, *ob, *pa; - if( PyArg_ParseTuple( res, "sss", &co, &ob, &pa ) ) { - aContext = co; - aObject = ob; - aParent = pa; - } - } - } // if ( IsCallOldMethods ... ) - - // first try to create menu via XML parser: - // we create popup menus without help of QtxPopupMgr - if ( myXmlHandler ) - myXmlHandler->createPopup( thePopupMenu, aContext, aParent, aObject ); - - PyObjWrapper sipPopup( sipBuildResult( 0, "M", thePopupMenu, sipClass_QMenu ) ); - - // then call Python module's createPopupMenu() method (for new modules) - if ( PyObject_HasAttrString( myModule , "createPopupMenu" ) ) { - PyObjWrapper res1( PyObject_CallMethod( myModule, - "createPopupMenu", - "Os", - sipPopup.get(), - aContext.toLatin1().constData() ) ); - if( !res1 ) { - PyErr_Print(); - } - } - - if ( IsCallOldMethods && PyObject_HasAttrString( myModule , "customPopup" ) ) { - // call customPopup() Python module's function - // this is obsolete function, used only for compatibility reasons - PyObjWrapper res2( PyObject_CallMethod( myModule, - "customPopup", - "Osss", - sipPopup.get(), - aContext.toLatin1().constData(), - aObject.toLatin1().constData(), - aParent.toLatin1().constData() ) ); - if( !res2 ) { - PyErr_Print(); - } - } -} - -/*! - \brief Internal GUI event handling. - - Performs the following actions: - - calls Python module's OnGUIEvent() method - - \param theId GUI action ID -*/ -void SALOME_PYQT_Module::guiEvent( const int theId ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::guiEvent()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule , "OnGUIEvent" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "OnGUIEvent", "i", theId ) ); - if( !res ) { - PyErr_Print(); - } - } -} - -/*! - \brief Initialize (internally) preferences for the module. - - Performs the following actions: - - calls Python module's createPreferences() method -*/ -void SALOME_PYQT_Module::initPreferences() -{ - FuncMsg fmsg( "SALOME_PYQT_Module::initPreferences()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - // temporary set myInitModule because createPreferences() method - // might be called during the module intialization process - myInitModule = this; - - if ( PyObject_HasAttrString( myModule , "createPreferences" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "createPreferences", "" ) ); - if( !res ) { - PyErr_Print(); - } - } - - myInitModule = 0; -} - -/*! - \brief Initialize python subinterpreter (one per study). - \param theStudyId study ID -*/ -void SALOME_PYQT_Module::initInterp( int theStudyId ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::initInterp()" ); - - // check study Id - if ( !theStudyId ) { - // Error! Study Id must not be 0! - myInterp = NULL; - return; - } - // try to find the subinterpreter - if( myInterpMap.contains( theStudyId ) ) { - // found! - myInterp = myInterpMap[ theStudyId ]; - return; - } - // not found - create a new one! - /////////////////////////////////////////////////////////////////// - // Attention: the creation of Python interpretor must be protected - // by a C++ Lock because of C threads - /////////////////////////////////////////////////////////////////// - myInterp = new SALOME_PYQT_PyInterp(); - myInterp->initialize(); - myInterpMap[ theStudyId ] = myInterp; - - // import 'salome' module and call 'salome_init' method; - // do it only once on interpreter creation - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - // ... then import a module - PyObjWrapper aMod = PyImport_ImportModule( "salome" ); - if( !aMod ) { - // Error! - PyErr_Print(); - return; - } - // ... then call a method - int embedded = 1; - PyObjWrapper aRes( PyObject_CallMethod( aMod, "salome_init", "ii", theStudyId, embedded ) ); - if( !aRes ) { - // Error! - PyErr_Print(); - return; - } -} - -/*! - \brief Import Python GUI module and remember the reference to the module. - - Attention! initInterp() should be called first!!! -*/ -void SALOME_PYQT_Module::importModule() -{ - FuncMsg fmsg( "SALOME_PYQT_Module::importModule()" ); - - // check if the subinterpreter is initialized - if ( !myInterp ) { - // Error! Python subinterpreter should be initialized first! - myModule = 0; - return; - } - // import Python GUI module and puts it in attribute - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - // ... then import a module - QString aMod = name() + "GUI"; - myModule = PyImport_ImportModule( aMod.toLatin1().data() ); - if( !myModule ) { - // Error! - PyErr_Print(); - return; - } -} - -/*! - \brief Set study workspace to the Python module. - - Calls setWorkSpace() method of the Pythohn module with - PyQt QWidget object to use with interpreter. - - Attention! initInterp() and importModule() should be called first!!! -*/ -void SALOME_PYQT_Module::setWorkSpace() -{ - FuncMsg fmsg( "SALOME_PYQT_Module::setWorkSpace()" ); - - // check if the subinterpreter is initialized and Python module is imported - if ( !myInterp || !myModule ) { - // Error! Python subinterpreter should be initialized and module should be imported first! - return; - } - - // call setWorkspace() method - // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); - - // ... then try to import SalomePyQt module. If it's not possible don't go on. - PyObjWrapper aQtModule( PyImport_ImportModule( "SalomePyQt" ) ); - if( !aQtModule ) { - // Error! - PyErr_Print(); - return; - } - - if ( IsCallOldMethods ) { - // ... then get workspace object - QWidget* aWorkspace = 0; - if ( getApp()->desktop()->inherits( "STD_MDIDesktop" ) ) { - STD_MDIDesktop* aDesktop = dynamic_cast( getApp()->desktop() ); - if ( aDesktop ) - aWorkspace = aDesktop->workspace(); - } - else if ( getApp()->desktop()->inherits( "STD_TabDesktop" ) ) { - STD_TabDesktop* aDesktop = dynamic_cast( getApp()->desktop() ); - if ( aDesktop ) - aWorkspace = aDesktop->workstack(); - } - PyObjWrapper pyws( sipBuildResult( 0, "M", aWorkspace, sipClass_QWidget ) ); - // ... and finally call Python module's setWorkspace() method (obsolete) - if ( PyObject_HasAttrString( myModule , "setWorkSpace" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, "setWorkSpace", "O", pyws.get() ) ); - if( !res ) { - PyErr_Print(); - } - } - } -} - -/*! - \brief Preference changing callback function (internal). - - Performs the following actions: - - call Python module's preferenceChanged() method - - \param section setting section name - \param setting setting name -*/ -void SALOME_PYQT_Module::prefChanged( const QString& section, const QString& setting ) -{ - FuncMsg fmsg( "SALOME_PYQT_Module::prefChanged()" ); - - // Python interpreter should be initialized and Python module should be - // import first - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule , "preferenceChanged" ) ) { - PyObjWrapper res( PyObject_CallMethod( myModule, - "preferenceChanged", - "ss", - section.toLatin1().constData(), - setting.toLatin1().constData() ) ); - if( !res ) { - PyErr_Print(); - } - } -} - -/*! - \brief Get default menu group identifier - \return menu group ID (40 by default) -*/ -int SALOME_PYQT_Module::defaultMenuGroup() -{ - return DEFAULT_GROUP; -} - -// -// The next methods call the parent implementation. -// This is done to open protected methods from CAM_Module class. -// - -/*! - \brief Create toolbar with specified \a name. - \param name toolbar name - \return toolbar ID or -1 if toolbar creation is failed -*/ -int SALOME_PYQT_Module::createTool( const QString& name ) -{ - return SalomeApp_Module::createTool( name ); -} - -/*! - \brief Insert action with specified \a id to the toolbar. - \param id action ID - \param tBar toolbar ID - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createTool( const int id, const int tBar, const int idx ) -{ - return SalomeApp_Module::createTool( id, tBar, idx ); -} - -/*! - \brief Insert action with specified \a id to the toolbar. - \param id action ID - \param tBar toolbar name - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createTool( const int id, const QString& tBar, const int idx ) -{ - return SalomeApp_Module::createTool( id, tBar, idx ); -} - -/*! - \brief Insert action to the toolbar. - \param a action - \param tBar toolbar ID - \param id required action ID - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createTool( QAction* a, const int tBar, const int id, const int idx ) -{ - return SalomeApp_Module::createTool( a, tBar, id, idx ); -} - -/*! - \brief Insert action to the toolbar. - \param a action - \param tBar toolbar name - \param id required action ID - \param idx required index in the toolbar - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createTool( QAction* a, const QString& tBar, const int id, const int idx ) -{ - return SalomeApp_Module::createTool( a, tBar, id, idx ); -} - -/*! - \brief Create main menu. - \param subMenu menu name - \param menu parent menu ID - \param id required menu ID - \param group menu group ID - \param idx required index in the menu - \return menu ID or -1 if menu could not be added -*/ -int SALOME_PYQT_Module::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( subMenu, menu, id, group, idx ); -} - -/*! - \brief Create main menu. - \param subMenu menu name - \param menu parent menu name (list of menu names separated by "|") - \param id required menu ID - \param group menu group ID - \param idx required index in the menu - \return menu ID or -1 if menu could not be added -*/ -int SALOME_PYQT_Module::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( subMenu, menu, id, group, idx ); -} - -/*! - \brief Insert action to the main menu. - \param id action ID - \param menu parent menu ID - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createMenu( const int id, const int menu, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( id, menu, group, idx ); -} - -/*! - \brief Insert action to the main menu. - \param id action ID - \param menu parent menu name (list of menu names separated by "|") - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createMenu( const int id, const QString& menu, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( id, menu, group, idx ); -} - -/*! - \brief Insert action to the main menu. - \param a action - \param menu parent menu ID - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createMenu( QAction* a, const int menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( a, menu, id, group, idx ); -} - -/*! - \brief Insert action to the main menu. - \param a action - \param menu parent menu name (list of menu names separated by "|") - \param group menu group ID - \param idx required index in the menu - \return action ID or -1 if action could not be added -*/ -int SALOME_PYQT_Module::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx ) -{ - return SalomeApp_Module::createMenu( a, menu, id, group, idx ); -} - -/*! - \brief Create separator action which can be used in the menu or toolbar. - \return new separator action -*/ -QAction* SALOME_PYQT_Module::separator() -{ - return SalomeApp_Module::separator(); -} - -/*! - \brief Get action by specified \a id. - \return action or 0 if it is not found -*/ -QAction* SALOME_PYQT_Module::action( const int id ) const -{ - QAction* a = SalomeApp_Module::action( id ); - if ( !a ) { - // try menu - QMenu* m = menuMgr()->findMenu( id ); - if ( m ) a = m->menuAction(); - } - return a; -} - -/*! - \brief Get action identifier. - \return action ID or -1 if action is not registered -*/ -int SALOME_PYQT_Module::actionId( const QAction* a ) const -{ - return SalomeApp_Module::actionId( a ); -} - -/*! - \brief Create new action. - - If the action with specified identifier already registered - it is not created, but its attributes are only modified. - - \param id action ID - \param text tooltip text - \param icon icon - \param menu menu text - \param tip status tip - \param key keyboard shortcut - \param toggle \c true for checkable action - \return created action -*/ -QAction* SALOME_PYQT_Module::createAction( const int id, const QString& text, const QString& icon, - const QString& menu, const QString& tip, const int key, - const bool toggle, QObject* parent ) -{ - QIcon anIcon = loadIcon( icon ); - QAction* a = action( id ); - if ( a ) { - if ( a->toolTip().isEmpty() && !text.isEmpty() ) a->setToolTip( text ); - if ( a->text().isEmpty() && !menu.isEmpty() ) a->setText( menu ); - if ( a->icon().isNull() && !anIcon.isNull() ) a->setIcon( anIcon ); - if ( a->statusTip().isEmpty() && !tip.isEmpty() ) a->setStatusTip( tip ); - if ( a->shortcut().isEmpty() && key ) a->setShortcut( key ); - if ( a->isCheckable() != toggle ) a->setCheckable( toggle ); - disconnect( a, SIGNAL( triggered( bool ) ), this, SLOT( onGUIEvent() ) ); - connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onGUIEvent() ) ); - } - else { - a = SalomeApp_Module::createAction( id, - text, - anIcon, - menu, - tip, - key, - parent ? parent : this, - toggle, - this, - SLOT( onGUIEvent() ) ); - } - return a; -} - -/*! - \brief Create new action group. - - If the action with specified identifier already registered - it is not created, but its attributes are only modified. - - \param id action ID - \param text tooltip text - \param icon icon - \param menu menu text - \param tip status tip - \param key keyboard shortcut - \param toggle \c true for checkable action - \return created action -*/ -QtxActionGroup* SALOME_PYQT_Module::createActionGroup(const int id, const bool exclusive) -{ - QtxActionGroup* a = qobject_cast( action( id ) ); - if ( !a ) { - a = new QtxActionGroup( this ); - SalomeApp_Module::registerAction( id, a ); - } - a->setExclusive( exclusive ); - return a; -} - -/*! - \brief Load icon from resource file. - \param fileName icon file name - \return icon (null icon if loading failed) -*/ -QIcon SALOME_PYQT_Module::loadIcon( const QString& fileName ) -{ - QIcon anIcon; - if ( !fileName.isEmpty() ) { - QPixmap pixmap = getApp()->resourceMgr()->loadPixmap( name(), tr( fileName.toLatin1() ) ); - if ( !pixmap.isNull() ) - anIcon = QIcon( pixmap ); - } - return anIcon; -} - -/*! - \brief Add global application preference (for example, - application specific section). - \param label preference name - \return preference ID -*/ -int SALOME_PYQT_Module::addGlobalPreference( const QString& label ) -{ - LightApp_Preferences* pref = preferences(); - if ( !pref ) - return -1; - - return pref->addPreference( label, -1 ); -} - -/*! - \brief Add preference. - \param label preference name - \return preference ID -*/ -int SALOME_PYQT_Module::addPreference( const QString& label ) -{ - return SalomeApp_Module::addPreference( label ); -} - -/*! - \brief Add preference. - \param label preference name - \param pId parent preference ID - \param type preference type - \param section resource file section name - \param param resource file setting name - \return preference ID -*/ -int SALOME_PYQT_Module::addPreference( const QString& label, - const int pId, const int type, - const QString& section, - const QString& param ) -{ - return SalomeApp_Module::addPreference( label, pId, type, section, param ); -} - -/*! - \brief Get the preference property. - \param id preference ID - \param prop property name - \return property value (invalid QVariant() if property is not found) -*/ -QVariant SALOME_PYQT_Module::preferenceProperty( const int id, - const QString& prop ) const -{ - QVariant v = SalomeApp_Module::preferenceProperty( id, prop ); - return v; -} - -/*! - \brief Set the preference property. - \param id preference ID - \param prop property name - \param var property value -*/ -void SALOME_PYQT_Module::setPreferenceProperty( const int id, - const QString& prop, - const QVariant& var ) -{ - SalomeApp_Module::setPreferenceProperty( id, prop, var ); -} - - -/*! - \brief Signal handler windowActivated(SUIT_ViewWindow*) of SUIT_Desktop - \param pview view being activated -*/ -void SALOME_PYQT_Module::onActiveViewChanged( SUIT_ViewWindow* pview ) -{ - class ActiveViewChange : public PyInterp_LockRequest - { - public: - ActiveViewChange( PyInterp_Interp* _py_interp, SALOME_PYQT_Module* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj),myView(_pview) {} - - protected: - virtual void execute() - { - myObj->activeViewChanged( myView ); - } - - private: - SALOME_PYQT_Module* myObj; - const SUIT_ViewWindow * myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ActiveViewChange( myInterp, this, pview ) ); -} - -/*! - \brief Processes the view changing, calls Python module's activeViewChanged() method - \param pview view being activated -*/ -void SALOME_PYQT_Module::activeViewChanged( const SUIT_ViewWindow* pview ) -{ - if ( !myInterp || !myModule ) - return; - - // Do not use SUIT_ViewWindow::closing() signal here. View manager reacts on - // this signal and deletes view. So our slot does not works if it is connected - // on this signal. SUIT_ViewManager::deleteView(SUIT_ViewWindow*) is used here - - connectView( pview ); - - if ( PyObject_HasAttrString( myModule, "activeViewChanged" ) ) - { - if ( !pview ) - return; - - PyObjWrapper res( PyObject_CallMethod( myModule, "activeViewChanged", "i" , pview->getId() ) ); - if( !res ) - PyErr_Print(); - } -} - -/*! - \brief Signal handler cloneView() of OCCViewer_ViewWindow - \param pview view being cloned -*/ -void SALOME_PYQT_Module::onViewCloned( SUIT_ViewWindow* pview ) -{ - class ViewClone : public PyInterp_LockRequest - { - public: - ViewClone( PyInterp_Interp* _py_interp, SALOME_PYQT_Module* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj), myView(_pview) {} - - protected: - virtual void execute() - { - myObj->viewCloned( myView ); - } - - private: - SALOME_PYQT_Module* myObj; - const SUIT_ViewWindow* myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ViewClone( myInterp, this, pview ) ); -} - -/*! - \brief Processes the view cloning, calls Python module's activeViewCloned() method - \param pview view being cloned -*/ -void SALOME_PYQT_Module::viewCloned( const SUIT_ViewWindow* pview ) -{ - if ( !myInterp || !myModule || !pview ) - return; - - if ( PyObject_HasAttrString( myModule, "viewCloned" ) ) - { - PyObjWrapper res( PyObject_CallMethod( myModule, "viewCloned", "i", pview->getId() ) ); - if( !res ) - PyErr_Print(); - } -} - -/*! - \brief Signal handler closing(SUIT_ViewWindow*) of a view - \param pview view being closed -*/ -void SALOME_PYQT_Module::onViewClosed( SUIT_ViewWindow* pview ) -{ - class ViewClose : public PyInterp_LockRequest - { - public: - ViewClose( PyInterp_Interp* _py_interp, SALOME_PYQT_Module* _obj, const SUIT_ViewWindow* _pview ) - : PyInterp_LockRequest( _py_interp, 0, true ), - myObj(_obj),myView(_pview) {} - - protected: - virtual void execute() - { - myObj->viewClosed( myView ); - } - - private: - SALOME_PYQT_Module* myObj; - const SUIT_ViewWindow * myView; - }; - - PyInterp_Dispatcher::Get()->Exec( new ViewClose( myInterp, this, pview ) ); -} - -/*! - \brief Processes the view closing, calls Python module's viewClosed() method - \param pview view being closed -*/ -void SALOME_PYQT_Module::viewClosed( const SUIT_ViewWindow* pview ) -{ - if ( !myInterp || !myModule ) - return; - - if ( PyObject_HasAttrString( myModule, "viewClosed" ) ) - { - PyObjWrapper res( PyObject_CallMethod( myModule, "viewClosed", "i", pview->getId() ) ); - if ( !res ) - { - PyErr_Print(); - } - } -} - -/*! - \brief Connects or disconnects signals about activating and cloning view on the module slots - \param pview view which is connected/disconnected -*/ -void SALOME_PYQT_Module::connectView( const SUIT_ViewWindow* pview ) -{ - SUIT_ViewManager* viewMgr = pview->getViewManager(); - SUIT_ViewModel* viewModel = viewMgr ? viewMgr->getViewModel() : 0; - - if ( viewMgr ) - { - disconnect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), - this, SLOT( onViewClosed( SUIT_ViewWindow* ) ) ); - - connect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), - this, SLOT( onViewClosed( SUIT_ViewWindow* ) ) ); - } - - // Connect cloneView() signal of an OCC View - if ( pview->inherits( "OCCViewer_ViewWindow" ) ) - { - disconnect( pview, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - connect( pview, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - } - // Connect cloneView() signal of Plot2d View manager - else if ( viewModel && viewModel->inherits( "Plot2d_Viewer" ) ) - { - disconnect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - connect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), - this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); - } -} - -/*! - \brief Get tag name for the DOM element. - \param element DOM element - \return empty string if the element does not have tag name - \internal -*/ -static QString tagName( const QDomElement& element ) -{ - return element.tagName().trimmed(); -} - -/*! - \brief Get DOM element's attribute by its name. - \param element DOM element - \param attName attribute name - \return empty string if the element does not have such attribute - \internal -*/ -static QString attribute( const QDomElement& element, const QString& attName ) -{ - return element.attribute( attName ).trimmed(); -} - -/*! - \brief Inspect specified string for the boolean value. - - This function returns \c true if string represents boolean value: - - "true", "yes" or "1" for \c true - - "false", "no" or "0" for \c false - Second parameter allows to specify what boolean value is expected: - - 1: \c true - - 0: \c false - - other value is not taken into account (return represented value) - - \param value inspected string - \param check expected boolean value - \return boolean value represented by the string (\a check is not 1 or 0) - or \c true if value correspond to the specified \a check -*/ -static bool checkBool( const QString& value, const int check = -1 ) -{ - QString v = value.toLower(); - if ( ( v == "true" || v == "yes" || v == "1" ) && ( check != 0 ) ) - return true; - if ( ( v == "false" || v == "no" || v == "0" ) && ( check == 0 ) ) - return true; - return false; -} - -/*! - \brief Inspect specified string for the integer value. - - This function returns returns -1 if item is empty or represents - an invalid number. - \param value inspected string - \param def default value - \param shift shift value (it is added to the integer value to produce shifted result) -*/ -static int checkInt( const QString& value, const int def = -1, const int shift = -1 ) -{ - bool bOk; - int val = value.toInt( &bOk ); - if ( !bOk ) val = def; - if ( shift > 0 && bOk && val < 0 ) - val += shift; - return val; -} - -/*! - \brief Constructor - \internal - \param module parent module pointer - \param fileName XML file path -*/ -SALOME_PYQT_Module::XmlHandler::XmlHandler( SALOME_PYQT_Module* module, - const QString& fileName ) -: myModule( module ) -{ - if ( fileName.isEmpty() ) - return; - QFile aFile( fileName ); - if ( !aFile.open( QIODevice::ReadOnly ) ) - return; - myDoc.setContent( &aFile ); - aFile.close(); -} - -/*! - \brief Parse XML file and create actions. - \internal - - Called by SALOME_PYQT_Module::activate() in order to create actions - (menus, toolbars). -*/ -void SALOME_PYQT_Module::XmlHandler::createActions() -{ - // get document element - QDomElement aDocElem = myDoc.documentElement(); - - // create main menu actions - QDomNodeList aMenuList = aDocElem.elementsByTagName( "menu-item" ); - for ( int i = 0; i < aMenuList.count(); i++ ) { - QDomNode n = aMenuList.item( i ); - createMenu( n ); - } - - // create toolbars actions - QDomNodeList aToolsList = aDocElem.elementsByTagName( "toolbar" ); - for ( int i = 0; i < aToolsList.count(); i++ ) { - QDomNode n = aToolsList.item( i ); - createToolBar( n ); - } -} - -/*! - \brief Create popup menu. - \internal - \param menu popup menu - \param context popup menu context - \param context popup menu parent object name - \param context popup menu object name -*/ -void SALOME_PYQT_Module::XmlHandler::createPopup( QMenu* menu, - const QString& context, - const QString& parent, - const QString& object ) -{ - // get document element - QDomElement aDocElem = myDoc.documentElement(); - - // get popup menus actions - QDomNodeList aPopupList = aDocElem.elementsByTagName( "popupmenu" ); - for ( int i = 0; i < aPopupList.count(); i++ ) { - QDomNode n = aPopupList.item( i ); - if ( !n.isNull() && n.isElement() ) { - QDomElement e = n.toElement(); - // QString lab = attribute( e, "label-id" ); // not used // - QString ctx = attribute( e, "context-id" ); - QString prt = attribute( e, "parent-id" ); - QString obj = attribute( e, "object-id" ); - if ( ctx == context && prt == parent && obj == object ) { - insertPopupItems( n, menu ); - break; - } - } - } -} - -/*! - \brief Activate menus - \internal - \param enable if \c true menus are activated, otherwise menus are deactivated -*/ -void SALOME_PYQT_Module::XmlHandler::activateMenus( bool enable ) -{ - if ( !myModule ) - return; - - QtxActionMenuMgr* mgr = myModule->menuMgr(); - int id; - foreach( id, myMenuItems ) mgr->setEmptyEnabled( id, enable ); -} - -/*! - \brief Create main menu item and insert actions to it. - \internal - \param parentNode XML node with menu description - \param parentMenuId parent menu ID (-1 for top-level menu) - \param parentPopup parent popup menu (0 for top-level menu) -*/ -void SALOME_PYQT_Module::XmlHandler::createMenu( QDomNode& parentNode, - const int parentMenuId, - QMenu* parentPopup ) -{ - if ( !myModule || parentNode.isNull() ) - return; - - QDomElement parentElement = parentNode.toElement(); - if ( !parentElement.isNull() ) { - QString plabel = attribute( parentElement, "label-id" ); - int pid = checkInt( attribute( parentElement, "item-id" ) ); - int ppos = checkInt( attribute( parentElement, "pos-id" ) ); - int group = checkInt( attribute( parentElement, "group-id" ), - myModule->defaultMenuGroup() ); - if ( !plabel.isEmpty() ) { - QMenu* popup = 0; - int menuId = -1; - // create menu - menuId = myModule->createMenu( plabel, // label - parentMenuId, // parent menu ID, -1 for top-level menu - pid, // ID - group, // group ID - ppos ); // position - myMenuItems.append( menuId ); - QDomNode node = parentNode.firstChild(); - while ( !node.isNull() ) { - if ( node.isElement() ) { - QDomElement elem = node.toElement(); - QString aTagName = tagName( elem ); - if ( aTagName == "popup-item" ) { - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - int group = checkInt( attribute( elem, "group-id" ), - myModule->defaultMenuGroup() ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - QString tooltip = attribute( elem, "tooltip-id" ); - QString accel = attribute( elem, "accel-id" ); - bool toggle = checkBool( attribute( elem, "toggle-id" ) ); - - // -1 action ID is not allowed : it means that attribute is missed in the XML file! - // also check if the action with given ID is already created - if ( id != -1 ) { - // create menu action - QAction* action = myModule->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - toggle ); // toogled action - myModule->createMenu( action, // action - menuId, // parent menu ID - id, // ID (same as for createAction()) - group, // group ID - pos ); // position - } - } - else if ( aTagName == "submenu" ) { - // create sub-menu - createMenu( node, menuId, popup ); - } - else if ( aTagName == "separator" ) { - // create menu separator - int id = checkInt( attribute( elem, "item-id" ) ); // separator can have ID - int pos = checkInt( attribute( elem, "pos-id" ) ); - int group = checkInt( attribute( elem, "group-id" ), - myModule->defaultMenuGroup() ); - QAction* action = myModule->separator(); - myModule->createMenu( action, // separator action - menuId, // parent menu ID - id, // ID - group, // group ID - pos ); // position - } - } - node = node.nextSibling(); - } - } - } -} - -/*! - \brief Create a toolbar and insert actions to it. - \param parentNode XML node with toolbar description -*/ -void SALOME_PYQT_Module::XmlHandler::createToolBar( QDomNode& parentNode ) -{ - if ( !myModule || parentNode.isNull() ) - return; - - QDomElement parentElement = parentNode.toElement(); - if ( !parentElement.isNull() ) { - QString aLabel = attribute( parentElement, "label-id" ); - if ( !aLabel.isEmpty() ) { - // create toolbar - int tbId = myModule->createTool( aLabel ); - QDomNode node = parentNode.firstChild(); - while ( !node.isNull() ) { - if ( node.isElement() ) { - QDomElement elem = node.toElement(); - QString aTagName = tagName( elem ); - if ( aTagName == "toolbutton-item" ) { - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - QString tooltip = attribute( elem, "tooltip-id" ); - QString accel = attribute( elem, "accel-id" ); - bool toggle = checkBool( attribute( elem, "toggle-id" ) ); - - // -1 action ID is not allowed : it means that attribute is missed in the XML file! - // also check if the action with given ID is already created - if ( id != -1 ) { - // create toolbar action - QAction* action = myModule->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - toggle ); // toogled action - myModule->createTool( action, tbId, -1, pos ); - } - } - else if ( aTagName == "separatorTB" || aTagName == "separator" ) { - // create toolbar separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - QAction* action = myModule->separator(); - myModule->createTool( action, tbId, -1, pos ); - } - } - node = node.nextSibling(); - } - } - } -} - -/*! - \brief Fill popup menu with the items. - \param parentNode XML node with popup menu description - \param menu popup menu -*/ -void SALOME_PYQT_Module::XmlHandler::insertPopupItems( QDomNode& parentNode, QMenu* menu ) -{ - if ( !myModule && parentNode.isNull() ) - return; - - // we create popup menus without help of QtxPopupMgr - QDomNode node = parentNode.firstChild(); - while ( !node.isNull() ) { - if ( node.isElement() ) { - QDomElement elem = node.toElement(); - QString aTagName = tagName( elem ); - QList actions = menu->actions(); - if ( aTagName == "popup-item" ) { - // insert a command item - int id = checkInt( attribute( elem, "item-id" ) ); - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - QString tooltip = attribute( elem, "tooltip-id" ); - QString accel = attribute( elem, "accel-id" ); - bool toggle = checkBool( attribute( elem, "toggle-id" ) ); - - // -1 action ID is not allowed : it means that attribute is missed in the XML file! - // also check if the action with given ID is already created - if ( id != -1 ) { - QAction* action = myModule->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - toggle ); // toogled action - QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; - menu->insertAction( before, action ); - } - } - else if ( aTagName == "submenu" ) { - // create sub-menu - ////int id = checkInt( attribute( elem, "item-id" ) ); // not used // - int pos = checkInt( attribute( elem, "pos-id" ) ); - QString label = attribute( elem, "label-id" ); - QString icon = attribute( elem, "icon-id" ); - - QIcon anIcon; - if ( !icon.isEmpty() ) { - QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(), icon ); - if ( !pixmap.isNull() ) - anIcon = QIcon( pixmap ); - } - - QMenu* newPopup = menu->addMenu( anIcon, label ); - QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; - menu->insertMenu( before, newPopup ); - insertPopupItems( node, newPopup ); - } - else if ( aTagName == "separator" ) { - // create menu separator - int pos = checkInt( attribute( elem, "pos-id" ) ); - QAction* action = myModule->separator(); - QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; - menu->insertAction( before, action ); - } - } - node = node.nextSibling(); - } + SALOME_PYQT_ModuleLight::onViewCloned(pview); } diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h index 3283416ad..3e1166ef2 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.h @@ -25,143 +25,41 @@ #ifndef SALOME_PYQT_MODULE_H #define SALOME_PYQT_MODULE_H -#include "SALOME_PYQT_GUI.h" -#include "SALOME_PYQT_PyInterp.h" // this include must be first (see PyInterp_Interp.h)! - -#include - -#include -#include -#include -#include - +#include "SALOME_PYQT_PyInterp.h" // this include must be first (see PyInterp_base.h)!*/ +#include "SALOME_PYQT_ModuleLight.h" +#include "SalomeApp_Module.h" #include #include CORBA_CLIENT_HEADER(SALOME_Component) -class SALOME_PYQT_PyInterp; -class SUIT_ViewWindow; -class QAction; -class QtxActionGroup; -class QMenu; -class SALOME_PYQT_EXPORT SALOME_PYQT_Module: public SalomeApp_Module + +class SALOME_PYQT_EXPORT SALOME_PYQT_Module: public SalomeApp_Module, + public SALOME_PYQT_ModuleLight { Q_OBJECT; -private: - class XmlHandler; - - //! study to Python subinterpreter map - typedef QMap InterpMap; - - static InterpMap myInterpMap; //!< study to Python subinterpreter map - SALOME_PYQT_PyInterp* myInterp; //!< current Python subinterpreter - PyObjWrapper myModule; //!< Python GUI module - static SALOME_PYQT_Module* myInitModule; //!< Python GUI being initialized (not zero only during the initialization) - - XmlHandler* myXmlHandler; //!< XML resource file parser - QMap myWindowsMap; //!< windows map - QStringList myViewMgrList;//!< compatible view managers list - - bool myLastActivateStatus; //!< latest module activation status - -public: + public: SALOME_PYQT_Module(); ~SALOME_PYQT_Module(); -public: - static SALOME_PYQT_Module* getInitModule(); - - void initialize( CAM_Application* ); - void windows( QMap& ) const; - void viewManagers( QStringList& ) const; - void contextMenuPopup( const QString&, QMenu*, QString& ); - void createPreferences(); - QString engineIOR() const; - void studyActivated(); - void preferencesChanged( const QString&, const QString& ); - - static int defaultMenuGroup(); + /* get module engine IOR */ + virtual QString engineIOR() const; - int createTool( const QString& ); - int createTool( const int, const int, const int = -1 ); - int createTool( const int, const QString&, const int = -1 ); - int createTool( QAction*, const int, - const int = -1, const int = -1 ); - int createTool( QAction*, const QString&, - const int = -1, const int = -1 ); - - int createMenu( const QString&, const int, - const int = -1, const int = -1, const int = -1 ); - int createMenu( const QString&, const QString&, - const int = -1, const int = -1, const int = -1 ); - int createMenu( const int, const int, - const int = -1, const int = -1 ); - int createMenu( const int, const QString&, - const int = -1, const int = -1 ); - int createMenu( QAction*, const int, - const int = -1, const int = -1, const int = -1 ); - int createMenu( QAction*, const QString&, - const int = -1, const int = -1, const int = -1 ); - - QAction* separator(); - - QAction* action( const int ) const; - int actionId( const QAction* ) const; - QAction* createAction( const int, const QString&, const QString&, - const QString&, const QString&, const int, - const bool = false, QObject* = 0 ); - QtxActionGroup* createActionGroup( const int, const bool ); - - - QIcon loadIcon( const QString& fileName ); - - int addGlobalPreference( const QString& ); - int addPreference( const QString& ); - int addPreference( const QString&, const int, const int = LightApp_Preferences::Auto, - const QString& = QString(), - const QString& = QString() ); - QVariant preferenceProperty( const int, const QString& ) const; - void setPreferenceProperty( const int, const QString&, - const QVariant& ); - -public slots: - virtual bool activateModule( SUIT_Study* ); - virtual bool deactivateModule( SUIT_Study* ); + public slots: void preferenceChanged( const QString&, const QString&, const QString& ); void onGUIEvent(); - void onActiveViewChanged( SUIT_ViewWindow* ); void onViewClosed( SUIT_ViewWindow* ); void onViewCloned( SUIT_ViewWindow* ); -protected: - Engines::Component_var getEngine() const; + protected: + /* create data model */ + virtual CAM_DataModel* createDataModel(); -private: - void init( CAM_Application* ); - void activate( SUIT_Study* ); - void deactivate( SUIT_Study* ); - bool lastActivationStatus() const; - void customize( SUIT_Study* ); - void studyChanged( SUIT_Study* ); - void contextMenu( const QString&, QMenu* ); - void guiEvent( const int ); - void initPreferences(); - void prefChanged( const QString&, const QString& ); - - void initInterp ( int ); - void importModule(); - void setWorkSpace(); - - void activeViewChanged( const SUIT_ViewWindow* ); - void viewClosed( const SUIT_ViewWindow* ); - void viewCloned( const SUIT_ViewWindow* ); - void connectView( const SUIT_ViewWindow* ); + Engines::Component_var getEngine() const; - friend class XmlHandler; }; #endif // SALOME_PYQT_MODULE_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am b/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am new file mode 100644 index 000000000..36358c6cc --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am @@ -0,0 +1,107 @@ +# Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +# +# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# File : Makefile.am +# Author : Roman NIKOLAEV Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) + + +include $(top_srcdir)/adm_local/unix/make_common_starter.am + +# Library target +lib_LTLIBRARIES = libSalomePyQtGUILight.la + + +# extra source files (generated by sip) +SIP_SRC = sipAPISalomePyQtGUILight.h \ + sipSalomePyQtGUILightcmodule.cc + +# Sip definition file +SIP_FILES = SALOME_PYQT_GUILight.sip + +# extra dist files +EXTRA_DIST += $(SIP_FILES) + + +# extra clean files +CLEANFILES = $(SIP_SRC) + +# moc files (generated my moc) +MOC_FILES = \ + SALOME_PYQT_ModuleLight_moc.cxx \ + SALOME_PYQT_DataModelLight_moc.cxx + + +# exported header files +salomeinclude_HEADERS = \ + SALOME_PYQT_GUILight.h \ + SALOME_PYQT_ModuleLight.h \ + SALOME_PYQT_DataObjectLight.h \ + SALOME_PYQT_DataModelLight.h \ + SALOME_PYQT_PyInterp.h + +# library sources +dist_libSalomePyQtGUILight_la_SOURCES = \ + SALOME_PYQT_ModuleLight.cxx \ + SALOME_PYQT_DataObjectLight.cxx \ + SALOME_PYQT_DataModelLight.cxx \ + SALOME_PYQT_PyInterp.cxx + +nodist_libSalomePyQtGUILight_la_SOURCES = $(MOC_FILES) $(SIP_SRC) + + +libSalomePyQtGUILight_la_CPPFLAGS = $(QT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INCLUDES) \ + $(CAS_CPPFLAGS) $(VTK_INCLUDES) $(OGL_INCLUDES) $(BOOST_CPPFLAGS) \ + -DHAVE_CONFIG_H @KERNEL_CXXFLAGS@ -DCALL_OLD_METHODS \ + -I@builddir@ -I$(srcdir)/../../PyInterp -I$(srcdir)/../../PyConsole \ + -I$(srcdir)/../../SUIT -I$(srcdir)/../../Qtx -I$(srcdir)/../../LightApp \ + -I$(srcdir)/../../Plot2d -I$(srcdir)/../../OCCViewer \ + -I$(srcdir)/../../CAM -I$(srcdir)/../../STD \ + -I$(srcdir)/../../SUITApp \ + -I$(srcdir)/../../CAM -I$(srcdir)/../../STD + +if GUI_ENABLE_CORBA +libSalomePyQtGUILight_la_CPPFLAGS += -I$(srcdir)/../../SalomeApp \ + -I$(top_builddir)/salome_adm/unix \ + @CORBA_CXXFLAGS@ @CORBA_INCLUDES@ +endif + + +if !GUI_ENABLE_CORBA + libSalomePyQtGUILight_la_CPPFLAGS += -DGUI_DISABLE_CORBA +endif + +# linkage flags +libSalomePyQtGUILight_la_LIBADD = $(PYTHON_LIBS) $(SIP_LIBS) $(PYQT_LIBS) $(VTK_LIBS) \ + $(OGL_LIBS) ../../PyInterp/libPyInterp.la + +if GUI_ENABLE_CORBA + libSalomePyQtGUILight_la_LIBADD +=../../SalomeApp/libSalomeApp.la +endif + + + +# Custom build step: generate C++ wrapping according to $(SIP_FILES) +$(SIP_SRC): $(SIP_FILES) + $(SIP) $(PYQT_SIPFLAGS) $< + +# extra dependency (SALOME_PYQT_Module.cxx depends on header files generated by sip) +$(dist_libSalomePyQtGUILight_la_SOURCES): $(SIP_SRC) + diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx new file mode 100644 index 000000000..614dfba64 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx @@ -0,0 +1,167 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + +#include "PyInterp_Interp.h" // // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! + +#include "SALOME_PYQT_DataModelLight.h" +#include "SALOME_PYQT_DataObjectLight.h" +#include "SALOME_PYQT_ModuleLight.h" +#include + +#include +#include +#include +#include + + +//================================================================================= +// function : SALOME_PYQT_DataModelLight() +// purpose : constructor +//================================================================================= +SALOME_PYQT_DataModelLight::SALOME_PYQT_DataModelLight(CAM_Module * theModule) + : LightApp_DataModel( theModule ), + myFileName( "" ), + myStudyURL( "" ) +{ + +} + +//================================================================================= +// function : ~SALOME_PYQT_DataModelLight() +// purpose : destructor +//================================================================================= +SALOME_PYQT_DataModelLight::~SALOME_PYQT_DataModelLight() +{ +} + +//================================================================================= +// function : open() +// purpose : Open data model operation +//================================================================================= +bool SALOME_PYQT_DataModelLight::open( const QString& theURL, CAM_Study* study, QStringList theListOfFiles) +{ + MESSAGE("SALOME_PYQT_DataModelLight::open()"); + LightApp_Study* aDoc = dynamic_cast( study ); + SALOME_PYQT_ModuleLight* aModule = dynamic_cast(module()); + if ( !aDoc || !aModule) + return false; + + LightApp_DataModel::open( theURL, aDoc, theListOfFiles ); + + return aModule->open(theListOfFiles); + +} + +//================================================================================= +// function : save() +// purpose : Save data model operation +//================================================================================= +bool SALOME_PYQT_DataModelLight::save( QStringList& theListOfFiles) +{ + MESSAGE("SALOME_PYQT_DataModelLight::save()"); + bool isMultiFile = false; // temporary solution + + LightApp_DataModel::save(theListOfFiles); + LightApp_Study* study = dynamic_cast( module()->application()->activeStudy() ); + SALOME_PYQT_ModuleLight* aModule = dynamic_cast(module()); + + if(!aModule || !study) + return false; + + + std::string aTmpDir = study->GetTmpDir(myStudyURL.toLatin1().constData(), isMultiFile ); + + theListOfFiles.append(QString(aTmpDir.c_str())); + int listSize = theListOfFiles.size(); + aModule->save(theListOfFiles); + //Return true if in the List of files was added item(s) + //else return false + return theListOfFiles.size() > listSize; +} + +//================================================================================= +// function : saveAs() +// purpose : SaveAs data model operation +//================================================================================= +bool SALOME_PYQT_DataModelLight::saveAs ( const QString& theURL, CAM_Study* theStudy, QStringList& theListOfFiles) +{ + myStudyURL = theURL; + return save(theListOfFiles); +} + + + +bool SALOME_PYQT_DataModelLight::create( CAM_Study* study ) +{ + return true; +} + +//================================================================================= +// function : isModified() +// purpose : default implementation, always returns false so as not to mask study's isModified() +//================================================================================= +bool SALOME_PYQT_DataModelLight::isModified() const +{ + return false; +} + +//================================================================================= +// function : isSaved() +// purpose : default implementation, always returns true so as not to mask study's isSaved() +//================================================================================= +bool SALOME_PYQT_DataModelLight::isSaved() const +{ + return true; +} + + +//================================================================================= +// function : close() +// purpose : Close data model operation +//================================================================================= +bool SALOME_PYQT_DataModelLight::close() +{ + LightApp_DataModel::close(); + return true; +} + + +void SALOME_PYQT_DataModelLight::update ( LightApp_DataObject* theObj, LightApp_Study* theStudy ) +{ + // Nothing to do here: we always keep the data tree in the up-to-date state + // The only goal of this method is to hide default behavior from LightApp_DataModel + return; +} + +LightApp_ModuleObject* SALOME_PYQT_DataModelLight::getRoot() +{ + LightApp_Study* study = dynamic_cast( module()->application()->activeStudy() ); + LightApp_ModuleObject *aModelRoot = dynamic_cast(root()); + if(aModelRoot == NULL) { + aModelRoot = new LightApp_ModuleObject(this,study->root()); + aModelRoot->setDataModel( this ); + setRoot(aModelRoot); + } + return aModelRoot; +} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h new file mode 100644 index 000000000..b5beead31 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h @@ -0,0 +1,64 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + +#ifndef SALOME_PYQT_DATAMODELLIGHT_H +#define SALOME_PYQT_DATAMODELLIGHT_H + +#include "SALOME_PYQT_GUILight.h" +#include + +#include +#include "SALOME_PYQT_DataObjectLight.h" + +class SALOME_PYQT_RootObjectLight; + + + +class SALOME_PYQT_EXPORT SALOME_PYQT_DataModelLight : public LightApp_DataModel +{ + Q_OBJECT + +public: + SALOME_PYQT_DataModelLight( CAM_Module* theModule ); + virtual ~SALOME_PYQT_DataModelLight(); + + virtual bool open ( const QString&, CAM_Study*, QStringList ); + virtual bool save ( QStringList& ); + virtual bool saveAs ( const QString&, CAM_Study*, QStringList& ); + virtual bool close (); + virtual bool create ( CAM_Study* ); + + virtual bool isModified () const; + virtual bool isSaved () const; + + virtual void update ( LightApp_DataObject* = 0, LightApp_Study* = 0 ); + + LightApp_ModuleObject* getRoot(); + + private: + QString myFileName; + QString myStudyURL; +}; + +#endif // SALOME_PYQT_DATAMODELLIGHT_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataObjectLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataObjectLight.cxx new file mode 100644 index 000000000..9e0ef56d6 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataObjectLight.cxx @@ -0,0 +1,130 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + + +#include "SALOME_PYQT_DataObjectLight.h" +#include +#include +#include +#include + + +#include +#include + + +/*! + * Class: SALOME_PYQT_DataObjectLight + * Description: LIGHT PYTHON module's data object + */ + +static int _ID = 0; + +//================================================================================= +// function : SALOME_PYQT_DataObjectLight() +// purpose : constructor +//================================================================================= +SALOME_PYQT_DataObjectLight::SALOME_PYQT_DataObjectLight ( SUIT_DataObject* parent ) + : CAM_DataObject(parent), + LightApp_DataObject( parent ) + +{ + _ID++; + myEntry = QString("PYLIGHT_OBJ_%1").arg(_ID); +} + +//================================================================================= +// function : SALOME_PYQT_DataObjectLight() +// purpose : destructor +//================================================================================= +SALOME_PYQT_DataObjectLight::~SALOME_PYQT_DataObjectLight() +{ + +} + +//================================================================================= +// function : SALOME_PYQT_DataObjectLight::entry() +// purpose : return entry of object +//================================================================================= +QString SALOME_PYQT_DataObjectLight::entry() const +{ + return myEntry; +} + +//================================================================================= +// function : SALOME_PYQT_DataObjectLight::name() +// purpose : return name of object +//================================================================================= +QString SALOME_PYQT_DataObjectLight::name() const +{ + return myName; +} + +//================================================================================= +// function : SALOME_PYQT_DataObjectLight::icon() +// purpose : return icon of object +//================================================================================= +QPixmap SALOME_PYQT_DataObjectLight::icon(const int index) const +{ + if(index == NameId) + return myIcon; + else + return LightApp_DataObject::icon( index ); +} + + +//================================================================================= +// function : SALOME_PYQT_DataObjectLight::toolTip() +// purpose : return toolTip of object +//================================================================================= +QString SALOME_PYQT_DataObjectLight::toolTip(const int index) const +{ + return myToolTip; +} + + +void SALOME_PYQT_DataObjectLight::setName(const QString& name) +{ + myName = name; +} + +void SALOME_PYQT_DataObjectLight::setIcon(const QString& iconname) +{ + if(!iconname.isEmpty()) { + LightApp_Application* anApp = dynamic_cast( SUIT_Session::session()->activeApplication() ); + if(anApp) { + QString modulename = anApp->activeModule()->name(); + if(!modulename.isEmpty()) + { + myIcon = SUIT_Session::session()->resourceMgr()->loadPixmap(modulename, + QObject::tr(iconname.toLatin1())); + } + } + } +} + +void SALOME_PYQT_DataObjectLight::setToolTip(const QString& tooltip) +{ + myToolTip = tooltip; +} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataObjectLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataObjectLight.h new file mode 100644 index 000000000..024feebfd --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataObjectLight.h @@ -0,0 +1,64 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + + +#ifndef SALOME_PYQT_DATAOBJECTLIGHT_H +#define SALOME_PYQT_DATAOBJECTLIGHT_H + + +#include "SALOME_PYQT_GUILight.h" +#include +#include + +#include + +/*! + * SALOME_PYQT_DataObjectLight - PYTHON LIGHT module's data object class + */ +class SALOME_PYQT_EXPORT SALOME_PYQT_DataObjectLight : public virtual LightApp_DataObject +{ + + public: + SALOME_PYQT_DataObjectLight( SUIT_DataObject* = 0 ); + + virtual ~SALOME_PYQT_DataObjectLight(); + + virtual QString entry() const; + + virtual QString name() const; + QPixmap icon(const int = NameId) const; + QString toolTip(const int = NameId) const; + + void setName(const QString& name); + void setIcon(const QString& icon); + void setToolTip(const QString& tooltip); + + private: + QString myEntry; + QString myName; + QString myToolTip; + QPixmap myIcon; +}; + +#endif // SALOME_PYQT_DATAOBJECTLIGHT_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_GUILight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_GUILight.h new file mode 100644 index 000000000..ada818fd7 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_GUILight.h @@ -0,0 +1,52 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SALOME_PYQT_GUI.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#if !defined ( SALOME_PYQT_GUILIGHT_H ) +#define SALOME_PYQT_GUIILIGHT_H + +// ======================================================== +// set dllexport type for Win platform +#ifdef WNT + +#ifdef SALOME_PYQT_EXPORTS +#define SALOME_PYQT_EXPORT __declspec(dllexport) +#else +#define SALOME_PYQT_EXPORT __declspec(dllimport) +#endif + +#else // WNT + +#define SALOME_PYQT_EXPORT + +#endif // WNT + +// ======================================================== +// avoid warning messages +#ifdef WNT +#pragma warning (disable : 4786) +#pragma warning (disable : 4251) +#endif + +#endif // SALOME_PYQT_GUIILIGHT_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_GUILight.sip b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_GUILight.sip new file mode 100644 index 000000000..df8efca88 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_GUILight.sip @@ -0,0 +1,29 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SALOME_PYQT_GUI.sip +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +%Module SalomePyQtGUILight + +%Import QtGuimod.sip +%Import QtXmlmod.sip diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx new file mode 100644 index 000000000..8b83c84fe --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx @@ -0,0 +1,2693 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SALOME_PYQT_Module.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#include +#include +#include +#include +#include +#include + +#include "SALOME_PYQT_ModuleLight.h" +#include "SALOME_PYQT_DataModelLight.h" + +#ifndef GUI_DISABLE_CORBA +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include "sipAPISalomePyQtGUILight.h" + +#include +#if SIP_VERSION < 0x040700 +#include "sipQtGuiQWidget.h" +#include "sipQtGuiQMenu.h" +#endif + +#include + +/*! + \brief Default name of the module, replaced at the moment + of module creation. + \internal +*/ +const char* DEFAULT_NAME = "SALOME_PYQT_ModuleLight"; + +/*! + \brief Default menu group number. + \internal +*/ +const int DEFAULT_GROUP = 40; + +/*! + \var IsCallOldMethods + \brief Allow calling obsolete callback methods. + \internal + + If the macro CALL_OLD_METHODS is not defined, the invoking + of obsolete Python module's methods like setSetting(), definePopup(), + etc. is blocked. + + CALL_OLD_METHODS macro can be defined for example by adding + -DCALL_OLD_METHODS compilation option to the Makefile. +*/ +#ifdef CALL_OLD_METHODS +const bool IsCallOldMethods = true; +#else +const bool IsCallOldMethods = false; +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +#endif + +// +// NB: Python requests. +// General rule for Python requests created by SALOME_PYQT_Module: +// all requests should be executed SYNCHRONOUSLY within the main GUI thread. +// However, it is obligatory that ANY Python call is wrapped with a request object, +// so that ALL Python API calls are serialized with PyInterp_Dispatcher. +// + +/*! + \class SALOME_PYQT_Module::XmlHandler + \brief XML resource files parser. + \internal + + This class is used to provide backward compatibility with + existing Python modules in which obsolete menu definition system + (via XML files) is used. +*/ + +class SALOME_PYQT_ModuleLight::XmlHandler +{ +public: + XmlHandler( SALOME_PYQT_ModuleLight* module, const QString& fileName ); + void createActions(); + void createPopup ( QMenu* menu, + const QString& context, + const QString& parent, + const QString& object ); + void activateMenus( bool ); + +protected: + void createToolBar ( QDomNode& parentNode ); + void createMenu ( QDomNode& parentNode, + const int parentMenuId = -1, + QMenu* parentPopup = 0 ); + + void insertPopupItems( QDomNode& parentNode, + QMenu* menu ); + +private: + SALOME_PYQT_ModuleLight* myModule; + QDomDocument myDoc; + QList myMenuItems; +}; + +// +// NB: Library initialization +// Since the SalomePyQtGUILight library is not imported in Python it's initialization function +// should be called manually (and only once) in order to initialize global sip data +// and to get C API from sip : sipBuildResult for example +// + +#define INIT_FUNCTION initSalomePyQtGUILight +#if defined(SIP_STATIC_MODULE) +extern "C" void INIT_FUNCTION(); +#else +PyMODINIT_FUNC INIT_FUNCTION(); +#endif + +/*! + \fn CAM_Module* createModule() + \brief Module factory function. + \internal + + Creates an instance of SALOME_PYQT_Module object by request + of an application when the module is loaded and initialized. + + \return new module object +*/ + +extern "C" { + SALOME_PYQT_EXPORT CAM_Module* createModule() { + + static bool alreadyInitialized = false; + if ( !alreadyInitialized ) { + // call only once (see comment above) ! + static PyThreadState *gtstate = 0; +#ifndef GUI_DISABLE_CORBA + if(SUIT_PYTHON::initialized) + gtstate = SUIT_PYTHON::_gtstate; + else + gtstate = KERNEL_PYTHON::_gtstate; +#else + gtstate = SUIT_PYTHON::_gtstate; +#endif + PyEval_RestoreThread( gtstate ); + INIT_FUNCTION(); + PyEval_ReleaseThread( gtstate ); + alreadyInitialized = !alreadyInitialized; + } + return new SALOME_PYQT_ModuleLight(); + } +} + +/*! + \class FuncMsg + \brief Function call in/out tracer. + \internal +*/ + +class FuncMsg +{ +public: + FuncMsg( const QString& funcName ) + { + myName = funcName; + MESSAGE( myName.toLatin1().constData() << " [ begin ]" ); + } + ~FuncMsg() + { + MESSAGE( myName.toLatin1().constData() << " [ end ]" ); + } + void message( const QString& msg ) + { + MESSAGE( myName.toLatin1().constData() << " : " << msg.toLatin1().constData() ); + } +private: + QString myName; +}; + +/*! + \class SALOME_PYQT_ModuleLight + \brief This class implements module API for all the Python-based + SALOME modules. +*/ + +// +// Static variables definition +// +SALOME_PYQT_ModuleLight::InterpMap SALOME_PYQT_ModuleLight::myInterpMap; +SALOME_PYQT_ModuleLight* SALOME_PYQT_ModuleLight::myInitModule = 0; + +/*! + \brief Get the module being initialized. + + This is a little trick :) needed to provide an access from Python + (SalomePyQt) to the module being currently activated. The problem + that during the process of module initialization (initialize() + function) it is not yet available via application->activeModule() + call. + + This method returns valid pointer only if called in scope of + initialize() function. + + \return the module being currently initialized +*/ +SALOME_PYQT_ModuleLight* SALOME_PYQT_ModuleLight::getInitModule() +{ + return myInitModule; +} + +/*! + \brief Constructor +*/ +SALOME_PYQT_ModuleLight::SALOME_PYQT_ModuleLight() +: LightApp_Module( DEFAULT_NAME ), + myInterp( 0 ), + myModule( 0 ), + myXmlHandler ( 0 ), + myLastActivateStatus( true ) +{ +} + +/*! + \brief Destructor +*/ +SALOME_PYQT_ModuleLight::~SALOME_PYQT_ModuleLight() +{ + if ( myXmlHandler ) + delete myXmlHandler; +} + +/*! + \brief Initialization of the module. + + This method can be used for creation of the menus, toolbars and + other such staff. + + There are two ways to do this: + - for obsolete modules this method first tries to read + _.xml resource file which contains a menu, + toolbars and popup menus description; + - new modules can create menus by direct calling of the + corresponding methods of SalomePyQt Python API in the Python + module's initialize() method which is called from here. + + NOTE: SALOME supports two modes of modules loading: + - immediate (all the modules are created and initialized + immediately when the application object is created; + - postponed modules loading (used currently); in this mode + the module is loaded only be request. + If postponed modules loading is not used, the active + study might be not yet defined at this stage, so initialize() + method should not perform any study-based initialization. + + \param app parent application object +*/ +void SALOME_PYQT_ModuleLight::initialize( CAM_Application* app ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::initialize()" ); + + // call base implementation + LightApp_Module::initialize( app ); + + // try to get XML resource file name + SUIT_ResourceMgr* aResMgr = getApp()->resourceMgr(); + if ( !myXmlHandler && aResMgr ) { + // get current language + QString aLang = aResMgr->stringValue( "language", "language", QString() ); + if ( aLang.isEmpty() ) + aLang = "en"; + // define resource file name + QString aFileName = name() + "_" + aLang + ".xml"; + aFileName = aResMgr->path( "resources", name(), aFileName ); + // create XML handler instance + if ( !aFileName.isEmpty() && QFile::exists( aFileName ) ) + myXmlHandler = new SALOME_PYQT_ModuleLight::XmlHandler( this, aFileName ); + // create menus & toolbars from XML file if required + if ( myXmlHandler ) + myXmlHandler->createActions(); + } + + // perform internal initialization and call module's initialize() funtion + // InitializeReq: request class for internal init() operation + class InitializeReq : public PyInterp_Request + { + public: + InitializeReq( CAM_Application* _app, + SALOME_PYQT_ModuleLight* _obj ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myApp( _app ), + myObj( _obj ) {} + + protected: + virtual void execute() + { + myObj->init( myApp ); + } + + private: + CAM_Application* myApp; + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new InitializeReq( app, this ) ); +} + +/*! + \brief Activation of the module. + + This function is usually used in order to show the module's + specific menus and toolbars, update actions state and perform + other such actions required when the module is activated. + + Note, that returning \c false in this function prevents the + module activation. + + \param theStudy parent study + \return \c true if activation is successful and \c false otherwise +*/ +bool SALOME_PYQT_ModuleLight::activateModule( SUIT_Study* theStudy ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::activateModule()" ); + + // call base implementation + bool res = LightApp_Module::activateModule( theStudy ); + + if ( !res ) + return res; + + // reset the activation status to the default value + myLastActivateStatus = true; + + // perform internal activation + // ActivateReq: request class for internal activate() operation + class ActivateReq : public PyInterp_Request + { + public: + ActivateReq( SUIT_Study* _study, + SALOME_PYQT_ModuleLight* _obj ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myStudy ( _study ), + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->activate( myStudy ); + } + + private: + SUIT_Study* myStudy; + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new ActivateReq( theStudy, this ) ); + + // check activation status (set by activate()) + if ( !lastActivationStatus() ) + return false; + + // activate menus, toolbars, etc + if ( myXmlHandler ) myXmlHandler->activateMenus( true ); + setMenuShown( true ); + setToolShown( true ); + + // connect preferences changing signal + connect( getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), + this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); + + // perform custom activation actions + // CustomizeReq: request class for internal customize() operation + class CustomizeReq : public PyInterp_Request + { + public: + CustomizeReq( SUIT_Study* _study, + SALOME_PYQT_ModuleLight* _obj ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myStudy ( _study ), + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->customize( myStudy ); + } + + private: + SUIT_Study* myStudy; + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new CustomizeReq( theStudy, this ) ); + + return true; +} + +/*! + \brief Deactivation of the module. + + This function is usually used in order to hide the module's + specific menus and toolbars and perform other such actions + required when the module is deactivated. + + \param theStudy parent study + \return \c true if deactivation is successful and \c false otherwise +*/ +bool SALOME_PYQT_ModuleLight::deactivateModule( SUIT_Study* theStudy ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::deactivateModule()" ); + + // disconnect preferences changing signal + disconnect( getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), + this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); + + // perform internal deactivation + // DeactivateReq: request class for internal deactivate() operation + class DeactivateReq : public PyInterp_LockRequest + { + public: + DeactivateReq( PyInterp_Interp* _py_interp, + SUIT_Study* _study, + SALOME_PYQT_ModuleLight* _obj ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myStudy ( _study ), + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->deactivate( myStudy ); + } + + private: + SUIT_Study* myStudy; + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new DeactivateReq( myInterp, theStudy, this ) ); + + // deactivate menus, toolbars, etc + if ( myXmlHandler ) myXmlHandler->activateMenus( false ); + setMenuShown( false ); + setToolShown( false ); + + // call base implementation + return LightApp_Module::deactivateModule( theStudy ); +} + +/*! + \brief Get last activation status. + \return status of last module activation operation + \sa activateModule() +*/ +bool SALOME_PYQT_ModuleLight::lastActivationStatus() const +{ + return myLastActivateStatus; +} + +/*! + \breif Process application preferences changing. + + Called when any application setting is changed. + + \param module preference module + \param section preference resource file section + \param setting preference resource name +*/ +void SALOME_PYQT_ModuleLight::preferenceChanged( const QString& module, + const QString& section, + const QString& setting ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::preferenceChanged()" ); + + // perform synchronous request to Python event dispatcher + class Event : public PyInterp_LockRequest + { + public: + Event( PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + const QString& _section, + const QString& _setting ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myObj ( _obj ), + mySection( _section ), + mySetting( _setting ) {} + + protected: + virtual void execute() + { + myObj->prefChanged( mySection, mySetting ); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + QString mySection, mySetting; + }; + + if ( module != moduleName() ) { + // module's own preferences are processed by preferencesChanged() method + // ... + // post the request only if dispatcher is not busy! + // execute request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this, section, setting ) ); + } +} + +/*! + \brief Process study activation. + + Called when study desktop is activated. Used for notifying the Python + module about changing of the active study. +*/ +void SALOME_PYQT_ModuleLight::studyActivated() +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::studyActivated()" ); + + // StudyChangedReq: request class for internal studyChanged() operation + class StudyChangedReq : public PyInterp_Request + { + public: + StudyChangedReq( SUIT_Study* _study, + SALOME_PYQT_ModuleLight* _obj ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myStudy ( _study ), + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->studyChanged( myStudy ); + } + + private: + SUIT_Study* myStudy; + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new StudyChangedReq( application()->activeStudy(), this ) ); +} + +/*! + \brief Process GUI action (from main menu, toolbar or + context popup menu action). +*/ +void SALOME_PYQT_ModuleLight::onGUIEvent() +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::onGUIEvent()" ); + + // get sender action + QAction* action = qobject_cast( sender() ); + if ( !action ) + return; + + // get action ID + int id = actionId( action ); + fmsg.message( QString( "action id = %1" ).arg( id ) ); + + // perform synchronous request to Python event dispatcher + class GUIEvent : public PyInterp_LockRequest + { + public: + GUIEvent( PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + int _id ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myId ( _id ), + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->guiEvent( myId ); + } + + private: + int myId; + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request + PyInterp_Dispatcher::Get()->Exec( new GUIEvent( myInterp, this, id ) ); +} + +/*! + \brief Process context popup menu request. + + Called when user activates popup menu in some window + (view, object browser, etc). + + \param theContext popup menu context (e.g. "ObjectBrowser") + \param thePopupMenu popup menu + \param title popup menu title (not used) +*/ +void SALOME_PYQT_ModuleLight::contextMenuPopup( const QString& theContext, + QMenu* thePopupMenu, + QString& /*title*/ ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::contextMenuPopup()" ); + fmsg.message( QString( "context: %1" ).arg( theContext ) ); + + // perform synchronous request to Python event dispatcher + class PopupMenuEvent : public PyInterp_LockRequest + { + public: + PopupMenuEvent( PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + const QString& _context, + QMenu* _popup ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myContext( _context ), + myPopup ( _popup ), + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->contextMenu( myContext, myPopup ); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + QString myContext; + QMenu* myPopup; + }; + + // post request only if dispatcher is not busy! + // execute request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new PopupMenuEvent( myInterp, this, theContext, thePopupMenu ) ); +} + +/*! + \brief Export preferences for the Python module. + + Called only once when the first instance of the module is created. +*/ +void SALOME_PYQT_ModuleLight::createPreferences() +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::createPreferences()" ); + + // perform synchronous request to Python event dispatcher + class Event : public PyInterp_LockRequest + { + public: + Event( PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myObj ( _obj ) {} + + protected: + virtual void execute() + { + myObj->initPreferences(); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + }; + + // post request only if dispatcher is not busy! + // execute request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this ) ); +} + +/*! + \brief Define the dockable windows associated with the module. + + To fill the list of windows the correspondind Python module's windows() + method is called from SALOME_PYQT_ModuleLight::init() method. + + By default, ObjectBrowser, PythonConsole and LogWindow windows are + associated to the module. + + Allowed dockable windows: + - LightApp_Application::WT_ObjectBrowser : object browser + - LightApp_Application::WT_PyConsole : python console + - LightApp_Application::WT_LogWindow : log messages output window + + Dock area is defined by Qt::DockWidgetArea enumeration: + - Qt::TopDockWidgetArea : top dock area + - Qt::BottomDockWidgetArea : bottom dock area + - Qt::LeftDockWidgetArea : left dock area + - Qt::RightDockWidgetArea : right dock area + + \param mappa map of dockable windows: { : } +*/ +void SALOME_PYQT_ModuleLight::windows( QMap& mappa ) const +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::windows()" ); + + mappa = myWindowsMap; +} + +/*! + \brief Define the compatible view windows associated with the module. + + The associated view windows are opened automatically when the module + is activated. + + To fill the list of views the correspondind Python module's views() + method is called from SALOME_PYQT_ModuleLight::init() method. + By default, the list is empty. + + \param listik list of view windows types +*/ +void SALOME_PYQT_ModuleLight::viewManagers( QStringList& lst ) const +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::viewManagers()" ); + + lst = myViewMgrList; +} + +/*! + \brief Process module's preferences changing. + + Called when the module's preferences are changed. + + \param section setting section + \param setting setting name +*/ +void SALOME_PYQT_ModuleLight::preferencesChanged( const QString& section, const QString& setting ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::preferencesChanged()" ); + + // perform synchronous request to Python event dispatcher + class Event : public PyInterp_LockRequest + { + public: + Event( PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + const QString& _section, + const QString& _setting ) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myObj ( _obj ), + mySection( _section ), + mySetting( _setting ) {} + + protected: + virtual void execute() + { + myObj->prefChanged( mySection, mySetting ); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + QString mySection, mySetting; + }; + + // post request only if dispatcher is not busy! + // execut request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new Event( myInterp, this, section, setting ) ); +} + +/*! + \brief Internal module initialization: + + Performs the following actions: + - initialize or get the Python interpreter (one per study) + - import the Python module + - pass the workspace widget to the Python module + - call Python module's initialize() method + - call Python module's windows() method + - call Python module's views() method + + \param app parent application object +*/ +void SALOME_PYQT_ModuleLight::init( CAM_Application* app ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::init()" ); + + // reset interpreter to NULL + myInterp = NULL; + + // get study Id + LightApp_Application* anApp = dynamic_cast( app ); + if ( !anApp ) + return; + LightApp_Study* aStudy = dynamic_cast( app->activeStudy() ); + if ( !aStudy ) + return; + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) + return; // Error + + // import Python GUI module + importModule(); + if ( !myModule ) + return; // Error + + // this module is being activated now! + myInitModule = this; + + // then call Python module's initialize() method + // ... first get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + // ... (the Python module is already imported) + // ... finally call Python module's initialize() method + if ( PyObject_HasAttrString( myModule , "initialize" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "initialize", "" ) ); + if ( !res ) { + PyErr_Print(); + } + } + + // get required dockable windows list from the Python module + // by calling windows() method + // ... first put default values + myWindowsMap.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea ); + myWindowsMap.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea ); + myWindowsMap.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea ); + + if ( PyObject_HasAttrString( myModule , "windows" ) ) { + PyObjWrapper res1( PyObject_CallMethod( myModule, "windows", "" ) ); + if ( !res1 ) { + PyErr_Print(); + } + else { + myWindowsMap.clear(); + if ( PyDict_Check( res1 ) ) { + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + while ( PyDict_Next( res1, &pos, &key, &value ) ) { + // parse the return value + // it should be a map: {integer:integer} + int aKey, aValue; + if( key && PyInt_Check( key ) && value && PyInt_Check( value ) ) { + aKey = PyInt_AsLong( key ); + aValue = PyInt_AsLong( value ); + myWindowsMap[ aKey ] = aValue; + } + } + } + } + } + + // get compatible view windows types from the Python module + // by calling views() method + if ( PyObject_HasAttrString( myModule , "views" ) ) { + PyObjWrapper res2( PyObject_CallMethod( myModule, "views", "" ) ); + if ( !res2 ) { + PyErr_Print(); + } + else { + // parse the return value + // result can be one string... + if ( PyString_Check( res2 ) ) { + myViewMgrList.append( PyString_AsString( res2 ) ); + } + // ... or list of strings + else if ( PyList_Check( res2 ) ) { + int size = PyList_Size( res2 ); + for ( int i = 0; i < size; i++ ) { + PyObject* value = PyList_GetItem( res2, i ); + if( value && PyString_Check( value ) ) { + myViewMgrList.append( PyString_AsString( value ) ); + } + } + } + } + } + // module is already activated! + myInitModule = 0; +} + +/*! + \brief Internal activation: + + Performs the following actions: + - initialize or get the Python interpreter (one per study) + - import the Python GUI module + - call Python module's activate() method + + \param theStudy parent study object +*/ +void SALOME_PYQT_ModuleLight::activate( SUIT_Study* theStudy ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::activate()" ); + + // get study Id + LightApp_Study* aStudy = dynamic_cast( theStudy ); + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) + return; // Error + + // import Python GUI module + importModule(); + if ( !myModule ) + return; // Error + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + // call Python module's activate() method (for the new modules) + if ( PyObject_HasAttrString( myModule , "activate" ) ) { + PyObject* res1 = PyObject_CallMethod( myModule, "activate", "" ); + if ( !res1 || !PyBool_Check( res1 ) ) { + PyErr_Print(); + // always true for old modules (no return value) + myLastActivateStatus = true; + } + else { + // detect return status + myLastActivateStatus = PyObject_IsTrue( res1 ); + } + } + + // Connect the SUIT_Desktop signal windowActivated() to this->onActiveViewChanged() + SUIT_Desktop* aDesk = theStudy->application()->desktop(); + if ( aDesk ) + { + connect( aDesk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), + this, SLOT( onActiveViewChanged( SUIT_ViewWindow* ) ) ); + // If a active window exists send activeViewChanged + // If a getActiveView() in SalomePyQt available we no longer need this + SUIT_ViewWindow* aView = aDesk->activeWindow(); + if ( aView ) + activeViewChanged( aView ); + + // get all view currently opened in the study and connect their signals to + // the corresponding slots of the class. + QList wndList = aDesk->windows(); + SUIT_ViewWindow* wnd; + foreach ( wnd, wndList ) + connectView( wnd ); + } +} + +/*! + \brief Additional customization after module is activated: + + Performs the following actions: + - get the Python interpreter (one per study) + - import the Python GUI module + - call Python module's setSettings() method (obsolete function, + used for compatibility with old code) + + \param theStudy parent study object +*/ +void SALOME_PYQT_ModuleLight::customize( SUIT_Study* theStudy ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::customize()" ); + + // get study Id + LightApp_Study* aStudy = dynamic_cast( theStudy ); + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) + return; // Error + + // import Python GUI module + importModule(); + if ( !myModule ) + return; // Error + + if ( IsCallOldMethods ) { + // call Python module's setWorkspace() method + setWorkSpace(); + } + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + if ( IsCallOldMethods ) { + // call Python module's setSettings() method (obsolete) + if ( PyObject_HasAttrString( myModule , "setSettings" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "setSettings", "" ) ); + if( !res ) { + PyErr_Print(); + } + } + } +} + +/*! + \brief Internal deactivation: + + Performs the following actions: + - call Python module's deactivate() method + + \param theStudy parent study object +*/ +void SALOME_PYQT_ModuleLight::deactivate( SUIT_Study* theStudy ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::deactivate()" ); + + // check if the subinterpreter is initialized and Python module is imported + if ( !myInterp || !myModule ) { + // Error! Python subinterpreter should be initialized and module should be imported first! + return; + } + // then call Python module's deactivate() method + if ( PyObject_HasAttrString( myModule , "deactivate" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "deactivate", "" ) ); + if( !res ) { + PyErr_Print(); + } + } + + // Disconnect the SUIT_Desktop signal windowActivated() + SUIT_Desktop* aDesk = theStudy->application()->desktop(); + if ( aDesk ) + { + disconnect( aDesk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), + this, SLOT( onActiveViewChanged( SUIT_ViewWindow* ) ) ); + } +} + +/*! + \brief Perform internal actions when active study is changed. + + Called when active the study is actived (user brings its + desktop to top): + - initialize or get the Python interpreter (one per study) + - import the Python GUI module + - call Python module's activeStudyChanged() method + + \param theStudy study being activated +*/ +void SALOME_PYQT_ModuleLight::studyChanged( SUIT_Study* theStudy ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::studyChanged()" ); + + // get study Id + LightApp_Study* aStudy = dynamic_cast( theStudy ); + int aStudyId = aStudy ? aStudy->id() : 0; + + // initialize Python subinterpreter (on per study) and put it in variable + initInterp( aStudyId ); + if ( !myInterp ) + return; // Error + + // import Python GUI module + importModule(); + if ( !myModule ) + return; // Error + + if ( IsCallOldMethods ) { + // call Python module's setWorkspace() method + setWorkSpace(); + } + + // get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + // call Python module's activeStudyChanged() method + if ( PyObject_HasAttrString( myModule , "activeStudyChanged" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "activeStudyChanged", "i", aStudyId ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Process (internally) context popup menu request. + + Performs the following actions: + - calls Python module's definePopup(...) method (obsolete function, + used for compatibility with old code) to define the popup menu context + - parses XML resourses file (if exists) and fills the popup menu with the items) + - calls Python module's customPopup(...) method (obsolete function, + used for compatibility with old code) to allow module to customize the popup menu + - for new modules calls createPopupMenu() function to allow the + modules to build the popup menu by using insertItem(...) Qt functions. + + \param theContext popup menu context + \param thePopupMenu popup menu +*/ +void SALOME_PYQT_ModuleLight::contextMenu( const QString& theContext, QMenu* thePopupMenu ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::contextMenu()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule ) + return; + + QString aContext( "" ), aObject( "" ), aParent( theContext ); + + if ( IsCallOldMethods && PyObject_HasAttrString( myModule , "definePopup" ) ) { + // call definePopup() Python module's function + // this is obsolete function, used only for compatibility reasons + PyObjWrapper res( PyObject_CallMethod( myModule, + "definePopup", + "sss", + theContext.toLatin1().constData(), + aObject.toLatin1().constData(), + aParent.toLatin1().constData() ) ); + if( !res ) { + PyErr_Print(); + } + else { + // parse return value + char *co, *ob, *pa; + if( PyArg_ParseTuple( res, "sss", &co, &ob, &pa ) ) { + aContext = co; + aObject = ob; + aParent = pa; + } + } + } // if ( IsCallOldMethods ... ) + + // first try to create menu via XML parser: + // we create popup menus without help of QtxPopupMgr + if ( myXmlHandler ) + myXmlHandler->createPopup( thePopupMenu, aContext, aParent, aObject ); + + PyObjWrapper sipPopup( sipBuildResult( 0, "M", thePopupMenu, sipClass_QMenu ) ); + + // then call Python module's createPopupMenu() method (for new modules) + if ( PyObject_HasAttrString( myModule , "createPopupMenu" ) ) { + PyObjWrapper res1( PyObject_CallMethod( myModule, + "createPopupMenu", + "Os", + sipPopup.get(), + theContext.toLatin1().constData() ) ); + if( !res1 ) { + PyErr_Print(); + } + } + + if ( IsCallOldMethods && PyObject_HasAttrString( myModule , "customPopup" ) ) { + // call customPopup() Python module's function + // this is obsolete function, used only for compatibility reasons + PyObjWrapper res2( PyObject_CallMethod( myModule, + "customPopup", + "Osss", + sipPopup.get(), + aContext.toLatin1().constData(), + aObject.toLatin1().constData(), + aParent.toLatin1().constData() ) ); + if( !res2 ) { + PyErr_Print(); + } + } +} + +/*! + \brief Internal GUI event handling. + + Performs the following actions: + - calls Python module's OnGUIEvent() method + + \param theId GUI action ID +*/ +void SALOME_PYQT_ModuleLight::guiEvent( const int theId ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::guiEvent()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule ) + return; + + if ( PyObject_HasAttrString( myModule , "OnGUIEvent" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "OnGUIEvent", "i", theId ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Initialize (internally) preferences for the module. + + Performs the following actions: + - calls Python module's createPreferences() method +*/ +void SALOME_PYQT_ModuleLight::initPreferences() +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::initPreferences()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule ) + return; + + // temporary set myInitModule because createPreferences() method + // might be called during the module intialization process + myInitModule = this; + + if ( PyObject_HasAttrString( myModule , "createPreferences" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "createPreferences", "" ) ); + if( !res ) { + PyErr_Print(); + } + } + + myInitModule = 0; +} + +/*! + \brief Initialize python subinterpreter (one per study). + \param theStudyId study ID +*/ +void SALOME_PYQT_ModuleLight::initInterp( int theStudyId ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::initInterp()" ); + + // check study Id + if ( !theStudyId ) { + // Error! Study Id must not be 0! + myInterp = NULL; + return; + } + // try to find the subinterpreter + if( myInterpMap.contains( theStudyId ) ) { + // found! + myInterp = myInterpMap[ theStudyId ]; + return; + } + + myInterp = new SALOME_PYQT_PyInterp(); + if(!myInterp) + return; + + myInterp->initialize(); + myInterpMap[ theStudyId ] = myInterp; + +#ifndef GUI_DISABLE_CORBA + if(!SUIT_PYTHON::initialized) { + // import 'salome' module and call 'salome_init' method; + // do it only once on interpreter creation + // ... first get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + // ... then import a module + PyObjWrapper aMod = PyImport_ImportModule( "salome" ); + if( !aMod ) { + // Error! + PyErr_Print(); + return; + } + // ... then call a method + int embedded = 1; + PyObjWrapper aRes( PyObject_CallMethod( aMod, "salome_init", "ii", theStudyId, embedded ) ); + if( !aRes ) { + // Error! + PyErr_Print(); + return; + } + } +#endif +} + +/*! + \brief Import Python GUI module and remember the reference to the module. + + Attention! initInterp() should be called first!!! +*/ +void SALOME_PYQT_ModuleLight::importModule() +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::importModule()" ); + + // check if the subinterpreter is initialized + if ( !myInterp ) { + // Error! Python subinterpreter should be initialized first! + myModule = 0; + return; + } + // import Python GUI module and puts it in attribute + // ... first get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + // ... then import a module + QString aMod = name() + "GUI"; + myModule = PyImport_ImportModule( aMod.toLatin1().data() ); + if( !myModule ) { + // Error! + PyErr_Print(); + return; + } +} + +/*! + \brief Set study workspace to the Python module. + + Calls setWorkSpace() method of the Pythohn module with + PyQt QWidget object to use with interpreter. + + Attention! initInterp() and importModule() should be called first!!! +*/ +void SALOME_PYQT_ModuleLight::setWorkSpace() +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::setWorkSpace()" ); + + // check if the subinterpreter is initialized and Python module is imported + if ( !myInterp || !myModule ) { + // Error! Python subinterpreter should be initialized and module should be imported first! + return; + } + + // call setWorkspace() method + // ... first get python lock + PyLockWrapper aLock = myInterp->GetLockWrapper(); + + // ... then try to import SalomePyQt module. If it's not possible don't go on. + PyObjWrapper aQtModule( PyImport_ImportModule( "SalomePyQt" ) ); + if( !aQtModule ) { + // Error! + PyErr_Print(); + return; + } + + if ( IsCallOldMethods ) { + // ... then get workspace object + QWidget* aWorkspace = 0; + if ( getApp()->desktop()->inherits( "STD_MDIDesktop" ) ) { + STD_MDIDesktop* aDesktop = dynamic_cast( getApp()->desktop() ); + if ( aDesktop ) + aWorkspace = aDesktop->workspace(); + } + else if ( getApp()->desktop()->inherits( "STD_TabDesktop" ) ) { + STD_TabDesktop* aDesktop = dynamic_cast( getApp()->desktop() ); + if ( aDesktop ) + aWorkspace = aDesktop->workstack(); + } + PyObjWrapper pyws( sipBuildResult( 0, "M", aWorkspace, sipClass_QWidget ) ); + // ... and finally call Python module's setWorkspace() method (obsolete) + if ( PyObject_HasAttrString( myModule , "setWorkSpace" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "setWorkSpace", "O", pyws.get() ) ); + if( !res ) { + PyErr_Print(); + } + } + } +} + +/*! + \brief Preference changing callback function (internal). + + Performs the following actions: + - call Python module's preferenceChanged() method + + \param section setting section name + \param setting setting name +*/ +void SALOME_PYQT_ModuleLight::prefChanged( const QString& section, const QString& setting ) +{ + FuncMsg fmsg( "SALOME_PYQT_ModuleLight::prefChanged()" ); + + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule ) + return; + + if ( PyObject_HasAttrString( myModule , "preferenceChanged" ) ) { + PyObjWrapper res( PyObject_CallMethod( myModule, + "preferenceChanged", + "ss", + section.toLatin1().constData(), + setting.toLatin1().constData() ) ); + if( !res ) { + PyErr_Print(); + } + } +} + +/*! + \brief Get default menu group identifier + \return menu group ID (40 by default) +*/ +int SALOME_PYQT_ModuleLight::defaultMenuGroup() +{ + return DEFAULT_GROUP; +} + +// +// The next methods call the parent implementation. +// This is done to open protected methods from CAM_Module class. +// + +/*! + \brief Create toolbar with specified \a name. + \param name toolbar name + \return toolbar ID or -1 if toolbar creation is failed +*/ +int SALOME_PYQT_ModuleLight::createTool( const QString& name ) +{ + return LightApp_Module::createTool( name ); +} + +/*! + \brief Insert action with specified \a id to the toolbar. + \param id action ID + \param tBar toolbar ID + \param idx required index in the toolbar + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createTool( const int id, const int tBar, const int idx ) +{ + return LightApp_Module::createTool( id, tBar, idx ); +} + +/*! + \brief Insert action with specified \a id to the toolbar. + \param id action ID + \param tBar toolbar name + \param idx required index in the toolbar + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createTool( const int id, const QString& tBar, const int idx ) +{ + return LightApp_Module::createTool( id, tBar, idx ); +} + +/*! + \brief Insert action to the toolbar. + \param a action + \param tBar toolbar ID + \param id required action ID + \param idx required index in the toolbar + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createTool( QAction* a, const int tBar, const int id, const int idx ) +{ + return LightApp_Module::createTool( a, tBar, id, idx ); +} + +/*! + \brief Insert action to the toolbar. + \param a action + \param tBar toolbar name + \param id required action ID + \param idx required index in the toolbar + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createTool( QAction* a, const QString& tBar, const int id, const int idx ) +{ + return LightApp_Module::createTool( a, tBar, id, idx ); +} + +/*! + \brief Create main menu. + \param subMenu menu name + \param menu parent menu ID + \param id required menu ID + \param group menu group ID + \param idx required index in the menu + \return menu ID or -1 if menu could not be added +*/ +int SALOME_PYQT_ModuleLight::createMenu( const QString& subMenu, const int menu, const int id, const int group, const int idx ) +{ + return LightApp_Module::createMenu( subMenu, menu, id, group, idx ); +} + +/*! + \brief Create main menu. + \param subMenu menu name + \param menu parent menu name (list of menu names separated by "|") + \param id required menu ID + \param group menu group ID + \param idx required index in the menu + \return menu ID or -1 if menu could not be added +*/ +int SALOME_PYQT_ModuleLight::createMenu( const QString& subMenu, const QString& menu, const int id, const int group, const int idx ) +{ + return LightApp_Module::createMenu( subMenu, menu, id, group, idx ); +} + +/*! + \brief Insert action to the main menu. + \param id action ID + \param menu parent menu ID + \param group menu group ID + \param idx required index in the menu + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createMenu( const int id, const int menu, const int group, const int idx ) +{ + return LightApp_Module::createMenu( id, menu, group, idx ); +} + +/*! + \brief Insert action to the main menu. + \param id action ID + \param menu parent menu name (list of menu names separated by "|") + \param group menu group ID + \param idx required index in the menu + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createMenu( const int id, const QString& menu, const int group, const int idx ) +{ + return LightApp_Module::createMenu( id, menu, group, idx ); +} + +/*! + \brief Insert action to the main menu. + \param a action + \param menu parent menu ID + \param group menu group ID + \param idx required index in the menu + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createMenu( QAction* a, const int menu, const int id, const int group, const int idx ) +{ + return LightApp_Module::createMenu( a, menu, id, group, idx ); +} + +/*! + \brief Insert action to the main menu. + \param a action + \param menu parent menu name (list of menu names separated by "|") + \param group menu group ID + \param idx required index in the menu + \return action ID or -1 if action could not be added +*/ +int SALOME_PYQT_ModuleLight::createMenu( QAction* a, const QString& menu, const int id, const int group, const int idx ) +{ + return LightApp_Module::createMenu( a, menu, id, group, idx ); +} + +/*! + \brief Create separator action which can be used in the menu or toolbar. + \return new separator action +*/ +QAction* SALOME_PYQT_ModuleLight::separator() +{ + return LightApp_Module::separator(); +} + +/*! + \brief Get action by specified \a id. + \return action or 0 if it is not found +*/ +QAction* SALOME_PYQT_ModuleLight::action( const int id ) const +{ + QAction* a = LightApp_Module::action( id ); + if ( !a ) { + // try menu + QMenu* m = menuMgr()->findMenu( id ); + if ( m ) a = m->menuAction(); + } + return a; +} + +/*! + \brief Get action identifier. + \return action ID or -1 if action is not registered +*/ +int SALOME_PYQT_ModuleLight::actionId( const QAction* a ) const +{ + return LightApp_Module::actionId( a ); +} + +/*! + \brief Create new action. + + If the action with specified identifier already registered + it is not created, but its attributes are only modified. + + \param id action ID + \param text tooltip text + \param icon icon + \param menu menu text + \param tip status tip + \param key keyboard shortcut + \param toggle \c true for checkable action + \return created action +*/ +QAction* SALOME_PYQT_ModuleLight::createAction( const int id, const QString& text, const QString& icon, + const QString& menu, const QString& tip, const int key, + const bool toggle, QObject* parent ) +{ + QIcon anIcon = loadIcon( icon ); + QAction* a = action( id ); + if ( a ) { + if ( a->toolTip().isEmpty() && !text.isEmpty() ) a->setToolTip( text ); + if ( a->text().isEmpty() && !menu.isEmpty() ) a->setText( menu ); + if ( a->icon().isNull() && !anIcon.isNull() ) a->setIcon( anIcon ); + if ( a->statusTip().isEmpty() && !tip.isEmpty() ) a->setStatusTip( tip ); + if ( a->shortcut().isEmpty() && key ) a->setShortcut( key ); + if ( a->isCheckable() != toggle ) a->setCheckable( toggle ); + disconnect( a, SIGNAL( triggered( bool ) ), this, SLOT( onGUIEvent() ) ); + connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onGUIEvent() ) ); + } + else { + a = LightApp_Module::createAction( id, + text, + anIcon, + menu, + tip, + key, + parent ? parent : this, + toggle, + this, + SLOT( onGUIEvent() ) ); + } + return a; +} + +/*! + \brief Create new action group. + + If the action with specified identifier already registered + it is not created, but its attributes are only modified. + + \param id action ID + \param text tooltip text + \param icon icon + \param menu menu text + \param tip status tip + \param key keyboard shortcut + \param toggle \c true for checkable action + \return created action +*/ +QtxActionGroup* SALOME_PYQT_ModuleLight::createActionGroup(const int id, const bool exclusive) +{ + QtxActionGroup* a = qobject_cast( action( id ) ); + if ( !a ) { + a = new QtxActionGroup( this ); + LightApp_Module::registerAction( id, a ); + } + a->setExclusive( exclusive ); + return a; +} + +/*! + \brief Load icon from resource file. + \param fileName icon file name + \return icon (null icon if loading failed) +*/ +QIcon SALOME_PYQT_ModuleLight::loadIcon( const QString& fileName ) +{ + QIcon anIcon; + if ( !fileName.isEmpty() ) { + QPixmap pixmap = getApp()->resourceMgr()->loadPixmap( name(), tr( fileName.toLatin1() ) ); + if ( !pixmap.isNull() ) + anIcon = QIcon( pixmap ); + } + return anIcon; +} + +/*! + \brief Add global application preference (for example, + application specific section). + \param label preference name + \return preference ID +*/ +int SALOME_PYQT_ModuleLight::addGlobalPreference( const QString& label ) +{ + LightApp_Preferences* pref = preferences(); + if ( !pref ) + return -1; + + return pref->addPreference( label, -1 ); +} + +/*! + \brief Add preference. + \param label preference name + \return preference ID +*/ +int SALOME_PYQT_ModuleLight::addPreference( const QString& label ) +{ + return LightApp_Module::addPreference( label ); +} + +/*! + \brief Add preference. + \param label preference name + \param pId parent preference ID + \param type preference type + \param section resource file section name + \param param resource file setting name + \return preference ID +*/ +int SALOME_PYQT_ModuleLight::addPreference( const QString& label, + const int pId, const int type, + const QString& section, + const QString& param ) +{ + return LightApp_Module::addPreference( label, pId, type, section, param ); +} + +/*! + \brief Get the preference property. + \param id preference ID + \param prop property name + \return property value (invalid QVariant() if property is not found) +*/ +QVariant SALOME_PYQT_ModuleLight::preferenceProperty( const int id, + const QString& prop ) const +{ + QVariant v = LightApp_Module::preferenceProperty( id, prop ); + return v; +} + +/*! + \brief Set the preference property. + \param id preference ID + \param prop property name + \param var property value +*/ +void SALOME_PYQT_ModuleLight::setPreferenceProperty( const int id, + const QString& prop, + const QVariant& var ) +{ + LightApp_Module::setPreferenceProperty( id, prop, var ); +} + + +/*! + \brief Signal handler windowActivated(SUIT_ViewWindow*) of SUIT_Desktop + \param pview view being activated +*/ +void SALOME_PYQT_ModuleLight::onActiveViewChanged( SUIT_ViewWindow* pview ) +{ + class ActiveViewChange : public PyInterp_LockRequest + { + public: + ActiveViewChange( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myObj(_obj),myView(_pview) {} + + protected: + virtual void execute() + { + myObj->activeViewChanged( myView ); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + const SUIT_ViewWindow * myView; + }; + + PyInterp_Dispatcher::Get()->Exec( new ActiveViewChange( myInterp, this, pview ) ); +} + +/*! + \brief Processes the view changing, calls Python module's activeViewChanged() method + \param pview view being activated +*/ +void SALOME_PYQT_ModuleLight::activeViewChanged( const SUIT_ViewWindow* pview ) +{ + if ( !myInterp || !myModule ) + return; + + // Do not use SUIT_ViewWindow::closing() signal here. View manager reacts on + // this signal and deletes view. So our slot does not works if it is connected + // on this signal. SUIT_ViewManager::deleteView(SUIT_ViewWindow*) is used here + + connectView( pview ); + + if ( PyObject_HasAttrString( myModule, "activeViewChanged" ) ) + { + if ( !pview ) + return; + + PyObjWrapper res( PyObject_CallMethod( myModule, "activeViewChanged", "i" , pview->getId() ) ); + if( !res ) + PyErr_Print(); + } +} + +/*! + \brief Signal handler cloneView() of OCCViewer_ViewWindow + \param pview view being cloned +*/ +void SALOME_PYQT_ModuleLight::onViewCloned( SUIT_ViewWindow* pview ) +{ + class ViewClone : public PyInterp_LockRequest + { + public: + ViewClone( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myObj(_obj), myView(_pview) {} + + protected: + virtual void execute() + { + myObj->viewCloned( myView ); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + const SUIT_ViewWindow* myView; + }; + + PyInterp_Dispatcher::Get()->Exec( new ViewClone( myInterp, this, pview ) ); +} + +/*! + \brief Processes the view cloning, calls Python module's activeViewCloned() method + \param pview view being cloned +*/ +void SALOME_PYQT_ModuleLight::viewCloned( const SUIT_ViewWindow* pview ) +{ + if ( !myInterp || !myModule || !pview ) + return; + + if ( PyObject_HasAttrString( myModule, "viewCloned" ) ) + { + PyObjWrapper res( PyObject_CallMethod( myModule, "viewCloned", "i", pview->getId() ) ); + if( !res ) + PyErr_Print(); + } +} + +/*! + \brief Signal handler closing(SUIT_ViewWindow*) of a view + \param pview view being closed +*/ +void SALOME_PYQT_ModuleLight::onViewClosed( SUIT_ViewWindow* pview ) +{ + class ViewClose : public PyInterp_LockRequest + { + public: + ViewClose( PyInterp_Interp* _py_interp, SALOME_PYQT_ModuleLight* _obj, const SUIT_ViewWindow* _pview ) + : PyInterp_LockRequest( _py_interp, 0, true ), + myObj(_obj),myView(_pview) {} + + protected: + virtual void execute() + { + myObj->viewClosed( myView ); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + const SUIT_ViewWindow * myView; + }; + + PyInterp_Dispatcher::Get()->Exec( new ViewClose( myInterp, this, pview ) ); +} + +/*! + \brief Processes the view closing, calls Python module's viewClosed() method + \param pview view being closed +*/ +void SALOME_PYQT_ModuleLight::viewClosed( const SUIT_ViewWindow* pview ) +{ + if ( !myInterp || !myModule ) + return; + + if ( PyObject_HasAttrString( myModule, "viewClosed" ) ) + { + PyObjWrapper res( PyObject_CallMethod( myModule, "viewClosed", "i", pview->getId() ) ); + if ( !res ) + { + PyErr_Print(); + } + } +} + +/*! + \brief Connects or disconnects signals about activating and cloning view on the module slots + \param pview view which is connected/disconnected +*/ +void SALOME_PYQT_ModuleLight::connectView( const SUIT_ViewWindow* pview ) +{ + SUIT_ViewManager* viewMgr = pview->getViewManager(); + SUIT_ViewModel* viewModel = viewMgr ? viewMgr->getViewModel() : 0; + + if ( viewMgr ) + { + disconnect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), + this, SLOT( onViewClosed( SUIT_ViewWindow* ) ) ); + + connect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), + this, SLOT( onViewClosed( SUIT_ViewWindow* ) ) ); + } + + // Connect cloneView() signal of an OCC View + if ( pview->inherits( "OCCViewer_ViewWindow" ) ) + { + disconnect( pview, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); + connect( pview, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); + } + // Connect cloneView() signal of Plot2d View manager + else if ( viewModel && viewModel->inherits( "Plot2d_Viewer" ) ) + { + disconnect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); + connect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), + this, SLOT( onViewCloned( SUIT_ViewWindow* ) ) ); + } +} + +/*! + \brief Get tag name for the DOM element. + \param element DOM element + \return empty string if the element does not have tag name + \internal +*/ +static QString tagName( const QDomElement& element ) +{ + return element.tagName().trimmed(); +} + +/*! + \brief Get DOM element's attribute by its name. + \param element DOM element + \param attName attribute name + \return empty string if the element does not have such attribute + \internal +*/ +static QString attribute( const QDomElement& element, const QString& attName ) +{ + return element.attribute( attName ).trimmed(); +} + +/*! + \brief Inspect specified string for the boolean value. + + This function returns \c true if string represents boolean value: + - "true", "yes" or "1" for \c true + - "false", "no" or "0" for \c false + Second parameter allows to specify what boolean value is expected: + - 1: \c true + - 0: \c false + - other value is not taken into account (return represented value) + + \param value inspected string + \param check expected boolean value + \return boolean value represented by the string (\a check is not 1 or 0) + or \c true if value correspond to the specified \a check +*/ +static bool checkBool( const QString& value, const int check = -1 ) +{ + QString v = value.toLower(); + if ( ( v == "true" || v == "yes" || v == "1" ) && ( check != 0 ) ) + return true; + if ( ( v == "false" || v == "no" || v == "0" ) && ( check == 0 ) ) + return true; + return false; +} + +/*! + \brief Inspect specified string for the integer value. + + This function returns returns -1 if item is empty or represents + an invalid number. + \param value inspected string + \param def default value + \param shift shift value (it is added to the integer value to produce shifted result) +*/ +static int checkInt( const QString& value, const int def = -1, const int shift = -1 ) +{ + bool bOk; + int val = value.toInt( &bOk ); + if ( !bOk ) val = def; + if ( shift > 0 && bOk && val < 0 ) + val += shift; + return val; +} + +/*! + \brief Constructor + \internal + \param module parent module pointer + \param fileName XML file path +*/ +SALOME_PYQT_ModuleLight::XmlHandler::XmlHandler( SALOME_PYQT_ModuleLight* module, + const QString& fileName ) +: myModule( module ) +{ + if ( fileName.isEmpty() ) + return; + QFile aFile( fileName ); + if ( !aFile.open( QIODevice::ReadOnly ) ) + return; + myDoc.setContent( &aFile ); + aFile.close(); +} + +/*! + \brief Parse XML file and create actions. + \internal + + Called by SALOME_PYQT_ModuleLight::activate() in order to create actions + (menus, toolbars). +*/ +void SALOME_PYQT_ModuleLight::XmlHandler::createActions() +{ + // get document element + QDomElement aDocElem = myDoc.documentElement(); + + // create main menu actions + QDomNodeList aMenuList = aDocElem.elementsByTagName( "menu-item" ); + for ( int i = 0; i < aMenuList.count(); i++ ) { + QDomNode n = aMenuList.item( i ); + createMenu( n ); + } + + // create toolbars actions + QDomNodeList aToolsList = aDocElem.elementsByTagName( "toolbar" ); + for ( int i = 0; i < aToolsList.count(); i++ ) { + QDomNode n = aToolsList.item( i ); + createToolBar( n ); + } +} + +/*! + \brief Create popup menu. + \internal + \param menu popup menu + \param context popup menu context + \param context popup menu parent object name + \param context popup menu object name +*/ +void SALOME_PYQT_ModuleLight::XmlHandler::createPopup( QMenu* menu, + const QString& context, + const QString& parent, + const QString& object ) +{ + // get document element + QDomElement aDocElem = myDoc.documentElement(); + + // get popup menus actions + QDomNodeList aPopupList = aDocElem.elementsByTagName( "popupmenu" ); + for ( int i = 0; i < aPopupList.count(); i++ ) { + QDomNode n = aPopupList.item( i ); + if ( !n.isNull() && n.isElement() ) { + QDomElement e = n.toElement(); + // QString lab = attribute( e, "label-id" ); // not used // + QString ctx = attribute( e, "context-id" ); + QString prt = attribute( e, "parent-id" ); + QString obj = attribute( e, "object-id" ); + if ( ctx == context && prt == parent && obj == object ) { + insertPopupItems( n, menu ); + break; + } + } + } +} + +/*! + \brief Activate menus + \internal + \param enable if \c true menus are activated, otherwise menus are deactivated +*/ +void SALOME_PYQT_ModuleLight::XmlHandler::activateMenus( bool enable ) +{ + if ( !myModule ) + return; + + QtxActionMenuMgr* mgr = myModule->menuMgr(); + int id; + foreach( id, myMenuItems ) mgr->setEmptyEnabled( id, enable ); +} + +/*! + \brief Create main menu item and insert actions to it. + \internal + \param parentNode XML node with menu description + \param parentMenuId parent menu ID (-1 for top-level menu) + \param parentPopup parent popup menu (0 for top-level menu) +*/ +void SALOME_PYQT_ModuleLight::XmlHandler::createMenu( QDomNode& parentNode, + const int parentMenuId, + QMenu* parentPopup ) +{ + if ( !myModule || parentNode.isNull() ) + return; + + QDomElement parentElement = parentNode.toElement(); + if ( !parentElement.isNull() ) { + QString plabel = attribute( parentElement, "label-id" ); + int pid = checkInt( attribute( parentElement, "item-id" ) ); + int ppos = checkInt( attribute( parentElement, "pos-id" ) ); + int group = checkInt( attribute( parentElement, "group-id" ), + myModule->defaultMenuGroup() ); + if ( !plabel.isEmpty() ) { + QMenu* popup = 0; + int menuId = -1; + // create menu + menuId = myModule->createMenu( plabel, // label + parentMenuId, // parent menu ID, -1 for top-level menu + pid, // ID + group, // group ID + ppos ); // position + myMenuItems.append( menuId ); + QDomNode node = parentNode.firstChild(); + while ( !node.isNull() ) { + if ( node.isElement() ) { + QDomElement elem = node.toElement(); + QString aTagName = tagName( elem ); + if ( aTagName == "popup-item" ) { + int id = checkInt( attribute( elem, "item-id" ) ); + int pos = checkInt( attribute( elem, "pos-id" ) ); + int group = checkInt( attribute( elem, "group-id" ), + myModule->defaultMenuGroup() ); + QString label = attribute( elem, "label-id" ); + QString icon = attribute( elem, "icon-id" ); + QString tooltip = attribute( elem, "tooltip-id" ); + QString accel = attribute( elem, "accel-id" ); + bool toggle = checkBool( attribute( elem, "toggle-id" ) ); + + // -1 action ID is not allowed : it means that attribute is missed in the XML file! + // also check if the action with given ID is already created + if ( id != -1 ) { + // create menu action + QAction* action = myModule->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + toggle ); // toogled action + myModule->createMenu( action, // action + menuId, // parent menu ID + id, // ID (same as for createAction()) + group, // group ID + pos ); // position + } + } + else if ( aTagName == "submenu" ) { + // create sub-menu + createMenu( node, menuId, popup ); + } + else if ( aTagName == "separator" ) { + // create menu separator + int id = checkInt( attribute( elem, "item-id" ) ); // separator can have ID + int pos = checkInt( attribute( elem, "pos-id" ) ); + int group = checkInt( attribute( elem, "group-id" ), + myModule->defaultMenuGroup() ); + QAction* action = myModule->separator(); + myModule->createMenu( action, // separator action + menuId, // parent menu ID + id, // ID + group, // group ID + pos ); // position + } + } + node = node.nextSibling(); + } + } + } +} + +/*! + \brief Create a toolbar and insert actions to it. + \param parentNode XML node with toolbar description +*/ +void SALOME_PYQT_ModuleLight::XmlHandler::createToolBar( QDomNode& parentNode ) +{ + if ( !myModule || parentNode.isNull() ) + return; + + QDomElement parentElement = parentNode.toElement(); + if ( !parentElement.isNull() ) { + QString aLabel = attribute( parentElement, "label-id" ); + if ( !aLabel.isEmpty() ) { + // create toolbar + int tbId = myModule->createTool( aLabel ); + QDomNode node = parentNode.firstChild(); + while ( !node.isNull() ) { + if ( node.isElement() ) { + QDomElement elem = node.toElement(); + QString aTagName = tagName( elem ); + if ( aTagName == "toolbutton-item" ) { + int id = checkInt( attribute( elem, "item-id" ) ); + int pos = checkInt( attribute( elem, "pos-id" ) ); + QString label = attribute( elem, "label-id" ); + QString icon = attribute( elem, "icon-id" ); + QString tooltip = attribute( elem, "tooltip-id" ); + QString accel = attribute( elem, "accel-id" ); + bool toggle = checkBool( attribute( elem, "toggle-id" ) ); + + // -1 action ID is not allowed : it means that attribute is missed in the XML file! + // also check if the action with given ID is already created + if ( id != -1 ) { + // create toolbar action + QAction* action = myModule->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + toggle ); // toogled action + myModule->createTool( action, tbId, -1, pos ); + } + } + else if ( aTagName == "separatorTB" || aTagName == "separator" ) { + // create toolbar separator + int pos = checkInt( attribute( elem, "pos-id" ) ); + QAction* action = myModule->separator(); + myModule->createTool( action, tbId, -1, pos ); + } + } + node = node.nextSibling(); + } + } + } +} + +/*! + \brief Fill popup menu with the items. + \param parentNode XML node with popup menu description + \param menu popup menu +*/ +void SALOME_PYQT_ModuleLight::XmlHandler::insertPopupItems( QDomNode& parentNode, QMenu* menu ) +{ + if ( !myModule && parentNode.isNull() ) + return; + + // we create popup menus without help of QtxPopupMgr + QDomNode node = parentNode.firstChild(); + while ( !node.isNull() ) { + if ( node.isElement() ) { + QDomElement elem = node.toElement(); + QString aTagName = tagName( elem ); + QList actions = menu->actions(); + if ( aTagName == "popup-item" ) { + // insert a command item + int id = checkInt( attribute( elem, "item-id" ) ); + int pos = checkInt( attribute( elem, "pos-id" ) ); + QString label = attribute( elem, "label-id" ); + QString icon = attribute( elem, "icon-id" ); + QString tooltip = attribute( elem, "tooltip-id" ); + QString accel = attribute( elem, "accel-id" ); + bool toggle = checkBool( attribute( elem, "toggle-id" ) ); + + // -1 action ID is not allowed : it means that attribute is missed in the XML file! + // also check if the action with given ID is already created + if ( id != -1 ) { + QAction* action = myModule->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + toggle ); // toogled action + QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; + menu->insertAction( before, action ); + } + } + else if ( aTagName == "submenu" ) { + // create sub-menu + ////int id = checkInt( attribute( elem, "item-id" ) ); // not used // + int pos = checkInt( attribute( elem, "pos-id" ) ); + QString label = attribute( elem, "label-id" ); + QString icon = attribute( elem, "icon-id" ); + + QIcon anIcon; + if ( !icon.isEmpty() ) { + QPixmap pixmap = myModule->getApp()->resourceMgr()->loadPixmap( myModule->name(), icon ); + if ( !pixmap.isNull() ) + anIcon = QIcon( pixmap ); + } + + QMenu* newPopup = menu->addMenu( anIcon, label ); + QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; + menu->insertMenu( before, newPopup ); + insertPopupItems( node, newPopup ); + } + else if ( aTagName == "separator" ) { + // create menu separator + int pos = checkInt( attribute( elem, "pos-id" ) ); + QAction* action = myModule->separator(); + QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; + menu->insertAction( before, action ); + } + } + node = node.nextSibling(); + } +} + +/* + * Save study request. + * Called when user save study. + */ +void SALOME_PYQT_ModuleLight::save(QStringList& theListOfFiles) +{ + MESSAGE("SALOME_PYQT_ModuleLight::save()") + // perform synchronous request to Python event dispatcher + class SaveEvent: public PyInterp_LockRequest + { + public: + SaveEvent(PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + QStringList& _files_list) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myObj( _obj ) , + myFilesList(_files_list) {} + protected: + virtual void execute() + { + myObj->saveEvent(myFilesList); + } + private: + SALOME_PYQT_ModuleLight* myObj; + QStringList& myFilesList; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new SaveEvent( myInterp, this, theListOfFiles ) ); +} + +void SALOME_PYQT_ModuleLight::saveEvent(QStringList& theListOfFiles) +{ + MESSAGE("SALOME_PYQT_ModuleLight::saveEvent()"); + QStringList::Iterator it = theListOfFiles.begin(); + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule || (it == theListOfFiles.end())) + return; + + if ( PyObject_HasAttrString(myModule , "saveFiles") ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "saveFiles", + "s", (*it).toLatin1().constData())); + if( !res ) { + PyErr_Print(); + } + else{ + // parse the return value + // result can be one string... + if ( PyString_Check( res ) ) { + QString astr = PyString_AsString( res ); + //SCRUTE(astr); + theListOfFiles.append(astr); + } + //also result can be a list... + else if ( PyList_Check( res ) ) { + int size = PyList_Size( res ); + for ( int i = 0; i < size; i++ ) { + PyObject* value = PyList_GetItem( res, i ); + if( value && PyString_Check( value ) ) { + theListOfFiles.append( PyString_AsString( value ) ); + } + } + } + } + } +} + +/* + * Open study request. + * Called when user open study. + */ +bool SALOME_PYQT_ModuleLight::open(QStringList theListOfFiles) +{ + MESSAGE("SALOME_PYQT_ModuleLight::open()"); + // perform synchronous request to Python event dispatcher + bool opened = false; + class OpenEvent: public PyInterp_LockRequest + { + public: + OpenEvent(PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + QStringList _files_list, + bool& _opened) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myObj( _obj ) , + myFilesList(_files_list), + myOpened(_opened) {} + protected: + virtual void execute() + { + myObj->openEvent(myFilesList,myOpened); + } + + private: + SALOME_PYQT_ModuleLight* myObj; + QStringList myFilesList; + bool& myOpened; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new OpenEvent( myInterp, this, theListOfFiles, opened) ); + return opened; +} + + +void SALOME_PYQT_ModuleLight::openEvent(QStringList theListOfFiles, bool &opened) +{ + MESSAGE("SALOME_PYQT_ModuleLight::openEvent()"); + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule || theListOfFiles.isEmpty()) + return; + QStringList* theList = new QStringList(theListOfFiles); + + PyObjWrapper sipList( sipBuildResult( 0, "M", theList, sipClass_QStringList ) ); + + if ( PyObject_HasAttrString(myModule , "openFiles") ) { + PyObjWrapper res( PyObject_CallMethod( myModule, "openFiles", + "O", sipList.get())); + if( !res || !PyBool_Check( res )) { + PyErr_Print(); + opened = false; + } + else{ + opened = PyObject_IsTrue( res ); + + } + } +} + +/* + * Create new empty Data Object and return its entry + */ +QString SALOME_PYQT_ModuleLight::createObject(const QString& parent) +{ + SALOME_PYQT_DataObjectLight* obj=0; + if(!parent.isEmpty()) + { + SALOME_PYQT_DataObjectLight* parentObj = findObject(parent); + if(parentObj) + { + obj = new SALOME_PYQT_DataObjectLight(parentObj); + } + } + else + { + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel()); + if(dm) + { + obj = new SALOME_PYQT_DataObjectLight(dm->getRoot()); + } + } + if (obj) + return obj->entry(); + else + return QString::null; +} + +/* + * Create new Data Object with name, icon and tooltip + * and return its entry + */ +QString SALOME_PYQT_ModuleLight::createObject(const QString& aname, + const QString& iconname, + const QString& tooltip, + const QString& parent) +{ + QString entry = createObject(parent); + SALOME_PYQT_DataObjectLight* obj = findObject(entry); + + if(obj) + { + obj->setName(aname); + obj->setToolTip(tooltip); + obj->setIcon(iconname); + return obj->entry(); + } + else + return QString::null; +} + +/* + * Find object by entry + */ +SALOME_PYQT_DataObjectLight* SALOME_PYQT_ModuleLight::findObject(const QString& entry) +{ + SALOME_PYQT_DataObjectLight* obj = 0; + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel()); + if(!entry.isEmpty() && dm ){ + for ( SUIT_DataObjectIterator it( dm->getRoot(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) { + SALOME_PYQT_DataObjectLight* curentobj = + dynamic_cast( it.current() ); + + if(curentobj && curentobj->entry() == entry) { + obj = curentobj; + return obj; + } + } + } + return obj; +} + +/* + * Set Name for object + */ +void SALOME_PYQT_ModuleLight::setName(const QString& obj, const QString& name) +{ + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) { + dataObj->setName(name); + } +} + +/* + * Set Icon for object + */ +void SALOME_PYQT_ModuleLight::setIcon(const QString& obj, const QString& iconname) +{ + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) { + dataObj->setIcon(iconname); + } +} + +/* + * Return Name of object + */ +QString SALOME_PYQT_ModuleLight::getName(const QString& obj) +{ + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) { + return dataObj->name(); + } + return QString::null; +} + +/* + * Return Tool Tip of object + */ +QString SALOME_PYQT_ModuleLight::getToolTip(const QString& obj) +{ + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) { + return dataObj->toolTip(); + } + return QString::null; +} + + +/* + * Set Tool Tip for object + */ +void SALOME_PYQT_ModuleLight::setToolTip(const QString& obj, const QString& tooltip) +{ + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) { + dataObj->setToolTip(tooltip); + } +} + +/* + * Remove object by entry + */ +void SALOME_PYQT_ModuleLight::removeObject(const QString& obj) +{ + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) { + dataObj->parent()->removeChild(dataObj); + } +} + + +/* + * Remove chields from object + */ +void SALOME_PYQT_ModuleLight::removeChild(const QString& obj) +{ + MESSAGE("SALOME_PYQT_ModuleLight::removeChild()"); + DataObjectList lst; + if(!obj.isEmpty()) + { + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) + { + dataObj->children(lst); + QListIterator it( lst ); + while( it.hasNext() ) + { + SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); + dataObj->removeChild(sobj); + } + } + } + else + { + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel()); + if(dm) + { + dm->getRoot()->children(lst); + QListIterator it( lst ); + while(it.hasNext() ) + { + SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); + dm->getRoot()->removeChild(sobj); + } + } + } +} + +QStringList SALOME_PYQT_ModuleLight::getChildren(const QString& obj, const bool rec) +{ + DataObjectList lst; + QStringList entryList; + if(!obj.isEmpty()) + { + SALOME_PYQT_DataObjectLight* dataObj = findObject(obj); + if(dataObj) + { + dataObj->children(lst,rec); + QListIterator it( lst ); + while(it.hasNext()) + { + SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); + entryList.append(sobj->entry()); + } + } + } + else + { + SALOME_PYQT_DataModelLight* dm = + dynamic_cast( dataModel()); + if(dm) + { + dm->getRoot()->children(lst); + QListIterator it( lst ); + while( it.hasNext() ) + { + SALOME_PYQT_DataObjectLight* sobj = dynamic_cast( it.next() ); + entryList.append(sobj->entry()); + } + } + } + return entryList; +} + +/*! + * Create new instance of data model and return it. + */ +CAM_DataModel* SALOME_PYQT_ModuleLight::createDataModel() +{ + MESSAGE( "SALOME_PYQT_ModuleLight::createDataModel()" ); + return new SALOME_PYQT_DataModelLight(this); +} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h new file mode 100644 index 000000000..2340b5ec3 --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h @@ -0,0 +1,201 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SALOME_PYQT_Module.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#ifndef SALOME_PYQT_MODULELIGHT_H +#define SALOME_PYQT_MODULELIGHT_H + +#include "PyInterp_Interp.h" // // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! +#include "SALOME_PYQT_GUILight.h" +#include "LightApp_Module.h" +#include "SALOME_PYQT_DataObjectLight.h" +#include + +#include +#include +#include +#include +#include + +class SALOME_PYQT_RootObjectLight; +class SALOME_PYQT_PyInterp; +class SUIT_ViewWindow; +class QAction; +class QtxActionGroup; +class QMenu; + + +class SALOME_PYQT_EXPORT SALOME_PYQT_ModuleLight: virtual public LightApp_Module +{ + Q_OBJECT; + +private: + class XmlHandler; + + //! study to Python subinterpreter map + typedef QMap InterpMap; + PyObjWrapper myModule; //!< Python GUI module + static SALOME_PYQT_ModuleLight* myInitModule; //!< Python GUI being initialized (not zero only during the initialization) + + XmlHandler* myXmlHandler; //!< XML resource file parser + QMap myWindowsMap; //!< windows map + QStringList myViewMgrList;//!< compatible view managers list + bool myLastActivateStatus; //!< latest module activation status + + +protected: + PyInterp_Interp* myInterp; //!< current Python subinterpreter + static InterpMap myInterpMap; //!< study to Python subinterpreter map + +public: + SALOME_PYQT_ModuleLight(); + ~SALOME_PYQT_ModuleLight(); + +public: + static SALOME_PYQT_ModuleLight* getInitModule(); + + void initialize( CAM_Application* ); + void windows( QMap& ) const; + void viewManagers( QStringList& ) const; + void contextMenuPopup( const QString&, QMenu*, QString& ); + void createPreferences(); + void studyActivated(); + void preferencesChanged( const QString&, const QString& ); + + static int defaultMenuGroup(); + + int createTool( const QString& ); + int createTool( const int, const int, const int = -1 ); + int createTool( const int, const QString&, const int = -1 ); + int createTool( QAction*, const int, + const int = -1, const int = -1 ); + int createTool( QAction*, const QString&, + const int = -1, const int = -1 ); + + int createMenu( const QString&, const int, + const int = -1, const int = -1, const int = -1 ); + int createMenu( const QString&, const QString&, + const int = -1, const int = -1, const int = -1 ); + int createMenu( const int, const int, + const int = -1, const int = -1 ); + int createMenu( const int, const QString&, + const int = -1, const int = -1 ); + int createMenu( QAction*, const int, + const int = -1, const int = -1, const int = -1 ); + int createMenu( QAction*, const QString&, + const int = -1, const int = -1, const int = -1 ); + + QAction* separator(); + + QAction* action( const int ) const; + int actionId( const QAction* ) const; + QAction* createAction( const int, const QString&, const QString&, + const QString&, const QString&, const int, + const bool = false, QObject* = 0 ); + QtxActionGroup* createActionGroup( const int, const bool ); + + + QIcon loadIcon( const QString& fileName ); + + int addGlobalPreference( const QString& ); + int addPreference( const QString& ); + int addPreference( const QString&, const int, const int = LightApp_Preferences::Auto, + const QString& = QString(), + const QString& = QString() ); + QVariant preferenceProperty( const int, const QString& ) const; + void setPreferenceProperty( const int, const QString&, + const QVariant& ); + + void save(QStringList& theListOfFiles); + + bool open(QStringList theListOfFiles); + + /*create new SALOME_PYQT_DataObjectLight and return its entry*/ + QString createObject(const QString& parent); + QString createObject(const QString& name, + const QString& iconname, + const QString& tooltip, + const QString& parent); + /*Sets Name, Icon and Tool Tip for object*/ + void setName(const QString& obj,const QString& iconname); + void setIcon(const QString& obj,const QString& name); + void setToolTip(const QString& obj, const QString& name); + + /*Gets Name and Tool Tip for object*/ + QString getName(const QString& obj); + QString getToolTip(const QString& obj); + /*remove object*/ + void removeObject(const QString& obj); + /*remove child*/ + void removeChild(const QString& obj); + /*return list of child objets*/ + QStringList getChildren(const QString& obj, const bool rec); + + +public slots: + virtual bool activateModule( SUIT_Study* ); + virtual bool deactivateModule( SUIT_Study* ); + void preferenceChanged( const QString&, + const QString&, + const QString& ); + void onGUIEvent(); + + void onActiveViewChanged( SUIT_ViewWindow* ); + void onViewClosed( SUIT_ViewWindow* ); + void onViewCloned( SUIT_ViewWindow* ); + +protected: + /* create data model */ + virtual CAM_DataModel* createDataModel(); + +private: + void init( CAM_Application* ); + void activate( SUIT_Study* ); + void deactivate( SUIT_Study* ); + bool lastActivationStatus() const; + void customize( SUIT_Study* ); + void studyChanged( SUIT_Study* ); + void contextMenu( const QString&, QMenu* ); + void guiEvent( const int ); + void initPreferences(); + void prefChanged( const QString&, const QString& ); + + virtual void initInterp ( int ); + void importModule(); + void setWorkSpace(); + + void activeViewChanged( const SUIT_ViewWindow* ); + void viewClosed( const SUIT_ViewWindow* ); + void viewCloned( const SUIT_ViewWindow* ); + void connectView( const SUIT_ViewWindow* ); + + void saveEvent(QStringList& theListOfFiles); + void openEvent(QStringList theListOfFiles, bool& opened); + + SALOME_PYQT_DataObjectLight* findObject(const QString& entry); + + friend class XmlHandler; +}; + +#endif // SALOME_PYQT_MODULELIGHT_H diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx new file mode 100644 index 000000000..eac78e7ea --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx @@ -0,0 +1,102 @@ + +#include "SALOME_PYQT_PyInterp.h" // this include must be first !! + +#include +#include +#include + +#ifndef GUI_DISABLE_CORBA +#include +#endif + + + + +/*! + * constructor : the main SALOME Python interpreter is used for PyQt GUI. + * calls initialize method defined in base class, which calls virtual methods + * initstate & initcontext redefined here + */ +SALOME_PYQT_PyInterp::SALOME_PYQT_PyInterp(): PyInterp_Interp() +{ +} + +SALOME_PYQT_PyInterp::~SALOME_PYQT_PyInterp() +{ +} + +void SALOME_PYQT_PyInterp::initPython() +{ + /* + * Do nothing + * The initialization has been done in main + */ + MESSAGE("SALOME_PYQT_PyInterp::initPython"); +#ifndef GUI_DISABLE_CORBA + if(SUIT_PYTHON::initialized) { + ASSERT(SUIT_PYTHON::_gtstate); // initialisation in main + SCRUTE(SUIT_PYTHON::_gtstate); + _tstate = SUIT_PYTHON::_gtstate; + } + else { + ASSERT(KERNEL_PYTHON::_gtstate); // initialisation in main + SCRUTE(KERNEL_PYTHON::_gtstate); + _tstate = KERNEL_PYTHON::_gtstate; + } +#else + SCRUTE(SUIT_PYTHON::_gtstate); + _tstate = SUIT_PYTHON::_gtstate; +#endif +} + +bool SALOME_PYQT_PyInterp::initState() +{ + /* + * The GIL is assumed to not be held on the call + * The GIL is acquired in initState and will be held on initState exit + * It is the caller responsability to release the lock on exit if needed + */ + PyEval_AcquireThread(_tstate); + SCRUTE(_tstate); + PyEval_ReleaseThread(_tstate); + return true; +} + + +bool SALOME_PYQT_PyInterp::initContext() +{ + /* + * The GIL is assumed to be held + * It is the caller responsability to acquire the GIL before calling initContext + * It will still be held on initContext exit + */ + _g = PyDict_New(); // create interpreter dictionnary context + PyObject *bimod = PyImport_ImportModule("__builtin__"); + PyDict_SetItemString(_g, "__builtins__", bimod); + Py_DECREF(bimod); + return true; +} + +int SALOME_PYQT_PyInterp::run(const char *command) +{ + MESSAGE("compile"); + PyObject *code = Py_CompileString((char *)command,"PyGUI",Py_file_input); + if(!code){ + // Une erreur s est produite en general SyntaxError + PyErr_Print(); + return -1; + } + //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 + // PyObject *r = PyEval_EvalCode(code,_g,_g); + //#else + PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_g,_g); + //#endif + Py_DECREF(code); + if(!r){ + // Une erreur s est produite a l execution + PyErr_Print(); + return -1 ; + } + Py_DECREF(r); + return 0; +} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h new file mode 100644 index 000000000..e49faabaa --- /dev/null +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h @@ -0,0 +1,48 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SALOME_PYQT_Module.h +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 13/04/2009 + + +#ifndef SALOME_PYQT_PYINTERP_H +#define SALOME_PYQT_PYINTERP_H + +#include "SALOME_PYQT_GUILight.h" + +#include "PyInterp_Interp.h" // this include must be first !!! + +class SALOME_PYQT_EXPORT SALOME_PYQT_PyInterp : public PyInterp_Interp +{ + public: + SALOME_PYQT_PyInterp(); + ~SALOME_PYQT_PyInterp(); + + int run(const char *command); + + protected: + virtual void initPython(); + virtual bool initState(); + virtual bool initContext(); +}; + +#endif // SALOME_PYQT_PYINTERP_H diff --git a/src/SALOME_PYQT/SalomePyQt/Makefile.am b/src/SALOME_PYQT/SalomePyQt/Makefile.am index 5ca53871e..6e82b8f09 100644 --- a/src/SALOME_PYQT/SalomePyQt/Makefile.am +++ b/src/SALOME_PYQT/SalomePyQt/Makefile.am @@ -47,27 +47,26 @@ CLEANFILES = $(SIP_SRC) MOC_FILES = SalomePyQt_moc.cxx # compilation flags -COMMON_CPP_FLAGS = $(QT_INCLUDES) $(QWT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INCLUDES) \ - $(CAS_CPPFLAGS) $(VTK_INCLUDES) $(OGL_INCLUDES) $(BOOST_CPPFLAGS) \ - -DHAVE_CONFIG_H @KERNEL_CXXFLAGS@ -I$(top_builddir)/salomeadn/unix \ - -I$(srcdir) -I$(top_builddir)/idl \ - -I$(srcdir)/../../SUIT -I$(srcdir)/../../CAM -I$(srcdir)/../../STD \ - -I$(srcdir)/../../Qtx -I$(srcdir)/../../SalomeApp -I$(srcdir)/../../Event \ - -I$(srcdir)/../../SalomeSession -I$(srcdir)/../../LogWindow \ - -I$(srcdir)/../../VTKViewer -I$(srcdir)/../../TOOLSGUI \ - -I$(srcdir)/../../OCCViewer -I$(srcdir)/../../Plot2d \ - -I$(srcdir)/../SALOME_PYQT_GUI -I$(srcdir)/../../PyInterp \ - -I$(srcdir)/../../LightApp -I$(srcdir)/../../ObjBrowser \ - -I$(srcdir)/../../OBJECT \ - -I$(top_builddir)/salome_adm/unix @CORBA_CXXFLAGS@ @CORBA_INCLUDES@ +COMMON_CPP_FLAGS = $(QT_INCLUDES) $(QWT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INCLUDES) \ + $(CAS_CPPFLAGS) $(VTK_INCLUDES) $(OGL_INCLUDES) $(BOOST_CPPFLAGS) \ + -DHAVE_CONFIG_H @KERNEL_CXXFLAGS@ -I$(top_builddir)/salomeadn/unix \ + -I$(srcdir) -I$(top_builddir)/idl \ + -I$(srcdir)/../../SUIT -I$(srcdir)/../../CAM -I$(srcdir)/../../STD \ + -I$(srcdir)/../../Qtx -I$(srcdir)/../../Event \ + -I$(srcdir)/../../LogWindow \ + -I$(srcdir)/../../VTKViewer \ + -I$(srcdir)/../../OCCViewer -I$(srcdir)/../../Plot2d \ + -I$(srcdir)/../SALOME_PYQT_GUILight -I$(srcdir)/../../PyInterp \ + -I$(srcdir)/../../LightApp -I$(srcdir)/../../ObjBrowser \ + -I$(srcdir)/../../OBJECT # linkage flags -COMMON_LIBS = $(PYTHON_LIBS) $(SIP_LIBS) $(PYQT_LIBS) $(VTK_LIBS) $(QWT_LIBS) \ - $(OGL_LIBS) ../../SUIT/libsuit.la ../../CAM/libCAM.la ../../STD/libstd.la \ - ../../Qtx/libqtx.la ../../SalomeApp/libSalomeApp.la ../../Event/libEvent.la \ - ../../Session/libSalomeSession.la ../../LogWindow/libLogWindow.la \ - ../../VTKViewer/libVTKViewer.la ../../TOOLSGUI/libToolsGUI.la \ - ../SALOME_PYQT_GUI/libSalomePyQtGUI.la ../../OCCViewer/libOCCViewer.la \ +COMMON_LIBS = $(PYTHON_LIBS) $(SIP_LIBS) $(PYQT_LIBS) $(VTK_LIBS) $(QWT_LIBS) \ + $(OGL_LIBS) ../../SUIT/libsuit.la ../../CAM/libCAM.la ../../STD/libstd.la \ + ../../Qtx/libqtx.la ../../Event/libEvent.la \ + ../../LogWindow/libLogWindow.la \ + ../../VTKViewer/libVTKViewer.la \ + ../SALOME_PYQT_GUILight/libSalomePyQtGUILight.la ../../OCCViewer/libOCCViewer.la \ ../../Plot2d/libPlot2d.la # libraries targets diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx index 8400e90e9..b665f34df 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx @@ -22,7 +22,7 @@ // File : SalomePyQt.cxx // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) // -#include // this include must be first!!! +#include // this include must be first!!! #include "SalomePyQt.h" #include @@ -44,8 +44,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -57,10 +57,10 @@ \internal \return active application object or 0 if there is no any */ -static SalomeApp_Application* getApplication() +static LightApp_Application* getApplication() { if ( SUIT_Session::session() ) - return dynamic_cast( SUIT_Session::session()->activeApplication() ); + return dynamic_cast( SUIT_Session::session()->activeApplication() ); return 0; } @@ -69,10 +69,10 @@ static SalomeApp_Application* getApplication() \internal \return active study or 0 if there is no study opened */ -static SalomeApp_Study* getActiveStudy() +static LightApp_Study* getActiveStudy() { if ( getApplication() ) - return dynamic_cast( getApplication()->activeStudy() ); + return dynamic_cast( getApplication()->activeStudy() ); return 0; } @@ -82,13 +82,13 @@ static SalomeApp_Study* getActiveStudy() This function returns correct result only if Python-based module is currently active. Otherwize, 0 is returned. */ -static SALOME_PYQT_Module* getActiveModule() +static SALOME_PYQT_ModuleLight* getActiveModule() { - SALOME_PYQT_Module* module = 0; - if ( SalomeApp_Application* anApp = getApplication() ) { - module = SALOME_PYQT_Module::getInitModule(); + SALOME_PYQT_ModuleLight* module = 0; + if ( LightApp_Application* anApp = getApplication() ) { + module = SALOME_PYQT_ModuleLight::getInitModule(); if ( !module ) - module = dynamic_cast( anApp->activeModule() ); + module = dynamic_cast( anApp->activeModule() ); } return module; } @@ -102,7 +102,7 @@ static SALOME_PYQT_Module* getActiveModule() \brief Map of created selection objects. \internal */ -static QMap SelMap; +static QMap SelMap; /*! \brief Get the selection object for the specified application. @@ -112,7 +112,7 @@ static QMap SelMap; \param app application object \return selection object or 0 if \a app is invalid */ -SALOME_Selection* SALOME_Selection::GetSelection( SalomeApp_Application* app ) +SALOME_Selection* SALOME_Selection::GetSelection( LightApp_Application* app ) { SALOME_Selection* sel = 0; if ( app && SelMap.find( app ) != SelMap.end() ) @@ -128,7 +128,7 @@ SALOME_Selection* SALOME_Selection::GetSelection( SalomeApp_Application* app ) */ SALOME_Selection::SALOME_Selection( QObject* p ) : QObject( 0 ), mySelMgr( 0 ) { - SalomeApp_Application* app = dynamic_cast( p ); + LightApp_Application* app = dynamic_cast( p ); if ( app ) { mySelMgr = app->selectionMgr(); connect( mySelMgr, SIGNAL( selectionChanged() ), this, SIGNAL( currentSelectionChanged() ) ); @@ -140,8 +140,8 @@ SALOME_Selection::SALOME_Selection( QObject* p ) : QObject( 0 ), mySelMgr( 0 ) */ SALOME_Selection::~SALOME_Selection() { - SalomeApp_Application* app = 0; - QMap::Iterator it; + LightApp_Application* app = 0; + QMap::Iterator it; for ( it = SelMap.begin(); it != SelMap.end() && !app; ++it ) { if ( it.value() == this ) app = it.key(); } @@ -285,7 +285,7 @@ public: TGetMainMenuBarEvent() : myResult( 0 ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { myResult = anApp->desktop()->menuBar(); } } @@ -325,7 +325,7 @@ public: TGetPopupMenuEvent( const QString& menu ) : myResult( 0 ), myMenuName( menu ) {} virtual void Execute() { - SalomeApp_Application* anApp = getApplication(); + LightApp_Application* anApp = getApplication(); if ( anApp && !myMenuName.isEmpty() ) { QtxActionMenuMgr* mgr = anApp->desktop()->menuMgr(); myResult = mgr->findMenu( myMenuName, -1, false ); // search only top menu @@ -384,8 +384,8 @@ public: TGetStudyIdEvent() : myResult( 0 ) {} virtual void Execute() { - if ( SalomeApp_Study* aStudy = getActiveStudy() ) { - myResult = aStudy->studyDS()->StudyId(); + if ( LightApp_Study* aStudy = getActiveStudy() ) { + myResult = aStudy->id(); } } }; @@ -440,7 +440,7 @@ public: TPutInfoEvent( const QString& msg, const int sec = 0 ) : myMsg( msg ), mySecs( sec ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { anApp->putInfo( myMsg, mySecs * 1000 ); } } @@ -464,7 +464,7 @@ public: TGetActiveComponentEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { if ( CAM_Module* mod = anApp->activeModule() ) { myResult = mod->name(); } @@ -506,7 +506,7 @@ void SalomePyQt::updateObjBrowser( const int studyId, bool updateSelection ) QList apps = SUIT_Session::session()->applications(); QList::Iterator it; for( it = apps.begin(); it != apps.end(); ++it ) { - SalomeApp_Application* anApp = dynamic_cast( *it ); + LightApp_Application* anApp = dynamic_cast( *it ); if ( anApp && anApp->activeStudy() && anApp->activeStudy()->id() == myStudyId ) { anApp->updateObjectBrowser(); return; @@ -1149,7 +1149,7 @@ public: myOpen ( open ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { myResult = anApp->getFileName( myOpen, myInitial, myFilters.join(";;"), myCaption, myParent ); } @@ -1197,7 +1197,7 @@ public: myCaption( caption ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { myResult = anApp->getOpenFileNames( myInitial, myFilters.join(";;"), myCaption, myParent ); } } @@ -1238,7 +1238,7 @@ public: myCaption( caption ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { myResult = anApp->getDirectory( myInitial, myCaption, myParent ); } } @@ -1270,7 +1270,7 @@ void SalomePyQt::helpContext( const QString& source, const QString& context ) : mySource( source ), myContext( context ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { anApp->onHelpContextModule( "", mySource, myContext ); } } @@ -1301,7 +1301,7 @@ public: : myResult ( false ), myFileName( filename ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewManager* vm = anApp->activeViewManager(); if ( vm ) { SUIT_ViewWindow* vw = vm->getActiveView(); @@ -1338,7 +1338,7 @@ public: TDefMenuGroupEvent() : myResult( -1 ) {} virtual void Execute() { - myResult = SALOME_PYQT_Module::defaultMenuGroup(); + myResult = SALOME_PYQT_ModuleLight::defaultMenuGroup(); } }; int SalomePyQt::defaultMenuGroup() @@ -1360,7 +1360,7 @@ public: CrTool( QAction* action, const QString& tBar, const int id, const int idx ) : myCase( 4 ), myAction( action ), myTbName( tBar ), myId( id ), myIndex( idx ) {} - int execute( SALOME_PYQT_Module* module ) const + int execute( SALOME_PYQT_ModuleLight* module ) const { if ( module ) { switch ( myCase ) { @@ -1397,7 +1397,7 @@ public: : myResult( -1 ), myCrTool( crTool ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = myCrTool.execute( module ); } @@ -1479,7 +1479,7 @@ public: CrMenu( QAction* action, const QString& menu, const int id, const int group, const int idx ) : myCase( 5 ), myAction( action ), myMenuName( menu ), myId( id ), myGroup( group ), myIndex( idx ) {} - int execute( SALOME_PYQT_Module* module ) const + int execute( SALOME_PYQT_ModuleLight* module ) const { if ( module ) { switch ( myCase ) { @@ -1520,7 +1520,7 @@ public: : myResult( -1 ), myCrMenu( crMenu ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = myCrMenu.execute( module ); } @@ -1621,7 +1621,7 @@ public: : myResult( 0 ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = (QAction*)module->separator(); } @@ -1667,7 +1667,7 @@ public: myStatusText( statusText ), myIcon( icon ), myKey( key ), myToggle( toggle ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = (QAction*)module->createAction( myId, myTipText, myIcon, myMenuText, myStatusText, myKey, myToggle ); } @@ -1695,7 +1695,7 @@ struct TcreateActionGroupEvent: public SALOME_Event { : myId( id ), myExclusive( exclusive ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = module->createActionGroup( myId, myExclusive ); } @@ -1721,7 +1721,7 @@ public: : myResult( 0 ), myId( id ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = (QAction*)module->action( myId ); } @@ -1747,7 +1747,7 @@ public: : myResult( -1 ), myAction( action ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = module->actionId( myAction ); } @@ -1774,7 +1774,7 @@ public: : myResult( -1 ), myLabel( label ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = module->addGlobalPreference( myLabel ); } @@ -1801,7 +1801,7 @@ public: : myResult( -1 ), myLabel( label ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = module->addPreference( myLabel ); } @@ -1842,7 +1842,7 @@ public: mySection( section ), myParam ( param ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = module->addPreference( myLabel, myPId, myType, mySection, myParam ); } @@ -1872,7 +1872,7 @@ public: : myId( id ), myProp( prop ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) myResult = module->preferenceProperty( myId, myProp ); } @@ -1902,7 +1902,7 @@ void SalomePyQt::setPreferenceProperty( const int id, : myId( id ), myProp( prop ), myVar( var ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) module->setPreferenceProperty( myId, myProp, myVar ); } @@ -1937,7 +1937,7 @@ void SalomePyQt::addPreferenceProperty( const int id, : myId( id ), myProp( prop ), myIdx( idx), myVar( var ) {} virtual void Execute() { - SALOME_PYQT_Module* module = getActiveModule(); + SALOME_PYQT_ModuleLight* module = getActiveModule(); if ( module ) { QVariant var = module->preferenceProperty( myId, myProp ); if ( var.isValid() ) { @@ -1986,7 +1986,7 @@ void SalomePyQt::message( const QString& msg, bool addSeparator ) : myMsg( msg ), myAddSep( addSeparator ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { LogWindow* lw = anApp->logWindow(); if ( lw ) lw->putMessage( myMsg, myAddSep ); @@ -2007,7 +2007,7 @@ void SalomePyQt::clearMessages() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { LogWindow* lw = anApp->logWindow(); if ( lw ) lw->clear(); @@ -2027,7 +2027,7 @@ static SUIT_ViewWindow* getWnd( const int id ) { SUIT_ViewWindow* resWnd = 0; - SalomeApp_Application* app = getApplication(); + LightApp_Application* app = getApplication(); if ( app ) { STD_TabDesktop* tabDesk = dynamic_cast( app->desktop() ); @@ -2064,7 +2064,7 @@ public: virtual void Execute() { myResult.clear(); - SalomeApp_Application* app = getApplication(); + LightApp_Application* app = getApplication(); if ( app ) { STD_TabDesktop* tabDesk = dynamic_cast( app->desktop() ); @@ -2098,7 +2098,7 @@ public: : myResult( -1 ) {} virtual void Execute() { - SalomeApp_Application* app = getApplication(); + LightApp_Application* app = getApplication(); if ( app ) { SUIT_ViewManager* viewMgr = app->activeViewManager(); @@ -2228,7 +2228,7 @@ public: virtual void Execute() { myResult.clear(); - SalomeApp_Application* app = getApplication(); + LightApp_Application* app = getApplication(); if ( app ) { ViewManagerList vmList; @@ -2301,7 +2301,7 @@ public: myType( theType ) {} virtual void Execute() { - SalomeApp_Application* app = getApplication(); + LightApp_Application* app = getApplication(); if ( app ) { SUIT_ViewManager* viewMgr = app->createViewManager( myType ); @@ -2452,7 +2452,7 @@ public: : myResult( false ) {} virtual void Execute() { - SalomeApp_Application* app = getApplication(); + LightApp_Application* app = getApplication(); if ( app ) { STD_TabDesktop* tabDesk = dynamic_cast( app->desktop() ); @@ -2623,3 +2623,246 @@ QList SalomePyQt::neighbourViews( const int id ) { return ProcessEvent( new TNeighbourViews( id ) ); } + + +/*! + SalomePyQt::createObject(parent) + Create empty data object +*/ +class TCreateEmptyObjectEvent: public SALOME_Event { +public: + typedef QString TResult; + TResult myResult; + QString myParent; + TCreateEmptyObjectEvent(const QString& parent) : myParent( parent ) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + myResult = (QString)module->createObject(myParent); + } +}; +QString SalomePyQt::createObject(const QString& parent) +{ + return ProcessEvent( new TCreateEmptyObjectEvent(parent) ); +} + +/*! + SalomePyQt::createObject( name, icon, tooltip, parent ) + Create data object with name, icon and tooltip +*/ +class TCreateObjectEvent: public SALOME_Event { +public: + typedef QString TResult; + TResult myResult; + QString myParent; + QString myName; + QString myIconName; + QString myToolTip; + TCreateObjectEvent(const QString& name, + const QString& iconname, + const QString& tooltip, + const QString& parent) : myName(name), + myIconName(iconname), + myToolTip(tooltip), + myParent( parent ){} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + myResult = (QString)module->createObject(myName, myIconName, + myToolTip, myParent); + } +}; +QString SalomePyQt::createObject(const QString& name, + const QString& iconname, + const QString& tooltip, + const QString& parent) +{ + return ProcessEvent( new TCreateObjectEvent(name, iconname, tooltip, parent) ); +} + + +/*! + SalomePyQt::setName(obj,name) + Set object name +*/ +class TSetNameEvent: public SALOME_Event +{ +public: + QString myObj; + QString myName; + TSetNameEvent( const QString& obj, + const QString& name) : myObj(obj), + myName(name) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + module->setName(myObj,myName); + } +}; +void SalomePyQt::setName(const QString& obj,const QString& name) +{ + ProcessVoidEvent(new TSetNameEvent(obj,name)); +} + + +/*! + SalomePyQt::setIcon(obj,icon) + Set object icon +*/ +class TSetIconEvent: public SALOME_Event +{ +public: + QString myObj; + QString myIconName; + TSetIconEvent( const QString& obj, + const QString& iconname) : myObj(obj), + myIconName(iconname) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + module->setIcon(myObj,myIconName); + } +}; + +void SalomePyQt::setIcon(const QString& obj,const QString& iconname) +{ + ProcessVoidEvent(new TSetIconEvent(obj,iconname)); +} + +/*! + SalomePyQt::setToolTip(obj,tooltip) + Set object tool tip +*/ +class TSetToolTipEvent: public SALOME_Event +{ +public: + QString myObj; + QString myToolTip; + TSetToolTipEvent( const QString& obj, + const QString& tooltip) : myObj(obj), + myToolTip(tooltip) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + module->setToolTip(myObj,myToolTip); + } +}; +void SalomePyQt::setToolTip(const QString& obj,const QString& tooltip) +{ + ProcessVoidEvent(new TSetToolTipEvent(obj,tooltip)); +} + +/*! + SalomePyQt::getName(obj) + Return name of object +*/ +class TGetNameEvent: public SALOME_Event +{ +public: + typedef QString TResult; + TResult myResult; + QString myObj; + TGetNameEvent( const QString& obj ) : myObj(obj) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + myResult = (QString) module->getName(myObj); + } +}; + +QString SalomePyQt::getName(const QString& obj) +{ + return ProcessEvent(new TGetNameEvent(obj)); +} + +/*! + SalomePyQt::getToolTip(obj) + Return tool tip of object +*/ +class TGetToolTipEvent: public SALOME_Event +{ +public: + typedef QString TResult; + TResult myResult; + QString myObj; + TGetToolTipEvent( const QString& obj ) : myObj(obj) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + myResult = (QString)module->getToolTip(myObj); + } +}; +QString SalomePyQt::getToolTip(const QString& obj) +{ + return ProcessEvent(new TGetToolTipEvent(obj)); +} + + +/*! + SalomePyQt::removeChild(obj) + Remove childrens from object +*/ +class TRemoveChildEvent: public SALOME_Event +{ +public: + QString myObj; + TRemoveChildEvent(const QString& obj) : myObj(obj) {} + + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + module->removeChild(myObj); + } +}; +void SalomePyQt::removeChild(const QString& obj) +{ + ProcessVoidEvent(new TRemoveChildEvent(obj)); +} + + +/*! + SalomePyQt::removeObject(obj) + Remove object +*/ +class TRemoveObjectEvent: public SALOME_Event +{ +public: + QString myObj; + + TRemoveObjectEvent( const QString& obj) : myObj(obj) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + module->removeObject(myObj); + } +}; +void SalomePyQt::removeObject(const QString& obj) +{ + ProcessVoidEvent(new TRemoveObjectEvent(obj)); +} + +/*! + SalomePyQt::getChildren(obj) + Return the list of the child objects + if rec == true then function get all sub children. +*/ + +class TGetChildrenEvent: public SALOME_Event +{ +public: + typedef QStringList TResult; + TResult myResult; + QString myObj; + bool myRec; + TGetChildrenEvent(const QString& obj, const bool rec) : myObj(obj), + myRec(rec) {} + virtual void Execute() { + SALOME_PYQT_ModuleLight* module = getActiveModule(); + if ( module ) + myResult = (QStringList)module->getChildren(myObj,myRec); + } +}; +QStringList SalomePyQt::getChildren(const QString& obj, const bool rec) +{ + return ProcessEvent( new TGetChildrenEvent(obj,rec) ); +} diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h index 2643b2112..7bb7b9c6d 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.h @@ -33,7 +33,7 @@ #include class LightApp_SelectionMgr; -class SalomeApp_Application; +class LightApp_Application; class QMenuBar; class QMenu; class QWidget; @@ -46,7 +46,7 @@ class SALOME_Selection : public QObject public: ~SALOME_Selection(); - static SALOME_Selection* GetSelection( SalomeApp_Application* ); + static SALOME_Selection* GetSelection( LightApp_Application* ); void Clear(); void ClearIObjects(); @@ -130,6 +130,21 @@ public: static QStringList getOpenFileNames ( QWidget*, const QString&, const QStringList&, const QString& ); static QString getExistingDirectory( QWidget*, const QString&, const QString& ); + static QString createObject(const QString& parent = QString("")); + static QString createObject(const QString& name, + const QString& iconname, + const QString& tooltip, + const QString& parent = QString("")); + + static void removeObject( const QString& obj); + static void removeChild( const QString& obj = QString("")); + static QStringList getChildren(const QString& obj = QString(""), const bool rec = false); + static void setName(const QString& obj,const QString& name); + static void setIcon(const QString& obj,const QString& iconname); + static void setToolTip(const QString& obj,const QString& tooltip); + static QString getName(const QString& obj); + static QString getToolTip(const QString& obj); + static void helpContext( const QString&, const QString& ); static bool dumpView( const QString& ); diff --git a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip index b4ff56444..02ae20e6f 100644 --- a/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip +++ b/src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip @@ -216,7 +216,26 @@ public: static QString getFileName ( QWidget*, const QString&, const QStringList&, const QString&, bool ) /ReleaseGIL/ ; static QStringList getOpenFileNames ( QWidget*, const QString&, const QStringList&, const QString& ) /ReleaseGIL/ ; - static QString getExistingDirectory( QWidget*, const QString&, const QString& ) /ReleaseGIL/ ; + static QString getExistingDirectory( QWidget*, const + QString&, const QString& ) /ReleaseGIL/ ; + + + + static QString createObject( const QString& = QString("") ) /ReleaseGIL/ ; + static QString createObject( const QString&, + const QString&, + const QString&, + const QString& = QString("") ) /ReleaseGIL/ ; + + static void setName(const QString& ,const QString& ) /ReleaseGIL/ ; + static void setIcon(const QString& ,const QString& ) /ReleaseGIL/ ; + static void setToolTip(const QString& ,const QString& ) /ReleaseGIL/ ; + static QString getName(const QString& ) /ReleaseGIL/ ; + static QString getToolTip(const QString& ) /ReleaseGIL/ ; + + static void removeObject(const QString& ) /ReleaseGIL/ ; + static void removeChild(const QString& = QString("") ) /ReleaseGIL/ ; + static QStringList getChildren(const QString&=QString("") , const bool = false) /ReleaseGIL/ ; static void helpContext( const QString&, const QString& ) /ReleaseGIL/ ; diff --git a/src/SALOME_SWIG/Makefile.am b/src/SALOME_SWIG/Makefile.am index 7719d37a1..d29f673dd 100755 --- a/src/SALOME_SWIG/Makefile.am +++ b/src/SALOME_SWIG/Makefile.am @@ -63,17 +63,16 @@ _libSALOME_Swig_la_CPPFLAGS = \ $(QT_INCLUDES) $(QWT_INCLUDES) $(PYTHON_INCLUDES) $(CAS_CPPFLAGS) $(VTK_INCLUDES) \ $(OGL_INCLUDES) $(BOOST_CPPFLAGS) -DHAVE_CONFIG_H @KERNEL_CXXFLAGS@ \ -I$(top_builddir)/salome_adm/unix -I$(top_builddir)/idl -I$(srcdir) \ - -I$(srcdir)/../SalomeApp -I$(srcdir)/../Qtx -I$(srcdir)/../SUIT \ + -I$(srcdir)/../LightApp -I$(srcdir)/../Qtx -I$(srcdir)/../SUIT \ -I$(srcdir)/../ObjBrowser -I$(srcdir)/../LightApp -I$(srcdir)/../SOCC \ -I$(srcdir)/../SVTK -I$(srcdir)/../Event -I$(srcdir)/../OBJECT \ -I$(srcdir)/../CAM -I$(srcdir)/../STD -I$(srcdir)/../OCCViewer \ -I$(srcdir)/../Prs -I$(srcdir)/../VTKViewer -I$(srcdir)/../SPlot2d \ - -I$(srcdir)/../Plot2d \ - @CORBA_CXXFLAGS@ @CORBA_INCLUDES@ + -I$(srcdir)/../Plot2d _libSALOME_Swig_la_LDFLAGS = -module _libSALOME_Swig_la_LIBADD = \ - ../SalomeApp/libSalomeApp.la \ + ../LightApp/libLightApp.la \ @PYTHON_LIBS@ swig_wrap.cpp : $(SWIG_SOURCES) diff --git a/src/SALOME_SWIG/SALOMEGUI_Swig.cxx b/src/SALOME_SWIG/SALOMEGUI_Swig.cxx index 51e670e46..a471eed86 100644 --- a/src/SALOME_SWIG/SALOMEGUI_Swig.cxx +++ b/src/SALOME_SWIG/SALOMEGUI_Swig.cxx @@ -31,10 +31,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include @@ -101,10 +101,10 @@ \internal \return active application or 0 if there is no any */ -static SalomeApp_Application* getApplication() +static LightApp_Application* getApplication() { if ( SUIT_Session::session() ) - return dynamic_cast( SUIT_Session::session()->activeApplication() ); + return dynamic_cast( SUIT_Session::session()->activeApplication() ); return 0; } @@ -113,10 +113,10 @@ static SalomeApp_Application* getApplication() \internal \return active study or 0 if there is no study opened */ -static SalomeApp_Study* getActiveStudy() +static LightApp_Study* getActiveStudy() { if ( getApplication() ) - return dynamic_cast( getApplication()->activeStudy() ); + return dynamic_cast( getApplication()->activeStudy() ); return 0; } @@ -168,7 +168,7 @@ void SALOMEGUI_Swig::updateObjBrowser( bool /*updateSelection*/ ) TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { anApp->updateObjectBrowser(); anApp->updateActions(); //SRN: added in order to update the toolbar } @@ -191,8 +191,8 @@ public: TGetActiveStudyIdEvent() : myResult( 0 ) {} virtual void Execute() { - if ( SalomeApp_Study* aStudy = getActiveStudy() ) { - myResult = aStudy->studyDS()->StudyId(); + if ( LightApp_Study* aStudy = getActiveStudy() ) { + myResult = aStudy->id(); } } }; @@ -215,8 +215,8 @@ public: TGetActiveStudyNameEvent() {} virtual void Execute() { - if ( SalomeApp_Study* aStudy = getActiveStudy() ) { - myResult = aStudy->studyDS()->Name(); + if ( LightApp_Study* aStudy = getActiveStudy() ) { + myResult = aStudy->id(); } } }; @@ -251,7 +251,7 @@ public: : myName( name ), myIsUserName( isUserName ) {} virtual void Execute() { - if ( SalomeApp_Application* app = getApplication() ) { + if ( LightApp_Application* app = getApplication() ) { myResult = myIsUserName ? app->moduleTitle( myName ) : app->moduleName( myName ); } } @@ -288,8 +288,8 @@ public: TGetSelectedEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { - SalomeApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! + if ( LightApp_Application* anApp = getApplication() ) { + LightApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! LightApp_SelectionMgr* aSelMgr = anApp->selectionMgr(); if ( aStudy && aSelMgr ) { SUIT_DataOwnerPtrList aList; @@ -334,8 +334,8 @@ void SALOMEGUI_Swig::AddIObject( const char* theEntry ) TEvent( const char* theEntry ) : myEntry( theEntry ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { - SalomeApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! + if ( LightApp_Application* anApp = getApplication() ) { + LightApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! LightApp_SelectionMgr* aSelMgr = anApp->selectionMgr(); if ( aStudy && aSelMgr ) { SALOME_ListIO anIOList; @@ -361,8 +361,8 @@ void SALOMEGUI_Swig::RemoveIObject( const char* theEntry ) TEvent( const char* theEntry ) : myEntry( theEntry ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { - SalomeApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! + if ( LightApp_Application* anApp = getApplication() ) { + LightApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! LightApp_SelectionMgr* aSelMgr = anApp->selectionMgr(); if ( aStudy && aSelMgr ) { SALOME_ListIO anIOList; @@ -398,8 +398,8 @@ void SALOMEGUI_Swig::ClearIObjects() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { - SalomeApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! + if ( LightApp_Application* anApp = getApplication() ) { + LightApp_Study* aStudy = dynamic_cast( anApp->activeStudy() ); // for sure! LightApp_SelectionMgr* aSelMgr = anApp->selectionMgr(); if ( aStudy && aSelMgr ) aSelMgr->clearSelected(); @@ -427,7 +427,7 @@ void SALOMEGUI_Swig::Display( const char* theEntry ) public: TEvent( const char* theEntry ) : myEntry( theEntry ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); @@ -460,7 +460,7 @@ void SALOMEGUI_Swig::DisplayOnly( const char* theEntry ) TEvent( const char* theEntry ) : myEntry( theEntry ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); @@ -494,7 +494,7 @@ void SALOMEGUI_Swig::Erase( const char* theEntry ) TEvent( const char* theEntry ) : myEntry( theEntry ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); @@ -524,15 +524,15 @@ void SALOMEGUI_Swig::DisplayAll() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { - SalomeApp_Study* study = dynamic_cast( anApp->activeStudy() ); // for sure! + if ( LightApp_Application* anApp = getApplication() ) { + LightApp_Study* study = dynamic_cast( anApp->activeStudy() ); // for sure! SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); - SalomeApp_Module* activeModule = dynamic_cast( anApp->activeModule() ); + LightApp_Module* activeModule = dynamic_cast( anApp->activeModule() ); if ( study && window && activeModule ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); if ( view ) { for ( SUIT_DataObjectIterator it( activeModule->dataModel()->root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) { - SalomeApp_DataObject* obj = dynamic_cast( it.current() ); + LightApp_DataObject* obj = dynamic_cast( it.current() ); if ( obj && !obj->entry().isEmpty() ) view->Display( view->CreatePrs( obj->entry().toLatin1() ) ); } @@ -557,7 +557,7 @@ void SALOMEGUI_Swig::EraseAll() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); @@ -590,7 +590,7 @@ public: TIsInViewerEvent( const char* theEntry ) : myEntry( theEntry ), myResult( false ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); @@ -618,7 +618,7 @@ void SALOMEGUI_Swig::UpdateView() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { SALOME_View* view = dynamic_cast( window->getViewManager()->getViewModel() ); @@ -642,7 +642,7 @@ void SALOMEGUI_Swig::FitAll() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { if ( dynamic_cast( window ) ) @@ -669,7 +669,7 @@ void SALOMEGUI_Swig::ResetView() TEvent() {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { if ( dynamic_cast( window ) ) @@ -715,7 +715,7 @@ static void setView( int view ) TEvent( int view ) : myView( view ) {} virtual void Execute() { - if ( SalomeApp_Application* anApp = getApplication() ) { + if ( LightApp_Application* anApp = getApplication() ) { SUIT_ViewWindow* window = anApp->desktop()->activeWindow(); if ( window ) { if ( dynamic_cast( window ) ) { diff --git a/src/SALOME_SWIG/SALOMEGUI_shared_modules.py b/src/SALOME_SWIG/SALOMEGUI_shared_modules.py index 02b161770..241e48d11 100755 --- a/src/SALOME_SWIG/SALOMEGUI_shared_modules.py +++ b/src/SALOME_SWIG/SALOMEGUI_shared_modules.py @@ -23,7 +23,10 @@ """ -import SALOME_Session_idl +try: + import SALOME_Session_idl +except: + pass from import_hook import register_name register_name("SalomePyQt") diff --git a/src/SUITApp/Makefile.am b/src/SUITApp/Makefile.am index fae3df008..54b198a57 100644 --- a/src/SUITApp/Makefile.am +++ b/src/SUITApp/Makefile.am @@ -29,11 +29,13 @@ include $(top_srcdir)/adm_local/unix/make_common_starter.am lib_LTLIBRARIES = libSUITApp.la salomeinclude_HEADERS = \ - SUITApp_Application.h + SUITApp_Application.h \ + SUITApp_init_python.hxx dist_libSUITApp_la_SOURCES = \ SUITApp.cxx \ - SUITApp_Application.cxx + SUITApp_Application.cxx \ + SUITApp_init_python.cxx MOC_FILES = \ SUITApp_Application_moc.cxx @@ -60,6 +62,7 @@ libSUITApp_la_LIBADD = ../Qtx/libqtx.la ../SUIT/libsuit.la ../Style/libSalomeS if ENABLE_PYCONSOLE libSUITApp_la_LDFLAGS += -Xlinker -export-dynamic $(PYTHON_LIBS) +CPPFLAGS+=-DSUIT_ENABLE_PYTHON endif # Executable diff --git a/src/SUITApp/SUITApp.cxx b/src/SUITApp/SUITApp.cxx index 0613d15c5..5432a6c89 100644 --- a/src/SUITApp/SUITApp.cxx +++ b/src/SUITApp/SUITApp.cxx @@ -36,6 +36,10 @@ #include #endif +#ifdef SUIT_ENABLE_PYTHON +#include +#endif + #endif //#if defined WIN32 #include "SUITApp_Application.h" @@ -172,15 +176,15 @@ private: int main( int argc, char* argv[] ) { -#ifdef SUIT_ENABLE_PYTHON - // First of all initialize Python, as in complex multi-component applications - // someone else might initialize it some way unsuitable for light SALOME! - Py_SetProgramName( argv[0] ); - Py_Initialize(); // Initialize the interpreter - PySys_SetArgv( argc, argv ); - PyEval_InitThreads(); // Create (and acquire) the interpreter lock - PyEval_ReleaseLock(); // Let the others use Python API until we need it again -#endif + //#ifdef SUIT_ENABLE_PYTHON + // // First of all initialize Python, as in complex multi-component applications + // // someone else might initialize it some way unsuitable for light SALOME! + // Py_SetProgramName( argv[0] ); + // Py_Initialize(); // Initialize the interpreter + // PySys_SetArgv( argc, argv ); + // PyEval_InitThreads(); // Create (and acquire) the interpreter lock + // PyEval_ReleaseLock(); // Let the others use Python API until we need it again + //#endif //qInstallMsgHandler( MessageOutput ); @@ -274,6 +278,23 @@ int main( int argc, char* argv[] ) } } +#ifdef SUIT_ENABLE_PYTHON + //...Initialize python + int _argc = 1; + char* _argv[] = {""}; + SUIT_PYTHON::init_python(_argc,_argv); + + PyEval_RestoreThread( SUIT_PYTHON::_gtstate ); + + if ( !SUIT_PYTHON::salome_shared_modules_module ) // import only once + SUIT_PYTHON::salome_shared_modules_module = PyImport_ImportModule( "salome_shared_modules" ); + if ( !SUIT_PYTHON::salome_shared_modules_module ) + PyErr_Print(); + + PyEval_ReleaseThread( SUIT_PYTHON::_gtstate ); + +#endif + SUIT_Application* theApp = aSession->startApplication( argList.first() ); if ( theApp ) { diff --git a/src/SUITApp/SUITApp_init_python.cxx b/src/SUITApp/SUITApp_init_python.cxx new file mode 100644 index 000000000..72c350f56 --- /dev/null +++ b/src/SUITApp/SUITApp_init_python.cxx @@ -0,0 +1,48 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + + +#include "SUITApp_init_python.hxx" + + +PyThreadState* SUIT_PYTHON::_gtstate = NULL; +PyObject *SUIT_PYTHON::salome_shared_modules_module = NULL; +PyInterpreterState* SUIT_PYTHON::_interp = NULL; +bool SUIT_PYTHON::initialized = false; + +void SUIT_PYTHON::init_python(int argc, char **argv) +{ + if (Py_IsInitialized()) + { + return; + } + Py_SetProgramName(argv[0]); + Py_Initialize(); // Initialize the interpreter + PySys_SetArgv(argc, argv); + SUIT_PYTHON::_interp = PyThreadState_Get()->interp; + PyEval_InitThreads(); // Create (and acquire) the interpreter lock + SUIT_PYTHON::_gtstate = PyEval_SaveThread(); // Release global thread state + SUIT_PYTHON::initialized = true; +} + diff --git a/src/SUITApp/SUITApp_init_python.hxx b/src/SUITApp/SUITApp_init_python.hxx new file mode 100644 index 000000000..99217a19a --- /dev/null +++ b/src/SUITApp/SUITApp_init_python.hxx @@ -0,0 +1,42 @@ +// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com) +// Date : 22/06/2007 + + +#ifndef _SUITAPP_INIT_PYTHON_ +#define _SUITAPP_INIT_PYTHON_ + +#include +#include + +struct SUIT_PYTHON +{ + static PyThreadState *_gtstate; + static PyInterpreterState *_interp; + static PyObject *salome_shared_modules_module; + static bool initialized; + static void init_python(int argc, char **argv); + +}; + +#endif // _SUITAPP_INIT_PYTHON_ diff --git a/src/SalomeApp/SalomeApp_Module.h b/src/SalomeApp/SalomeApp_Module.h index 3e4af4e13..b248966db 100644 --- a/src/SalomeApp/SalomeApp_Module.h +++ b/src/SalomeApp/SalomeApp_Module.h @@ -39,7 +39,7 @@ class QString; /*! * \brief Base class for all salome modules */ -class SALOMEAPP_EXPORT SalomeApp_Module : public LightApp_Module +class SALOMEAPP_EXPORT SalomeApp_Module : virtual public LightApp_Module { Q_OBJECT