//
// 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 <Python.h>
-#define _DEBUG
-
-#else // _DEBUG
-
-//#include <Python.h>
-
-#endif // _DEBUG
-
// ========================================================
// avoid warning messages
#ifdef WIN32
#pragma warning (disable : 4251)
#endif
-#endif // _PYTHONCONSOLE_H
+#endif // PYCONSOLE_H
INCLUDEPATH += ../../include $$(PYTHONINC)
unix:LIBS += -L../../$(CONFIG_ID)/lib -L$$(PYTHONLIB) -lpython2.5 -lSUIT -lPyInterp
-win32:LIBS += -L../../$(CONFIG_ID)/lib -L$$(PYTHONLIB) -lpython25_d -lSUIT -lPyInterp
+win32:LIBS += -L../../$(CONFIG_ID)/lib -L$$(PYTHONLIB) -lpython25_d -lSUIT -lPyInterp -lQtx
CONFIG -= debug release debug_and_release
CONFIG += qt thread debug dll shared
-win32:DEFINES += WNT WIN32
+win32:DEFINES += WNT WIN32 HAVE_DEBUG_PYTHON
DEFINES += PYCONSOLE_EXPORTS
HEADERS = *.h
//
// 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 <Python.h>
-
+#include "PyConsole_Interp.h" /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
#include "PyConsole_Console.h"
#include "PyConsole_Editor.h"
-#include <PyInterp_base.h>
-
-#include <QtGui/qmenu.h>
-#include <QtGui/qevent.h>
-#include <QtGui/qaction.h>
-#include <QtGui/qlayout.h>
-#include <QtGui/qclipboard.h>
-#include <QtGui/qapplication.h>
+#include <Qtx.h>
-using namespace std;
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
+#include <QEvent>
+#include <QMenu>
+#include <QVBoxLayout>
/*!
\brief Constructor.
\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;
// 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 );
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 );
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 );
\brief Get python console font.
\return current python console's font
*/
-QFont PythonConsole::font() const
+QFont PyConsole_Console::font() const
{
QFont res;
if( myEditor )
}
/*!
- 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() );
//
// 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 <QtCore/qmap.h>
-#include <QtGui/qframe.h>
-
#include <SUIT_PopupClient.h>
+#include <QWidget>
+#include <QMap>
-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<int, QAction*> myActions;
+ QMap<int, QAction*> myActions; //!< menu actions list
};
-#endif
+#endif // PYCONSOLE_CONSOLE_H
//
// 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
- 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 <PyInterp_Dispatcher.h>
#include <SUIT_Tools.h>
-#include <SUIT_Session.h>
-
-#include <QtGui/qmenu.h>
-#include <QtGui/qevent.h>
-#include <QtGui/qclipboard.h>
-#include <QtGui/qscrollbar.h>
-#include <QtGui/qtextobject.h>
-#include <QtGui/qtextcursor.h>
-#include <QtGui/qapplication.h>
-#include <QtGui/qtextdocument.h>
-using namespace std;
+#include <QApplication>
+#include <QClipboard>
+#include <QDropEvent>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMouseEvent>
+#include <QScrollBar>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextDocument>
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:
\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 )
{
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 =
-#ifdef WIN32
- PyInterp_Event::EV_ERROR;
-#else
- PyInterp_Event::ERROR;
-#endif
- }
+ if ( ret < 0 )
+ 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 = "";
- }
}
/*!
*/
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.
\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 ),
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 );
}
{
}
+/*!
+ \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;
}
/*!
\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 )
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 )
// add command to the history
if ( !cmd.trimmed().isEmpty() )
myHistory.push_back( cmd );
+
+ // IPAL19397
+ addText( "", true );
// set read-only mode
setReadOnly( true );
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 );
}
{
switch( event->type() )
{
-#ifdef WIN32
- case PyInterp_Event::EV_ERROR:
-#else
- case PyInterp_Event::ERROR:
-#endif
- {
- PyInterp_Event* pe = dynamic_cast<PyInterp_Event*>( event );
- if ( pe )
+ case PRINT_EVENT:
{
- ExecCommand* ec = dynamic_cast<ExecCommand*>( 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 );
- }
+ PrintEvent* pe=(PrintEvent*)event;
+ addText( pe->text() );
+ return;
}
+ case PyInterp_Event::OK:
+ case PyInterp_Event::ERROR:
+ {
// 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 );
{
// 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)
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
//
// 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 <QtGui/qtextedit.h>
+#include <QTextEdit>
-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 );
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
\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.<br>
+ This is fine because every study has its own modules (sys.modules) stdout and stderr.
+
<b>But</b> 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.<br>
+ the other interpreters.
+
<b>But</b> 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
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()
{
}
/*!
\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<<"; _tstate = "<<_tstate);
- }
-
+ PySys_SetArgv(PyInterp_Interp::_argc,PyInterp_Interp::_argv); // initialize sys.argv
//If builtinmodule has been initialized all the sub interpreters
// will have the same __builtin__ module
The GIL is assumed to be held.
It is the caller responsability caller to acquire the GIL.
It will still be held on initContext() exit.
+
+ \return \c true on success
*/
bool PyConsole_Interp::initContext()
{
#include "PyConsole.h"
-#include <PyInterp_base.h> // this include must be first (see PyInterp_base.h)!
+#include <PyInterp_Interp.h> /// !!! 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();
virtual bool initContext();
};
-#endif
+#endif // PYCONSOLE_INTERP_H
//
// 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
-#ifndef WIN32
+// little trick - if we do not have debug python libraries
#ifdef _DEBUG
-
-#undef _DEBUG
-#include <Python.h>
-#define _DEBUG
-
-#else // _DEBUG
+ #ifndef HAVE_DEBUG_PYTHON
+ #undef _DEBUG
+ #endif
+#endif
#include <Python.h>
-#endif // _DEBUG
+#ifdef _DEBUG
+ #ifndef HAVE_DEBUG_PYTHON
+ #define _DEBUG
+ #endif
+#endif
-#endif // WIN32
// ========================================================
// avoid warning messages
#ifdef WIN32
#pragma warning (disable : 4251)
#endif
-#endif // _PYINTERP_H
+#endif // PYINTERP_H
CONFIG -= debug release debug_and_release
CONFIG += qt thread debug dll shared
-win32:DEFINES += WNT WIN32
+win32:DEFINES += WNT WIN32 HAVE_DEBUG_PYTHON
DEFINES += PYINTERP_EXPORTS
HEADERS = *.h
//
// 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 <QtCore/qobject.h>
-#include <QtCore/qcoreapplication.h>
+#include <QObject>
+#include <QCoreApplication>
using namespace std;
// Clear the request queue
myQueueMutex.lock();
- for ( std::list<PyInterp_Request*>::iterator it = myQueue.begin(); it != myQueue.end(); ++it )
- PyInterp_Request::Destroy( *it );
+ QListIterator<RequestPtr> it( myQueue );
+ while ( it.hasNext() )
+ PyInterp_Request::Destroy( it.next() );
myQueue.clear();
myQueueMutex.unlock();
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();
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();
// 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")
}
// prepare for modification of the queue
myQueueMutex.lock();
- for ( std::list<RequestPtr>::iterator it = myQueue.begin(); it != myQueue.end(); ++it )
+ QMutableListIterator<RequestPtr> 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();
}
}
//
// 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 <QtCore/qmutex.h>
-#include <QtCore/qthread.h>
+#ifndef PYINTERP_DISPATCHER_H
+#define PYINTERP_DISPATCHER_H
-#include <QtGui/qevent.h>
+#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
-#include <list>
+#include <QMutex>
+#include <QThread>
+#include <QEvent>
+#include <QQueue>
class QObject;
-class PyInterp_base;
+class PyInterp_Interp;
class PyInterp_Watcher;
class PyInterp_Dispatcher;
virtual void processEvent( QObject* );
-private:
- void process();
QObject* listener() const { return myListener; }
void setListener( QObject* );
+private:
+ void process();
+
private:
QMutex myMutex;
bool myIsSync;
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
PyInterp_Event( const PyInterp_Event& );
public:
- enum { NOTIFY = QEvent::User + 5000, OK,
-#ifdef WIN32
- EV_ERROR,
-#else
- ERROR,
-#endif
- INCOMPLETE, LAST };
+ enum { NOTIFY = QEvent::User + 5000, OK, ERROR, INCOMPLETE, LAST };
PyInterp_Event( int type, PyInterp_Request* request )
: QEvent( (QEvent::Type)type ), myRequest( request ) {}
private:
typedef PyInterp_Request* RequestPtr;
- std::list<RequestPtr> myQueue;
+ QQueue<RequestPtr> myQueue;
QMutex myQueueMutex;
PyInterp_Watcher* myWatcher;
friend class PyInterp_Watcher;
};
-#endif
+#endif // PYINTERP_DISPATCHER_H
--- /dev/null
+// 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 <cStringIO.h>
+#include <structmember.h>
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+#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;
+}
--- /dev/null
+// 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 <list>
+#include <string>
+
+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<std::string> _history;
+ std::list<std::string>::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
//
// 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 <QtCore/qobject.h>
+#include <QObject>
// Private class that keeps track of destructions of request listeners
class PYINTERP_EXPORT PyInterp_Watcher : public QObject
void onDestroyed( QObject* o ) { PyInterp_Dispatcher::Get()->objectDestroyed( o ); }
};
-#endif // _PYINTERP_WATCHER_H_
+#endif // PYINTERP_WATCHER_H
+++ /dev/null
-// 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 <cStringIO.h>
-
-#include <string>
-#include <vector>
-
-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;
-}
+++ /dev/null
-// 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 <list>
-#include <string>
-#include <iostream>
-
-// include order important!
-// pthread then python then qt
-//#include <pthread.h> // must be before Python.h !
-
-#include <Python.h> // must be before qt includes ...
-#include <compile.h> // Python include needed for versions before 2.4. Included in Python.h now.
-#include <eval.h> // 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<std::string> _history;
- std::list<std::string>::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