From 5bceac193975ab8d272a7fb354cbb2b99f97ff82 Mon Sep 17 00:00:00 2001 From: vsr Date: Fri, 7 Oct 2016 15:25:37 +0300 Subject: [PATCH] Add Python wrappings for Python console. --- src/LightApp/LightApp_PyEditor.cxx | 2 +- src/SalomeApp/SalomeApp_PyInterp.cxx | 17 +++ src/SalomeApp/SalomeApp_PyInterp.h | 1 + tools/PyConsole/CMakeLists.txt | 15 +++ tools/PyConsole/src/CMakeLists.txt | 4 + tools/PyConsole/src/PyConsole_Console.cxx | 32 +++-- tools/PyConsole/src/PyConsole_Console.h | 6 +- tools/PyConsole/src/PyConsole_Editor.cxx | 51 +++++--- tools/PyConsole/src/PyConsole_Editor.h | 5 +- tools/PyConsole/src/python/CMakeLists.txt | 63 ++++++++++ tools/PyConsole/src/python/PyConsolePy.sip | 137 +++++++++++++++++++++ tools/PyInterp/src/PyInterp_Interp.cxx | 4 +- 12 files changed, 309 insertions(+), 28 deletions(-) create mode 100644 tools/PyConsole/src/python/CMakeLists.txt create mode 100644 tools/PyConsole/src/python/PyConsolePy.sip diff --git a/src/LightApp/LightApp_PyEditor.cxx b/src/LightApp/LightApp_PyEditor.cxx index 7d71b8de0..d2072b3dc 100644 --- a/src/LightApp/LightApp_PyEditor.cxx +++ b/src/LightApp/LightApp_PyEditor.cxx @@ -29,7 +29,7 @@ \param parent parent widget */ LightApp_PyEditor::LightApp_PyEditor( PyConsole_Interp* interp, QWidget* parent ) - : PyConsole_Editor( interp, parent ) + : PyConsole_Editor( parent, interp ) { } diff --git a/src/SalomeApp/SalomeApp_PyInterp.cxx b/src/SalomeApp/SalomeApp_PyInterp.cxx index e79c83613..0ab36f99a 100755 --- a/src/SalomeApp/SalomeApp_PyInterp.cxx +++ b/src/SalomeApp/SalomeApp_PyInterp.cxx @@ -39,6 +39,23 @@ SalomeApp_PyInterp::~SalomeApp_PyInterp() { } +/*! + * Initialize context dictionaries. GIL is held already. + * The code executed in an embedded interpreter is expected to be run at the module + * level, in which case local and global context have to be the same dictionary. + * See: http://stackoverflow.com/questions/12265756/c-python-running-python-code-within-a-context + * for an explanation. + */ +bool SalomeApp_PyInterp::initContext() +{ + bool ok = PyConsole_Interp::initContext(); + if ( ok ) { + int ret = PyRun_SimpleString( "import salome_iapp; salome_iapp.IN_SALOME_GUI = True" ); + ok = ok && (ret == 0); + } + return ok; +} + /*! \brief Called before each Python command running. */ diff --git a/src/SalomeApp/SalomeApp_PyInterp.h b/src/SalomeApp/SalomeApp_PyInterp.h index 567b25235..45bbc0178 100755 --- a/src/SalomeApp/SalomeApp_PyInterp.h +++ b/src/SalomeApp/SalomeApp_PyInterp.h @@ -39,6 +39,7 @@ public: protected: SalomeApp_PyInterp(); + virtual bool initContext(); virtual int beforeRun(); private: diff --git a/tools/PyConsole/CMakeLists.txt b/tools/PyConsole/CMakeLists.txt index 30f21888b..57cb1e4ca 100644 --- a/tools/PyConsole/CMakeLists.txt +++ b/tools/PyConsole/CMakeLists.txt @@ -45,6 +45,7 @@ INCLUDE(SalomeSetupPlatform) # Options # ======= OPTION(PYCONSOLE_BUILD_WITH_QT5 "Build PYCONSOLE with Qt 5" ON) +OPTION(PYCONSOLE_BUILD_PYTHON "Build Python wrapping for PyConsole" ON) # # Set list of prerequisites @@ -60,6 +61,20 @@ ELSE() FIND_PACKAGE(SalomeQt5 REQUIRED) ENDIF() +IF(PYCONSOLE_BUILD_PYTHON) + # Sip + FIND_PACKAGE(SalomeSIP REQUIRED) # should come after Python and before PyQt + SALOME_LOG_OPTIONAL_PACKAGE(SalomeSIP PYCONSOLE_BUILD_PYTHON) + # PyQt + IF (NOT PYCONSOLE_BUILD_WITH_QT5) + FIND_PACKAGE(SalomePyQt4 REQUIRED) + SALOME_LOG_OPTIONAL_PACKAGE(SalomePyQt4 PYCONSOLE_BUILD_PYTHON) + ELSE() + FIND_PACKAGE(SalomePyQt5 REQUIRED) + SALOME_LOG_OPTIONAL_PACKAGE(SalomePyQt5 PYCONSOLE_BUILD_PYTHON) + ENDIF() +ENDIF(PYCONSOLE_BUILD_PYTHON) + # Detection report SALOME_PACKAGE_REPORT_AND_CHECK() diff --git a/tools/PyConsole/src/CMakeLists.txt b/tools/PyConsole/src/CMakeLists.txt index 113f808b3..f64ad21cb 100755 --- a/tools/PyConsole/src/CMakeLists.txt +++ b/tools/PyConsole/src/CMakeLists.txt @@ -19,6 +19,10 @@ INCLUDE(UseQtExt) +IF(PYCONSOLE_BUILD_PYTHON) + ADD_SUBDIRECTORY(python) +ENDIF(PYCONSOLE_BUILD_PYTHON) + # --- options --- # additional include directories diff --git a/tools/PyConsole/src/PyConsole_Console.cxx b/tools/PyConsole/src/PyConsole_Console.cxx index 3aaa52ccb..26f8b1cdc 100644 --- a/tools/PyConsole/src/PyConsole_Console.cxx +++ b/tools/PyConsole/src/PyConsole_Console.cxx @@ -44,24 +44,42 @@ This will create a console with default editor and interpreter. - To use custom editor and/or interpreter class with the console, you can use additional parameter - of the constructor; in this case you have to ensure that Python interpeter is initialized properly: + To use custom editor with the console, you can use alternative constructor: \code - PyConsole_Interp* interp = new PyConsole_Interp(); - interp->initialize(); - PyConsole_Console c(myWindow, new MyEditor(interp)); + PyConsole_Console c(myWindow, new MyEditor()); \endcode */ +/*! + \brief Default constructor. + + Creates new python console widget. + \param parent parent widget +*/ +PyConsole_Console::PyConsole_Console( QWidget* parent ) +: QWidget( parent ) +{ + init( 0 ); +} + /*! \brief Constructor. Creates new python console widget. \param parent parent widget - \param interp python interpreter + \param editor python editor */ PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Editor* editor ) : QWidget( parent ) +{ + init( editor ); +} + +/*! + \brief Initialize console widget. + \param editor python editor +*/ +void PyConsole_Console::init( PyConsole_Editor* editor ) { // initialize Python interpretator PyConsole_Interp* interp = editor ? editor->getInterp() : new PyConsole_Interp(); @@ -70,7 +88,7 @@ PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Editor* editor // create editor console QVBoxLayout* lay = new QVBoxLayout( this ); lay->setMargin( 0 ); - myEditor = editor ? editor : new PyConsole_Editor( interp, this ); + myEditor = editor ? editor : new PyConsole_Editor( this, interp ); myEditor->setContextMenuPolicy( Qt::NoContextMenu ); lay->addWidget( myEditor ); diff --git a/tools/PyConsole/src/PyConsole_Console.h b/tools/PyConsole/src/PyConsole_Console.h index e0b111e53..2a2becd3e 100644 --- a/tools/PyConsole/src/PyConsole_Console.h +++ b/tools/PyConsole/src/PyConsole_Console.h @@ -54,7 +54,8 @@ public: }; public: - PyConsole_Console( QWidget* parent, PyConsole_Editor* editor = 0 ); + PyConsole_Console( QWidget* = 0 ); + PyConsole_Console( QWidget*, PyConsole_Editor* ); virtual ~PyConsole_Console(); PyConsole_Interp* getInterp() const; @@ -89,6 +90,9 @@ protected: virtual void contextMenuEvent( QContextMenuEvent* ); +private: + void init( PyConsole_Editor* ); + protected: PyConsole_Editor* myEditor; //!< python console editor widget QMap myActions; //!< menu actions list diff --git a/tools/PyConsole/src/PyConsole_Editor.cxx b/tools/PyConsole/src/PyConsole_Editor.cxx index e177a03ef..7ec727292 100644 --- a/tools/PyConsole/src/PyConsole_Editor.cxx +++ b/tools/PyConsole/src/PyConsole_Editor.cxx @@ -147,26 +147,47 @@ void PyConsole_CallbackStderr( void* data, char* c ) } /*! - \brief Constructor. + \brief Default constructor. Creates python editor window. - \param theInterp python interper \param theParent parent widget */ -PyConsole_Editor::PyConsole_Editor( PyConsole_Interp* theInterp, - QWidget* theParent ) -: QTextEdit( theParent ), - myInterp( theInterp ), - myCmdInHistory( -1 ), - myEventLoop( 0 ), - myShowBanner( true ), - myIsSync( true ), - myIsSuppressOutput( false ), - myMultiLinePaste( false ), - myAutoCompletion( false ), - myTabMode( false ), - myComplCursorPos( -1 ) +PyConsole_Editor::PyConsole_Editor( QWidget* parent ) + : QTextEdit( parent ) +{ + PyConsole_Interp* interp = new PyConsole_Interp(); + interp->initialize(); + init( interp ); +} + +/*! + \brief Constructor. + + Creates python editor window. + \param parent parent widget + \param interp python interper +*/ +PyConsole_Editor::PyConsole_Editor( QWidget* parent, + PyConsole_Interp* interp ) + : QTextEdit( parent ) { + init( interp ); +} + + +void PyConsole_Editor::init( PyConsole_Interp* interp ) +{ + myInterp = interp; + myCmdInHistory = -1; + myEventLoop = 0; + myShowBanner = true; + myIsSync = true; + myIsSuppressOutput = false; + myMultiLinePaste = false; + myAutoCompletion = false; + myTabMode = false; + myComplCursorPos = -1; + setFont( QFont( "Courier", 11 ) ); // default font setUndoRedoEnabled( false ); diff --git a/tools/PyConsole/src/PyConsole_Editor.h b/tools/PyConsole/src/PyConsole_Editor.h index a63e8fcd1..01c35c92e 100644 --- a/tools/PyConsole/src/PyConsole_Editor.h +++ b/tools/PyConsole/src/PyConsole_Editor.h @@ -39,7 +39,8 @@ class PYCONSOLE_EXPORT PyConsole_Editor : public QTextEdit Q_OBJECT; public: - PyConsole_Editor( PyConsole_Interp*, QWidget* = 0 ); + PyConsole_Editor( QWidget* = 0 ); + PyConsole_Editor( QWidget*, PyConsole_Interp* ); ~PyConsole_Editor(); PyConsole_Interp* getInterp() const; @@ -95,6 +96,8 @@ protected: virtual QString getLogFileName(); private: + void init( PyConsole_Interp* ); + void multilinePaste( const QString& ); void multiLineProcessNextLine(); diff --git a/tools/PyConsole/src/python/CMakeLists.txt b/tools/PyConsole/src/python/CMakeLists.txt new file mode 100644 index 000000000..1d2ee2106 --- /dev/null +++ b/tools/PyConsole/src/python/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (C) 2015-2016 OPEN CASCADE +# +# 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, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +# + +INCLUDE(UseQtExt) +INCLUDE(UsePyQt) + +# --- options --- + +# additional include directories +INCLUDE_DIRECTORIES( + $(QT_INCLUDES) + ${PYTHON_INCLUDE_DIRS} + ${SIP_INCLUDE_DIR} + ${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) + +# additional preprocessor / compiler flags +ADD_DEFINITIONS(${QT_DEFINITIONS}) + +# libraries to link to +SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} PyConsole) + +# --- sources --- + +# sip files / to be processed by sip +SET(_sip_files PyConsolePy.sip) + +# sources / sip wrappings +PYQT_WRAP_SIP(_sip_SOURCES ${_sip_files}) + +# sources / to compile +SET(PyConsolePy_SOURCES ${_sip_SOURCES}) +message("PyConsolePy_SOURCES = ${PyConsolePy_SOURCES}") + +# --- rules --- + +ADD_LIBRARY(PyConsolePy ${PyConsolePy_SOURCES}) +IF(WIN32) + SET_TARGET_PROPERTIES(PyConsolePy PROPERTIES SUFFIX ".pyd" DEBUG_OUTPUT_NAME PyConsolePy_d RELEASE_OUTPUT_NAME PyConsolePy) +ELSE() + SET_TARGET_PROPERTIES(PyConsolePy PROPERTIES PREFIX "") +ENDIF() +TARGET_LINK_LIBRARIES(PyConsolePy ${_link_LIBRARIES}) +INSTALL(TARGETS PyConsolePy EXPORT ${TOOLS_EXPORT_NAME}TargetGroup DESTINATION ${PYCONSOLE_INSTALL_LIBS}) diff --git a/tools/PyConsole/src/python/PyConsolePy.sip b/tools/PyConsole/src/python/PyConsolePy.sip new file mode 100644 index 000000000..67645c86d --- /dev/null +++ b/tools/PyConsole/src/python/PyConsolePy.sip @@ -0,0 +1,137 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// 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 : PyConsolePy.sip +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +%Module PyConsolePy + +%Import QtCore/QtCoremod.sip +%Import QtGui/QtGuimod.sip +%If (Qt_5_0_0 -) +%Import QtWidgets/QtWidgetsmod.sip +%End + +class PyConsole_Editor : QTextEdit +{ +%TypeHeaderCode +#include +%End + +public: + explicit PyConsole_Editor( QWidget* /TransferThis/ = 0 ); + virtual ~PyConsole_Editor(); + + virtual void addText( const QString&, const bool = false, const bool = false ); + bool isCommand( const QString& ) const; + + virtual void exec( const QString& ); + void execAndWait( const QString& ); + + bool isSync() const; + void setIsSync( const bool ); + + bool isSuppressOutput() const; + void setIsSuppressOutput( const bool ); + + bool isShowBanner() const; + void setIsShowBanner( const bool ); + + void setAutoCompletion( bool ); + bool autoCompletion() const; + + bool isLogging() const; + + virtual QSize sizeHint() const; + + bool startLog( const QString& ); + bool dump( const QString& ); + +signals: + void updateDoc( const QString& ); + +public slots: + void cut(); + void paste(); + void clear(); + void dump(); + void startLog(); + void stopLog(); + +protected: + virtual void dropEvent( QDropEvent* ); + virtual void mousePressEvent( QMouseEvent* ); + virtual void mouseReleaseEvent( QMouseEvent* ); + virtual void keyPressEvent ( QKeyEvent* ); + virtual void customEvent( QEvent* ); + virtual void insertFromMimeData( const QMimeData* ); + void putLog( const QString& ); + + virtual QString getDumpFileName(); + virtual QString getLogFileName(); + +private: + PyConsole_Editor( const PyConsole_Editor& ); + PyConsole_Editor& operator=( const PyConsole_Editor& ); +}; + +class PyConsole_Console : QWidget +{ +%TypeHeaderCode +#include +%End + +public: + explicit PyConsole_Console( QWidget* /TransferThis/ = 0 ); + virtual ~PyConsole_Console(); + + QFont font() const; + virtual void setFont( const QFont& ); + + bool isSync() const; + void setIsSync( const bool ); + + bool isSuppressOutput() const; + void setIsSuppressOutput( const bool ); + + bool isShowBanner() const; + void setIsShowBanner( const bool ); + + void setAutoCompletion( bool ); + bool autoCompletion() const; + + void exec( const QString& ); + void execAndWait( const QString& ); + + void setMenuActions( const int ); + int menuActions() const; + + void startLog( const QString& ); + void stopLog(); + +protected: + virtual void contextMenuEvent( QContextMenuEvent* ); + +private: + PyConsole_Console( const PyConsole_Console& ); + PyConsole_Console& operator=( const PyConsole_Console& ); +}; diff --git a/tools/PyInterp/src/PyInterp_Interp.cxx b/tools/PyInterp/src/PyInterp_Interp.cxx index 5946e8d7f..ebee5fda2 100644 --- a/tools/PyInterp/src/PyInterp_Interp.cxx +++ b/tools/PyInterp/src/PyInterp_Interp.cxx @@ -295,9 +295,7 @@ bool PyInterp_Interp::initContext() Py_INCREF(_global_context); _local_context = _global_context; - int ret = PyRun_SimpleString("import salome_iapp;salome_iapp.IN_SALOME_GUI=True"); - - return ret == 0; + return true; } /*! -- 2.39.2