#include "PyInterp_base.h" // this include must be first (see PyInterp_base.h)!
#include <cStringIO.h>
+#include <structmember.h>
using namespace std;
return _tstate;
}
+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;
+}
// main python interpreter (static attributes)
return;
}
- // Create cStringIO to capture stdout and stderr
- PycString_IMPORT;
- if (PycStringIO) { // CTH11627 : additional check
- _vout = PycStringIO->NewOutput(128);
- _verr = PycStringIO->NewOutput(128);
- }
+ // 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();
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
}
int PyInterp_base::initRun()
{
+ //
+ // probably all below code isn't required
+ //
+ /*
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;
}
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)
}
-string PyInterp_base::getverr(){
- //PyLockWrapper aLock(_tstate);
- PyObjWrapper v(PycStringIO->cgetvalue(_verr));
- string aRet(PyString_AsString(v));
- return aRet;
+void PyInterp_base::setvoutcb(PyOutChanged* cb, void* data)
+{
+ ((PyStdOut*)_vout)->_cb=cb;
+ ((PyStdOut*)_vout)->_data=data;
}
-string PyInterp_base::getvout(){
- //PyLockWrapper aLock(_tstate);
- PyObjWrapper v(PycStringIO->cgetvalue(_vout));
- string aRet(PyString_AsString(v));
- return aRet;
+void PyInterp_base::setverrcb(PyOutChanged* cb, void* data)
+{
+ ((PyStdOut*)_verr)->_cb=cb;
+ ((PyStdOut*)_verr)->_data=data;
}
#include <qapplication.h>
#include <qpopupmenu.h>
#include <qfontmetrics.h>
+#include <iostream>
using namespace std;
class ExecCommand : public PyInterp_LockRequest
{
public:
- ExecCommand(PyInterp_base* theInterp, const char* theCommand,
+ ExecCommand(PyInterp_base* theInterp, const QString& theCommand,
PythonConsole_PyEditor* theListener, bool sync = false)
: PyInterp_LockRequest( theInterp, theListener, sync ),
myCommand( theCommand ), myState( PyInterp_Event::OK )
protected:
virtual void execute(){
- if(myCommand != ""){
+ if( !myCommand.stripWhiteSpace().isEmpty() ) {
// if(MYDEBUG) MESSAGE("*** ExecCommand::execute() started");
SUIT_Session::SetPythonExecuted(true); // disable GUI user actions
int ret = getInterp()->run( myCommand.latin1() );
SUIT_Session::SetPythonExecuted(false); // enable GUI user actions
// if(MYDEBUG) MESSAGE("ExecCommand::execute() - myInterp = "<<getInterp()<<"; myCommand = '"<<myCommand.latin1()<<"' - "<<ret);
- if(ret < 0)
+ if( ret < 0 )
myState = PyInterp_Event::ERROR;
- else if(ret > 0)
+ else if( ret > 0 )
myState = PyInterp_Event::INCOMPLETE;
- myError = getInterp()->getverr().c_str();
- myOutput = getInterp()->getvout().c_str();
// if(MYDEBUG) MESSAGE("*** ExecCommand::execute() finished");
- }else{
- myError = "";
- myOutput = "";
}
}
return new PyInterp_Event( myState, (PyInterp_Request*)this );
}
-public:
- QString myError;
- QString myOutput;
-
private:
QString myCommand;
int myState;
};
+#define PRINT_EVENT 65432
+
+class PrintEvent : public QCustomEvent
+{
+public:
+ PrintEvent( const char* c ) : QCustomEvent( PRINT_EVENT ), myText( c ) {}
+ QString text() const { return myText; }
+private:
+ QString myText;
+};
+
+void staticCallback( void* data, char* c )
+{
+ QApplication::postEvent( (PythonConsole_PyEditor*)data, new PrintEvent( c ) );
+}
/*!
Constructor
setUndoRedoEnabled( false );
_currentPrompt = READY_PROMPT;
- setWordWrap(NoWrap);
+ setWordWrap( WidgetWidth );
+ setWrapPolicy( Anywhere );
+
+ theInterp->setvoutcb( staticCallback, this );
+ theInterp->setverrcb( staticCallback, this );
connect(this,SIGNAL(returnPressed()),this,SLOT(handleReturn()) );
// Post a request to execute Python command
// Editor will be informed via a custom event that execution has been completed
- PyInterp_Dispatcher::Get()->Exec( new ExecCommand( myInterp, _buf.latin1(), this ) );
+ PyInterp_Dispatcher::Get()->Exec( new ExecCommand( myInterp, _buf, this ) );
}
/*!
void PythonConsole_PyEditor::customEvent(QCustomEvent* e)
{
switch( e->type() ) {
+ case PRINT_EVENT:
+ {
+ PrintEvent* pe=(PrintEvent*)e;
+ setText( pe->text() );
+ return;
+ }
case PyInterp_Event::OK:
case PyInterp_Event::ERROR:
{
- PyInterp_Event* pe = dynamic_cast<PyInterp_Event*>( e );
- if ( pe ){
- 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...
- setText(ec->myOutput);
- setText(ec->myError);
- }
- }
_buf.truncate(0);
_currentPrompt = READY_PROMPT;
+ QString txt = text( paragraphs()-1 );
+ txt.truncate( txt.length()-1 );
+ if ( !txt.isEmpty() )
+ setText("\n");
setText(_currentPrompt);
viewport()->unsetCursor();
if( myIsInLoop )
{
_buf.append("\n");
_currentPrompt = DOTS_PROMPT;
+ QString txt = text( paragraphs()-1 );
+ txt.truncate( txt.length()-1 );
+ if ( !txt.isEmpty() )
+ setText("\n");
setText(_currentPrompt);
viewport()->unsetCursor();
if( myIsInLoop )