From 3759d7cb292f6f5081ebcb1661cffb3522c8051e Mon Sep 17 00:00:00 2001 From: smh Date: Fri, 30 Apr 2004 11:54:23 +0000 Subject: [PATCH] Realisation of multythreading for instantination of QAD_Study and QAD_PyEditor classes --- src/SALOMEGUI/PyInterp_base.cxx | 190 +++++++++++++++------------- src/SALOMEGUI/PyInterp_base.h | 26 ++++ src/SALOMEGUI/QAD_Application.cxx | 2 + src/SALOMEGUI/QAD_Desktop.cxx | 1 + src/SALOMEGUI/QAD_PyEditor.cxx | 186 ++++++++++++++++++++------- src/SALOMEGUI/QAD_PyEditor.h | 20 ++- src/SALOMEGUI/QAD_PyInterp.cxx | 33 +++-- src/SALOMEGUI/QAD_PyInterp_mono.cxx | 1 - src/SALOMEGUI/QAD_RightFrame.cxx | 30 +++-- src/SALOMEGUI/QAD_RightFrame.h | 13 +- src/SALOMEGUI/QAD_Study.cxx | 156 +++++++++++++++-------- src/SALOMEGUI/QAD_Study.h | 9 +- src/SALOMEGUI/QAD_StudyFrame.cxx | 59 +++++---- src/SALOMEGUI/QAD_StudyFrame.h | 19 +-- 14 files changed, 488 insertions(+), 257 deletions(-) diff --git a/src/SALOMEGUI/PyInterp_base.cxx b/src/SALOMEGUI/PyInterp_base.cxx index ec972ff71..d460ee541 100644 --- a/src/SALOMEGUI/PyInterp_base.cxx +++ b/src/SALOMEGUI/PyInterp_base.cxx @@ -25,23 +25,25 @@ using namespace std; #ifdef _DEBUG_ -static int MYDEBUG = 1; +static int MYDEBUG = 0; #else static int MYDEBUG = 0; #endif -static QMutex myMutex; + +static QMutex myMutex(false); + PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): myThreadState(theThreadState), mySaveThreadState(PyInterp_base::_gtstate) { - if(MYDEBUG) MESSAGE(" PyLockWrapper(...) - myThreadState = "<locked()); + myMutex->lock(); +} + + +ThreadLock::~ThreadLock(){ + if(MYDEBUG && myComment != "") MESSAGE("~ThreadLock "<unlock(); +} + + +bool IsPyLocked(){ + return myMutex.locked(); +} + + +ThreadLock GetPyThreadLock(const char* theComment){ + return ThreadLock(&myMutex,theComment); +} + + class PyReleaseLock{ public: ~PyReleaseLock(){ - if(MYDEBUG) MESSAGE("~PyReleaseLock()"); + //if(MYDEBUG) MESSAGE("~PyReleaseLock()"); //PyEval_SaveThread(); PyEval_ReleaseLock(); @@ -80,6 +107,7 @@ PyLockWrapper PyInterp_base::GetLockWrapper(){ return PyLockWrapper(_tstate); } + // main python interpreter PyThreadState *PyInterp_base::_gtstate = 0; // force 0 before execution @@ -89,46 +117,6 @@ char* PyInterp_base::_argv[] = {""}; PyObject *PyInterp_base::builtinmodule = NULL; PyObject *PyInterp_base::salome_shared_modules_module = NULL; -/*! - * 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. - PyObjWrapper r(PyEval_EvalCode(v,context,context)); - if(!r){ - // Execution error. We return -1 - PyErr_Print(); - return -1; - } - // The command has been successfully executed. Return 0 - return 0; - } -} - /*! * basic constructor here : herited classes constructors must call initalize() method @@ -136,41 +124,18 @@ int compile_command(const char *command,PyObject *context) */ PyInterp_base::PyInterp_base(): _tstate(0), _vout(0), _verr(0), _g(0), _atFirst(true) { - MESSAGE("PyInterp_base::PyInterp_base()"); + //if(MYDEBUG) MESSAGE("PyInterp_base::PyInterp_base() - this = "<ob_refcnt); - } -} - - /*! * Must be called by herited classes constructors. initialize() calls virtuals methods * initstate & initcontext, not defined here in base class. initstate & initcontext methods @@ -179,12 +144,24 @@ void init_python() */ void PyInterp_base::initialize() { - if(MYDEBUG) MESSAGE("PyInterp_base::initialize()"); _history.clear(); // start a new list of user's commands _ith = _history.begin(); PyReleaseLock aReleaseLock; - init_python(); + if(!_gtstate){ + Py_Initialize(); // Initialize the interpreter + PyEval_InitThreads(); // Initialize and acquire the global interpreter lock + PySys_SetArgv(_argc,_argv); // initialize sys.argv + _gtstate = PyThreadState_Get(); + } + //if(MYDEBUG) MESSAGE("PyInterp_base::initialize() - this = "<cgetvalue(_verr)); string aRet(PyString_AsString(v)); return aRet; @@ -313,7 +329,7 @@ string PyInterp_base::getverr(){ string PyInterp_base::getvout(){ - //PyLockWrapper aLock(_tstate); + PyLockWrapper aLock(_tstate); PyObjWrapper v(PycStringIO->cgetvalue(_vout)); string aRet(PyString_AsString(v)); return aRet; diff --git a/src/SALOMEGUI/PyInterp_base.h b/src/SALOMEGUI/PyInterp_base.h index 216b1e596..157d5c3f7 100644 --- a/src/SALOMEGUI/PyInterp_base.h +++ b/src/SALOMEGUI/PyInterp_base.h @@ -18,12 +18,24 @@ #include +class QSemaphore; +class QMutex; + extern "C" PyObject * PyEval_EvalCode(PyObject *co, PyObject *g, PyObject *l); #define TOP_HISTORY_PY "--- top of history ---" #define BEGIN_HISTORY_PY "--- begin of history ---" +class SemaphoreLock{ + QSemaphore* mySemaphore; + std::string myComment; + public: + SemaphoreLock(QSemaphore* theSemaphore, const char* theComment = ""); + ~SemaphoreLock(); +}; + + class PyLockWrapper{ PyThreadState* myThreadState; PyThreadState* mySaveThreadState; @@ -33,6 +45,20 @@ class PyLockWrapper{ }; +class ThreadLock{ + QMutex* myMutex; + std::string myComment; + public: + ThreadLock(QMutex* theMutex, const char* theComment = ""); + ~ThreadLock(); +}; + + +bool IsPyLocked(); + +ThreadLock GetPyThreadLock(const char* theComment = ""); + + class PyInterp_base{ public: static PyThreadState *_gtstate; diff --git a/src/SALOMEGUI/QAD_Application.cxx b/src/SALOMEGUI/QAD_Application.cxx index 99e1eca15..eb8b43d5e 100644 --- a/src/SALOMEGUI/QAD_Application.cxx +++ b/src/SALOMEGUI/QAD_Application.cxx @@ -823,6 +823,8 @@ QAD_Study* QAD_Application::newStudy() newStudy = new QAD_Study( this, aStudy, StudyName); } + newStudy->Init(); + if ( newStudy->getResult() ) { addStudy( newStudy ); diff --git a/src/SALOMEGUI/QAD_Desktop.cxx b/src/SALOMEGUI/QAD_Desktop.cxx index 14b525a88..8aef9880c 100644 --- a/src/SALOMEGUI/QAD_Desktop.cxx +++ b/src/SALOMEGUI/QAD_Desktop.cxx @@ -43,6 +43,7 @@ #include "QAD_Desktop.h" #include "QAD_LeftFrame.h" #include "QAD_RightFrame.h" +#include "QAD_PyEditor.h" #include "QAD_Operation.h" #include "QAD_XmlHandler.h" #include "QAD_MessageBox.h" diff --git a/src/SALOMEGUI/QAD_PyEditor.cxx b/src/SALOMEGUI/QAD_PyEditor.cxx index 8d0ae9fc5..de74767d5 100644 --- a/src/SALOMEGUI/QAD_PyEditor.cxx +++ b/src/SALOMEGUI/QAD_PyEditor.cxx @@ -33,8 +33,6 @@ #include "QAD_Config.h" #include "QAD_Tools.h" #include "QAD_MessageBox.h" -//#include "QAD_RightFrame.h" -using namespace std; #include #include @@ -48,78 +46,164 @@ using namespace std; #include CORBA_SERVER_HEADER(SALOMEDS_Attributes) //NRI +using namespace std; + + +#ifdef _DEBUG_ +static int MYDEBUG = 1; +#else +static int MYDEBUG = 0; +#endif + + #define SIZEPR 4 enum { IdCopy, IdPaste, IdClear, IdSelectAll }; -class PythonThread : public QThread + +static QString PROMPT = ">>> "; + + +class TInitEditorThread : public QThread { public: - PythonThread( PyInterp_base* interp, QAD_PyEditor* listener ) - : QThread(), myInterp( interp ), myListener( listener ), myCommand( 0 ) - {} + TInitEditorThread(QAD_PyInterp*& theInterp, + QMutex* theStudyMutex, QMutex* theMutex, + QAD_PyEditor* theListener): + myInterp(theInterp), + myMutex(theMutex), + myStudyMutex(theStudyMutex), + myListener(theListener) + { + QThread::postEvent(myListener, new QCustomEvent(QAD_PyEditor::SET_WAIT_CURSOR)); + } - virtual ~PythonThread() {} + virtual ~TInitEditorThread(){} - void exec( const char* command ) +protected: + virtual void run(){ + ThreadLock anEditorLock(myMutex,"TInitEditorThread::anEditorLock"); + ThreadLock aStudyLock(myStudyMutex,"TInitEditorThread::aStudyLock"); + ThreadLock aPyLock = GetPyThreadLock("TInitEditorThread::aPyLock"); + if(MYDEBUG) MESSAGE("TInitEditorThread::run() - myInterp = "<viewport()->setCursor( waitCursor ); - int ret = myInterp->run( myCommand ); - QThread::postEvent( myListener, - new QCustomEvent( ret < 0 ? QAD_PyEditor::PYTHON_ERROR : ( ret ? QAD_PyEditor::PYTHON_INCOMPLETE : QAD_PyEditor::PYTHON_OK ) ) ); + virtual void run(){ + if(myCommand != ""){ + ThreadLock anEditorLock(myMutex,"TExecCommandThread::anEditorLock"); + //ThreadLock aStudyLock(myStudyMutex,"TExecCommandThread::aStudyLock"); + ThreadLock aPyLock = GetPyThreadLock("TExecCommandThread::aPyLock"); + int ret = myInterp->run( myCommand.latin1() ); + if(MYDEBUG) MESSAGE("TExecCommand::run() - myInterp = "< 0) + anId = QAD_PyEditor::PYTHON_INCOMPLETE; myListener->viewport()->unsetCursor(); + QThread::postEvent(myListener, new QCustomEvent(anId)); + QThread::postEvent(myListener, new QCustomEvent(QAD_PyEditor::UNSET_CURSOR)); } } private: - PyInterp_base* myInterp; - QAD_PyEditor* myListener; - char* myCommand; + QMutex* myMutex; + QMutex* myStudyMutex; + QAD_PyInterp*& myInterp; + QAD_PyEditor* myListener; + QString myCommand; }; + /*! Constructor */ -QAD_PyEditor::QAD_PyEditor(QAD_PyInterp* interp, - QWidget *parent, const char *name) - : QTextEdit(parent,name) +QAD_PyEditor::QAD_PyEditor(QAD_PyInterp*& theInterp, QMutex* theMutex, + QWidget *theParent, const char* theName): + QTextEdit(theParent,theName), + myStudyMutex(theMutex), + myInitEditorMutex(new QMutex), + myExecCommandMutex(new QMutex), + myInterp(theInterp), + myInitEditorThread(0), + myExecCommandThread(0) { QString fntSet = QAD_CONFIG->getSetting("Viewer:ConsoleFont"); QFont myFont = QAD_Tools::stringToFont( fntSet ); // QFont myFont("Courier",11); setFont(myFont); setTextFormat(QTextEdit::PlainText); - _interp = interp; - string banner = _interp->getbanner(); - setText(banner.c_str()); - _isInHistory = false; - _currentPrompt = ">>> "; - // put error messages of interpreter if they exist. - _buf.truncate(0); - setText(_interp->getverr().c_str()); - setText(_currentPrompt); + + myInitEditorThread = new TInitEditorThread(myInterp,myStudyMutex,myInitEditorMutex,this); + myExecCommandThread = new TExecCommandThread(myInterp,myStudyMutex,myExecCommandMutex,this); + + _currentPrompt = PROMPT; setPalette( QAD_Application::getPalette(true) ); setWordWrap(NoWrap); - _thread = new PythonThread( interp, this ); - connect(this,SIGNAL(returnPressed()),this,SLOT(handleReturn()) ); } + +void QAD_PyEditor::Init() +{ + myInitEditorThread->start(); +} + + /*! Destructor */ QAD_PyEditor::~QAD_PyEditor() { - if ( _thread->wait( 1000 ) ) - delete _thread; + if(MYDEBUG) MESSAGE("QAD_PyEditor::~QAD_PyEditor()"); + { + { + ThreadLock aLock(myInitEditorMutex,"myInitEditorMutex"); + delete myInitEditorThread; + } + delete myInitEditorMutex; + } + { + { + ThreadLock aLock(myExecCommandMutex,"myExecCommandMutex"); + delete myExecCommandThread; + } + delete myExecCommandMutex; + } } /*! @@ -127,7 +211,6 @@ QAD_PyEditor::~QAD_PyEditor() */ void QAD_PyEditor::setText(QString s) { -// MESSAGE("setText"); int para=paragraphs()-1; int col=paragraphLength(para); insertAt(s,para,col); @@ -163,7 +246,7 @@ void QAD_PyEditor::handleReturn() _buf.append(text(para).remove(0,SIZEPR)); _buf.truncate( _buf.length() - 1 ); setReadOnly( true ); - _thread->exec(_buf.latin1()); + myExecCommandThread->exec(_buf.latin1()); } /* @@ -206,8 +289,8 @@ void QAD_PyEditor::mousePressEvent (QMouseEvent * event) } else if ( r == idMap[ IdClear ] ) { clear(); - string banner = _interp->getbanner(); - setText(banner.c_str()); + ThreadLock aPyLock = GetPyThreadLock(); + setText(myInterp->getbanner().c_str()); setText(_currentPrompt); } else if ( r == idMap[ IdSelectAll ] ) { @@ -317,7 +400,7 @@ void QAD_PyEditor::keyPressEvent( QKeyEvent *e ) _currentCommand.truncate( _currentCommand.length() - 1 ); SCRUTE(_currentCommand); } - QString previousCommand = _interp->getPrevious(); + QString previousCommand = myInterp->getPrevious(); if (previousCommand.compare(BEGIN_HISTORY_PY) != 0) { removeParagraph(endLine); @@ -341,7 +424,7 @@ void QAD_PyEditor::keyPressEvent( QKeyEvent *e ) // scroll the commands stack down else { QString histLine = _currentPrompt; - QString nextCommand = _interp->getNext(); + QString nextCommand = myInterp->getNext(); if (nextCommand.compare(TOP_HISTORY_PY) != 0) { removeParagraph(endLine); @@ -444,8 +527,9 @@ void QAD_PyEditor::customEvent(QCustomEvent *e) case PYTHON_ERROR: { _buf.truncate(0); - setText(_interp->getvout().c_str()); - setText(_interp->getverr().c_str()); + ThreadLock aPyLock = GetPyThreadLock(); + setText(myInterp->getvout().c_str()); + setText(myInterp->getverr().c_str()); _currentPrompt = ">>> "; setText(_currentPrompt); break; @@ -457,6 +541,22 @@ void QAD_PyEditor::customEvent(QCustomEvent *e) setText(_currentPrompt); break; } + case INITIALIZE: + { + setText(myInterp->getbanner().c_str()); + _buf.truncate(0); + break; + } + case SET_WAIT_CURSOR: + { + viewport()->setCursor( waitCursor ); + break; + } + case UNSET_CURSOR: + { + viewport()->unsetCursor(); + break; + } default: QTextEdit::customEvent( e ); } diff --git a/src/SALOMEGUI/QAD_PyEditor.h b/src/SALOMEGUI/QAD_PyEditor.h index 6e8c8d3d4..94c92c3af 100644 --- a/src/SALOMEGUI/QAD_PyEditor.h +++ b/src/SALOMEGUI/QAD_PyEditor.h @@ -32,18 +32,24 @@ #include #include +class QMutex; + class QAD_PyInterp; -class PythonThread; +class TInitEditorThread; +class TExecCommandThread; class QAD_PyEditor : public QTextEdit { Q_OBJECT public: - enum { PYTHON_OK = QEvent::User + 5000, PYTHON_ERROR, PYTHON_INCOMPLETE }; + enum { PYTHON_OK = QEvent::User + 5000, PYTHON_ERROR, PYTHON_INCOMPLETE, + INITIALIZE, SET_WAIT_CURSOR, UNSET_CURSOR }; public: - QAD_PyEditor(QAD_PyInterp* interp, QWidget *parent=0, const char *name=0); + QAD_PyEditor(QAD_PyInterp*& theInterp, QMutex* theMutex, + QWidget *theParent = 0, const char* theName = ""); + virtual void Init(); ~QAD_PyEditor(); virtual void setText(QString s); @@ -60,13 +66,17 @@ public slots: void handleReturn(); private: - QAD_PyInterp * _interp; QString _buf; QString _currentCommand; QString _currentPrompt; bool _isInHistory; - PythonThread* _thread; + QAD_PyInterp*& myInterp; + QMutex* myStudyMutex; + QMutex* myInitEditorMutex; + QMutex* myExecCommandMutex; + TInitEditorThread* myInitEditorThread; + TExecCommandThread* myExecCommandThread; }; #endif diff --git a/src/SALOMEGUI/QAD_PyInterp.cxx b/src/SALOMEGUI/QAD_PyInterp.cxx index 94fed0921..d7da14e42 100644 --- a/src/SALOMEGUI/QAD_PyInterp.cxx +++ b/src/SALOMEGUI/QAD_PyInterp.cxx @@ -26,11 +26,19 @@ // Module : SALOME // $Header$ -using namespace std; -using namespace std; #include "QAD_PyInterp.h" #include "utilities.h" +using namespace std; + + +#ifdef _DEBUG_ +static int MYDEBUG = 0; +#else +static int MYDEBUG = 0; +#endif + + /*! * constructor : multi Python interpreter, one per SALOME study. * calls initialize method defined in base class, which calls virtual methods @@ -64,36 +72,35 @@ QAD_PyInterp::~QAD_PyInterp() void QAD_PyInterp::initState() { - MESSAGE("QAD_PyInterp::initState"); _tstate = Py_NewInterpreter(); // create an interpreter and save current state PySys_SetArgv(PyInterp_base::_argc,PyInterp_base::_argv); // initialize sys.argv + if(MYDEBUG) MESSAGE("QAD_PyInterp::initState - this = "<ob_refcnt); // builtinmodule reference counter - _tstate->interp->builtins = PyModule_GetDict(builtinmodule); - Py_INCREF(_tstate->interp->builtins); + if(builtinmodule){ + PyObject *m = PyImport_GetModuleDict(); + PyDict_SetItemString(m, "__builtin__", builtinmodule); + SCRUTE(builtinmodule->ob_refcnt); // builtinmodule reference counter + _tstate->interp->builtins = PyModule_GetDict(builtinmodule); + Py_INCREF(_tstate->interp->builtins); + } } void QAD_PyInterp::initContext() { - MESSAGE("QAD_PyInterp::initContext"); PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context) if(!m){ - MESSAGE("problem..."); + if(MYDEBUG) MESSAGE("problem..."); PyErr_Print(); ASSERT(0); return; } _g = PyModule_GetDict(m); // get interpreter dictionnary context - SCRUTE(_g); + if(MYDEBUG) MESSAGE("QAD_PyInterp::initContext - this = "< @@ -54,19 +55,19 @@ typedef QAD_ViewFrame* View(QAD_RightFrame*); /*! Constructor */ -QAD_RightFrame::QAD_RightFrame(QWidget *parent, const char *name, - QAD_PyInterp* interp, ViewType vt) - : QAD_Splitter( Qt::Vertical, parent, name ) +QAD_RightFrame::QAD_RightFrame(QWidget *theParent, + const char *theTitle, ViewType theTypeView, + QAD_PyInterp*& theInterp, QMutex* theMutex): + QAD_Splitter( Qt::Vertical, theParent, theTitle ), + myViewType(theTypeView), + myInterp(theInterp) { this->setCompressEnabled( true ); - myViewType = vt; QAD_Desktop* Desktop = QAD_Application::getDesktop(); int DesktopHeight = Desktop->getMainFrame()->width(); int DesktopWidth = Desktop->getMainFrame()->height(); - _interp = interp; - OSD_SharedLibrary SharedLib = OSD_SharedLibrary(); QString ComponentLib; QCString dir; @@ -187,12 +188,15 @@ QAD_RightFrame::QAD_RightFrame(QWidget *parent, const char *name, QValueList sizes; myViewFrame->setMinimumSize( 1, 1 ); - vsplitter = new QAD_Splitter( Qt::Horizontal, this ); - vsplitter->setMinimumSize( 1, 1 ); - vsplitter->setCompressEnabled( true ); - myPyEditor = new QAD_PyEditor(_interp, vsplitter ,"Python Interpreter"); + mySplitter = new QAD_Splitter( Qt::Horizontal, this ); + mySplitter->setMinimumSize( 1, 1 ); + mySplitter->setCompressEnabled( true ); + + myPyEditor = new QAD_PyEditor(myInterp, theMutex, mySplitter ,"Python Interpreter"); myPyEditor->setMinimumSize( 1, 1 ); - myMessage = new QAD_Message( vsplitter ,"Message"); + myPyEditor->Init(); + + myMessage = new QAD_Message( mySplitter ,"Message"); myMessage->setMinimumSize( 1, 1 ); sizes.append( (int)(0.48 * DesktopHeight) ); @@ -201,7 +205,7 @@ QAD_RightFrame::QAD_RightFrame(QWidget *parent, const char *name, sizes.clear(); sizes.append( (int)(0.25 * DesktopWidth) ); sizes.append( (int)(0.25 * DesktopWidth) ); - vsplitter->setSizes( sizes ); + mySplitter->setSizes( sizes ); } /*! @@ -229,7 +233,7 @@ QAD_Message* QAD_RightFrame::getMessage() const */ QAD_PyInterp* QAD_RightFrame::get_PyInterp(void) { - return _interp; + return myInterp; } /*! diff --git a/src/SALOMEGUI/QAD_RightFrame.h b/src/SALOMEGUI/QAD_RightFrame.h index e28a9e430..b92b6eb66 100644 --- a/src/SALOMEGUI/QAD_RightFrame.h +++ b/src/SALOMEGUI/QAD_RightFrame.h @@ -31,16 +31,19 @@ #include "QAD_ViewFrame.h" #include "QAD_Message.h" -#include "QAD_PyEditor.h" #include "QAD_Splitter.h" +class QMutex; + +class QAD_PyEditor; class QAD_PyInterp; class QAD_EXPORT QAD_RightFrame : public QAD_Splitter { public: - QAD_RightFrame(QWidget *parent, const char *name, - QAD_PyInterp* interp, ViewType vt); + QAD_RightFrame(QWidget *theParent, + const char *theTitle, ViewType theTypeView, + QAD_PyInterp*& theInterp, QMutex* theMutex); ~QAD_RightFrame(); QAD_ViewFrame* getViewFrame() const; @@ -59,8 +62,8 @@ protected: QAD_ViewFrame* myViewFrame; QAD_PyEditor* myPyEditor; QAD_Message* myMessage; - QAD_Splitter* vsplitter; - QAD_PyInterp* _interp; + QAD_Splitter* mySplitter; + QAD_PyInterp*& myInterp; }; #endif diff --git a/src/SALOMEGUI/QAD_Study.cxx b/src/SALOMEGUI/QAD_Study.cxx index 64939d0d1..fbd95d9e4 100644 --- a/src/SALOMEGUI/QAD_Study.cxx +++ b/src/SALOMEGUI/QAD_Study.cxx @@ -26,7 +26,6 @@ // Module : SALOME // $Header$ -using namespace std; /*! \class QAD_Study QAD_Study.h \brief Study for QAD-based application. @@ -43,6 +42,7 @@ using namespace std; #include "QAD_ObjectBrowser.h" #include "QAD_PyInterp.h" #include "QAD_Config.h" +#include "QAD_PyInterp.h" #include "utilities.h" @@ -59,59 +59,104 @@ using namespace std; // QT Include #include +#include +#include -/*! - Constructor -*/ -QAD_Study::QAD_Study(QAD_Application* app, - SALOMEDS::Study_var aStudy, - const QString& path ) : -myOperationState( Undef ), -myApp( app ), -myActiveStudyFrame( 0 ), -myStudyFrameCount( 0 ), -myPath( path ) -{ - myStudy = aStudy; +using namespace std; - myTitle = QAD_Tools::getFileNameFromPath( path, true ); - myIsActive = false; - myIsSaved = false; - myIsModified = false; - myIsReadOnly = false; +#ifdef _DEBUG_ +static int MYDEBUG = 1; +#else +static int MYDEBUG = 0; +#endif - myStudyFrames.clear(); - myOperations.clear(); - myStudyFrames.setAutoDelete( true ); - myOperations.setAutoDelete( true ); - myChildWidgets.setAutoDelete( true ); +class TInitStudyThread : public QThread{ + TInitStudyThread(); + TInitStudyThread(const TInitStudyThread&); - /* create python interpreter */ - _interp = new QAD_PyInterp(); - SCRUTE(_interp); - _interp->initialize(); +public: + TInitStudyThread(QAD_PyInterp*& theInterp, QMutex* theMutex): + myInterp(theInterp), + myStudyLock(new ThreadLock(theMutex,"TInitStudyThread::TInitStudyThread")) + {} + virtual ~TInitStudyThread() { + if(myStudyLock) + delete myStudyLock; + } - /* create default selection */ - //NRI Selection( "Salome" ); - Selection( QAD_Application::getDesktop()->getComponentUserName( "KERNEL" ) ); +protected: + virtual void run(){ + { + ThreadLock aPyLock = GetPyThreadLock("TInitStudyThread::aPyLock"); + if(MYDEBUG) MESSAGE("TInitStudyThread::run()"); + myInterp = new QAD_PyInterp(); + myInterp->initialize(); + } + delete myStudyLock; + myStudyLock = NULL; + } + +private: + QAD_PyInterp*& myInterp; + ThreadLock* myStudyLock; +}; - /* create study frame */ - myResult = true; - createStudyFrame( getNextStudyFrameName() ); - /* set default Undo/Redo limit */ - QAD_ASSERT_DEBUG_ONLY( !myStudy->_is_nil() ); - SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder(); +/*! + Constructor +*/ +QAD_Study::QAD_Study(QAD_Application* theApp, + SALOMEDS::Study_var theStudy, + const QString& thePath): + myStudy(theStudy), + myOperationState(Undef), + myApp(theApp), + myActiveStudyFrame(0), + myStudyFrameCount(0), + myPath(thePath), + myTitle(QAD_Tools::getFileNameFromPath(thePath,true)), + myIsActive(false), + myIsSaved(false), + myIsModified(false), + myIsReadOnly(false), + myResult(true), + myInterp(0), + myInitStudyThread(0), + myMutex(new QMutex()) +{ + myStudyFrames.setAutoDelete( true ); + myOperations.setAutoDelete( true ); + myChildWidgets.setAutoDelete( true ); + + /* create default selection */ + //NRI Selection( "Salome" ); + Selection( QAD_Application::getDesktop()->getComponentUserName( "KERNEL" ) ); + + /* create python interpreter */ + myInitStudyThread = new TInitStudyThread(myInterp,myMutex); + myInitStudyThread->start(); + + /* create study frame */ + createStudyFrame( getNextStudyFrameName() ); + + /* set default Undo/Redo limit */ + QAD_ASSERT_DEBUG_ONLY( !myStudy->_is_nil() ); + SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder(); + + int aLocked = myStudy->GetProperties()->IsLocked(); + if (aLocked) myStudy->GetProperties()->SetLocked(false); + SB->UndoLimit(QAD_Desktop::getUndoLevel()); + if (aLocked) myStudy->GetProperties()->SetLocked(true); +} - int aLocked = myStudy->GetProperties()->IsLocked(); - if (aLocked) myStudy->GetProperties()->SetLocked(false); - SB->UndoLimit(QAD_Desktop::getUndoLevel()); - if (aLocked) myStudy->GetProperties()->SetLocked(true); +void QAD_Study::Init() +{ } + /*! Destructor */ @@ -120,6 +165,13 @@ QAD_Study::~QAD_Study () close(); //SRN: added - clear selection in case the study will be loaded again so the title will coincide SALOME_Selection::RemoveSelection( QString(myTitle + "_" + mySelection) ); + { + { + ThreadLock aLock(myMutex,"QAD_Study::~QAD_Study()"); + delete myInitStudyThread; + } + delete myMutex; + } } /*! @@ -345,10 +397,10 @@ void QAD_Study::setReadOnly(bool state) */ void QAD_Study::onStudyFrameActivated( QAD_StudyFrame* activeStudyFrame ) { - static int IS_FIRST_STUDY = 1; - if(IS_FIRST_STUDY){ //for normally initialize "salome.py and ..." - _interp->run(""); IS_FIRST_STUDY = 0; - } +// static int IS_FIRST_STUDY = 1; +// if(IS_FIRST_STUDY){ //for normally initialize "salome.py and ..." +// _interp->run(""); IS_FIRST_STUDY = 0; +// } // bool found = false; for ( QAD_StudyFrame* studyframe = myStudyFrames.first(); studyframe; studyframe = myStudyFrames.next() ) { if ( studyframe == activeStudyFrame) { /* one of my study frames */ @@ -592,7 +644,8 @@ QAD_StudyFrame* QAD_Study::createStudyFrame( const QString& title, ViewType theV if ( theViewType == VIEW_OCC) { // MESSAGE ("Create Study Frame for OCC viewer"); sf = new QAD_StudyFrame ( this, parent->getMainFrame(), - title, _interp, VIEW_OCC ); + title, VIEW_OCC, + myInterp, myMutex ); Standard_CString name = strdup(sf->title().latin1()); anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName"); @@ -609,7 +662,8 @@ QAD_StudyFrame* QAD_Study::createStudyFrame( const QString& title, ViewType theV else if ( theViewType == VIEW_VTK) { // MESSAGE ("Create Study Frame for VTK viewer"); sf = new QAD_StudyFrame ( this, parent->getMainFrame(), - title, _interp, VIEW_VTK ); + title, VIEW_VTK, + myInterp, myMutex ); Standard_CString name = strdup(sf->title().latin1()); anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName"); aName = SALOMEDS::AttributeName::_narrow(anAttr); @@ -625,7 +679,8 @@ QAD_StudyFrame* QAD_Study::createStudyFrame( const QString& title, ViewType theV else if ( theViewType == VIEW_GRAPHSUPERV) { //MESSAGE ("Create Study Frame for SUPER`VISOR Graph"); sf = new QAD_StudyFrame ( this, parent->getMainFrame(), - title, _interp, VIEW_GRAPHSUPERV ); + title, VIEW_GRAPHSUPERV, + myInterp, myMutex ); Standard_CString name = strdup(sf->title().latin1()); anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName"); aName = SALOMEDS::AttributeName::_narrow(anAttr); @@ -640,7 +695,8 @@ QAD_StudyFrame* QAD_Study::createStudyFrame( const QString& title, ViewType theV } else if ( theViewType == VIEW_PLOT2D ) { sf = new QAD_StudyFrame ( this, parent->getMainFrame(), - title, _interp, VIEW_PLOT2D ); + title, VIEW_PLOT2D, + myInterp, myMutex ); Standard_CString name = strdup(sf->title().latin1()); anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName"); aName = SALOMEDS::AttributeName::_narrow(anAttr); @@ -1246,7 +1302,7 @@ QString QAD_Study::getNextStudyFrameName() */ QAD_PyInterp* QAD_Study::get_PyInterp(void) { - return _interp; + return myInterp; } /*! diff --git a/src/SALOMEGUI/QAD_Study.h b/src/SALOMEGUI/QAD_Study.h index 94fe80305..8139e8a5d 100644 --- a/src/SALOMEGUI/QAD_Study.h +++ b/src/SALOMEGUI/QAD_Study.h @@ -44,7 +44,10 @@ #include class QAD_Application; + +class QMutex; class QAD_PyInterp; +class TInitStudyThread; class QAD_EXPORT QAD_Study : public QObject { @@ -54,6 +57,7 @@ public: QAD_Study(QAD_Application* app, SALOMEDS::Study_var aStudy, const QString& title); + virtual void Init(); ~QAD_Study(); /* Event filter */ @@ -189,7 +193,10 @@ private: bool myIsModified; bool myIsReadOnly; bool myResult; - QAD_PyInterp* _interp; + + QMutex* myMutex; + QAD_PyInterp* myInterp; + TInitStudyThread* myInitStudyThread; }; #endif diff --git a/src/SALOMEGUI/QAD_StudyFrame.cxx b/src/SALOMEGUI/QAD_StudyFrame.cxx index 8e65a6ae5..b54b6dfc0 100644 --- a/src/SALOMEGUI/QAD_StudyFrame.cxx +++ b/src/SALOMEGUI/QAD_StudyFrame.cxx @@ -34,11 +34,13 @@ #include "QAD_StudyFrame.h" #include "QAD_RightFrame.h" #include "QAD_LeftFrame.h" +#include "QAD_Splitter.h" #include "QAD_Application.h" #include "QAD_Desktop.h" #include "QAD_Study.h" #include "QAD_ObjectBrowser.h" #include "QAD_PyInterp.h" + #include using namespace std; @@ -46,45 +48,37 @@ using namespace std; /*! Constructor */ -QAD_StudyFrame::QAD_StudyFrame(QAD_Study* study, QWidget* parent, const QString& title, - QAD_PyInterp* interp, ViewType typeView) : - QMainWindow( parent , title, WStyle_NormalBorder | +QAD_StudyFrame::QAD_StudyFrame(QAD_Study* theStudy, QWidget* theParent, + const QString& theTitle, ViewType theTypeView, + QAD_PyInterp*& theInterp, QMutex* theMutex): + QMainWindow( theParent , theTitle, WStyle_NormalBorder | WStyle_MinMax | WStyle_SysMenu | WDestructiveClose), - myStudy(study) + myTitle(theTitle), + myEntry(""), + myTypeView(theTypeView), + myStudy(theStudy), + myInterp(theInterp) { - myTypeView = typeView; - myTitle = title; setCaption( myTitle ); setPalette(QAD_Application::getPalette()); - myEntry = ""; - _interp = interp; - - s1 = new QAD_Splitter( Qt::Horizontal, this); - s1->setCompressEnabled( true ); + mySplitter = new QAD_Splitter( Qt::Horizontal, this); + mySplitter->setCompressEnabled( true ); - setCentralWidget( s1 ); - myLeftFrm = new QAD_LeftFrame(study->getStudyDocument(), s1 , title ); - myRightFrm = new QAD_RightFrame( s1, title, _interp, myTypeView); + setCentralWidget(mySplitter); + myLeftFrm = new QAD_LeftFrame(myStudy->getStudyDocument(), mySplitter, theTitle ); + myRightFrm = new QAD_RightFrame( mySplitter, theTitle, myTypeView, myInterp, theMutex); QValueList sizes; sizes.append( (int)(0.30*QAD_Application::getDesktop()->getMainFrame()->width()) ); sizes.append( (int)(0.50*QAD_Application::getDesktop()->getMainFrame()->width()) ); - s1->setSizes( sizes ); + mySplitter->setSizes( sizes ); - QAD_ASSERT_DEBUG_ONLY ( parent->inherits("QWorkspaceP") ); - QAD_ASSERT ( QObject::connect( (QWorkspaceP*)parent, SIGNAL(windowActivated(QWidget*)), + QAD_ASSERT_DEBUG_ONLY ( theParent->inherits("QWorkspaceP") ); + QAD_ASSERT ( QObject::connect( (QWorkspaceP*)theParent, SIGNAL(windowActivated(QWidget*)), this, SLOT(onStudyFrameActivated(QWidget*))) ); } -/*! - Constructor -*/ -QAD_StudyFrame::QAD_StudyFrame(QAD_Study* study, QWidget* parent ) : - QMainWindow ( parent ), - myStudy(study) -{ -} /*! Destructor @@ -126,6 +120,11 @@ void QAD_StudyFrame::setVisible( bool visible ) */ void QAD_StudyFrame::closeEvent(QCloseEvent* e) { + if ( IsPyLocked() ) { + e->ignore(); + return; + } + emit sfStudyFrameClosing(this); } @@ -134,22 +133,22 @@ void QAD_StudyFrame::closeEvent(QCloseEvent* e) */ void QAD_StudyFrame::compressLeft() { - s1->compress(myLeftFrm); + mySplitter->compress(myLeftFrm); } void QAD_StudyFrame::compressRight() { - s1->compress(myRightFrm); + mySplitter->compress(myRightFrm); } void QAD_StudyFrame::unCompressLeft() { - s1->unCompress(myLeftFrm); + mySplitter->unCompress(myLeftFrm); } void QAD_StudyFrame::unCompressRight() { - s1->unCompress(myRightFrm); + mySplitter->unCompress(myRightFrm); } /*! @@ -203,5 +202,5 @@ void QAD_StudyFrame::onStudyFrameActivated ( QWidget* activeWindow ) */ QAD_PyInterp* QAD_StudyFrame::get_PyInterp(void) { - return _interp; + return myInterp; } diff --git a/src/SALOMEGUI/QAD_StudyFrame.h b/src/SALOMEGUI/QAD_StudyFrame.h index 5727e13c0..cdb83befa 100644 --- a/src/SALOMEGUI/QAD_StudyFrame.h +++ b/src/SALOMEGUI/QAD_StudyFrame.h @@ -30,12 +30,13 @@ #define QAD_StudyFrame_H #include "QAD.h" -#include "QAD_Splitter.h" // QT Includes #include #include +class QMutex; + class QAD_RightFrame; class QAD_LeftFrame; class QAD_Splitter; @@ -55,11 +56,9 @@ class QAD_EXPORT QAD_StudyFrame: public QMainWindow Q_OBJECT public: - QAD_StudyFrame(QAD_Study* study, - QWidget* parent, const QString& title, - QAD_PyInterp* interp, ViewType typeView); - QAD_StudyFrame(QAD_Study*, - QWidget* parent = 0); + QAD_StudyFrame(QAD_Study* theStudy, QWidget* theParent, + const QString& theTitle, ViewType theTypeView, + QAD_PyInterp*& theInterp, QMutex* theMutex); virtual ~QAD_StudyFrame(); QAD_Study* getStudy() { return myStudy; } @@ -77,7 +76,6 @@ class QAD_EXPORT QAD_StudyFrame: public QMainWindow const QString& entry() const; void setVisible( bool isVisible = true ); - void closeEvent(QCloseEvent* e); void compressLeft(); void compressRight(); @@ -90,6 +88,9 @@ class QAD_EXPORT QAD_StudyFrame: public QMainWindow public slots: void onStudyFrameActivated ( QWidget* ); + + protected: + virtual void closeEvent ( QCloseEvent* ); private: @@ -99,9 +100,9 @@ class QAD_EXPORT QAD_StudyFrame: public QMainWindow ViewType myTypeView; QAD_LeftFrame* myLeftFrm; QAD_RightFrame* myRightFrm; - QAD_Splitter* s1; - QAD_PyInterp* _interp; + QAD_Splitter* mySplitter; QAD_Study* myStudy; + QAD_PyInterp*& myInterp; }; #endif -- 2.39.2