From 4192fecf4e828bc70113660a0aaf558fdb68e481 Mon Sep 17 00:00:00 2001 From: nds Date: Fri, 29 Aug 2008 08:59:11 +0000 Subject: [PATCH] Win32 porting. --- src/ObjBrowser/ObjBrowser.pro | 20 +- src/Plot2d/Plot2d.pro | 29 +- src/Plot2d/Plot2d_HistogramItem.h | 1 - src/Plot2d/Plot2d_Object.h | 4 +- src/Plot2d/Plot2d_ViewFrame.h | 1 + src/Prs/Prs.pro | 16 +- src/PyConsole/PyConsole.h | 40 +-- src/PyConsole/PyConsole.pro | 19 +- src/PyConsole/PyConsole_Console.cxx | 175 +++++++---- src/PyConsole/PyConsole_Console.h | 60 ++-- src/PyConsole/PyConsole_Editor.cxx | 175 +++++++---- src/PyConsole/PyConsole_Editor.h | 41 ++- src/PyConsole/PyConsole_Interp.cxx | 48 ++- src/PyConsole/PyConsole_Interp.h | 6 +- src/PyInterp/PyInterp.h | 44 +-- src/PyInterp/PyInterp.pro | 17 +- src/PyInterp/PyInterp_Dispatcher.cxx | 35 +-- src/PyInterp/PyInterp_Dispatcher.h | 37 +-- src/PyInterp/PyInterp_Interp.cxx | 449 +++++++++++++++++++++++++++ src/PyInterp/PyInterp_Interp.h | 116 +++++++ src/PyInterp/PyInterp_Watcher.h | 14 +- src/PyInterp/PyInterp_base.cxx | 317 ------------------- src/PyInterp/PyInterp_base.h | 145 --------- src/Qtx/Qtx.pro | 18 +- src/STD/STD.pro | 25 +- 25 files changed, 1079 insertions(+), 773 deletions(-) create mode 100644 src/PyInterp/PyInterp_Interp.cxx create mode 100644 src/PyInterp/PyInterp_Interp.h delete mode 100644 src/PyInterp/PyInterp_base.cxx delete mode 100644 src/PyInterp/PyInterp_base.h diff --git a/src/ObjBrowser/ObjBrowser.pro b/src/ObjBrowser/ObjBrowser.pro index 61bf93c5b..ff7dd2bd0 100644 --- a/src/ObjBrowser/ObjBrowser.pro +++ b/src/ObjBrowser/ObjBrowser.pro @@ -1,4 +1,7 @@ -TEMPLATE = lib +unix:TEMPLATE = lib +win32:TEMPLATE = vclib + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc @@ -6,12 +9,14 @@ OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET INCLUDEPATH += ../../include ../Qtx LIBS += -L../../$(CONFIG_ID)/lib -lQtx +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 -DEFINES += LOGWINDOW_EXPORTS +win32:DEFINES += WNT WIN32 +DEFINES += OB_EXPORTS HEADERS = *.h @@ -24,7 +29,7 @@ win32:GUIResources = ..\\..\\resources lrelease.name = LRELASE ${QMAKE_FILE_IN} unix:lrelease.commands = $(QTDIR)/bin/lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}/${QMAKE_FILE_BASE}.qm -win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm +win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_IN} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm unix:lrelease.output = $${GUIResources}/${QMAKE_FILE_BASE}.qm win32:lrelease.output = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.input = TRANSLATIONS @@ -33,6 +38,13 @@ win32:lrelease.clean = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += lrelease +win32:copy_hdr.name = Install ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + + includes.files = $$HEADERS includes.path = ../../include diff --git a/src/Plot2d/Plot2d.pro b/src/Plot2d/Plot2d.pro index 9a06a130f..976b8d7c1 100644 --- a/src/Plot2d/Plot2d.pro +++ b/src/Plot2d/Plot2d.pro @@ -1,4 +1,7 @@ -TEMPLATE = lib +unix:TEMPLATE = lib +win32:TEMPLATE = vclib + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc @@ -7,13 +10,15 @@ OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET INCLUDEPATH += ../../include $$(QWTINC) $$(PYTHONINC) INCLUDEPATH += ../Qtx ../SUIT unix:LIBS += -L$$(QWTLIB) -lqwt -win32:LIBS += /LIBPATH:$$(QWTLIB) +win32:LIBS += /LIBPATH:$$(QWTLIB) -lqwt5 LIBS += -L../../$(CONFIG_ID)/lib -lQtx -lSUIT +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 +win32:DEFINES += WNT WIN32 QWT_DLL DEFINES += PLOT2D_EXPORTS HEADERS = *.h @@ -26,9 +31,15 @@ TRANSLATIONS = resources/Plot2d_msg_en.ts \ unix:GUIResources = ../../resources win32:GUIResources = ..\\..\\resources +win32:copy_hdr.name = Install headers ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + lrelease.name = LRELASE ${QMAKE_FILE_IN} -unix:lrelease.commands = $(QTDIR)/bin/lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}/${QMAKE_FILE_BASE}.qm -win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm +unix:lrelease.commands = $(QTDIR)/bin/lrelease ${QMAKE_FILE_NAME} -qm ${QMAKE_FILE_OUT} +win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} unix:lrelease.output = $${GUIResources}/${QMAKE_FILE_BASE}.qm win32:lrelease.output = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.input = TRANSLATIONS @@ -39,6 +50,14 @@ QMAKE_EXTRA_COMPILERS += lrelease ICONS = resources/*.png +win32:SOURCES+=$$ICONS +win32:Resource=$$ICONS +win32:copy_res.name = Install resources ${QMAKE_FILE_IN} +win32:copy_res.commands = type ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +win32:copy_res.output = $${GUIResources}\\${QMAKE_FILE_BASE}.png +win32:copy_res.input = Resource +win32:QMAKE_EXTRA_COMPILERS += copy_res + includes.files = $$HEADERS includes.path = ../../include diff --git a/src/Plot2d/Plot2d_HistogramItem.h b/src/Plot2d/Plot2d_HistogramItem.h index 0e62a7293..889e829bb 100644 --- a/src/Plot2d/Plot2d_HistogramItem.h +++ b/src/Plot2d/Plot2d_HistogramItem.h @@ -66,7 +66,6 @@ protected: protected: void init(); - class PrivateData; PrivateData* m_pData; }; diff --git a/src/Plot2d/Plot2d_Object.h b/src/Plot2d/Plot2d_Object.h index 3db5b1b91..da2ea362d 100755 --- a/src/Plot2d/Plot2d_Object.h +++ b/src/Plot2d/Plot2d_Object.h @@ -28,12 +28,12 @@ #include #include -typedef struct +struct PLOT2D_EXPORT Plot2d_Point { double x; double y; QString text; -} Plot2d_Point; +}; typedef QList pointList; diff --git a/src/Plot2d/Plot2d_ViewFrame.h b/src/Plot2d/Plot2d_ViewFrame.h index 2637a16ab..ced090ea8 100755 --- a/src/Plot2d/Plot2d_ViewFrame.h +++ b/src/Plot2d/Plot2d_ViewFrame.h @@ -225,6 +225,7 @@ class Plot2d_Plot2d : public QwtPlot Q_OBJECT public: Plot2d_Plot2d( QWidget* parent ); + virtual ~Plot2d_Plot2d() {}; void setLogScale( int axisId, bool log10 ); diff --git a/src/Prs/Prs.pro b/src/Prs/Prs.pro index 06b145539..b4fe7e1fc 100644 --- a/src/Prs/Prs.pro +++ b/src/Prs/Prs.pro @@ -1,19 +1,31 @@ -TEMPLATE = lib +unix:TEMPLATE = lib +win32:TEMPLATE = vclib + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml + CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 +win32:DEFINES += WNT WIN32 DEFINES += PRS_EXPORTS HEADERS = *.h SOURCES = *.cxx +win32:copy_hdr.name = Install ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + includes.files = $$HEADERS includes.path = ../../include diff --git a/src/PyConsole/PyConsole.h b/src/PyConsole/PyConsole.h index 10a7106f6..d27c40c0f 100644 --- a/src/PyConsole/PyConsole.h +++ b/src/PyConsole/PyConsole.h @@ -16,39 +16,25 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#if !defined ( _PYTHONCONSOLE_H ) -#define _PYTHONCONSOLE_H +// File : PyConsole.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#if !defined ( PYCONSOLE_H ) +#define PYCONSOLE_H // ======================================================== // set dllexport type for Win platform #ifdef WIN32 - -#ifdef PYCONSOLE_EXPORTS -#define PYCONSOLE_EXPORT __declspec(dllexport) -#else -#define PYCONSOLE_EXPORT __declspec(dllimport) -#endif - +# ifdef PYCONSOLE_EXPORTS +# define PYCONSOLE_EXPORT __declspec(dllexport) +# else +# define PYCONSOLE_EXPORT __declspec(dllimport) +# endif #else // WIN32 - -#define PYCONSOLE_EXPORT - +# define PYCONSOLE_EXPORT #endif // WIN32 -// ======================================================== -// little trick - we do not have debug python libraries -#ifdef _DEBUG - -#undef _DEBUG -//#include -#define _DEBUG - -#else // _DEBUG - -//#include - -#endif // _DEBUG - // ======================================================== // avoid warning messages #ifdef WIN32 @@ -56,4 +42,4 @@ #pragma warning (disable : 4251) #endif -#endif // _PYTHONCONSOLE_H +#endif // PYCONSOLE_H diff --git a/src/PyConsole/PyConsole.pro b/src/PyConsole/PyConsole.pro index a4fd5061b..04e08a5e9 100644 --- a/src/PyConsole/PyConsole.pro +++ b/src/PyConsole/PyConsole.pro @@ -1,4 +1,7 @@ -TEMPLATE = lib +unix:TEMPLATE = lib +win32:TEMPLATE = vclib + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc @@ -6,12 +9,14 @@ OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET INCLUDEPATH += ../../include $$(PYTHONINC) unix:LIBS += -L../../$(CONFIG_ID)/lib -L$$(PYTHONLIB) -lpython2.5 -lSUIT -lPyInterp -win32:LIBS += /LIBPATH:$$(PYTHONLIB) ../../lib/pyinterp.lib ../../lib/suit.lib +win32:LIBS += -L../../$(CONFIG_ID)/lib -L$$(PYTHONLIB) -lpython25_d -lSUIT -lPyInterp -lQtx +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 +win32:DEFINES += WNT WIN32 HAVE_DEBUG_PYTHON DEFINES += PYCONSOLE_EXPORTS HEADERS = *.h @@ -25,7 +30,7 @@ win32:GUIResources = ..\\..\\resources lrelease.name = LRELASE ${QMAKE_FILE_IN} unix:lrelease.commands = $(QTDIR)/bin/lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}/${QMAKE_FILE_BASE}.qm -win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm +win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_IN} ${QMAKE_FILE_NAME} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm unix:lrelease.output = $${GUIResources}/${QMAKE_FILE_BASE}.qm win32:lrelease.output = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.input = TRANSLATIONS @@ -34,6 +39,12 @@ win32:lrelease.clean = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += lrelease +win32:copy_hdr.name = Install ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + includes.files = $$HEADERS includes.path = ../../include diff --git a/src/PyConsole/PyConsole_Console.cxx b/src/PyConsole/PyConsole_Console.cxx index 85ba6c722..85df7307a 100644 --- a/src/PyConsole/PyConsole_Console.cxx +++ b/src/PyConsole/PyConsole_Console.cxx @@ -16,30 +16,27 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : PythonConsole_PyConcole.cxx -// Author : Vadim SANDLER -// Module : SALOME +// File : PyConsole_Console.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// /*! - \class PythonConsole + \class PyConsole_Console \brief Python console widget. */ -#include - +#include "PyConsole_Interp.h" /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!! #include "PyConsole_Console.h" #include "PyConsole_Editor.h" -#include - -#include -#include -#include -#include -#include -#include +#include -using namespace std; +#include +#include +#include +#include +#include +#include /*! \brief Constructor. @@ -48,9 +45,9 @@ using namespace std; \param parent parent widget \param interp python interpreter */ -PythonConsole::PythonConsole( QWidget* parent, PyInterp_base* interp ) -: QFrame( parent ), -myEditor( 0 ) +PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* interp ) +: QWidget( parent ), + myEditor( 0 ) { // create python interpreter myInterp = interp; @@ -62,7 +59,7 @@ myEditor( 0 ) // create editor console QVBoxLayout* lay = new QVBoxLayout( this ); - lay->setMargin( 5 ); + lay->setMargin( 0 ); myEditor = new PyConsole_Editor( myInterp, this ); myEditor->viewport()->installEventFilter( this ); lay->addWidget( myEditor ); @@ -75,15 +72,15 @@ myEditor( 0 ) Does nothing for the moment. */ -PythonConsole::~PythonConsole() +PyConsole_Console::~PyConsole_Console() { } /*! \brief Execute python command in the interpreter. - \param command - string with command and arguments + \param command string with command and arguments */ -void PythonConsole::exec( const QString& command ) +void PyConsole_Console::exec( const QString& command ) { if ( myEditor ) myEditor->exec( command ); @@ -94,29 +91,45 @@ void PythonConsole::exec( const QString& command ) and wait until it is finished. Block execution of main application until the python command is executed. - \param command - string with command and arguments + \param command string with command and arguments */ -void PythonConsole::execAndWait( const QString& command ) +void PyConsole_Console::execAndWait( const QString& command ) { if ( myEditor ) myEditor->execAndWait( command ); } -bool PythonConsole::isSync() const +/*! + \brief Get synchronous mode flag value. + + \sa setIsSync() + \return True if python console works in synchronous mode +*/ +bool PyConsole_Console::isSync() const { return myEditor->isSync(); } -void PythonConsole::setIsSync( const bool s ) +/*! + \brief Set synchronous mode flag value. + + In synhronous mode the Python commands are executed in the GUI thread + and the GUI is blocked until the command is finished. In the asynchronous + mode each Python command is executed in the separate thread that does not + block the main GUI loop. + + \param on synhronous mode flag +*/ +void PyConsole_Console::setIsSync( const bool on ) { - myEditor->setIsSync( s ); + myEditor->setIsSync( on ); } /*! \brief Change the python console's font. - \param f - new font + \param f new font */ -void PythonConsole::setFont( const QFont& f ) +void PyConsole_Console::setFont( const QFont& f ) { if( myEditor ) myEditor->setFont( f ); @@ -126,7 +139,7 @@ void PythonConsole::setFont( const QFont& f ) \brief Get python console font. \return current python console's font */ -QFont PythonConsole::font() const +QFont PyConsole_Console::font() const { QFont res; if( myEditor ) @@ -135,60 +148,112 @@ QFont PythonConsole::font() const } /*! - Custom event handler + \brief Event handler. + + Handles context menu request event. + + \param o object + \param e event + \return True if the event is processed and further processing should be stopped */ -bool PythonConsole::eventFilter( QObject* o, QEvent* e ) +bool PyConsole_Console::eventFilter( QObject* o, QEvent* e ) { if ( o == myEditor->viewport() && e->type() == QEvent::ContextMenu ) { contextMenuRequest( (QContextMenuEvent*)e ); return true; } - return QFrame::eventFilter( o, e ); + return QWidget::eventFilter( o, e ); } /*! - \brief Process context popup menu event. + \brief Create the context popup menu. + + Fill in the popup menu with the commands. - Show popup menu which includes standard copy/paste operations. - \param event context menu event + \param menu context popup menu */ -void PythonConsole::contextMenuPopup( QMenu* menu ) +void PyConsole_Console::contextMenuPopup( QMenu* menu ) { if ( myEditor->isReadOnly() ) return; - updateActions(); - menu->addAction( myActions[CopyId] ); menu->addAction( myActions[PasteId] ); menu->addAction( myActions[ClearId] ); - menu->addSeparator(); - menu->addAction( myActions[SelectAllId] ); + + Qtx::simplifySeparators( menu ); + + updateActions(); } -void PythonConsole::createActions() +/*! + \brief Set actions to be visible in the context popup menu. + + Actions, which IDs are set in \a flags parameter, will be shown in the + context popup menu. Other actions will not be shown. + + \param flags ORed together actions flags +*/ +void PyConsole_Console::setMenuActions( const int flags ) { - QAction* copyAction = new QAction( tr( "EDIT_COPY_CMD" ), this ); - connect( copyAction, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) ); - myActions.insert( CopyId, copyAction ); + myActions[CopyId]->setVisible( flags & CopyId ); + myActions[PasteId]->setVisible( flags & PasteId ); + myActions[ClearId]->setVisible( flags & ClearId ); + myActions[SelectAllId]->setVisible( flags & SelectAllId ); +} - QAction* pasteAction = new QAction( tr( "EDIT_PASTE_CMD" ), this ); - connect( pasteAction, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) ); - myActions.insert( PasteId, pasteAction ); +/*! + \brief Get menu actions which are currently visible in the context popup menu. + \return ORed together actions flags + \sa setMenuActions() +*/ +int PyConsole_Console::menuActions() const +{ + int ret = 0; + ret = ret | ( myActions[CopyId]->isVisible() ? CopyId : 0 ); + ret = ret | ( myActions[PasteId]->isVisible() ? PasteId : 0 ); + ret = ret | ( myActions[ClearId]->isVisible() ? ClearId : 0 ); + ret = ret | ( myActions[SelectAllId]->isVisible() ? SelectAllId : 0 ); + return ret; +} - QAction* clearAction = new QAction( tr( "EDIT_CLEAR_CMD" ), this ); - connect( clearAction, SIGNAL( triggered( bool ) ), myEditor, SLOT( clear() ) ); - myActions.insert( ClearId, clearAction ); +/*! + \brief Create menu actions. + + Create context popup menu actions. +*/ +void PyConsole_Console::createActions() +{ + QAction* a = new QAction( tr( "EDIT_COPY_CMD" ), this ); + a->setStatusTip( tr( "EDIT_COPY_CMD" ) ); + connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) ); + myActions.insert( CopyId, a ); + + a = new QAction( tr( "EDIT_PASTE_CMD" ), this ); + a->setStatusTip( tr( "EDIT_PASTE_CMD" ) ); + connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) ); + myActions.insert( PasteId, a ); - QAction* selAllAction = new QAction( tr( "EDIT_SELECTALL_CMD" ), this ); - connect( selAllAction, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) ); - myActions.insert( SelectAllId, selAllAction ); + a = new QAction( tr( "EDIT_CLEAR_CMD" ), this ); + a->setStatusTip( tr( "EDIT_CLEAR_CMD" ) ); + connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( clear() ) ); + myActions.insert( ClearId, a ); + + a = new QAction( tr( "EDIT_SELECTALL_CMD" ), this ); + a->setStatusTip( tr( "EDIT_SELECTALL_CMD" ) ); + connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) ); + myActions.insert( SelectAllId, a ); } -void PythonConsole::updateActions() +/*! + \brief Update menu actions. + + Update context popup menu action state. +*/ +void PyConsole_Console::updateActions() { myActions[CopyId]->setEnabled( myEditor->textCursor().hasSelection() ); myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() ); diff --git a/src/PyConsole/PyConsole_Console.h b/src/PyConsole/PyConsole_Console.h index b25f4d191..ed1203b83 100644 --- a/src/PyConsole/PyConsole_Console.h +++ b/src/PyConsole/PyConsole_Console.h @@ -16,65 +16,69 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : PythonConsole_PyConsole.h -// Author : Vadim SANDLER -// Module : SALOME +// File : PyConsole_Console.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// #ifndef PYCONSOLE_CONSOLE_H #define PYCONSOLE_CONSOLE_H #include "PyConsole.h" -#include -#include - #include +#include +#include -class PyInterp_base; +class PyConsole_Interp; class PyConsole_Editor; -class PYCONSOLE_EXPORT PythonConsole : public QFrame, public SUIT_PopupClient +class PYCONSOLE_EXPORT PyConsole_Console : public QWidget, public SUIT_PopupClient { Q_OBJECT public: + //! Context popup menu actions flags enum { - CopyId = 0x01, - PasteId = 0x02, - ClearId = 0x04, - SelectAllId = 0x08, - All = CopyId | PasteId | ClearId | SelectAllId + CopyId = 0x01, //!< "Copy" menu action + PasteId = 0x02, //!< "Paste" menu action + ClearId = 0x04, //!< "Clear" menu action + SelectAllId = 0x08, //!< "Select All" menu action + All = CopyId | PasteId | ClearId | SelectAllId //!< all menu actions }; public: - PythonConsole( QWidget* parent, PyInterp_base* interp = 0 ); - virtual ~PythonConsole(); + PyConsole_Console( QWidget* parent, PyConsole_Interp* interp = 0 ); + virtual ~PyConsole_Console(); //! \brief Get python interperter - PyInterp_base* getInterp() { return myInterp; } - QFont font() const; - virtual void setFont( const QFont& ); + PyConsole_Interp* getInterp() { return myInterp; } + QFont font() const; + virtual void setFont( const QFont& ); + + bool isSync() const; + void setIsSync( const bool ); - bool isSync() const; - void setIsSync( const bool ); + void exec( const QString& ); + void execAndWait( const QString& ); - void exec( const QString& command ); - void execAndWait( const QString& command ); + virtual bool eventFilter( QObject*, QEvent* ); - virtual bool eventFilter( QObject* o, QEvent* e ); + //! \brief Get popup client symbolic name + virtual QString popupClientType() const { return QString( "PyConsole" ); } + virtual void contextMenuPopup( QMenu* ); - virtual QString popupClientType() const { return QString( "PyConsole" ); } - virtual void contextMenuPopup( QMenu* ); + void setMenuActions( const int ); + int menuActions() const; private: void createActions(); void updateActions(); private: - PyInterp_base* myInterp; //!< python interpreter + PyConsole_Interp* myInterp; //!< python interpreter PyConsole_Editor* myEditor; //!< python console editor widget - QMap myActions; + QMap myActions; //!< menu actions list }; -#endif +#endif // PYCONSOLE_CONSOLE_H diff --git a/src/PyConsole/PyConsole_Editor.cxx b/src/PyConsole/PyConsole_Editor.cxx index 23268097e..fea5d6804 100644 --- a/src/PyConsole/PyConsole_Editor.cxx +++ b/src/PyConsole/PyConsole_Editor.cxx @@ -19,9 +19,9 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : PyConsole_Editor.cxx -// Author : Vadim SANDLER -// Module : SALOME +// File : PyConsole_Editor.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// /*! \class PyConsole_Editor @@ -92,32 +92,35 @@ - the same for drag-n-drop of multiline text */ -#include "PyConsole_Editor.h" // this include must be first (see PyInterp_base.h)! - +#include "PyConsole_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! +#include "PyConsole_Editor.h" #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -using namespace std; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include static QString READY_PROMPT = ">>> "; static QString DOTS_PROMPT = "... "; #define PROMPT_SIZE myPrompt.length() +#define PRINT_EVENT 65432 + /*! \class ExecCommand - \brief Python command execution request [internal]. - */ + \brief Python command execution request. + \internal +*/ + class ExecCommand : public PyInterp_LockRequest { public: @@ -130,7 +133,7 @@ public: \param theListener widget to get the notification messages \param sync if True the request is processed synchronously */ - ExecCommand( PyInterp_base* theInterp, + ExecCommand( PyInterp_Interp* theInterp, const QString& theCommand, PyConsole_Editor* theListener, bool sync = false ) @@ -147,21 +150,12 @@ protected: { if ( myCommand != "" ) { -// SUIT_Session::SetPythonExecuted( true ); // disable GUI user actions int ret = getInterp()->run( myCommand.toLatin1() ); -// SUIT_Session::SetPythonExecuted(false); // enable GUI user actions if ( ret < 0 ) - myState = PyInterp_Event::ERROR; + myState = PyInterp_Event::ERROR; else if ( ret > 0 ) - myState = PyInterp_Event::INCOMPLETE; - myError = getInterp()->getverr().c_str(); - myOutput = getInterp()->getvout().c_str(); + myState = PyInterp_Event::INCOMPLETE; } - else - { - myError = ""; - myOutput = ""; - } } /*! @@ -170,18 +164,45 @@ protected: */ virtual QEvent* createEvent() const { + if ( IsSync() ) + QCoreApplication::sendPostedEvents( listener(), PRINT_EVENT ); return new PyInterp_Event( myState, (PyInterp_Request*)this ); } -public: - QString myError; //!< Python command error message - QString myOutput; //!< Python command output log - private: QString myCommand; //!< Python command int myState; //!< Python command execution status }; +/*! + \class PrintEvent + \brief Python command output backend event. + \internal +*/ + +class PrintEvent : public QEvent +{ +public: + /*! + \brief Constructor + \param c message text (python trace) + */ + PrintEvent( const char* c ) : QEvent( (QEvent::Type)PRINT_EVENT ), myText( c ) {} + /*! + \brief Get message + \return message text (python trace) + */ + QString text() const { return myText; } + +private: + QString myText; //!< Event message (python trace) +}; + +void staticCallback( void* data, char* c ) +{ + QApplication::postEvent( (PyConsole_Editor*)data, new PrintEvent( c ) ); +} + /*! \brief Constructor. @@ -189,8 +210,8 @@ private: \param theInterp python interper \param theParent parent widget */ -PyConsole_Editor::PyConsole_Editor( PyInterp_base* theInterp, - QWidget* theParent ) +PyConsole_Editor::PyConsole_Editor( PyConsole_Interp* theInterp, + QWidget* theParent ) : QTextEdit( theParent ), myInterp( 0 ), myCmdInHistory( -1 ), @@ -203,10 +224,13 @@ PyConsole_Editor::PyConsole_Editor( PyInterp_base* theInterp, setUndoRedoEnabled( false ); myPrompt = READY_PROMPT; - setLineWrapMode( QTextEdit::NoWrap ); - setWordWrapMode( QTextOption::NoWrap ); + setLineWrapMode( QTextEdit::WidgetWidth ); + setWordWrapMode( QTextOption::WrapAnywhere ); setAcceptRichText( false ); + theInterp->setvoutcb( staticCallback, this ); + theInterp->setverrcb( staticCallback, this ); + // san - This is necessary for troubleless initialization onPyInterpChanged( theInterp ); } @@ -220,14 +244,30 @@ PyConsole_Editor::~PyConsole_Editor() { } +/*! + \brief Get synchronous mode flag value. + + \sa setIsSync() + \return True if python console works in synchronous mode +*/ bool PyConsole_Editor::isSync() const { return myIsSync; } -void PyConsole_Editor::setIsSync( const bool s ) +/*! + \brief Set synchronous mode flag value. + + In synhronous mode the Python commands are executed in the GUI thread + and the GUI is blocked until the command is finished. In the asynchronous + mode each Python command is executed in the separate thread that does not + block the main GUI loop. + + \param on synhronous mode flag +*/ +void PyConsole_Editor::setIsSync( const bool on ) { - myIsSync = s; + myIsSync = on; } /*! @@ -236,7 +276,7 @@ void PyConsole_Editor::setIsSync( const bool s ) \param newBlock if True, then the string is printed on a new line */ void PyConsole_Editor::addText( const QString& str, - const bool newBlock ) + const bool newBlock ) { moveCursor( QTextCursor::End ); if ( newBlock ) @@ -288,14 +328,20 @@ void PyConsole_Editor::exec( const QString& command ) PyInterp_Dispatcher::Get()->Exec( createRequest( cmd ) ); } -PyInterp_Request* PyConsole_Editor::createRequest( const QString& cmd ) +/*! + \brief Create request to the python dispatcher for the command execution. + + \param command python command to be executed + */ +PyInterp_Request* PyConsole_Editor::createRequest( const QString& command ) { - return new ExecCommand( myInterp, cmd, this, isSync() ); + return new ExecCommand( myInterp, command, this, isSync() ); } /*! \brief Execute command in the python interpreter and wait until it is finished. + \param command python command to be executed */ void PyConsole_Editor::execAndWait( const QString& command ) @@ -333,6 +379,9 @@ void PyConsole_Editor::handleReturn() // add command to the history if ( !cmd.trimmed().isEmpty() ) myHistory.push_back( cmd ); + + // IPAL19397 + addText( "", true ); // set read-only mode setReadOnly( true ); @@ -566,7 +615,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event ) moveCursor( QTextCursor::End ); moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor ); textCursor().removeSelectedText(); - addText( myPrompt + ( nextCommand != TOP_HISTORY_PY ? nextCommand : myCurrentCommand ) ); + addText( myPrompt + nextCommand ); // move cursor to the end moveCursor( QTextCursor::End ); } @@ -851,25 +900,24 @@ void PyConsole_Editor::customEvent( QEvent* event ) { switch( event->type() ) { + case PRINT_EVENT: + { + PrintEvent* pe=(PrintEvent*)event; + addText( pe->text() ); + return; + } case PyInterp_Event::OK: case PyInterp_Event::ERROR: { - PyInterp_Event* pe = dynamic_cast( event ); - if ( pe ) - { - ExecCommand* ec = dynamic_cast( pe->GetRequest() ); - if ( ec ) - { - // The next line has appeared dangerous in case if - // Python command execution has produced very large output. - // A more clever approach is needed... - // print python output - addText( ec->myOutput, true ); - addText( ec->myError ); - } - } // clear command buffer myCommandBuffer.truncate( 0 ); + // add caret return line if necessary + QTextBlock par = document()->end().previous(); + QString txt = par.text(); + txt.truncate( txt.length() - 1 ); + // IPAL19397 : addText moved to handleReturn() method + //if ( !txt.isEmpty() ) + // addText( "", true ); // set "ready" prompt myPrompt = READY_PROMPT; addText( myPrompt ); @@ -884,9 +932,16 @@ void PyConsole_Editor::customEvent( QEvent* event ) { // extend command buffer (multi-line command) myCommandBuffer.append( "\n" ); + // add caret return line if necessary + QTextBlock par = document()->end().previous(); + QString txt = par.text(); + txt.truncate( txt.length() - 1 ); + // IPAL19397 : addText moved to handleReturn() method + //if ( !txt.isEmpty() ) + // addText( "", true ); // set "dot" prompt myPrompt = DOTS_PROMPT; - addText( myPrompt, true ); + addText( myPrompt/*, true*/ ); // IPAL19397 // unset busy cursor unsetCursor(); // stop event loop (if running) @@ -918,7 +973,7 @@ void PyConsole_Editor::customEvent( QEvent* event ) Perform initialization actions if the interpreter is changed. \param interp python interpreter is being set */ -void PyConsole_Editor::onPyInterpChanged( PyInterp_base* interp ) +void PyConsole_Editor::onPyInterpChanged( PyConsole_Interp* interp ) { if ( myInterp != interp // Force read-only state and wait cursor when myInterp is NULL diff --git a/src/PyConsole/PyConsole_Editor.h b/src/PyConsole/PyConsole_Editor.h index 12deee059..222708c6e 100644 --- a/src/PyConsole/PyConsole_Editor.h +++ b/src/PyConsole/PyConsole_Editor.h @@ -19,28 +19,27 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : PyConsole_Editor.h -// Author : Vadim SANDLER -// Module : SALOME +// File : PyConsole_Editor.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// #ifndef PYCONSOLE_EDITOR_H #define PYCONSOLE_EDITOR_H -#include "PyConsole_Interp.h" // this include must be first (see PyInterp_base.h)! +#include "PyConsole.h" -#include +#include -class QMenu; -class QEventLoop; class PyConsole_Interp; class PyInterp_Request; +class QEventLoop; class PYCONSOLE_EXPORT PyConsole_Editor : public QTextEdit { Q_OBJECT; public: - PyConsole_Editor( PyInterp_base* theInterp, QWidget *theParent = 0 ); + PyConsole_Editor( PyConsole_Interp* theInterp, QWidget *theParent = 0 ); ~PyConsole_Editor(); virtual void addText( const QString& str, const bool newBlock = false ); @@ -59,26 +58,26 @@ protected: virtual void customEvent( QEvent* event); virtual PyInterp_Request* createRequest( const QString& ); - + public slots: void cut(); void paste(); void clear(); void handleReturn(); - void onPyInterpChanged( PyInterp_base* ); + void onPyInterpChanged( PyConsole_Interp* ); private: - PyInterp_base* myInterp; //!< python interpreter + PyConsole_Interp* myInterp; //!< python interpreter - QString myCommandBuffer; //!< python comman buffer - QString myCurrentCommand; //!< currently being printed command - QString myPrompt; //!< current command line prompt - int myCmdInHistory; //!< current history command index - QStringList myHistory; //!< commands history buffer - QEventLoop* myEventLoop; //!< internal event loop - QString myBanner; //!< current banner - QStringList myQueue; //!< python commands queue - bool myIsSync; + QString myCommandBuffer; //!< python comman buffer + QString myCurrentCommand; //!< currently being printed command + QString myPrompt; //!< current command line prompt + int myCmdInHistory; //!< current history command index + QStringList myHistory; //!< commands history buffer + QEventLoop* myEventLoop; //!< internal event loop + QString myBanner; //!< current banner + QStringList myQueue; //!< python commands queue + bool myIsSync; //!< synchronous mode flag }; -#endif +#endif // PYCONSOLE_EDITOR_H diff --git a/src/PyConsole/PyConsole_Interp.cxx b/src/PyConsole/PyConsole_Interp.cxx index b71c02178..234e55973 100644 --- a/src/PyConsole/PyConsole_Interp.cxx +++ b/src/PyConsole/PyConsole_Interp.cxx @@ -30,21 +30,32 @@ \brief Python interpreter to be embedded to the SALOME study's GUI. Python interpreter is created one per SALOME study. - Calls initialize method defined in the base class, which calls redefined - virtual methods initState() & initContext(). + + Call initialize method defined in the base class PyInterp_Interp, + to intialize interpreter after instance creation. + + The method initialize() calls virtuals methods + - initPython() to initialize global Python interpreter + - initState() to initialize embedded interpreter state + - initContext() to initialize interpreter internal context + - initRun() to prepare interpreter for running commands /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.
+ 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. - For example, the pyqt module must be imported only once because + For example, 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.
+ 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 @@ -52,14 +63,12 @@ have identical __builtin__ module. */ -using namespace std; - /*! \brief Constructor. Creates new python interpreter. */ -PyConsole_Interp::PyConsole_Interp(): PyInterp_base() +PyConsole_Interp::PyConsole_Interp(): PyInterp_Interp() { } @@ -74,32 +83,15 @@ PyConsole_Interp::~PyConsole_Interp() /*! \brief Initialize internal Python interpreter state. + \return \c true on success */ bool PyConsole_Interp::initState() { // The GIL is acquired and will be held on initState output // It is the caller responsability to release the lock if needed - -/* LLS PyEval_AcquireLock(); _tstate = Py_NewInterpreter(); // create an interpreter and save current state - PySys_SetArgv(PyInterp_base::_argc,PyInterp_base::_argv); // initialize sys.argv -*/ - - PyEval_AcquireLock(); -#ifdef WIN32 - _tstate = PyGILState_GetThisThreadState(); - // if no thread state defined - if ( _tstate ) - PyThreadState_Swap(_tstate); - else -#endif - { - _tstate = Py_NewInterpreter(); // create an interpreter and save current state - PySys_SetArgv(PyInterp_base::_argc,PyInterp_base::_argv); // initialize sys.argv - //if(MYDEBUG) MESSAGE("PythonConsole_PyInterp::initState - this = "< // this include must be first (see PyInterp_base.h)! +#include /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!! -class PYCONSOLE_EXPORT PyConsole_Interp : public PyInterp_base +class PYCONSOLE_EXPORT PyConsole_Interp : public PyInterp_Interp { public: PyConsole_Interp(); @@ -41,4 +41,4 @@ protected: virtual bool initContext(); }; -#endif +#endif // PYCONSOLE_INTERP_H diff --git a/src/PyInterp/PyInterp.h b/src/PyInterp/PyInterp.h index 86772a124..eab58424e 100755 --- a/src/PyInterp/PyInterp.h +++ b/src/PyInterp/PyInterp.h @@ -16,38 +16,40 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#if !defined ( _PYINTERP_H ) -#define _PYINTERP_H +// File : PyInterp.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#if !defined ( PYINTERP_H ) +#define PYINTERP_H // ======================================================== // set dllexport type for Win platform #ifdef WIN32 - -#ifdef PYINTERP_EXPORTS -#define PYINTERP_EXPORT __declspec(dllexport) -#else -#define PYINTERP_EXPORT __declspec(dllimport) -#endif - +# ifdef PYINTERP_EXPORTS +# define PYINTERP_EXPORT __declspec(dllexport) +# else +# define PYINTERP_EXPORT __declspec(dllimport) +# endif #else // WIN32 - -#define PYINTERP_EXPORT - +# define PYINTERP_EXPORT #endif // WIN32 // ======================================================== -// little trick - we do not have debug python libraries +// little trick - if we do not have debug python libraries #ifdef _DEBUG - -#undef _DEBUG -#include -#define _DEBUG - -#else // _DEBUG + #ifndef HAVE_DEBUG_PYTHON + #undef _DEBUG + #endif +#endif #include -#endif // _DEBUG +#ifdef _DEBUG + #ifndef HAVE_DEBUG_PYTHON + #define _DEBUG + #endif +#endif // ======================================================== // avoid warning messages @@ -56,4 +58,4 @@ #pragma warning (disable : 4251) #endif -#endif // _PYINTERP_H +#endif // PYINTERP_H diff --git a/src/PyInterp/PyInterp.pro b/src/PyInterp/PyInterp.pro index 8ee7c1f25..bc1afac79 100644 --- a/src/PyInterp/PyInterp.pro +++ b/src/PyInterp/PyInterp.pro @@ -1,4 +1,7 @@ -TEMPLATE = lib +unix:TEMPLATE = lib +win32:TEMPLATE = vclib + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc @@ -6,18 +9,26 @@ OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET INCLUDEPATH += ../../include $$(PYTHONINC) unix:LIBS += -L$$(PYTHONLIB) -lpython2.5 -win32:LIBS += /LIBPATH:$$(PYTHONLIB) +win32:LIBS += -L$$(PYTHONLIB) -lpython25_d +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 +win32:DEFINES += WNT WIN32 HAVE_DEBUG_PYTHON DEFINES += PYINTERP_EXPORTS HEADERS = *.h SOURCES = *.cxx +win32:copy_hdr.name = Install ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + includes.files = $$HEADERS includes.path = ../../include diff --git a/src/PyInterp/PyInterp_Dispatcher.cxx b/src/PyInterp/PyInterp_Dispatcher.cxx index 917298417..e3adb001d 100755 --- a/src/PyInterp/PyInterp_Dispatcher.cxx +++ b/src/PyInterp/PyInterp_Dispatcher.cxx @@ -16,20 +16,16 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// // File : PyInterp_Dispatcher.cxx // Author : Sergey ANIKIN, OCC // Module : GUI -// $Header$ - -#include "PyInterp_base.h" +#include "PyInterp_Dispatcher.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! +#include "PyInterp_Interp.h" #include "PyInterp_Watcher.h" -#include "PyInterp_Dispatcher.h" -#include -#include +#include +#include using namespace std; @@ -126,8 +122,9 @@ PyInterp_Dispatcher::~PyInterp_Dispatcher() // Clear the request queue myQueueMutex.lock(); - for ( std::list::iterator it = myQueue.begin(); it != myQueue.end(); ++it ) - PyInterp_Request::Destroy( *it ); + QListIterator it( myQueue ); + while ( it.hasNext() ) + PyInterp_Request::Destroy( it.next() ); myQueue.clear(); myQueueMutex.unlock(); @@ -155,7 +152,7 @@ void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest ) else // asynchronous processing { myQueueMutex.lock(); - myQueue.push_back( theRequest ); + myQueue.enqueue( theRequest ); if ( theRequest->listener() ) QObject::connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) ); myQueueMutex.unlock(); @@ -175,7 +172,7 @@ void PyInterp_Dispatcher::run() while( myQueue.size() ) { // MESSAGE("*** PyInterp_Dispatcher::run(): next request taken from the queue") - aRequest = myQueue.front(); + aRequest = myQueue.head(); // let other threads append their requests to the end of the queue myQueueMutex.unlock(); @@ -187,8 +184,8 @@ void PyInterp_Dispatcher::run() // prepare for removal of the first request in the queue myQueueMutex.lock(); // IMPORTANT: the first item could have been removed by objectDestroyed() --> we have to check it - if ( myQueue.front() == aRequest ) // It's still here --> remove it - myQueue.pop_front(); + if ( myQueue.head() == aRequest ) // It's still here --> remove it + myQueue.dequeue(); // MESSAGE("*** PyInterp_Dispatcher::run(): request processed") } @@ -207,12 +204,14 @@ void PyInterp_Dispatcher::objectDestroyed( const QObject* o ) // prepare for modification of the queue myQueueMutex.lock(); - for ( std::list::iterator it = myQueue.begin(); it != myQueue.end(); ++it ) + QMutableListIterator it( myQueue ); + while ( it.hasNext() ) { - if ( o == (*it)->listener() ) + RequestPtr r = it.next(); + if ( o == r->listener() ) { - (*it)->setListener( 0 ); // to prevent event posting - it = myQueue.erase( it ); + r->setListener( 0 ); // to prevent event posting + it.remove(); } } diff --git a/src/PyInterp/PyInterp_Dispatcher.h b/src/PyInterp/PyInterp_Dispatcher.h index 6f6240794..cf46694e4 100755 --- a/src/PyInterp/PyInterp_Dispatcher.h +++ b/src/PyInterp/PyInterp_Dispatcher.h @@ -16,27 +16,23 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// // File : PyInterp_Dispatcher.h // Author : Sergey Anikin, OCC // Module : SALOME -#ifndef _PYINTERP_DISPATCHER_H_ -#define _PYINTERP_DISPATCHER_H_ - -#include "PyInterp.h" - -#include -#include +#ifndef PYINTERP_DISPATCHER_H +#define PYINTERP_DISPATCHER_H -#include +#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! -#include +#include +#include +#include +#include class QObject; -class PyInterp_base; +class PyInterp_Interp; class PyInterp_Watcher; class PyInterp_Dispatcher; @@ -73,11 +69,12 @@ protected: virtual void processEvent( QObject* ); -private: - void process(); QObject* listener() const { return myListener; } void setListener( QObject* ); +private: + void process(); + private: QMutex myMutex; bool myIsSync; @@ -87,16 +84,16 @@ private: class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request { public: - PyInterp_LockRequest( PyInterp_base* interp, QObject* listener = 0, bool sync = false ) + PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener = 0, bool sync = false ) : PyInterp_Request( listener, sync ), myInterp( interp ) {} protected: - PyInterp_base* getInterp() const { return myInterp; } + PyInterp_Interp* getInterp() const { return myInterp; } - virtual void safeExecute(); + virtual void safeExecute(); private: - PyInterp_base* myInterp; + PyInterp_Interp* myInterp; }; class PYINTERP_EXPORT PyInterp_Event : public QEvent @@ -139,7 +136,7 @@ private: private: typedef PyInterp_Request* RequestPtr; - std::list myQueue; + QQueue myQueue; QMutex myQueueMutex; PyInterp_Watcher* myWatcher; @@ -148,4 +145,4 @@ private: friend class PyInterp_Watcher; }; -#endif +#endif // PYINTERP_DISPATCHER_H diff --git a/src/PyInterp/PyInterp_Interp.cxx b/src/PyInterp/PyInterp_Interp.cxx new file mode 100644 index 000000000..891d02908 --- /dev/null +++ b/src/PyInterp/PyInterp_Interp.cxx @@ -0,0 +1,449 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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 : PyInterp_Interp.cxx +// Author : Christian CAREMOLI, Paul RASCLE, EDF +// Module : SALOME + +#include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! + +#include +#include + +#include +#include +#include + +#define TOP_HISTORY_PY "--- top of history ---" +#define BEGIN_HISTORY_PY "--- begin of history ---" + +/*! + \class PyLockWrapper + \brief Python GIL wrapper. +*/ + +/*! + \brief Constructor. Automatically acquires GIL. + \param theThreadState python thread state +*/ +PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): + myThreadState(theThreadState), + mySaveThreadState(0) +{ + if (myThreadState->interp == PyInterp_Interp::_interp) + _savestate = PyGILState_Ensure(); + else + PyEval_AcquireThread(myThreadState); +} + +/*! + \brief Desstructor. Automatically releases GIL. +*/ +PyLockWrapper::~PyLockWrapper() +{ + if (myThreadState->interp == PyInterp_Interp::_interp) + PyGILState_Release(_savestate); + else + PyEval_ReleaseThread(myThreadState); +} + +/*! + \brief Get Python GIL wrapper. + \return GIL lock wrapper (GIL is automatically acquired here) +*/ +PyLockWrapper PyInterp_Interp::GetLockWrapper() +{ + return _tstate; +} + +/* + The following functions are used to hook the Python + interpreter output. +*/ + +static void +PyStdOut_dealloc(PyStdOut *self) +{ + PyObject_Del(self); +} + +static PyObject* +PyStdOut_write(PyStdOut *self, PyObject *args) +{ + char *c; + int l; + if (!PyArg_ParseTuple(args, "t#:write",&c, &l)) + return NULL; + if(self->_cb==NULL) { + if ( self->_iscerr ) + std::cerr << c ; + else + std::cout << c ; + } + else { + self->_cb(self->_data,c); + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef PyStdOut_methods[] = { + {"write", (PyCFunction)PyStdOut_write, METH_VARARGS, + PyDoc_STR("write(string) -> None")}, + {NULL, NULL} /* sentinel */ +}; + +static PyMemberDef PyStdOut_memberlist[] = { + {"softspace", T_INT, offsetof(PyStdOut, softspace), 0, + "flag indicating that a space needs to be printed; used by print"}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject PyStdOut_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "PyOut", /*tp_name*/ + sizeof(PyStdOut), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyStdOut_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr, /*tp_getattro*/ + /* softspace is writable: we must supply tp_setattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + PyStdOut_methods, /*tp_methods*/ + PyStdOut_memberlist, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +#define PyStdOut_Check(v) ((v)->ob_type == &PyStdOut_Type) + +static PyStdOut* newPyStdOut( bool iscerr ) +{ + PyStdOut *self; + self = PyObject_New(PyStdOut, &PyStdOut_Type); + if (self == NULL) + return NULL; + self->softspace = 0; + self->_cb = NULL; + self->_iscerr = iscerr; + return self; +} + +/*! + \class PyInterp_Interp + \brief Generic embedded Python interpreter. +*/ + +int PyInterp_Interp::_argc = 1; +char* PyInterp_Interp::_argv[] = {""}; +PyObject* PyInterp_Interp::builtinmodule = NULL; +PyThreadState* PyInterp_Interp::_gtstate = NULL; +PyInterpreterState* PyInterp_Interp::_interp = NULL; + +/*! + \brief Basic constructor. + + After construction the interpreter instance successor classes + must call virtual method initalize(). +*/ +PyInterp_Interp::PyInterp_Interp(): + _tstate(0), _vout(0), _verr(0), _g(0) +{ +} + +/*! + \brief Destructor. +*/ +PyInterp_Interp::~PyInterp_Interp() +{ +} + +/*! + \brief Initialize embedded interpreter. + + This method shoud be called after construction of the interpreter. + The method initialize() calls virtuals methods + - initPython() to initialize global Python interpreter + - initState() to initialize embedded interpreter state + - initContext() to initialize interpreter internal context + - initRun() to prepare interpreter for running commands + which should be implemented in the successor classes, according to the + embedded Python interpreter policy (mono or multi interpreter, etc). +*/ +void PyInterp_Interp::initialize() +{ + _history.clear(); // start a new list of user's commands + _ith = _history.begin(); + + initPython(); + // Here the global lock is released + + initState(); + + PyLockWrapper aLock = GetLockWrapper(); + + initContext(); + + // used to interpret & compile commands + PyObjWrapper m(PyImport_ImportModule("codeop")); + if(!m) { + PyErr_Print(); + return; + } + + // Create python objects to capture stdout and stderr + _vout=(PyObject*)newPyStdOut( false ); // stdout + _verr=(PyObject*)newPyStdOut( true ); // stderr + + // All the initRun outputs are redirected to the standard output (console) + initRun(); +} + +/*! + \brief Initialize Python interpreter. + + Set program name, initialize interpreter, set program arguments, + initiaize threads. + */ +void PyInterp_Interp::initPython() +{ + if (Py_IsInitialized()) + return; + + // Python is not initialized + Py_SetProgramName(_argv[0]); + Py_Initialize(); // Initialize the interpreter + PySys_SetArgv(_argc, _argv); + PyEval_InitThreads(); // Create (and acquire) the interpreter lock + _interp = PyThreadState_Get()->interp; + if (PyType_Ready(&PyStdOut_Type) < 0) { + PyErr_Print(); + } + _gtstate = PyEval_SaveThread(); // Release global thread state +} + +/*! + \brief Get embedded Python interpreter banner. + \return banner string + */ +std::string PyInterp_Interp::getbanner() +{ + // Should we take the lock ? + // PyEval_RestoreThread(_tstate); + std::string aBanner("Python "); + aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ; + aBanner = aBanner + "\ntype help to get general information on environment\n"; + //PyEval_SaveThread(); + return aBanner; +} + +/*! + \brief Initialize run command. + + This method is used to prepare interpreter for running + Python commands. + + \return \c true on success and \c false on error +*/ +bool PyInterp_Interp::initRun() +{ + // + // probably all below code isn't required + // + /* + PySys_SetObject("stderr",_verr); + PySys_SetObject("stdout",_vout); + + //PyObject *m = PyImport_GetModuleDict(); + + PySys_SetObject("stdout",PySys_GetObject("__stdout__")); + PySys_SetObject("stderr",PySys_GetObject("__stderr__")); + */ + return true; +} + +/*! + \brief Compile Python command and evaluate it in the + python dictionary context if possible. + \internal + \param command Python command string + \param context Python context (dictionary) + \return -1 on fatal error, 1 if command is incomplete and 0 + if command is executed successfully + */ +static int compile_command(const char *command,PyObject *context) +{ + PyObject *m = PyImport_AddModule("codeop"); + if(!m) { // Fatal error. No way to go on. + PyErr_Print(); + return -1; + } + PyObjWrapper v(PyObject_CallMethod(m,"compile_command","s",command)); + if(!v) { + // Error encountered. It should be SyntaxError, + //so we don't write out traceback + PyObjWrapper exception, value, tb; + PyErr_Fetch(&exception, &value, &tb); + PyErr_NormalizeException(&exception, &value, &tb); + PyErr_Display(exception, value, NULL); + return -1; + } + else if (v == Py_None) { + // Incomplete text we return 1 : we need a complete text to execute + return 1; + } + else { + // Complete and correct text. We evaluate it. + //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 + // PyObjWrapper r(PyEval_EvalCode(v,context,context)); + //#else + PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context)); + //#endif + if(!r) { + // Execution error. We return -1 + PyErr_Print(); + return -1; + } + // The command has been successfully executed. Return 0 + return 0; + } +} + +/*! + \brief Run Python command. + \param command Python command + \return command status +*/ +int PyInterp_Interp::run(const char *command) +{ + beforeRun(); + return simpleRun(command); +} + +/*! + \brief Run Python command (used internally). + \param command Python command + \param addToHistory if \c true (default), the command is added to the commands history + \return command status +*/ +int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory) +{ + if( addToHistory && strcmp(command,"") != 0 ) { + _history.push_back(command); + _ith = _history.end(); + } + + // We come from C++ to enter Python world + // We need to acquire the Python global lock + //PyLockWrapper aLock(_tstate); // san - lock is centralized now + + // Reset redirected outputs before treatment + PySys_SetObject("stderr",_verr); + PySys_SetObject("stdout",_vout); + + int ier = compile_command(command,_g); + + // Outputs are redirected on standards outputs (console) + PySys_SetObject("stdout",PySys_GetObject("__stdout__")); + PySys_SetObject("stderr",PySys_GetObject("__stderr__")); + + return ier; +} + +/*! + \brief Get previous command in the commands history. + \return previous command +*/ +const char * PyInterp_Interp::getPrevious() +{ + if(_ith != _history.begin()){ + _ith--; + return (*_ith).c_str(); + } + else + return BEGIN_HISTORY_PY; +} + +/*! + \brief Get next command in the commands history. + \return next command +*/ +const char * PyInterp_Interp::getNext() +{ + if(_ith != _history.end()){ + _ith++; + } + if (_ith == _history.end()) + return TOP_HISTORY_PY; + else + return (*_ith).c_str(); +} + +/*! + \brief Set Python standard output device hook. + \param cb callback function + \param data callback function parameters +*/ +void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data) +{ + ((PyStdOut*)_vout)->_cb=cb; + ((PyStdOut*)_vout)->_data=data; +} + +/*! + \brief Set Python standard error device hook. + \param cb callback function + \param data callback function parameters +*/ +void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data) +{ + ((PyStdOut*)_verr)->_cb=cb; + ((PyStdOut*)_verr)->_data=data; +} diff --git a/src/PyInterp/PyInterp_Interp.h b/src/PyInterp/PyInterp_Interp.h new file mode 100644 index 000000000..397a79167 --- /dev/null +++ b/src/PyInterp/PyInterp_Interp.h @@ -0,0 +1,116 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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 : PyInterp_Interp.h +// Author : Christian CAREMOLI, Paul RASCLE, EDF +// Module : SALOME + +#ifndef PYINTERP_INTERP_H +#define PYINTERP_INTERP_H + +#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! + +#include +#include + +class PYINTERP_EXPORT PyLockWrapper +{ + PyThreadState* myThreadState; + PyThreadState* mySaveThreadState; + PyGILState_STATE _savestate; +public: + PyLockWrapper(PyThreadState* theThreadState); + ~PyLockWrapper(); +}; + +typedef void PyOutChanged(void* data,char * c); + +class PYINTERP_EXPORT PyInterp_Interp +{ +public: + static int _argc; + static char* _argv[]; + static PyObject *builtinmodule; + static PyThreadState *_gtstate; + static PyInterpreterState *_interp; + + PyInterp_Interp(); + virtual ~PyInterp_Interp(); + + void initialize(); + + virtual int run(const char *command); + + PyLockWrapper GetLockWrapper(); + + std::string getbanner(); + void setverrcb(PyOutChanged*,void*); + void setvoutcb(PyOutChanged*,void*); + + const char * getPrevious(); + const char * getNext(); + +protected: + PyThreadState * _tstate; + PyObject * _vout; + PyObject * _verr; + PyObject * _g; + PyObject * _codeop; + std::list _history; + std::list::iterator _ith; + + virtual int beforeRun() { return 0; } + int simpleRun(const char* command, const bool addToHistory = true); + + virtual bool initRun(); + virtual void initPython(); + virtual bool initState() = 0; + virtual bool initContext() = 0; +}; + +class PYINTERP_EXPORT PyObjWrapper +{ + PyObject* myObject; +public: + PyObjWrapper(PyObject* theObject) : myObject(theObject) {} + PyObjWrapper() : myObject(0) {} + virtual ~PyObjWrapper() { Py_XDECREF(myObject); } + + operator PyObject*() { return myObject; } + PyObject* operator->() { return myObject; } + PyObject* get() { return myObject; } + bool operator!() { return !myObject; } + bool operator==(PyObject* theObject) { return myObject == theObject; } + PyObject** operator&() { return &myObject; } + PyObjWrapper& operator=(PyObjWrapper* theObjWrapper) + { + Py_XDECREF(myObject); + myObject = theObjWrapper->myObject; + return *this; + } +}; + +typedef struct { + PyObject_HEAD + int softspace; + PyOutChanged* _cb; + void* _data; + bool _iscerr; +} PyStdOut; + +#endif // PYINTERP_INTERP_H diff --git a/src/PyInterp/PyInterp_Watcher.h b/src/PyInterp/PyInterp_Watcher.h index f5d776034..1d50f5bf8 100755 --- a/src/PyInterp/PyInterp_Watcher.h +++ b/src/PyInterp/PyInterp_Watcher.h @@ -16,14 +16,18 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#ifndef _PYINTERP_WATCHER_H_ -#define _PYINTERP_WATCHER_H_ +// File : PyInterp_Watcher.h +// Author : Sergey Anikin, OCC +// Module : SALOME -#include "PyInterp.h" +#ifndef PYINTERP_WATCHER_H +#define PYINTERP_WATCHER_H + +#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! #include "PyInterp_Dispatcher.h" -#include +#include // Private class that keeps track of destructions of request listeners class PYINTERP_EXPORT PyInterp_Watcher : public QObject @@ -38,4 +42,4 @@ public slots: void onDestroyed( QObject* o ) { PyInterp_Dispatcher::Get()->objectDestroyed( o ); } }; -#endif // _PYINTERP_WATCHER_H_ +#endif // PYINTERP_WATCHER_H diff --git a/src/PyInterp/PyInterp_base.cxx b/src/PyInterp/PyInterp_base.cxx deleted file mode 100644 index 1ff7cd241..000000000 --- a/src/PyInterp/PyInterp_base.cxx +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// -// 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 -// -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// -// File : PyInterp_base.cxx -// Author : Christian CAREMOLI, Paul RASCLE, EDF -// Module : SALOME -// $Header$ - - -#include "PyInterp_base.h" // this include must be first (see PyInterp_base.h)! - -#include - -#include -#include - -using namespace std; - -PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): - myThreadState(theThreadState), - mySaveThreadState(0) -{ -#if defined(USE_GILSTATE) - if (myThreadState->interp == PyInterp_base::_interp) { - _savestate = PyGILState_Ensure(); - } else { - PyEval_AcquireThread(myThreadState); - } -#else - PyEval_AcquireThread(myThreadState); -#endif -} - -PyLockWrapper::~PyLockWrapper() -{ -#if defined(USE_GILSTATE) - if (myThreadState->interp == PyInterp_base::_interp) { - PyGILState_Release(_savestate); - } else { - PyEval_ReleaseThread(myThreadState); - } -#else - PyEval_ReleaseThread(myThreadState); -#endif -} - -class PyReleaseLock{ -public: - ~PyReleaseLock(){ - PyEval_ReleaseLock(); - } -}; - - -PyLockWrapper PyInterp_base::GetLockWrapper(){ - return _tstate; -} - - -// main python interpreter (static attributes) - -int PyInterp_base::_argc = 1; -char* PyInterp_base::_argv[] = {""}; - -PyObject *PyInterp_base::builtinmodule = NULL; - -PyThreadState *PyInterp_base::_gtstate = NULL; -PyInterpreterState *PyInterp_base::_interp = NULL; - - -/*! - * basic constructor here : herited classes constructors must call initalize() method - * defined here. - */ -PyInterp_base::PyInterp_base(): _tstate(0), _vout(0), _verr(0), _g(0), _atFirst(true) -{ -} - -PyInterp_base::~PyInterp_base() -{ -} - - -/*! - * Must be called by herited classes constructors. initialize() calls virtuals methods - * initstate & initcontext, not defined here in base class. initstate & initcontext methods - * must be implemented in herited classes, following the Python interpreter policy - * (mono or multi interpreter...). - */ -void PyInterp_base::initialize() -{ - _history.clear(); // start a new list of user's commands - _ith = _history.begin(); - - init_python(); - // Here the global lock is released - - initState(); - - PyLockWrapper aLock= GetLockWrapper(); - - initContext(); - - // used to interpret & compile commands - PyObjWrapper m(PyImport_ImportModule("codeop")); - if(!m){ - PyErr_Print(); - return; - } - - // Create cStringIO to capture stdout and stderr - PycString_IMPORT; - if (PycStringIO) { // CTH11627 : additional check - _vout = PycStringIO->NewOutput(128); - _verr = PycStringIO->NewOutput(128); - } - - // All the initRun outputs are redirected to the standard output (console) - initRun(); -} - -void PyInterp_base::init_python() -{ - _atFirst = false; - if (Py_IsInitialized()) - return; - - // Python is not initialized - Py_SetProgramName(_argv[0]); - Py_Initialize(); // Initialize the interpreter - PySys_SetArgv(_argc, _argv); - PyEval_InitThreads(); // Create (and acquire) the interpreter lock - _interp = PyThreadState_Get()->interp; - _gtstate = PyEval_SaveThread(); // Release global thread state -} - -string PyInterp_base::getbanner() -{ - // Should we take the lock ? - // PyEval_RestoreThread(_tstate); - string aBanner("Python "); - aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ; - aBanner = aBanner + "\ntype help to get general information on environment\n"; - //PyEval_SaveThread(); - return aBanner; -} - - -int PyInterp_base::initRun() -{ - PySys_SetObject("stderr",_verr); - PySys_SetObject("stdout",_vout); - - PyObjWrapper verr(PyObject_CallMethod(_verr,"reset","")); - PyObjWrapper vout(PyObject_CallMethod(_vout,"reset","")); - - //PyObject *m = PyImport_GetModuleDict(); - - PySys_SetObject("stdout",PySys_GetObject("__stdout__")); - PySys_SetObject("stderr",PySys_GetObject("__stderr__")); - - return 0; -} - - -/*! - * This function compiles a string (command) and then evaluates it in the dictionnary - * context if possible. - * Returns : - * -1 : fatal error - * 1 : incomplete text - * 0 : complete text executed with success - */ -int compile_command(const char *command,PyObject *context) -{ - PyObject *m = PyImport_AddModule("codeop"); - if(!m){ // Fatal error. No way to go on. - PyErr_Print(); - return -1; - } - PyObjWrapper v(PyObject_CallMethod(m,"compile_command","s",command)); - if(!v){ - // Error encountered. It should be SyntaxError, - //so we don't write out traceback - PyObjWrapper exception, value, tb; - PyErr_Fetch(&exception, &value, &tb); - PyErr_NormalizeException(&exception, &value, &tb); - PyErr_Display(exception, value, NULL); - return -1; - }else if (v == Py_None){ - // Incomplete text we return 1 : we need a complete text to execute - return 1; - }else{ - // Complete and correct text. We evaluate it. - //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 - // PyObjWrapper r(PyEval_EvalCode(v,context,context)); - //#else - PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context)); - //#endif - if(!r){ - // Execution error. We return -1 - PyErr_Print(); - return -1; - } - // The command has been successfully executed. Return 0 - return 0; - } -} - - -int PyInterp_base::run(const char *command) -{ - if(_atFirst){ - int ret = 0; - ret = simpleRun("from Help import *"); - if (ret) { - _atFirst = false; - return ret; - } - ret = simpleRun("import salome"); - if (ret) { - _atFirst = false; - return ret; - } - ret = simpleRun("salome.salome_init(0,1)"); - if (ret) { - _atFirst = false; - return ret; - } - _atFirst = false; - } - return simpleRun(command); -} - - -int PyInterp_base::simpleRun(const char *command) -{ - if( !_atFirst && strcmp(command,"") != 0 ) { - _history.push_back(command); - _ith = _history.end(); - } - - // We come from C++ to enter Python world - // We need to acquire the Python global lock - //PyLockWrapper aLock(_tstate); // san - lock is centralized now - - // Reset redirected outputs before treatment - PySys_SetObject("stderr",_verr); - PySys_SetObject("stdout",_vout); - - PyObjWrapper verr(PyObject_CallMethod(_verr,"reset","")); - PyObjWrapper vout(PyObject_CallMethod(_vout,"reset","")); - - int ier = compile_command(command,_g); - - // Outputs are redirected on standards outputs (console) - PySys_SetObject("stdout",PySys_GetObject("__stdout__")); - PySys_SetObject("stderr",PySys_GetObject("__stderr__")); - - return ier; -} - - -const char * PyInterp_base::getPrevious() -{ - if(_ith != _history.begin()){ - _ith--; - return (*_ith).c_str(); - } - else - return BEGIN_HISTORY_PY; -} - - -const char * PyInterp_base::getNext() -{ - if(_ith != _history.end()){ - _ith++; - } - if (_ith == _history.end()) - return TOP_HISTORY_PY; - else - return (*_ith).c_str(); -} - - -string PyInterp_base::getverr(){ - //PyLockWrapper aLock(_tstate); - PyObjWrapper v(PycStringIO->cgetvalue(_verr)); - string aRet(PyString_AsString(v)); - return aRet; -} - - -string PyInterp_base::getvout(){ - //PyLockWrapper aLock(_tstate); - PyObjWrapper v(PycStringIO->cgetvalue(_vout)); - string aRet(PyString_AsString(v)); - return aRet; -} diff --git a/src/PyInterp/PyInterp_base.h b/src/PyInterp/PyInterp_base.h deleted file mode 100644 index a00056e86..000000000 --- a/src/PyInterp/PyInterp_base.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// -// 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 -// -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// -// File : PyInterp_base.h -// Author : Christian CAREMOLI, Paul RASCLE, EDF -// Module : SALOME - -#ifndef _PYINTERP_BASE_H_ -#define _PYINTERP_BASE_H_ - -#include "PyInterp.h" - -#include -#include -#include - -// include order important! -// pthread then python then qt -//#include // must be before Python.h ! - -#include // must be before qt includes ... -#include // Python include needed for versions before 2.4. Included in Python.h now. -#include // Python include needed for versions before 2.4. Included in Python.h now. - -//#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 -//extern "C" PyObject * PyEval_EvalCode(PyObject *co, PyObject *g, PyObject *l); -//#endif - -/* For 2.3, use the PyGILState_ calls */ -#if (PY_VERSION_HEX >= 0x02030000) -#define USE_GILSTATE -#endif - -#define TOP_HISTORY_PY "--- top of history ---" -#define BEGIN_HISTORY_PY "--- begin of history ---" - -class PYINTERP_EXPORT PyLockWrapper -{ - PyThreadState* myThreadState; - PyThreadState* mySaveThreadState; -#if defined(USE_GILSTATE) - PyGILState_STATE _savestate ; -#endif - public: - PyLockWrapper(PyThreadState* theThreadState); - ~PyLockWrapper(); -}; - -class PYINTERP_EXPORT PyInterp_base{ - public: - static int _argc; - static char* _argv[]; - static PyObject *builtinmodule; - static PyThreadState *_gtstate; - static PyInterpreterState *_interp; - - PyInterp_base(); - virtual ~PyInterp_base(); - - virtual void initialize(); - virtual void init_python(); - // init_python() made virtual to: - // 1. Remove dependency on KERNEL in light SALOME configuration - // 2. Allow redefinition of this method in SalomeApp_PyInterp class (it should be empty there and rely on KERNEL_PYTHON) - - virtual int run(const char *command); - - PyLockWrapper GetLockWrapper(); - - std::string getbanner(); - std::string getverr(); - std::string getvout(); - - const char * getPrevious(); - const char * getNext(); - - protected: - PyThreadState * _tstate; - PyObject * _vout; - PyObject * _verr; - PyObject * _g; - PyObject * _codeop; - std::list _history; - std::list::iterator _ith; - bool _atFirst; - - int simpleRun(const char* command); - int initRun(); - - virtual bool initState() = 0; - virtual bool initContext() = 0; -}; - - -class PYINTERP_EXPORT PyObjWrapper{ - PyObject* myObject; -public: - PyObjWrapper(PyObject* theObject): myObject(theObject) {} - PyObjWrapper(): myObject(0) {} - operator PyObject*(){ - return myObject; - } - PyObject* operator->(){ - return myObject; - } - PyObject* get(){ - return myObject; - } - bool operator!(){ - return !myObject; - } - bool operator==(PyObject* theObject){ - return myObject == theObject; - } - PyObject** operator&(){ - return &myObject; - } - PyObjWrapper& operator=(PyObjWrapper* theObjWrapper){ - Py_XDECREF(myObject); - myObject = theObjWrapper->myObject; - return *this; - } - virtual ~PyObjWrapper(){ - Py_XDECREF(myObject); - } -}; - -#endif diff --git a/src/Qtx/Qtx.pro b/src/Qtx/Qtx.pro index 2d1eaeee6..f0dcfcb17 100644 --- a/src/Qtx/Qtx.pro +++ b/src/Qtx/Qtx.pro @@ -1,20 +1,34 @@ -TEMPLATE = lib +win32:TEMPLATE = vclib +unix:TEMPLATE = lib + +CONFIG += embed_manifest_exe + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml + QT += xml CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 +win32:DEFINES += WNT WIN32 DEFINES += QTX_EXPORTS HEADERS = *.h SOURCES = *.cxx +win32:copy_hdr.name = Install ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + includes.files = $$HEADERS includes.path = ../../include diff --git a/src/STD/STD.pro b/src/STD/STD.pro index 5d283c758..06b048327 100644 --- a/src/STD/STD.pro +++ b/src/STD/STD.pro @@ -1,4 +1,7 @@ -TEMPLATE = lib +unix:TEMPLATE = lib +win32:TEMPLATE = vclib + +win32:QMAKE_MOC=$(QTDIR)\bin\moc.exe DESTDIR = ../../$(CONFIG_ID)/lib MOC_DIR = ../../moc @@ -6,11 +9,13 @@ OBJECTS_DIR = ../../$(CONFIG_ID)/obj/$$TARGET INCLUDEPATH = ../../include LIBS += -L../../$(CONFIG_ID)/lib -lSUIT -lQtx +win32:LIBS *= -L$(QTLIB) +win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml CONFIG -= debug release debug_and_release CONFIG += qt thread debug dll shared -win32:DEFINES += WIN32 +win32:DEFINES += WNT WIN32 DEFINES += STD_EXPORTS HEADERS = *.h @@ -25,7 +30,7 @@ win32:GUIResources = ..\\..\\resources lrelease.name = LRELASE ${QMAKE_FILE_IN} unix:lrelease.commands = $(QTDIR)/bin/lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}/${QMAKE_FILE_BASE}.qm -win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_NAME} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm +win32:lrelease.commands = $(QTDIR)\\bin\\lrelease ${QMAKE_FILE_IN} -qm $${GUIResources}\\${QMAKE_FILE_BASE}.qm unix:lrelease.output = $${GUIResources}/${QMAKE_FILE_BASE}.qm win32:lrelease.output = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.input = TRANSLATIONS @@ -34,8 +39,22 @@ win32:lrelease.clean = $${GUIResources}\\${QMAKE_FILE_BASE}.qm lrelease.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += lrelease +win32:copy_hdr.name = Install ${QMAKE_FILE_IN} +win32:copy_hdr.commands = type ${QMAKE_FILE_IN} > ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.output = ../../include/${QMAKE_FILE_BASE}.h +win32:copy_hdr.input = HEADERS +win32:QMAKE_EXTRA_COMPILERS += copy_hdr + ICONS = resources/*.png +win32:SOURCES+=$$ICONS +win32:Resource=$$ICONS +win32:copy_res.name = Install resources ${QMAKE_FILE_IN} +win32:copy_res.commands = type ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +win32:copy_res.output = $${GUIResources}\\${QMAKE_FILE_BASE}.png +win32:copy_res.input = Resource +win32:QMAKE_EXTRA_COMPILERS += copy_res + includes.files = $$HEADERS includes.path = ../../include -- 2.39.2