]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Modifying build procedure to expose PyConsole and PyInterp as tools.
authorabn <adrien.bruneton@cea.fr>
Fri, 20 May 2016 12:51:16 +0000 (14:51 +0200)
committerabn <adrien.bruneton@cea.fr>
Fri, 20 May 2016 12:51:16 +0000 (14:51 +0200)
61 files changed:
src/CMakeLists.txt
src/LightApp/CMakeLists.txt
src/PVServerService/CMakeLists.txt
src/PyConsole/CMakeLists.txt [deleted file]
src/PyConsole/PyConsole.h [deleted file]
src/PyConsole/PyConsole_Console.cxx [deleted file]
src/PyConsole/PyConsole_Console.h [deleted file]
src/PyConsole/PyConsole_Editor.cxx [deleted file]
src/PyConsole/PyConsole_Editor.h [deleted file]
src/PyConsole/PyConsole_Event.cxx [deleted file]
src/PyConsole/PyConsole_Event.h [deleted file]
src/PyConsole/PyConsole_Interp.cxx [deleted file]
src/PyConsole/PyConsole_Interp.h [deleted file]
src/PyConsole/PyConsole_Request.cxx [deleted file]
src/PyConsole/PyConsole_Request.h [deleted file]
src/PyConsole/resources/PyConsole_msg_en.ts [deleted file]
src/PyConsole/resources/PyConsole_msg_fr.ts [deleted file]
src/PyConsole/resources/PyConsole_msg_ja.ts [deleted file]
src/PyInterp/CMakeLists.txt [deleted file]
src/PyInterp/PyInterp.h [deleted file]
src/PyInterp/PyInterp_Dispatcher.cxx [deleted file]
src/PyInterp/PyInterp_Dispatcher.h [deleted file]
src/PyInterp/PyInterp_Event.cxx [deleted file]
src/PyInterp/PyInterp_Event.h [deleted file]
src/PyInterp/PyInterp_Interp.cxx [deleted file]
src/PyInterp/PyInterp_Interp.h [deleted file]
src/PyInterp/PyInterp_Request.cxx [deleted file]
src/PyInterp/PyInterp_Request.h [deleted file]
src/PyInterp/PyInterp_Utils.h [deleted file]
src/SALOME_PYQT/SALOME_PYQT_GUI/CMakeLists.txt
src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt
src/SALOME_PYQT/SalomePyQt/CMakeLists.txt
src/SalomeApp/CMakeLists.txt
tools/PyConsole/CMakeLists.txt [new file with mode: 0644]
tools/PyConsole/src/CMakeLists.txt [new file with mode: 0755]
tools/PyConsole/src/PyConsole.h [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Console.cxx [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Console.h [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Editor.cxx [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Editor.h [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Event.cxx [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Event.h [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Interp.cxx [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Interp.h [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Request.cxx [new file with mode: 0644]
tools/PyConsole/src/PyConsole_Request.h [new file with mode: 0644]
tools/PyConsole/src/resources/PyConsole_msg_en.ts [new file with mode: 0644]
tools/PyConsole/src/resources/PyConsole_msg_fr.ts [new file with mode: 0644]
tools/PyConsole/src/resources/PyConsole_msg_ja.ts [new file with mode: 0644]
tools/PyInterp/CMakeLists.txt [new file with mode: 0644]
tools/PyInterp/src/CMakeLists.txt [new file with mode: 0755]
tools/PyInterp/src/PyInterp.h [new file with mode: 0755]
tools/PyInterp/src/PyInterp_Dispatcher.cxx [new file with mode: 0755]
tools/PyInterp/src/PyInterp_Dispatcher.h [new file with mode: 0755]
tools/PyInterp/src/PyInterp_Event.cxx [new file with mode: 0644]
tools/PyInterp/src/PyInterp_Event.h [new file with mode: 0644]
tools/PyInterp/src/PyInterp_Interp.cxx [new file with mode: 0644]
tools/PyInterp/src/PyInterp_Interp.h [new file with mode: 0644]
tools/PyInterp/src/PyInterp_Request.cxx [new file with mode: 0644]
tools/PyInterp/src/PyInterp_Request.h [new file with mode: 0644]
tools/PyInterp/src/PyInterp_Utils.h [new file with mode: 0644]

index 17fd52a98ec29b5b600856a60a7bbac6226d006a..05ef01bc8bf809c54347b13b4008f7d647e2720b 100755 (executable)
@@ -122,9 +122,14 @@ ENDIF(SALOME_USE_PYVIEWER)
 ##
 # Python-based packages, part 1 (generic)
 ##
-IF(SALOME_USE_PYCONSOLE) 
-  ADD_SUBDIRECTORY(PyInterp)
-  ADD_SUBDIRECTORY(PyConsole)
+IF(SALOME_USE_PYCONSOLE)
+  # Include sub-project PyConsole:
+  SET(TOOLS_EXPORT_NAME ${PROJECT_NAME})
+  SET(PYCONSOLE_INSTALL_LIBS "${SALOME_INSTALL_LIBS}")
+  SET(PYCONSOLE_INSTALL_HEADERS "${SALOME_INSTALL_HEADERS}") 
+  SET(PYCONSOLE_INSTALL_RES "${SALOME_GUI_INSTALL_RES_DATA}")   
+  ADD_SUBDIRECTORY(../tools/PyConsole ${CMAKE_CURRENT_BINARY_DIR}/PyConsole) # will bring in PyInterp automatically
+  
   ADD_SUBDIRECTORY(SALOME_PYQT)
 ENDIF(SALOME_USE_PYCONSOLE)
 
index 770f9690f74dfb40ea555a0b28eb9cbb51d49554..de54a19705659c81979052dd887409832b6f64d5 100755 (executable)
@@ -81,8 +81,8 @@ ENDIF()
 IF(SALOME_USE_PYCONSOLE)
   INCLUDE_DIRECTORIES(
     ${PYTHON_INCLUDE_DIRS}
-    ${PROJECT_SOURCE_DIR}/src/PyConsole
-    ${PROJECT_SOURCE_DIR}/src/PyInterp
+    ${PROJECT_SOURCE_DIR}/tools/PyConsole/src
+    ${PROJECT_SOURCE_DIR}/tools/PyInterp/src
     ${PROJECT_SOURCE_DIR}/src/SUITApp
   )
 ENDIF()
index 76cfef96a43c902c35c443a30a4cb517e2fc8078..7d34b87cf0a5fb1152470c68daee142e277107b9 100644 (file)
@@ -25,7 +25,7 @@ ENDIF()
 INCLUDE_DIRECTORIES(
   ${CMAKE_CURRENT_SOURCE_DIR}
   ${KERNEL_INCLUDE_DIRS}
-  ${PROJECT_SOURCE_DIR}/src/PyInterp
+  ${PROJECT_SOURCE_DIR}/tools/PyInterp/src
   )
 
 ADD_DEFINITIONS(
diff --git a/src/PyConsole/CMakeLists.txt b/src/PyConsole/CMakeLists.txt
deleted file mode 100755 (executable)
index 713769e..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) 2012-2016  CEA/DEN, EDF R&D, 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
-#
-
-INCLUDE(UseQtExt)
-
-# --- options ---
-
-# additional include directories
-INCLUDE_DIRECTORIES(
-  ${QT_INCLUDES}
-  ${PYTHON_INCLUDE_DIRS}
-  ${PROJECT_SOURCE_DIR}/src/PyInterp
-)
-
-# additional preprocessor / compiler flags
-ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
-
-# libraries to link to
-SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} PyInterp)
-
-# --- headers ---
-
-# header files / to be processed by moc
-SET(_moc_HEADERS
-  PyConsole_Console.h
-  PyConsole_Editor.h
-)
-
-# header files / no moc processing
-SET(_other_HEADERS
-  PyConsole.h
-  PyConsole_Event.h
-  PyConsole_Interp.h
-  PyConsole_Request.h
-)
-
-# header files / to install
-SET(PyConsole_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
-
-# --- resources ---
-
-# resource files / to be processed by lrelease
-SET(_ts_RESOURCES
-  resources/PyConsole_msg_en.ts
-  resources/PyConsole_msg_fr.ts
-  resources/PyConsole_msg_ja.ts
-)
-
-# --- sources ---
-
-# sources / moc wrappings
-QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS})
-
-# sources / static
-SET(_other_SOURCES
-  PyConsole_Console.cxx
-  PyConsole_Event.cxx
-  PyConsole_Interp.cxx
-  PyConsole_Request.cxx
-  PyConsole_Editor.cxx
-)
-
-# sources / to compile
-SET(PyConsole_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
-
-# --- rules ---
-
-ADD_LIBRARY(PyConsole ${PyConsole_SOURCES})
-TARGET_LINK_LIBRARIES(PyConsole ${_link_LIBRARIES})
-INSTALL(TARGETS PyConsole EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
-
-INSTALL(FILES ${PyConsole_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
-QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}")
diff --git a/src/PyConsole/PyConsole.h b/src/PyConsole/PyConsole.h
deleted file mode 100644 (file)
index 4c72bdf..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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   : 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
-#  if defined PYCONSOLE_EXPORTS || defined PyConsole_EXPORTS
-#    define PYCONSOLE_EXPORT __declspec(dllexport)
-#  else
-#    define PYCONSOLE_EXPORT __declspec(dllimport)
-#  endif
-#else   // WIN32
-#  define PYCONSOLE_EXPORT
-#endif  // WIN32
-
-// ========================================================
-// avoid warning messages
-#ifdef WIN32
-#pragma warning (disable : 4786)
-#pragma warning (disable : 4251)
-#endif
-
-#endif // PYCONSOLE_H
diff --git a/src/PyConsole/PyConsole_Console.cxx b/src/PyConsole/PyConsole_Console.cxx
deleted file mode 100644 (file)
index 3aaa52c..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-// 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   : PyConsole_Console.cxx
-// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
-
-#include "PyConsole_Console.h"
-#include "PyConsole_Interp.h"
-#include "PyConsole_Editor.h"
-
-#include <QAction>
-#include <QApplication>
-#include <QClipboard>
-#include <QContextMenuEvent>
-#include <QMenu>
-#include <QVBoxLayout>
-
-/*!
-  \class PyConsole_Console
-  \brief Python console widget.
-
-  To create a Python console, just use default contstructor, specifying only a parent widget:
-  \code
-  PyConsole_Console c(myWindow);
-  \endcode
-
-  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:
-  \code
-  PyConsole_Interp* interp = new PyConsole_Interp();
-  interp->initialize();
-  PyConsole_Console c(myWindow, new MyEditor(interp));
-  \endcode
-*/  
-
-/*!
-  \brief Constructor.
-
-  Creates new python console widget.
-  \param parent parent widget
-  \param interp python interpreter
-*/
-PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Editor* editor )
-: QWidget( parent )
-{
-  // initialize Python interpretator
-  PyConsole_Interp* interp = editor ? editor->getInterp() : new PyConsole_Interp();
-  interp->initialize();
-  
-  // create editor console
-  QVBoxLayout* lay = new QVBoxLayout( this );
-  lay->setMargin( 0 );
-  myEditor = editor ? editor : new PyConsole_Editor( interp, this );
-  myEditor->setContextMenuPolicy( Qt::NoContextMenu );
-  lay->addWidget( myEditor );
-
-  // force synchronous mode
-  QString synchronous = qgetenv( "PYTHON_CONSOLE_SYNC" );
-  if ( !synchronous.isEmpty() && synchronous.toInt() > 0 )
-    setIsSync( true );
-
-  // create actions
-  createActions();
-}
-
-/*!
-  \brief Destructor.
-*/
-PyConsole_Console::~PyConsole_Console()
-{
-}
-
-/*!
-  \brief Get Python interpreter
-  \return pointer to Python interpreter
-*/
-PyConsole_Interp* PyConsole_Console::getInterp() const
-{
-  return myEditor ? myEditor->getInterp() : 0;
-}
-
-/*!
-  \brief Execute python command in the interpreter.
-  \param command string with command and arguments
-*/
-void PyConsole_Console::exec( const QString& command )
-{
-  if ( myEditor )
-    myEditor->exec( command );
-}
-
-/*!
-  \brief Execute python command in the interpreter 
-         and wait until it is finished.
-  
-  Block execution of main application until the python command is executed.
-  \param command string with command and arguments
-*/
-void PyConsole_Console::execAndWait( const QString& command )
-{
-  if ( myEditor )
-    myEditor->execAndWait( command );
-}
-
-/*!
-  \brief Get synchronous mode flag value.
-  
-  \sa setIsSync()
-  \return \c true if python console works in synchronous mode
-*/
-bool PyConsole_Console::isSync() const
-{
-  return myEditor ? myEditor->isSync() : false;
-}
-
-/*!
-  \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 )
-{
-  if ( myEditor ) 
-    myEditor->setIsSync( on );
-}
-
-/*!
-  \brief Get suppress output flag value.
-  
-  \sa setIsSuppressOutput()
-  \return \c true if python console output is suppressed.
-*/
-bool PyConsole_Console::isSuppressOutput() const
-{
-  return myEditor ? myEditor->isSuppressOutput() : false;
-}
-
-/*!
-  \brief Set suppress output flag value.
-
-  In case if suppress output flag is \c true, the python 
-  console output suppressed.
-
-  \param on suppress output flag
-*/
-void PyConsole_Console::setIsSuppressOutput( const bool on )
-{
-  if ( myEditor )
-    myEditor->setIsSuppressOutput( on );
-}
-
-/*!
-  \brief Get 'show banner' flag value.
-  
-  \sa setIsShowBanner()
-  \return \c true if python console shows banner
-*/
-bool PyConsole_Console::isShowBanner() const
-{
-  return myEditor ? myEditor->isShowBanner() : false;
-}
-
-/*!
-  \brief Set 'show banner' flag value.
-
-  The banner is shown in the top of the python console window.
-
-  \sa isShowBanner()
-  \param on 'show banner' flag
-*/
-void PyConsole_Console::setIsShowBanner( const bool on )
-{
-  if ( myEditor )
-    myEditor->setIsShowBanner( on );
-}
-
-/*!
-  \brief Returns \c true if auto-completion feature is switched on
-  or \c false otherwise
-  \sa setAutoCompletion()
-*/
-bool PyConsole_Console::autoCompletion() const
-{
-  return myEditor ? myEditor->autoCompletion() : false;
-}
-
-/*!
-  \brief Switch on/off commands auto-completion feature
-  \sa autoCompletion()
-*/
-void PyConsole_Console::setAutoCompletion( const bool on )
-{
-  if ( myEditor )
-    myEditor->setAutoCompletion( on );
-}
-
-/*!
-  \brief Change the python console's font.
-  \param f new font
-*/
-void PyConsole_Console::setFont( const QFont& f )
-{
-  if ( myEditor )
-    myEditor->setFont( f );
-}
-
-/*!
-  \brief Get python console font.
-  \return current python console font
-*/
-QFont PyConsole_Console::font() const
-{
-  return myEditor ? myEditor->font() : QFont();
-}
-
-/*!
-  \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 )
-{
-  myActions[CopyId]->setVisible( flags & CopyId );
-  myActions[PasteId]->setVisible( flags & PasteId );
-  myActions[ClearId]->setVisible( flags & ClearId );
-  myActions[SelectAllId]->setVisible( flags & SelectAllId );
-  myActions[DumpCommandsId]->setVisible( flags & DumpCommandsId );
-  myActions[StartLogId]->setVisible( flags & StartLogId );
-  myActions[StopLogId]->setVisible( flags & StopLogId );
-}
-
-/*!
-  \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 );
-  ret = ret | ( myActions[DumpCommandsId]->isVisible() ? DumpCommandsId : 0 );
-  ret = ret | ( myActions[StartLogId]->isVisible() ? StartLogId : 0 );
-  ret = ret | ( myActions[StopLogId]->isVisible() ? StopLogId : 0 );
-  return ret;
-}
-
-/*!
-  \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 );
-
-  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 );
-  
-  a = new QAction( tr( "EDIT_DUMPCOMMANDS_CMD" ), this );
-  a->setStatusTip( tr( "EDIT_DUMPCOMMANDS_CMD" ) );
-  connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( dump() ) );
-  myActions.insert( DumpCommandsId, a );
-
-  a = new QAction( tr( "EDIT_STARTLOG_CMD" ), this );
-  a->setStatusTip( tr( "EDIT_STARTLOG_CMD" ) );
-  connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( startLog() ) );
-  myActions.insert( StartLogId, a );
-
-  a = new QAction( tr( "EDIT_STOPLOG_CMD" ), this );
-  a->setStatusTip( tr( "EDIT_STOPLOG_CMD" ) );
-  connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( stopLog() ) );
-  myActions.insert( StopLogId, a );
-}
-
-/*!
-  \brief Update menu actions.
-
-  Update context popup menu action state.
-*/
-void PyConsole_Console::updateActions()
-{
-  myActions[CopyId]->setEnabled( myEditor && myEditor->textCursor().hasSelection() );
-  myActions[PasteId]->setEnabled( myEditor && !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
-  myActions[SelectAllId]->setEnabled( myEditor && !myEditor->document()->isEmpty() );
-}
-
-/*!
-  \brief Start python trace logging
-  \param fileName the path to the log file
-*/
-void PyConsole_Console::startLog( const QString& fileName )
-{
-  if ( myEditor ) 
-    myEditor->startLog( fileName );
-}
-
-/*!
-  \brief Stop python trace logging
-*/
-void PyConsole_Console::stopLog()
-{
-  if ( myEditor ) 
-    myEditor->stopLog();
-}
-
-/*!
-  \brief Process context popup menu request
-
-  Show the context popup menu.
-
-  \param event context popup menu event
-*/
-void PyConsole_Console::contextMenuEvent( QContextMenuEvent* event )
-{
-  if ( !myEditor || myEditor->isReadOnly() )
-    return;
-
-  QMenu* menu = new QMenu( this );
-  menu->addAction( myActions[CopyId] );
-  menu->addAction( myActions[PasteId] );
-  menu->addAction( myActions[ClearId] );
-  menu->addSeparator();
-  menu->addAction( myActions[SelectAllId] );
-  menu->addSeparator();
-  menu->addAction( myActions[DumpCommandsId] );
-  if ( !myEditor->isLogging() )
-    menu->addAction( myActions[StartLogId] );
-  else
-    menu->addAction( myActions[StopLogId] );
-
-  updateActions();
-
-  menu->exec( event->globalPos());
-
-  delete menu;
-}
diff --git a/src/PyConsole/PyConsole_Console.h b/src/PyConsole/PyConsole_Console.h
deleted file mode 100644 (file)
index e0b111e..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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   : 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 <QWidget>
-#include <QMap>
-
-class QMenu;
-
-class PyConsole_Interp;
-class PyConsole_Editor;
-
-class PYCONSOLE_EXPORT PyConsole_Console : public QWidget
-{
-  Q_OBJECT
-
-public:
-  //! Context popup menu actions flags
-  enum
-  {
-    CopyId         = 0x01,  //!< "Copy" menu action
-    PasteId        = 0x02,  //!< "Paste" menu action
-    ClearId        = 0x04,  //!< "Clear" menu action
-    SelectAllId    = 0x08,  //!< "Select All" menu action
-    DumpCommandsId = 0x10,  //!< "DumpCommands" menu action
-    StartLogId     = 0x20,  //!< "Start log" menu action
-    StopLogId      = 0x40,  //!< "Stop log" menu action
-    All            = 0xFF,  //!< all menu actions 
-  };
-
-public:
-  PyConsole_Console( QWidget* parent, PyConsole_Editor* editor = 0 );
-  virtual ~PyConsole_Console();
-
-  PyConsole_Interp*   getInterp() const;
-
-  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:
-  void                createActions();
-  void                updateActions();
-
-  virtual void        contextMenuEvent( QContextMenuEvent* );
-
-protected:
-  PyConsole_Editor*   myEditor;    //!< python console editor widget
-  QMap<int, QAction*> myActions;   //!< menu actions list
-};
-
-#endif // PYCONSOLE_CONSOLE_H
diff --git a/src/PyConsole/PyConsole_Editor.cxx b/src/PyConsole/PyConsole_Editor.cxx
deleted file mode 100644 (file)
index 7d540f6..0000000
+++ /dev/null
@@ -1,1700 +0,0 @@
-// 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   : PyConsole_Editor.cxx
-// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
-
-/*!
-  \class PyConsole_Editor
-  \brief Python command line interpreter front-end GUI widget.
-  
-  This class provides simple GUI interface to the Python interpreter, including basic 
-  navigation operations, executing commands (both interactively and programmatically), 
-  copy-paste operations, history of the commands and so on.
-
-  Here below is the shortcut keyboard boundings used for navigation and other operations:
-  - <Enter>              : execute current command
-  - <Ctrl><Break>        : clear current command
-  - <Escape>             : clear current command
-  - <Up>                 : previous command in the history
-  - <Shift><Up>          : move cursor one row up with selection
-  - <Ctrl><Up>           : move cursor one row up without selection
-  - <Ctrl><Shift><Up>    : move cursor one row up with selection
-  - <Down>               : next command in the history
-  - <Shift><Down>        : move cursor one row down with selection
-  - <Ctrl><Down>         : move cursor one row down without selection
-  - <Ctrl><Shift><Down>  : move cursor one row down with selection
-  - <Left>               : move one symbol left without selection
-  - <Shift><Left>        : move one symbol left with selection
-  - <Ctrl><Left>         : move one word left without selection
-  - <Ctrl><Shift><Left>  : move one word left with selection
-  - <Right>              : move one symbol right without selection
-  - <Shift><Right>       : move one symbol right with selection
-  - <Ctrl><Right>        : move one word right without selection
-  - <Ctrl><Shift><Right> : move one word right with selection
-  - <PgUp>               : first command in the history
-  - <Shift><PgUp>        : move one page up with selection
-  - <Ctrl><PgUp>         : move one page up without selection
-  - <Ctrl><Shift><PgUp>  : scroll one page up
-  - <PgDn>               : last command in the history
-  - <Shift><PgDn>        : move one page down with selection
-  - <Ctrl><PgDn>         : move one page down without selection
-  - <Ctrl><Shift><PgDn>  : scroll one page down
-  - <Home>               : move to the beginning of the line without selection
-  - <Shift><Home>        : move to the beginning of the line with selection
-  - <Ctrl><Home>         : move to the very first symbol without selection
-  - <Ctrl><Shift><Home>  : move to the very first symbol with selection
-  - <End>                : move to the end of the line without selection
-  - <Shift><End>         : move to the end of the line with selection
-  - <Ctrl><End>          : move to the very last symbol without selection
-  - <Ctrl><Shift><End>   : move to the very last symbol with selection
-  - <Backspace>          : delete symbol before the cursor
-                           / remove selected text and put it to the clipboard (cut)
-  - <Shift><Backspace>   : delete previous word
-                           / remove selected text and put it to the clipboard (cut)
-  - <Ctrl><Backspace>    : delete text from the cursor to the beginning of the line 
-                           / remove selected text and put it to the clipboard (cut)
-  - <Delete>             : delete symbol after the cursor 
-                           / remove selected text and put it to the clipboard (cut)
-  - <Shift><Delete>      : delete next word
-                           / remove selected text and put it to the clipboard (cut)
-  - <Ctrl><Delete>       : delete text from the cursor to the end of the line
-                           / remove selected text and put it to the clipboard (cut)
-  - <Ctrl><Insert>       : copy
-  - <Shift><Insert>      : paste
-  - <Ctrl><V>            : paste
-  - <Ctrl><C>            : copy
-  - <Ctrl><X>            : cut
-  - <Ctrl><V>            : paste
-  - <Tab>                : performs auto-completion
-  - <Ctrl><Tab>          : undoes auto-completion
-*/
-
-#include "PyConsole_Editor.h"
-#include "PyConsole_Interp.h"
-#include "PyConsole_Event.h"
-#include "PyInterp_Dispatcher.h"
-#include "PyConsole_Request.h"
-
-#include <QApplication>
-#include <QClipboard>
-#include <QDropEvent>
-#include <QEvent>
-#include <QKeyEvent>
-#include <QMimeData>
-#include <QMouseEvent>
-#include <QScrollBar>
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QTextStream>
-#include <QChar>
-#include <QFileDialog>
-#include <QMessageBox>
-
-//VSR: uncomment below macro to support unicode text properly in SALOME
-//     current commented out due to regressions
-//#define PAL22528_UNICODE
-
-namespace
-{
-  QString fromUtf8( const char* txt )
-  {
-#ifdef PAL22528_UNICODE
-    return QString::fromUtf8( txt );
-#else
-    return QString( txt );
-#endif
-  }
-}
-
-static QString READY_PROMPT = ">>> ";
-static QString DOTS_PROMPT  = "... ";
-
-void staticCallbackStdout( void* data, char* c )
-{
-  if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
-    PyConsole_Editor* e = (PyConsole_Editor*)data;
-    QApplication::postEvent( e, new PyConsole_PrintEvent( fromUtf8(c), false ) );
-  }
-}
-
-void staticCallbackStderr( void* data, char* c )
-{
-  if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
-    PyConsole_Editor* e = (PyConsole_Editor*)data;
-    QApplication::postEvent( e, new PyConsole_PrintEvent( fromUtf8(c), true ) );
-  }
-}
-
-/*!
-  \brief 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 )
-{
-  setFont( QFont( "Courier", 11 ) ); // default font
-  setUndoRedoEnabled( false );
-
-  myPrompt = READY_PROMPT;
-  setLineWrapMode( QTextEdit::WidgetWidth );
-  setWordWrapMode( QTextOption::WrapAnywhere );
-  setAcceptRichText( false );
-
-  // set callbacks to interpeter
-  myInterp->setvoutcb( staticCallbackStdout, this );
-  myInterp->setverrcb( staticCallbackStderr, this );
-  // print banner
-  if ( isShowBanner() )
-    addText( banner() );
-  // clear command buffer
-  myCommandBuffer.truncate(0);
-  // unset read-only state
-  setReadOnly( false );
-  // unset history browsing mode
-  myCmdInHistory = -1;
-  // add prompt
-  addText( myPrompt );
-  // unset busy cursor
-  viewport()->unsetCursor();
-}
-
-/*!
-  \brief Destructor.
-*/
-PyConsole_Editor::~PyConsole_Editor()
-{
-  myInterp = 0;
-}
-
-/*!
-  \brief Get Python interpreter
-*/
-PyConsole_Interp* PyConsole_Editor::getInterp() const
-{
-  return myInterp;
-}
-
-/*!
-  \brief Get synchronous mode flag value.
-  
-  \sa setIsSync()
-  \return \c true if python console works in synchronous mode
-*/
-bool PyConsole_Editor::isSync() const
-{
-  return myIsSync;
-}
-
-/*!
-  \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 = on;
-}
-
-/*!
-  \brief Get suppress output flag value.
-  
-  \sa setIsSuppressOutput()
-  \return \c true if python console output is suppressed.
-*/
-bool PyConsole_Editor::isSuppressOutput() const
-{
-  return myIsSuppressOutput;
-}
-
-/*!
-  \brief Set suppress output flag value.
-
-  In case if suppress output flag is \c true, the python 
-  console output suppressed.
-
-  \param on suppress output flag
-*/
-void PyConsole_Editor::setIsSuppressOutput( const bool on )
-{
-  myIsSuppressOutput = on;
-}
-
-/*!
-  \brief Get 'show banner' flag value.
-  
-  \sa setIsShowBanner()
-  \return \c true if python console shows banner
-*/
-bool PyConsole_Editor::isShowBanner() const
-{
-  return myShowBanner;
-}
-
-/*!
-  \brief Set 'show banner' flag value.
-
-  The banner is shown in the top of the python console window.
-
-  \sa isShowBanner()
-  \param on 'show banner' flag
-*/
-void PyConsole_Editor::setIsShowBanner( const bool on )
-{
-  if ( myShowBanner != on ) {
-    myShowBanner = on;
-    clear();
-  }
-}
-
-/*!
-  \brief Switch on/off commands auto-completion feature
-  \sa autoCompletion()
-*/
-void PyConsole_Editor::setAutoCompletion( bool on )
-{
-  myAutoCompletion = on;
-  document()->setUndoRedoEnabled( myAutoCompletion );
-}
-  
-/*!
-  \brief Returns \c true if auto-completion feature is switched on
-  or \c false otherwise
-  \sa setAutoCompletion()
-*/
-bool PyConsole_Editor::autoCompletion() const
-{
-  return myAutoCompletion;
-}
-
-/*!
-  \brief Check if trace logging is switched on.
-  
-  \sa startLog(), stopLog()
-  \return \c true if trace logging is switched on
-*/
-bool PyConsole_Editor::isLogging() const
-{
-  return !myLogFile.isEmpty();
-}
-
-/*!
-  \brief Get size hint for the Python console window
-  \return size hint value
-*/
-QSize PyConsole_Editor::sizeHint() const
-{
-  QFontMetrics fm( font() );
-  int nbLines = ( isShowBanner() ? banner().split("\n").count() : 0 ) + 1;
-  QSize s(100, fm.lineSpacing()*nbLines);
-  return s;
-}
-
-/*!
-  \brief Put the string \a str to the python editor.
-  \param str string to be put in the command line of the editor
-  \param newBlock if \c true, then the string is printed on a new line
-  \param isError if \c true, the text is printed in dark red
-*/
-void PyConsole_Editor::addText( const QString& str, 
-                                const bool     newBlock,
-                                const bool     isError )
-{
-  QTextCursor aCursor = textCursor();
-  QTextCharFormat cf;
-
-  moveCursor( QTextCursor::End );
-  if ( newBlock )
-    aCursor.insertBlock();
-  if ( isError )
-    cf.setForeground( QBrush( Qt::red ) );
-  else
-    cf.setForeground( QBrush( Qt::black ) );
-  aCursor.insertText( str, cf );
-  moveCursor( QTextCursor::End );
-  ensureCursorVisible();
-}
-
-/*!
-  \brief Convenient method for executing a Python command,
-  as if the user typed it manually.
-  \param command python command to be executed
-
-  !!! WARNING: doesn't work properly with multi-line commands. !!!
-*/
-void PyConsole_Editor::exec( const QString& command )
-{
-  if ( isReadOnly() ) {
-    // some interactive command is being executed in this editor...
-    // shedule the command to the queue
-    myQueue.push_back( command );
-    return;
-  }
-
-  // remove last line
-  moveCursor( QTextCursor::End );
-  moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
-  textCursor().removeSelectedText();
-
-  // set "ready" prompt
-  myPrompt = READY_PROMPT;
-
-  // clear command buffer
-  myCommandBuffer.truncate( 0 );
-
-  // unset history browsing mode
-  myCmdInHistory = -1;
-
-  // print command line by line
-  QString cmd = command;
-  if ( !cmd.endsWith( "\n" ) ) cmd += "\n";
-  QStringList lines = command.split( "\n" );
-  for ( int i = 0; i < lines.size(); i++ ) {
-    if ( !lines[i].trimmed().isEmpty() )
-      myHistory.push_back( lines[i] );
-    addText( ( i == 0 ? READY_PROMPT : DOTS_PROMPT ) + lines[i], i != 0 );
-    putLog( QString( "%1%2\n" ).arg( i == 0 ? READY_PROMPT : DOTS_PROMPT ).arg( lines[i] ) );
-  }
-
-  // IPAL20182
-  addText( "", true );
-
-  // set read-only mode
-  setReadOnly( true );
-
-  // set busy cursor
-  setCursor( Qt::BusyCursor );
-  
-  // post a request to execute Python command;
-  // editor will be informed via a custom event that execution has been completed
-  PyInterp_Dispatcher::Get()->Exec( createCmdRequest( cmd ) );
-}
-
-/*!
-  \brief Create request to the python dispatcher for the command execution.
-  \param command python command to be executed
- */
-PyInterp_Request* PyConsole_Editor::createCmdRequest( const QString& command )
-{
-  return new PyConsole_ExecCommand( myInterp, command, this, isSync() );
-}
-
-/*!
-  \brief Create the Python request that will be posted to the interpreter to
-  get the completions.
-  \param input line entered by the user at the time <TAB> was pressed
-  \return completion command
-  \sa CompletionCommand
-*/
-PyInterp_Request* PyConsole_Editor::createTabRequest( const QString& input )
-{
-  // valid separators
-  static QStringList separators;
-  if ( separators.isEmpty() ) {
-    separators << " " << "(" << "[" << "+" << "-" << "*" << "/" << ";" << "^" << "=";
-  }
-
-  // parse input to extract on what part the dir() has to be executed
-
-  QString input2( input );
-
-  // split up to the last syntaxical separator
-  int lastSp = -1;
-  foreach ( QString separator, separators ) {
-    int j = input2.lastIndexOf( separator );
-    if ( j > lastSp )
-      lastSp = j;
-  }
-  if ( lastSp >= 0 )
-    input2 = input.mid( lastSp + 1 );
-
-  // detect a qualified name (with a point)
-  int lastPt = input2.lastIndexOf( "." );
-
-  if ( lastPt != -1 ) {
-    // split the 2 surrounding parts of the qualified name
-    myComplBeforePoint = input2.left( lastPt );
-    myComplAfterPoint = input2.mid( lastPt+1 );
-  }
-  else {
-    // no point found - do a global matching
-    // (the following will call dir() with an empty string)
-    myComplAfterPoint = input2;
-    myComplBeforePoint = "";
-  }
-
-  return new PyConsole_CompletionCommand( myInterp, myComplBeforePoint,
-                                          myComplAfterPoint, 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 )
-{
-  // already running ?
-  if ( myEventLoop )
-    return;
-
-  // create new event loop
-  bool sync = isSync();
-  if ( !sync ) {
-    myEventLoop = new QEventLoop( this );
-  }
-
-  // execute command
-  exec( command );
-
-  if ( !sync ) {
-    // run event loop
-    myEventLoop->exec();
-    // delete event loop after command is processed
-    delete myEventLoop;
-    myEventLoop = 0;
-  }
-}
-
-/*!
-  \brief Process <Enter> key press event. 
-  
-  Execute the command entered by the user.
-*/
-void PyConsole_Editor::handleReturn()
-{
-  // Position cursor at the end
-  QTextCursor aCursor = textCursor();
-  aCursor.movePosition( QTextCursor::End );
-  setTextCursor( aCursor );
-
-  // get last line
-  QTextBlock par = document()->end().previous();
-  if ( !par.isValid() ) return;
-
-  // get command
-  QString cmd = par.text().remove( 0, promptSize() );
-
-  // extend the command buffer with the current command 
-  myCommandBuffer.append( cmd );
-
-  // add command to the history
-  if ( !cmd.trimmed().isEmpty() )
-    myHistory.push_back( cmd );
-  putLog( QString( "%1%2\n" ).arg( myPrompt ).arg( cmd ) );
-
-  // IPAL19397
-  addText( "", true ); 
-  
-  // set read-only mode
-  setReadOnly( true );
-
-  // set busy cursor
-  setCursor( Qt::BusyCursor );
-  
-  // post a request to execute Python command;
-  // editor will be informed via a custom event that execution has been completed
-  PyInterp_Dispatcher::Get()->Exec( createCmdRequest( myCommandBuffer ) );
-}
-
-/*!
-  \brief Process <Tab> key press event. 
-  
-  Perform auto-completion of the currently entered command, if this feature is enabled
-*/
-void PyConsole_Editor::handleTab()
-{
-  if ( !autoCompletion() )
-    return; // auto-completion feature is disabled
-
-  if ( myTabMode )
-    return; // already in tab mode
-
-  QTextCursor aCursor = textCursor();
-
-  // move cursor to the end of input
-  aCursor.movePosition( QTextCursor::End );
-  setTextCursor( aCursor );
-
-  // save cursor position if needed
-  if ( myComplCursorPos == -1 )
-    myComplCursorPos = textCursor().position();
-
-  // get last line
-  QTextBlock par = document()->end().previous();
-  if ( !par.isValid() ) return; // empty line
-
-  // switch to completion mode
-  myTabMode = true;
-
-  // get currently entered command
-  QString cmd = par.text().mid( promptSize() );
-
-  // post completion request
-  // editor will be informed that completion has been done via a custom event 
-  PyInterp_Dispatcher::Get()->Exec( createTabRequest( cmd ) );
-}
-
-/*!
-  \brief Process <Ctrl><Tab> key press event. 
-  
-  Undoe last auto-completion
-*/
-void PyConsole_Editor::handleBackTab()
-{
-  if ( !autoCompletion() )
-    return; // auto-completion feature is disabled
-
-  QTextCursor aCursor = textCursor();
-
-  if ( myComplCursorPos == -1 )
-    return; // invalid cursor position
-
-  // ensure cursor is at the end of command line
-  aCursor.setPosition( myComplCursorPos );
-  aCursor.movePosition( QTextCursor::EndOfLine );
-  //setCursor( aCursor );
-
-  // delete last completed text
-  int i = aCursor.position() - myComplCursorPos;
-  aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, i );
-  aCursor.removeSelectedText();
-  myComplCursorPos = -1;
-}
-
-/*!
-  \brief Process drop event.
-
-  Paste dragged text.
-  \param event drop event
-*/
-void PyConsole_Editor::dropEvent( QDropEvent* event )
-{
-  // get the initial drop position
-  QPoint pos = event->pos();
-  QTextCursor aCursor = cursorForPosition( event->pos() );
-
-  // if the position is not in the last line move it to the end of the command line
-  if ( aCursor.position() < document()->end().previous().position() + promptSize() ) {
-    moveCursor( QTextCursor::End );
-    pos = cursorRect().center();
-  }
-
-  // create new drop event and use it instead of the original
-  QDropEvent de( pos,
-                 event->possibleActions(),
-                 event->mimeData(),
-                 event->mouseButtons(),
-                 event->keyboardModifiers(),
-                 event->type() );
-  QTextEdit::dropEvent( &de );
-
-  // accept the original event
-  event->acceptProposedAction();
-}
-
-/*!
-  \brief Process mouse press event
-
-  Clear the completion when any mouse button is pressed.
-
-  \param e mouse press event
-*/
-void PyConsole_Editor::mousePressEvent( QMouseEvent* event )
-{
-  if ( autoCompletion() ) {
-    clearCompletion();
-    myComplCursorPos = -1;
-  }
-  QTextEdit::mousePressEvent( event );
-}
-
-/*!
-  \brief Process mouse button release event.
-
-  Left mouse button: copy selection to the clipboard.
-  Middle mouse button: paste clipboard's contents.
-
-  \param event mouse event
-*/
-void PyConsole_Editor::mouseReleaseEvent( QMouseEvent* event )
-{
-  if ( event->button() == Qt::LeftButton ) {
-    QTextEdit::mouseReleaseEvent( event );
-  }
-  else if ( event->button() == Qt::MidButton ) {
-    QTextCursor aCursor = cursorForPosition( event->pos() );
-    // if the position is not in the last line move it to the end of the command line
-    if ( aCursor.position() < document()->end().previous().position() + promptSize() ) {
-      moveCursor( QTextCursor::End );
-    }
-    else {
-      setTextCursor( aCursor );
-    }
-    const QMimeData* md = QApplication::clipboard()->mimeData( QApplication::clipboard()->supportsSelection() ? 
-                                                              QClipboard::Selection : QClipboard::Clipboard );
-    if ( md )
-      insertFromMimeData( md );
-  }
-  else {
-    QTextEdit::mouseReleaseEvent( event );
-  }
-}
-
-/*!
-  \brief Check if the string is command.
-  
-  Return \c true if the string \a str is likely to be the command
-  (i.e. it is started from the '>>>' or '...').
-  \param str string to be checked
-*/
-bool PyConsole_Editor::isCommand( const QString& str ) const
-{
-  return str.startsWith( READY_PROMPT ) || str.startsWith( DOTS_PROMPT );
-}
-
-/*!
-  \brief Handle keyboard event.
-
-  Implement navigation, history browsing, copy/paste and other common
-  operations.
-
-  \param event keyboard event
-*/
-void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
-{
-  // get cursor position
-  QTextCursor aCursor = textCursor();
-  int curLine = aCursor.blockNumber();
-  int curCol  = aCursor.columnNumber();
-
-  // get last edited line
-  int endLine = document()->blockCount()-1;
-
-  // get pressed key code
-  int aKey = event->key();
-
-  // check if <Ctrl> is pressed
-  bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
-  // check if <Shift> is pressed
-  bool shftPressed = event->modifiers() & Qt::ShiftModifier;
-
-  if ( autoCompletion() ) {
-    // auto-completion support
-    if ( aKey == Qt::Key_Tab && !shftPressed ) {
-      // process <Tab> key
-      if ( !ctrlPressed ) {
-        handleTab();
-      }
-      else {
-        clearCompletion();
-        handleBackTab();
-      }
-      return;
-    }
-
-    // If <Ctrl> is not pressed (or if something else is pressed with <Ctrl>),
-    // or if <Ctrl> is not pressed alone, we have to clear completion
-    if ( !ctrlPressed || ( ctrlPressed && aKey != Qt::Key_Control ) ) {
-      clearCompletion();
-      myComplCursorPos = -1;
-    }
-    
-    // Discard <Ctrl> pressed alone:
-    if ( aKey == Qt::Key_Control )
-      return;
-  }
-
-  if ( aKey == Qt::Key_Escape || ( ctrlPressed && aKey == -1 ) ) {
-    // process <Ctrl>+<Break> key-binding and <Escape> key: clear current command
-    myCommandBuffer.truncate( 0 );
-    myPrompt = READY_PROMPT;
-    addText( myPrompt, true );
-    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-    return;
-  }
-  else if ( ctrlPressed && aKey == Qt::Key_C ) {
-    // process <Ctrl>+<C> key-binding : copy
-    copy();
-    return;
-  }
-  else if ( ctrlPressed && aKey == Qt::Key_X ) {
-    // process <Ctrl>+<X> key-binding : cut
-    cut();
-    return;
-  }
-  else if ( ctrlPressed && aKey == Qt::Key_V ) {
-    // process <Ctrl>+<V> key-binding : paste
-    paste();
-    return;
-  }
-
-  // check for printed key
-  // #### aKey = ( aKey < Qt::Key_Space || aKey > Qt::Key_ydiaeresis ) ? aKey : 0;
-  // Better:
-  aKey = !(QChar(aKey).isPrint()) ? aKey : 0;
-
-  switch ( aKey ) {
-  case 0 :
-    // any printed key: just print it
-    {
-      if ( curLine < endLine || curCol < promptSize() ) {
-        moveCursor( QTextCursor::End );
-      }
-      QTextEdit::keyPressEvent( event );
-      break;
-    }
-  case Qt::Key_Return:
-  case Qt::Key_Enter:
-    // <Enter> key: process the current command
-    {
-      handleReturn();
-      break;
-    }
-  case Qt::Key_Up:
-    // <Up> arrow key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: previous command in history
-    // - with <Ctrl> modifier key pressed:  move cursor one row up without selection
-    // - with <Shift> modifier key pressed: move cursor one row up with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row up
-    {
-      if ( ctrlPressed && shftPressed ) {
-        int value   = verticalScrollBar()->value();
-        int spacing = fontMetrics().lineSpacing();
-        verticalScrollBar()->setValue( value > spacing ? value-spacing : 0 );
-      }
-      else if ( shftPressed || ctrlPressed ) {
-        if ( curLine > 0 )
-          moveCursor( QTextCursor::Up, 
-                      shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
-      }
-      else { 
-        if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
-          // set history browsing mode
-          myCmdInHistory = myHistory.count();
-          // remember current command
-          QTextBlock par = document()->end().previous();
-          myCurrentCommand = par.text().remove( 0, promptSize() );
-        }
-        if ( myCmdInHistory > 0 ) {
-          myCmdInHistory--;
-          // get previous command in the history
-          QString previousCommand = myHistory.at( myCmdInHistory );
-          // print previous command
-          moveCursor( QTextCursor::End );
-          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-          addText( myPrompt + previousCommand ); 
-          // move cursor to the end
-          moveCursor( QTextCursor::End );
-        }
-      }
-      break;
-    }
-  case Qt::Key_Down:
-    // <Down> arrow key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: next command in history
-    // - with <Ctrl> modifier key pressed:  move cursor one row down without selection
-    // - with <Shift> modifier key pressed: move cursor one row down with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row down
-    {
-      if ( ctrlPressed && shftPressed ) {
-        int value   = verticalScrollBar()->value();
-        int maxval  = verticalScrollBar()->maximum();
-        int spacing = fontMetrics().lineSpacing();
-        verticalScrollBar()->setValue( value+spacing < maxval ? value+spacing : maxval );
-      }
-      else if ( shftPressed || ctrlPressed) {
-        if ( curLine < endLine )
-          moveCursor( QTextCursor::Down, 
-                      shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
-      }
-      else { 
-        if ( myCmdInHistory >= 0 ) {
-          // get next command in the history
-          myCmdInHistory++;
-          QString nextCommand;
-          if ( myCmdInHistory < myHistory.count() ) {
-            // next command in history
-            nextCommand = myHistory.at( myCmdInHistory );
-          }
-          else {
-            // end of history is reached
-            // last printed command
-            nextCommand = myCurrentCommand;
-            // unset history browsing mode
-            myCmdInHistory = -1;
-          }
-          // print next or current command
-          moveCursor( QTextCursor::End );
-          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-          addText( myPrompt + nextCommand );
-          // move cursor to the end
-          moveCursor( QTextCursor::End );
-        }
-      }
-      break;
-    }
-  case Qt::Key_Left:
-    // <Left> arrow key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: move one symbol left (taking into account prompt)
-    // - with <Ctrl> modifier key pressed:  move one word left (taking into account prompt)
-    // - with <Shift> modifier key pressed: move one symbol left with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: move one word left with selection
-    {
-      QString txt = textCursor().block().text();
-      if ( !shftPressed && isCommand( txt ) && curCol <= promptSize() ) {
-        moveCursor( QTextCursor::Up );
-        moveCursor( QTextCursor::EndOfBlock );
-      }
-      else {
-        QTextEdit::keyPressEvent( event );
-      }
-      break;
-    }
-  case Qt::Key_Right:
-    // <Right> arrow key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: move one symbol right (taking into account prompt)
-    // - with <Ctrl> modifier key pressed:  move one word right (taking into account prompt)
-    // - with <Shift> modifier key pressed: move one symbol right with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: move one word right with selection
-    {
-      QString txt = textCursor().block().text();
-      if ( !shftPressed ) {
-        if ( curCol < txt.length() ) {
-          if ( isCommand( txt ) && curCol < promptSize() ) {
-            aCursor.setPosition( aCursor.block().position() + promptSize() );
-            setTextCursor( aCursor );
-            break;
-          }
-        }
-        else {
-          if ( curLine < endLine && isCommand( textCursor().block().next().text() ) ) {
-            aCursor.setPosition( aCursor.position() + promptSize()+1 );
-            setTextCursor( aCursor );
-            horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-            break;
-          }
-        }
-      }
-      QTextEdit::keyPressEvent( event );
-      break;
-    }
-  case Qt::Key_PageUp:
-    // <PageUp> key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: first command in history
-    // - with <Ctrl> modifier key pressed:  move cursor one page up without selection
-    // - with <Shift> modifier key pressed: move cursor one page up with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page up
-    {
-      if ( ctrlPressed && shftPressed ) {
-        verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub);
-      }
-      else if ( shftPressed || ctrlPressed ) {
-        bool moved = false;
-        qreal lastY = cursorRect( aCursor ).top();
-        qreal distance = 0;
-        // move using movePosition to keep the cursor's x
-        do {
-          qreal y = cursorRect( aCursor ).top();
-          distance += qAbs( y - lastY );
-          lastY = y;
-          moved = aCursor.movePosition( QTextCursor::Up, 
-                                        shftPressed ? QTextCursor::KeepAnchor : 
-                                        QTextCursor::MoveAnchor );
-        } while ( moved && distance < viewport()->height() );
-        if ( moved ) {
-          aCursor.movePosition( QTextCursor::Down, 
-                                shftPressed ? QTextCursor::KeepAnchor : 
-                                QTextCursor::MoveAnchor );
-          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
-        }
-        setTextCursor( aCursor );
-      }
-      else { 
-        if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
-          // set history browsing mode
-          myCmdInHistory = myHistory.count();
-          // remember current command
-          QTextBlock par = document()->end().previous();
-          myCurrentCommand = par.text().remove( 0, promptSize() );
-        }
-        if ( myCmdInHistory > 0 ) {
-          myCmdInHistory = 0;
-          // get very first command in the history
-          QString firstCommand = myHistory.at( myCmdInHistory );
-          // print first command
-          moveCursor( QTextCursor::End );
-          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-          addText( myPrompt + firstCommand ); 
-          // move cursor to the end
-          moveCursor( QTextCursor::End );
-        }
-      }
-      break;
-    }
-  case Qt::Key_PageDown:
-    // <PageDown> key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: last command in history
-    // - with <Ctrl> modifier key pressed:  move cursor one page down without selection
-    // - with <Shift> modifier key pressed: move cursor one page down with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page down
-    {
-      if ( ctrlPressed && shftPressed ) {
-        verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd);
-      }
-      else if ( shftPressed || ctrlPressed ) {
-        bool moved = false;
-        qreal lastY = cursorRect( aCursor ).top();
-        qreal distance = 0;
-        // move using movePosition to keep the cursor's x
-        do {
-          qreal y = cursorRect( aCursor ).top();
-          distance += qAbs( y - lastY );
-          lastY = y;
-          moved = aCursor.movePosition( QTextCursor::Down, 
-                                        shftPressed ? QTextCursor::KeepAnchor : 
-                                        QTextCursor::MoveAnchor );
-        } while ( moved && distance < viewport()->height() );
-        if ( moved ) {
-          aCursor.movePosition( QTextCursor::Up, 
-                                shftPressed ? QTextCursor::KeepAnchor : 
-                                QTextCursor::MoveAnchor );
-          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
-        }
-        setTextCursor( aCursor );
-      }
-      else { 
-        if ( myCmdInHistory >= 0 ) {
-          // unset history browsing mode
-          myCmdInHistory = -1;
-          // print current command
-          moveCursor( QTextCursor::End );
-          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-          addText( myPrompt + myCurrentCommand ); 
-          // move cursor to the end
-          moveCursor( QTextCursor::End );
-        }
-      }
-      break;
-    }
-  case Qt::Key_Home: 
-    // <Home> key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: move cursor to the beginning of the current line without selection
-    // - with <Ctrl> modifier key pressed:  move cursor to the very first symbol without selection
-    // - with <Shift> modifier key pressed: move cursor to the beginning of the current line with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very first symbol with selection
-    {
-      if ( ctrlPressed ) { 
-        moveCursor( QTextCursor::Start, 
-                    shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
-      }
-      else {
-        QString txt = textCursor().block().text();
-        if ( isCommand( txt ) ) {
-          if ( shftPressed ) {
-            if ( curCol > promptSize() ) {
-              aCursor.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
-              aCursor.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
-            }
-          }
-          else {
-            aCursor.movePosition( QTextCursor::StartOfLine );
-            aCursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
-          }
-          setTextCursor( aCursor );
-        }
-        else {
-          moveCursor( QTextCursor::StartOfBlock, 
-                      shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
-        }
-        horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-      }
-      break;
-    }
-  case Qt::Key_End:
-    // <End> key: process as follows:
-    // - without <Ctrl>, <Shift> modifiers: move cursor to the end of the current line without selection
-    // - with <Ctrl> modifier key pressed:  move cursor to the very last symbol without selection
-    // - with <Shift> modifier key pressed: move cursor to the end of the current line with selection
-    // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very last symbol with selection
-    {
-      moveCursor( ctrlPressed ? QTextCursor::End : QTextCursor::EndOfBlock, 
-                  shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
-      break;
-    }  
-  case Qt::Key_Backspace :
-    // <Backspace> key: process as follows
-    // - without any modifiers : delete symbol before the cursor / selection (taking into account prompt)
-    // - with <Shift> modifier key pressed: delete previous word
-    // - with <Ctrl> modifier key pressed: delete text from the cursor to the line beginning
-    // works only for last (command) line
-    {
-      if ( aCursor.hasSelection() ) {
-        cut();
-      }
-      else if ( aCursor.position() > document()->end().previous().position() + promptSize() ) {
-        if ( shftPressed ) {
-          moveCursor( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-        }
-        else if ( ctrlPressed ) {
-          aCursor.setPosition( document()->end().previous().position() + promptSize(),
-                               QTextCursor::KeepAnchor );
-          setTextCursor( aCursor );
-          textCursor().removeSelectedText();
-        }
-        else {
-          QTextEdit::keyPressEvent( event );
-        }
-      }
-      else {
-        aCursor.setPosition( document()->end().previous().position() + promptSize() );
-        setTextCursor( aCursor );
-        horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-      }
-      break;
-    }
-  case Qt::Key_Delete :
-    // <Delete> key: process as follows
-    // - without any modifiers : delete symbol after the cursor / selection (taking into account prompt)
-    // - with <Shift> modifier key pressed: delete next word
-    // - with <Ctrl> modifier key pressed: delete text from the cursor to the end of line
-    // works only for last (command) line
-    {
-      if ( aCursor.hasSelection() ) {
-        cut();
-      }
-      else if ( aCursor.position() > document()->end().previous().position() + promptSize()-1 ) {
-        if ( shftPressed ) {
-          moveCursor( QTextCursor::NextWord, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-        }
-        else if ( ctrlPressed ) {
-          moveCursor( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-        }
-        else {
-          QTextEdit::keyPressEvent( event );
-        }
-      }
-      else {
-        aCursor.setPosition( document()->end().previous().position() + promptSize() );
-        setTextCursor( aCursor );
-        horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-      }
-      break;
-    }
-  case Qt::Key_Insert :
-    // <Insert> key: process as follows
-    // - with <Ctrl> modifier key pressed:  copy()
-    // - with <Shift> modifier key pressed: paste() to the command line
-    {
-      if ( ctrlPressed ) {
-        copy();
-      }
-      else if ( shftPressed ) {
-        paste();
-      }
-      else
-        QTextEdit::keyPressEvent( event );
-      break;
-    }
-  default:
-    break;
-  }
-}
-
-/*!
-  \brief Handle notification event coming from Python dispatcher.
-  \param event notification event
-*/
-void PyConsole_Editor::customEvent( QEvent* event )
-{
-  switch( event->type() )
-  {
-  case PyConsole_PrintEvent::EVENT_ID:
-  {
-    PyConsole_PrintEvent* pe = (PyConsole_PrintEvent*)event;
-    putLog( pe->text());
-    addText( pe->text(), false, pe->isError() );
-    return;
-  }
-  case PyConsole_CompletionEvent::EVENT_ID:
-  {
-    PyConsole_CompletionEvent* ce = (PyConsole_CompletionEvent*)event;
-    bool status = ce->status();
-    QStringList matches = ce->matches();
-    QString doc = ce->doc();
-
-    if ( status ) {
-      // completion was successful
-      QTextCursor aCursor = textCursor();
-
-      if ( matches.isEmpty() ) {
-       // completion successful but there are no matches.
-        myTabMode = false;
-        myComplCursorPos = -1;
-        return;
-      }
-      
-      if ( matches.size() == 1 ) {
-        // there's only one match - complete directly and update doc string window
-        aCursor.insertText( matches[0].mid( myComplAfterPoint.size() ) );
-        myTabMode = false;
-        if ( doc.isEmpty() )
-          emit updateDoc( formatDocHTML( QString( "(%1)\n" ).arg( tr( "NO_DOC_AVAILABLE" ) ) ) );
-        else
-          emit updateDoc( formatDocHTML( doc ) );
-      }
-      else {
-        // there are several matches
-        
-        // detect if there is a common base to all available completion
-        // in this case append this base to the text
-        QString base = extractCommon( matches );
-        aCursor.insertText( base.mid( myComplAfterPoint.size() ) );
-        
-        // if this happens to match exactly the first completion
-        // also provide doc
-        if ( base == matches[0] )
-          emit updateDoc( formatDocHTML( doc ) );
-        
-        // print all matching completion in a "undo-able" block
-        int cursorPos = aCursor.position();
-        aCursor.insertBlock();
-        aCursor.beginEditBlock();
-        
-        // insert all matches
-        QTextCharFormat cf;
-        cf.setForeground( QBrush( Qt::darkGreen ) );
-        aCursor.setCharFormat( cf );
-        aCursor.insertText( formatCompletion( matches ) );
-        aCursor.endEditBlock();
-        
-        // position cursor where it was before inserting the completion list
-        aCursor.setPosition( cursorPos );
-        setTextCursor( aCursor );
-      }
-    }
-    else {
-      // completion failed
-      myTabMode = false;
-      myComplCursorPos = -1;
-    }
-    return;
-  }
-  case PyInterp_Event::ES_OK:
-  case PyInterp_Event::ES_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 );
-    // unset busy cursor
-    unsetCursor();
-    // stop event loop (if running)
-    if ( myEventLoop )
-      myEventLoop->exit();
-    // if we are in multi_paste_mode, process the next item
-    multiLineProcessNextLine();
-    break;
-  }
-  case PyInterp_Event::ES_INCOMPLETE:
-  {
-    // 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*/ ); // IPAL19397
-    // unset busy cursor
-    unsetCursor();
-    // stop event loop (if running)
-    if ( myEventLoop )
-      myEventLoop->exit();
-    // if we are in multi_paste_mode, process the next item
-    multiLineProcessNextLine();
-    break;
-  }
-  default:
-    QTextEdit::customEvent( event );
-  }
-  
-  // unset read-only state
-  setReadOnly( false );
-  // unset history browsing mode
-  myCmdInHistory = -1;
-
-  if ( (int)event->type() == (int)PyInterp_Event::ES_OK && myQueue.count() > 0 )
-  {
-    // process the next sheduled command from the queue (if there is any)
-    QString nextcmd = myQueue[0];
-    myQueue.pop_front();
-    exec( nextcmd );
-  }
-}
-
-/*!
-  \brief "Copy" operation.
-  
-  Reimplemented from Qt.
-  Warning! In Qt this method is not virtual.
-*/
-void PyConsole_Editor::cut()
-{
-  QTextCursor aCursor = textCursor();
-  if ( aCursor.hasSelection() ) {
-    QApplication::clipboard()->setText( aCursor.selectedText() );
-    int startSelection = aCursor.selectionStart();
-    if ( startSelection < document()->end().previous().position() + promptSize() )
-      startSelection = document()->end().previous().position() + promptSize();
-    int endSelection = aCursor.selectionEnd();
-    if ( endSelection < document()->end().previous().position() + promptSize() )
-      endSelection = document()->end().previous().position() + promptSize();
-    aCursor.setPosition( startSelection );
-    aCursor.setPosition( endSelection, QTextCursor::KeepAnchor );
-    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-    setTextCursor( aCursor );
-    textCursor().removeSelectedText();
-  }
-}
-
-/*!
-  \brief "Paste" operation.
-
-  Reimplemented from Qt.
-  Warning! In Qt this method is not virtual.
-*/
-void PyConsole_Editor::paste()
-{
-  QTextCursor aCursor = textCursor();
-  if ( aCursor.hasSelection() ) {
-    int startSelection = aCursor.selectionStart();
-    if ( startSelection < document()->end().previous().position() + promptSize() )
-      startSelection = document()->end().previous().position() + promptSize();
-    int endSelection = aCursor.selectionEnd();
-    if ( endSelection < document()->end().previous().position() + promptSize() )
-      endSelection = document()->end().previous().position() + promptSize();
-    aCursor.setPosition( startSelection );
-    aCursor.setPosition( endSelection, QTextCursor::KeepAnchor );
-    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-    setTextCursor( aCursor );
-    textCursor().removeSelectedText();
-  }
-  if ( textCursor().position() < document()->end().previous().position() + promptSize() )
-    moveCursor( QTextCursor::End );
-  QTextEdit::paste();
-}
-
-/*!
-  \brief "Clear" operation.
-
-  Reimplemented from Qt.
-  Warning! In Qt this method is not virtual.
-*/
-void PyConsole_Editor::clear()
-{
-  QTextEdit::clear();
-  if ( isShowBanner() )
-    addText( banner() );
-  myPrompt = READY_PROMPT;
-  addText( myPrompt );
-}
-
-/*!
-  \brief Dumps recorded Python commands to the file
-  \param fileName path to the dump file
-  \return \c true if dump operation succeeded or \c false otherwise
-*/
-bool PyConsole_Editor::dump( const QString& fileName )
-{
-  bool ok = false;
-  if ( !fileName.isEmpty() ) {
-    QFile file( fileName ); 
-    if ( file.open( QFile::WriteOnly ) ) {
-      QTextStream out( &file );
-      for ( int i = 0; i < myHistory.count(); i++ ) {
-        out << myHistory[i] << endl;
-      }
-      file.close();
-      ok = true;
-    }
-  }
-  return ok;
-}
-
-/*!
-  \brief Dump menu action slot
-*/
-void PyConsole_Editor::dump()
-{
-  forever {
-    // get file name
-    QString fileName = getDumpFileName();
-
-    if ( fileName.isEmpty() )
-      break; // cancelled
-    
-    if ( dump( fileName ) )
-      break;
-    else
-      QMessageBox::warning( this,
-                            tr( "WARNING" ),
-                            tr( "ERR_FILE_NOT_WRITEABLE" ) );
-  }
-}
-
-/*!
-  \brief Get file name for Dump commands operation.
-  
-  This function can be redefined in successor classes to show application
-  specific dialog box.
-
-  \return path to the dump file
-*/
-QString PyConsole_Editor::getDumpFileName()
-{
-  return QFileDialog::getSaveFileName( this,
-                                       tr( "GET_DUMP_COMMANDS_FILENAME" ),
-                                       QString(),
-                                       QString( "%1 (*.py)" ).arg( tr( "PYTHON_SCRIPTS" ) ) );
-}
-
-/*!
-  \brief Get file name for Log Python trace operation.
-  
-  This function can be redefined in successor classes to show application
-  specific dialog box.
-
-  \return path to the log file
-*/
-QString PyConsole_Editor::getLogFileName()
-{
-  return QFileDialog::getSaveFileName( this,
-                                       tr( "GET_PYTHON_TRACE_FILENAME" ),
-                                       QString(),
-                                       QString( "%1 (*.log *.txt)" ).arg( tr( "LOG_FILES" ) ) );
-}
-
-/*!
-  \brief Start python trace logging
-  \param fileName the path to the log file
-  \return \c true if operation succeeded or \c false otherwise
-          (for example, if file is not writeable)
-  \sa stopLog()
- */
-bool PyConsole_Editor::startLog( const QString& fileName )
-{
-  // stop possibly already running logging
-  if ( isLogging() )
-    stopLog();
-
-  bool ok = false;
-  if ( !fileName.isEmpty() ) {
-    QFile file( fileName );
-    if ( file.open( QFile::WriteOnly ) ) {
-      file.close();
-      myLogFile = fileName;
-      ok = true;
-    }
-  }
-  return ok;
-}
-
-/*!
-  \brief Start log action slot
-*/
-void PyConsole_Editor::startLog()
-{
-  forever {
-    // get file name
-    QString fileName = getLogFileName();
-
-    if ( fileName.isEmpty() )
-      break; // cancelled
-    
-    if ( startLog( fileName ) )
-      break;
-    else
-      QMessageBox::warning( this,
-                            tr( "WARNING" ),
-                            tr( "File is not writable" ) );
-  }
-}
-
-/*!
-  \brief Stop log action slot
-  
-  Stops Python trace logging.
-*/
-void PyConsole_Editor::stopLog()
-{
-  myLogFile = QString();
-}
-
-/*!
-  \brief Put data to the log file
-*/
-void PyConsole_Editor::putLog( const QString& s )
-{
-  if ( !myLogFile.isEmpty() ) {
-    QFile file( myLogFile );
-    if ( !file.open( QFile::Append ) )
-      return;
-    
-    QTextStream out( &file );
-    out << s;
-    
-    file.close();
-  }
-}
-
-/*!
-  \brief Handle properly multi-line pasting. Qt documentation recommends overriding this function.
-  If the pasted text doesn't contain a line return, no special treatment is done.
-  \param source
-*/
-void PyConsole_Editor::insertFromMimeData(const QMimeData* source)
-{
-  if ( myMultiLinePaste )
-    return;
-
-  if ( source->hasText() ) {
-    QString s = source->text();
-    if ( s.contains( "\n" ) )
-      multilinePaste( s );
-    else
-      QTextEdit::insertFromMimeData( source );
-  }
-  else {
-    QTextEdit::insertFromMimeData( source );
-  }
-}
-
-/*!
-  Start multi-line paste operation
-  \internal
-*/
-void PyConsole_Editor::multilinePaste( const QString& s )
-{
-  // Turn on multi line pasting mode
-  myMultiLinePaste = true;
-
-  // Split string data to lines
-  QString s2 = s;
-  s2.replace( "\r", "" ); // Windows string format converted to Unix style
-  QStringList lst = s2.split( QChar('\n'), QString::KeepEmptyParts );
-
-  // Perform the proper paste operation for the first line to handle the case where
-  // something was already there
-  QMimeData source;
-  source.setText( lst[0] );
-  QTextEdit::insertFromMimeData( &source );
-
-  // Prepare what will have to be executed after the first line
-  myMultiLineContent.clear();
-  for ( int i = 1; i < lst.size(); ++i )
-    myMultiLineContent.enqueue( lst[i] );
-
-  // Trigger the execution of the first (mixed) line
-  handleReturn();
-
-  // See customEvent() and multiLineProcessNext() for the rest of the handling.
-}
-
-/*!
-  \brief Process the next line in the queue of multi-line paste operation; called
-  from customEvent() function
-  \internal
-*/
-void PyConsole_Editor::multiLineProcessNextLine()
-{
-  // not in multi-line paste mode
-  if ( !myMultiLinePaste || myMultiLineContent.isEmpty() )
-    return;
-
-  QString line = myMultiLineContent.dequeue();
-  if ( myMultiLineContent.empty() )
-  {
-    // this isa last line in the queue, just paste it
-    addText( line, false, false );
-    myMultiLinePaste = false;
-  }
-  else
-  {
-    // paste the line and simulate a <RETURN> key stroke
-    addText( line, false, false );
-    handleReturn();
-  }
-}
-
-/*!
-  \brief Clear results of completion
-*/
-void PyConsole_Editor::clearCompletion()
-{
-  // delete completion text if present
-  if ( myTabMode ) {
-    // remove completion display
-    document()->undo();
-    // remove trailing line return:
-    QTextCursor tc( textCursor() );
-    tc.setPosition( document()->characterCount()-1 );
-    setTextCursor( tc );
-    textCursor().deletePreviousChar();
-    // TODO: before wait for any <Tab> event to be completed
-  }
-  myTabMode = false;
-}
-
-/*!
- \brief Format completion results - this is where we should create 3 columns etc ...
- \param matches list of possible completions
- \return result string
-*/
-QString PyConsole_Editor::formatCompletion( const QStringList& matches ) const
-{
-  static const int MAX_COMPLETIONS = 70;
-
-  QStringList result;
-  int sz = matches.size();
-
-  if ( sz > MAX_COMPLETIONS )
-    result.append( QString( "[%1]" ).arg( tr( "TOO_MANY_MATCHES" ) ) );
-
-  for ( int i = 0; i < qMin( sz, MAX_COMPLETIONS); ++i )
-    result.append( matches[i] );
-
-  return result.join( "\n" );
-}
-
-/*!
-  \brief Format the doc string in HTML format with the first line in bold blue
-  \param doc initial doc string
-  \return HTML string
-*/
-QString PyConsole_Editor::formatDocHTML( const QString& doc ) const
-{
-  static const char* templ = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " \
-    "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" \
-    "<html><head><meta name=\"qrichtext\" content=\"1\" /> " \
-    "<style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style> " \
-    "</head><body style=\" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;\">\n" \
-    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> " \
-    "<span style=\" font-weight:600; color:#0000ff;\">%1</span></p> " \
-    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%2</p> " \
-    "</body></html>";
-  
-  QString fst, rest("");
-
-  // Extract first line of doc
-  int idx = doc.indexOf( "\n" );
-  if ( idx > 0 ) {
-    fst = doc.left( idx );
-    rest = doc.mid( idx+1 );
-  }
-  else {
-    fst = doc;
-  }
-
-  fst = fst.replace( "\n", " " );
-  rest = rest.replace(" \n", " " );
-  return QString( templ ).arg( fst ).arg( rest );
-}
-
-/*!
-  \fn void PyConsole_Editor::updateDoc( const QString& doc);
-  \brief Signal emitted by the editor widget when the doc string should be updated.
-  \param doc a HTML block with the formatted doc string.
-  \todo currently this signal is left uncaught.
-*/
-
-/*!
- \brief Extract the common leading part of all strings in matches.
- \param matches
- \param result
-*/
-QString PyConsole_Editor::extractCommon( const QStringList& matches ) const
-{
-  QString result = "";
-  
-  if ( matches.size() > 1 ) {
-    int l = 0;
-    bool ok = true;
-    while ( ok && l+1 < matches[0].size() ) {
-      QString match = matches[0].left( l+1 );
-      for ( int j = 1; j < matches.size() && ok; j++ )
-        ok = matches[j].startsWith( match );
-      if ( ok )
-        l++;
-    }
-    result = matches[0].left( l );
-  }
-
-  return result;
-}
-
-/*!
-  \brief Useful method to get banner from Python interpreter
-  \return banner
-*/
-QString PyConsole_Editor::banner() const
-{
-  return myInterp->getBanner().c_str();
-}
diff --git a/src/PyConsole/PyConsole_Editor.h b/src/PyConsole/PyConsole_Editor.h
deleted file mode 100644 (file)
index 774e101..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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   : 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.h"
-
-#include <QTextEdit>
-#include <QQueue>
-
-class PyConsole_Interp;
-class PyInterp_Request;
-class QEventLoop;
-
-class PYCONSOLE_EXPORT PyConsole_Editor : public QTextEdit
-{
-  Q_OBJECT;
-
-public:
-  PyConsole_Editor( PyConsole_Interp*, QWidget* = 0 );
-  ~PyConsole_Editor();
-
-  PyConsole_Interp* getInterp() const;
-  
-  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:
-  void           multilinePaste( const QString& );
-  void           multiLineProcessNextLine();
-
-  void           handleReturn();
-  void           handleTab();
-  void           handleBackTab();
-  void           clearCompletion();
-  QString        formatCompletion( const QStringList& ) const;
-  QString        formatDocHTML( const QString& ) const;
-  QString        extractCommon( const QStringList& ) const;
-
-  PyInterp_Request* createCmdRequest( const QString& );
-  PyInterp_Request* createTabRequest( const QString& );
-
-  QString        banner() const;
-  inline int     promptSize() const { return myPrompt.size(); }
-
-  PyConsole_Interp* myInterp;           //!< python interpreter
-  QString           myCommandBuffer;    //!< python command buffer
-  QString           myCurrentCommand;   //!< currently being printed command
-  QString           myPrompt;           //!< current command line prompt
-  int               myCmdInHistory;     //!< current history command index
-  QString           myLogFile;          //!< current output log
-  QStringList       myHistory;          //!< commands history buffer
-  QEventLoop*       myEventLoop;        //!< internal event loop
-  bool              myShowBanner;       //!< 'show banner' flag
-  QStringList       myQueue;            //!< python commands queue
-  bool              myIsSync;           //!< synchronous mode flag
-  bool              myIsSuppressOutput; //!< suppress output flag
-  bool              myMultiLinePaste;   //!< true when pasting several lines
-  QQueue<QString>   myMultiLineContent; //!< queue of lines being pasted
-  bool              myAutoCompletion;   //!< auto-completion mode flag
-  bool              myTabMode;          //!< flag that is \c true when editor performs completion
-  QString           myComplBeforePoint; //!< string on which the dir() command is executed
-  QString           myComplAfterPoint;  //!< string on which the results of the dir() are matched
-  int               myComplCursorPos;   //!< cursor position when <TAB> is hit
-
-};
-
-#endif // PYCONSOLE_EDITOR_H
diff --git a/src/PyConsole/PyConsole_Event.cxx b/src/PyConsole/PyConsole_Event.cxx
deleted file mode 100644 (file)
index 5c3f1fd..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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   : PyConsole_Event.cxx
-// Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
-
-#include "PyConsole_Event.h"
-
-/*!
-  \class PyConsole_PrintEvent
-  \brief Python command output backend event.
-  \internal
-*/
-
-/*!
-  \brief Constructor
-  \param message message text (python trace)
-  \param isError default to \c false - if \c true indicates that an error is being printed.
-*/
-PyConsole_PrintEvent::PyConsole_PrintEvent( const QString& message, bool isError )
-  : QEvent( (QEvent::Type)EVENT_ID ), myText( message ), myError( isError )
-{
-}
-
-/*!
-  \brief Get message
-  \return message text (python trace)
-*/
-QString PyConsole_PrintEvent::text() const
-{
-  return myText;
-}
-
-/*!
-  \brief Get error flag
-  \return \c true if this is an error message
-*/
-bool PyConsole_PrintEvent::isError() const
-{
-  return myError;
-}
-
-/*!
-  \class PyConsole_CompletionEvent
-  \brief Python command completion event.
-  \internal
-*/
-
-/*!
-  \brief Constructor
-  \param request python request
-  \param s status of execution of completion command
-  \param ms command matches (completions)
-  \param d docstring of the match (in case if there is sinlge match)
-*/
-PyConsole_CompletionEvent::PyConsole_CompletionEvent( PyInterp_Request* request,
-                                                      bool s,
-                                                      const QStringList& ms,
-                                                      const QString& d )
-  : PyInterp_Event( (QEvent::Type)EVENT_ID, request ),
-    myStatus( s ), myMatches( ms ), myDoc( d )
-{}
-
-/*!
-  \brief Get status of execution of completion command
-  \return execution status
-*/
-bool PyConsole_CompletionEvent::status() const
-{
-  return myStatus;
-}
-
-/*!
-  \brief Get matches (completions)
-  \return detected command matches (completions)
-*/
-QStringList PyConsole_CompletionEvent::matches() const
-{
-  return myMatches;
-}
-
-/*!
-  \brief Get docstring
-  \return docstring of the match (in case if there is sinlge match)
-*/
-QString PyConsole_CompletionEvent::doc() const
-{
-  return myDoc;
-}
diff --git a/src/PyConsole/PyConsole_Event.h b/src/PyConsole/PyConsole_Event.h
deleted file mode 100644 (file)
index d22b78b..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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   : PyConsole_Event.h
-// Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
-
-#ifndef PYCONSOLE_EVENT_H
-#define PYCONSOLE_EVENT_H
-
-#include "PyConsole.h"
-#include "PyInterp_Event.h"
-
-#include <QEvent>
-#include <QString>
-#include <QStringList>
-
-class PyConsole_PrintEvent : public QEvent
-{
-public:
-  static const int EVENT_ID = 65432;
-
-  PyConsole_PrintEvent( const QString&, bool = false );
-
-  QString text() const;
-  bool isError() const;
-
-private:
-  QString myText;  //!< Event message (python trace)
-  bool    myError; //!< Set to \c true if an error msg is to be displayed
-};
-
-class PyConsole_CompletionEvent : public PyInterp_Event
-{
-public:
-  static const int EVENT_ID = 65433;
-  
-  PyConsole_CompletionEvent( PyInterp_Request*, bool, const QStringList&, const QString& );
-
-  bool status() const;
-  QStringList matches() const;
-  QString doc() const;
-
-protected:
-  bool        myStatus;  //!< Status of execution
-  QStringList myMatches; //!< Command matches (completions)
-  QString     myDoc;     //!< Docstring of the match (in case if there is sinlge match)
-};
-
-#endif // PYCONSOLE_EVENT_H
diff --git a/src/PyConsole/PyConsole_Interp.cxx b/src/PyConsole/PyConsole_Interp.cxx
deleted file mode 100644 (file)
index 7224136..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-// 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   : PyConsole_Interp.cxx
-// Author : Nicolas REJNERI (OPEN CASCADE), Adrien BRUNETON (CEA/DEN), Vadim SANDLER (OPEN CASCADE)
-
-#include "PyConsole_Interp.h"
-
-/*!
-  \class PyConsole_Interp
-  \brief Python interpreter to be embedded to the SALOME study's GUI.
-
-  There is only one Python interpreter for the whole SALOME environment.
-
-  Call the initialize() method defined in the base class PyInterp_Interp,
-  to initialize the interpreter after instance creation.
-
-  The method initialize() calls virtuals methods
-  - initPython()  to initialize global Python interpreter
-  - initContext() to initialize interpreter internal context
-  - initRun()     to prepare interpreter for running commands
-
-  See PyInterp_Interp class for more details.
-*/
-
-/*!
-  \brief Constructor.
-
-  Creates new python interpreter.
-*/
-PyConsole_Interp::PyConsole_Interp()
-  : PyInterp_Interp()
-{
-}
-
-/*!
-  \brief Destructor.
-*/
-PyConsole_Interp::~PyConsole_Interp()
-{
-}
-
-/*!
-  \brief Performs specific actions before each Python command
-  
-  Sets the variable "__IN_SALOME_GUI_CONSOLE" to True.
-  This is not attached to a module (like salome_iapp.IN_SALOME_GUI_CONSOLE)
-  since modules are shared across all interpreters in SALOME.
-
-  \note GIL is already acquired here.
-*/
-int PyConsole_Interp::beforeRun()
-{
-  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=True");
-}
-/*!
-  \brief Performs specific actions after each Python command
-
-  Sets the variable "__IN_SALOME_GUI_CONSOLE" to False.
-  \sa beforeRun()
-
-  \note GIL is already acquired here.
-*/
-int PyConsole_Interp::afterRun()
-{
-  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=False");
-}
-
-/*!
-  \brief Run Python dir() command to get matches.
-  \internal
-  \param dirArgument Python expression to pass to the dir command. The parsing of what the
-  user actually started typing is dedicated to the caller
-  \param startMatch string representing the begining of the patter to be completed. For example, when
-  the user types "a_string_variable.rsp <TAB>", this is "rsp".
-  \param[out] matches resulting list of matches
-  \param[out] docString resulting docstring of single match
-  \return \true if completion succeeded, \c false otherwise
-*/
-bool PyConsole_Interp::runDirCommand( const QString& dirArgument, const QString& startMatch, 
-                                      QStringList& matches, QString& docString )
-{
-  static QStringList keywords;
-  if ( keywords.isEmpty() ) {
-    keywords << "and" << "as" << "assert" << "break" << "class" << "continue"
-             << "def" << "del" << "elif" << "else" << "except" << "exec"
-             << "finally" << "for" << "from" << "global" << "if" << "import"
-             << "in" << "is" << "lambda" << "not" << "or" << "pass" << "print" << "raise"
-             << "return" << "try" << "while" << "with" << "yield";
-  }
-  
-  // run dir() command and extract completions
-  if ( !runDirAndExtract( dirArgument, startMatch, matches ) )
-    return false;
-  
-  // If dirArgument is empty, we append the __builtins__
-  if ( dirArgument.isEmpty() ) {
-    if ( !runDirAndExtract( QString( "__builtins__" ), startMatch, matches, false ) )
-      return false;
-    
-    // ... and we match on Python's keywords as well
-    foreach( QString keyword, keywords ) {
-      if ( keyword.startsWith( startMatch ) )
-        matches.append( keyword );
-    }
-  }
-  
-  // Try to get doc string of the first match
-  if ( matches.size() > 0 ) {
-    QString cmd = QString( "%1.__doc__" ).arg( matches[0] );
-    if ( !dirArgument.trimmed().isEmpty() )
-      cmd.prepend( QString( "%1." ).arg( dirArgument ) );
-    
-    PyObject* str = PyRun_String( cmd.toStdString().c_str(), Py_eval_input, _global_context, _local_context );
-    if ( !str || str == Py_None || !PyString_Check( str ) )
-      {
-        if ( !str )
-          PyErr_Clear();
-      }
-    else {
-      docString = QString( PyString_AsString( str ) );
-    }
-    Py_XDECREF( str );
-  }
-  return true;
-}
-
-/*!
-  \internal
-  \sa runDirCommand()
-  \param dirArgument see runDirCommand()
-  \param startMatch  see runDirCommand()
-  \param[out] result resulting list of matches
-  \param discardSwig if \c true, a regular expression is used to discard all static method generated
-  by SWIG. Typically: MEDCouplingUMesh_Blabla
-  \return \c true if the call to dir() and parsing of the result succeeded, \false otherwise.
-*/
-bool PyConsole_Interp::runDirAndExtract( const QString& dirArgument,
-                                         const QString& startMatch,
-                                         QStringList& result,
-                                         bool discardSwig ) const
-{
-  QRegExp re( "^[A-Z].+_[A-Z]+[a-z]+.+$" ); // REX to discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
-
-  // Execute dir() command
-  QString command( "dir(" + dirArgument + ")" );
-  PyObject* plst = PyRun_String( command.toStdString().c_str(), Py_eval_input, _global_context, _local_context );
-  if ( !plst || plst == Py_None ) {
-    if ( !plst )
-      PyErr_Clear();
-    Py_XDECREF( plst );
-    return false;
-  }
-
-  // Check result
-  if ( !PySequence_Check( plst ) ) {
-    // Should never happen ...
-    Py_XDECREF( plst );
-    return false;
-  }
-
-  // Extract the returned list
-  int n = PySequence_Length( plst );
-  for ( int i = 0; i < n; i++ ) {
-    PyObject* it;
-    it = PySequence_GetItem( plst, i );
-    QString s( PyString_AsString( it ) );
-    // if the method is not from swig, not static (guessed from the reg exp) and matches
-    // what is already there
-    if ( s.startsWith( startMatch ) ) {
-      if ( !discardSwig || ( !re.exactMatch( s ) && !s.contains( "swig" ) ) )
-        result.append( s );
-    }
-    Py_DECREF( it );
-  }
-  Py_DECREF( plst );
-  
-  return true;
-}
diff --git a/src/PyConsole/PyConsole_Interp.h b/src/PyConsole/PyConsole_Interp.h
deleted file mode 100644 (file)
index 4275c35..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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   : PyConsole_Interp.h
-// Author : Nicolas REJNERI (OPEN CASCADE), Adrien BRUNETON (CEA/DEN), Vadim SANDLER (OPEN CASCADE)
-
-#ifndef PYCONSOLE_INTERP_H
-#define PYCONSOLE_INTERP_H
-
-#include "PyConsole.h"
-#include "PyInterp_Interp.h"
-
-#include <QStringList>
-
-class PYCONSOLE_EXPORT PyConsole_Interp : public PyInterp_Interp
-{
-  friend class PyConsole_CompletionCommand;
-
-public:
-  PyConsole_Interp();
-  ~PyConsole_Interp();
-
-  virtual int afterRun();
-  virtual int beforeRun();
-
-private:
-  bool runDirCommand( const QString&, const QString&, QStringList&, QString& );
-  bool runDirAndExtract( const QString&, const QString&, QStringList&, bool = true ) const;
-};
-
-#endif // PYCONSOLE_INTERP_H
diff --git a/src/PyConsole/PyConsole_Request.cxx b/src/PyConsole/PyConsole_Request.cxx
deleted file mode 100644 (file)
index aa41c25..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, 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
-//
-// File   : PyConsole_Request.cxx
-// Author : Vadim SANDLER (OPEN CASCADE), Adrien Bruneton (CEA/DEN)
-
-#include "PyConsole_Request.h"
-#include "PyConsole_Interp.h"
-#include "PyConsole_Event.h"
-
-#include <QCoreApplication>
-
-/*!
-  \class PyConsole_ExecCommand
-  \brief Python command execution request.
-  \internal
-*/
-
-/*!
-  \brief Constructor.
-  
-  Creates new python command execution request.
-
-  \param theInterp   python interpreter
-  \param theCommand  python command
-  \param theListener widget to get the notification messages
-  \param theSync     if \c true, the request is processed synchronously
-*/
-PyConsole_ExecCommand::PyConsole_ExecCommand( PyInterp_Interp*        theInterp,
-                                              const QString&          theCommand,
-                                              QObject*                theListener,
-                                              bool                    theSync )
-  : PyInterp_LockRequest( theInterp, theListener, theSync ),
-    myCommand( theCommand ), myState( PyInterp_Event::ES_OK )
-{}
-
-/*!
-  \brief Execute the python command in the interpreter and
-  get its execution status.
-*/
-void PyConsole_ExecCommand::execute()
-{
-  if ( myCommand != "" ) {
-    int ret = getInterp()->run( myCommand.toLatin1().data() );
-    if ( ret < 0 )
-      myState = PyInterp_Event::ES_ERROR;
-    else if ( ret > 0 )
-      myState = PyInterp_Event::ES_INCOMPLETE;
-  }
-}
-
-/*!
-  \brief Create and return a notification event.
-  \return new notification event
-*/
-QEvent* PyConsole_ExecCommand::createEvent()
-{
-  if ( IsSync() )
-    QCoreApplication::sendPostedEvents( listener(), PyConsole_PrintEvent::EVENT_ID );
-  return new PyInterp_Event( myState, this );
-}
-
-/*!
-  \class PyConsole_CompletionCommand
-  \brief Python command completion request.
-  \internal
-*/
-
-/*!
-  \brief Constructor.
-
-  Creates a new python completion request.
-
-  \param theInterp python interpreter
-  \param theInput  string containing the dir() command to be executed
-  \param theStartMatch part to be matched with the results of the dir() command
-  \param theListener widget to get the notification messages
-  \param theSync if \c true the request is processed synchronously
-*/
-PyConsole_CompletionCommand::PyConsole_CompletionCommand( PyInterp_Interp*   theInterp,
-                                                          const QString&     theInput,
-                                                          const QString&     theStartMatch,
-                                                          QObject*           theListener,
-                                                          bool               theSync )
-  : PyInterp_LockRequest( theInterp, theListener, theSync ),
-    myDirArg( theInput ), myStartMatch( theStartMatch ), myStatus( false )
-{}
-
-/*!
-  \brief Execute the completion command by invoking runDirCommand() function
-  of interpreter.
-*/
-void PyConsole_CompletionCommand::execute()
-{
-  myStatus = static_cast<PyConsole_Interp*>( getInterp() )->runDirCommand( myDirArg,  myStartMatch, myMatches, myDoc );
-}
-
-/*!
- \brief Create and return completion event
-  \return new completion event
- */
-QEvent* PyConsole_CompletionCommand::createEvent()
-{
-  return new PyConsole_CompletionEvent( this, myStatus, myMatches, myDoc );
-}
diff --git a/src/PyConsole/PyConsole_Request.h b/src/PyConsole/PyConsole_Request.h
deleted file mode 100644 (file)
index 827823b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, 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
-//
-// File   : PyConsole_Request.h
-// Author : Vadim SANDLER (OPEN CASCADE), Adrien Bruneton (CEA/DEN)
-
-#ifndef PYCONSOLE_REQUEST_H
-#define PYCONSOLE_REQUEST_H
-
-#include "PyInterp_Request.h"
-
-#include <QString>
-#include <QStringList>
-
-class QEvent;
-class PyInterp_Interp;
-
-class PyConsole_ExecCommand : public PyInterp_LockRequest
-{
-public:
-  PyConsole_ExecCommand( PyInterp_Interp*, const QString&, QObject*, bool = false );
-
-protected:
-  virtual void execute();
-  virtual QEvent* createEvent();
-
-private:
-  QString myCommand;   //!< Python command
-  int     myState;     //!< Python command execution status
-};
-
-class PyConsole_CompletionCommand : public PyInterp_LockRequest
-{
-public:
-  PyConsole_CompletionCommand( PyInterp_Interp*, const QString&, const QString&, QObject*, bool = false );
-
-protected:
-  virtual void execute();
-  virtual QEvent* createEvent();
-
-private:
-  QString     myDirArg;       //!< String to be passed to the dir() comman
-  QString     myStartMatch;   //!< Begining of the command (as typed by the user)
-  bool        myStatus;       //!< Status of completion command execution
-  QStringList myMatches;      //!< Matches
-  QString     myDoc;          //!< Docstring of single match
-};
-
-#endif // PYCONSOLE_REQUEST_H
diff --git a/src/PyConsole/resources/PyConsole_msg_en.ts b/src/PyConsole/resources/PyConsole_msg_en.ts
deleted file mode 100644 (file)
index 7fac57c..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.0" language="en_US">
-<context>
-    <name>PyConsole_Console</name>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="216"/>
-        <source>EDIT_COPY_CMD</source>
-        <translation>&amp;Copy</translation>
-    </message>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="221"/>
-        <source>EDIT_PASTE_CMD</source>
-        <translation>&amp;Paste</translation>
-    </message>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="226"/>
-        <source>EDIT_CLEAR_CMD</source>
-        <translation>Clea&amp;r</translation>
-    </message>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="231"/>
-        <source>EDIT_SELECTALL_CMD</source>
-        <translation>Select &amp;All</translation>
-    </message>
-    <message>
-        <source>EDIT_DUMPCOMMANDS_CMD</source>
-        <translation>D&amp;ump Commands</translation>
-    </message>
-    <message>
-        <source>EDIT_STARTLOG_CMD</source>
-        <translation>Start &amp;Log</translation>
-    </message>
-    <message>
-      <source>EDIT_STOPLOG_CMD</source>
-        <translation>Stop &amp;Log</translation>
-    </message>
-</context>
-<context>
-    <name>PyConsole_Editor</name>
-    <message>
-        <source>GET_DUMP_COMMANDS_FILENAME</source>
-        <translation>Dump commands to file</translation>
-    </message>
-    <message>
-        <source>GET_PYTHON_TRACE_FILENAME</source>
-        <translation>Save Python trace to file</translation>
-    </message>
-    <message>
-        <source>PYTHON_SCRIPTS</source>
-        <translation>Python scripts</translation>
-    </message>
-    <message>
-        <source>WARNING</source>
-        <translation>Warning!</translation>
-    </message>
-    <message>
-        <source>LOG_FILES</source>
-        <translation>Log files</translation>
-    </message>
-    <message>
-        <source>ERR_FILE_NOT_WRITEABLE</source>
-        <translation>File is not writeable!</translation>
-    </message>
-    <message>
-        <source>TOO_MANY_MATCHES</source>
-        <translation>Too many matches! Displaying first ones only...</translation>
-    </message>
-    <message>
-        <source>NO_DOC_AVAILABLE</source>
-        <translation>no documentation available</translation>
-    </message>
-</context>
-</TS>
diff --git a/src/PyConsole/resources/PyConsole_msg_fr.ts b/src/PyConsole/resources/PyConsole_msg_fr.ts
deleted file mode 100644 (file)
index 9eaf244..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.0" language="fr_FR">
-<context>
-    <name>PyConsole_Console</name>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="216"/>
-        <source>EDIT_COPY_CMD</source>
-        <translation>&amp;Copier</translation>
-    </message>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="221"/>
-        <source>EDIT_PASTE_CMD</source>
-        <translation>C&amp;oller</translation>
-    </message>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="226"/>
-        <source>EDIT_CLEAR_CMD</source>
-        <translation>&amp;Effacer</translation>
-    </message>
-    <message>
-        <location filename="../PyConsole_Console.cxx" line="231"/>
-        <source>EDIT_SELECTALL_CMD</source>
-        <translation>&amp;Tout sélectionner</translation>
-    </message>
-    <message>
-        <source>EDIT_DUMPCOMMANDS_CMD</source>
-        <translation>&amp;Générer le script des commandes</translation>
-    </message>
-    <message>
-        <source>EDIT_STARTLOG_CMD</source>
-        <translation>Démarrer une &amp;trace</translation>
-    </message>
-    <message>
-        <source>EDIT_STOPLOG_CMD</source>
-        <translation>Arrêter la &amp;trace</translation>
-    </message>
-</context>
-<context>
-    <name>PyConsole_Editor</name>
-    <message>
-        <source>GET_DUMP_COMMANDS_FILENAME</source>
-        <translation>Choisissez un fichier python où sauver le dump</translation>
-    </message>
-    <message>
-        <source>GET_PYTHON_TRACE_FILENAME</source>
-        <translation>Choisissez un fichier où sauver le log</translation>
-    </message>
-    <message>
-        <source>PYTHON_SCRIPTS</source>
-        <translation>Scripts Python</translation>
-    </message>
-    <message>
-        <source>WARNING</source>
-        <translation>Attention !</translation>
-    </message>
-    <message>
-        <source>LOG_FILES</source>
-        <translation>Fichiers log</translation>
-    </message>
-    <message>
-        <source>ERR_FILE_NOT_WRITEABLE</source>
-        <translation>Le fichier n'a pas été écrit !</translation>
-    </message>
-    <message>
-        <source>TOO_MANY_MATCHES</source>
-        <translation type="unfinished">Too many matches! Displaying first ones only...</translation>
-    </message>
-    <message>
-        <source>NO_DOC_AVAILABLE</source>
-        <translation type="unfinished">no documentation available</translation>
-    </message>
-</context>
-</TS>
diff --git a/src/PyConsole/resources/PyConsole_msg_ja.ts b/src/PyConsole/resources/PyConsole_msg_ja.ts
deleted file mode 100644 (file)
index 8861d5e..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.0" language="ja" sourcelanguage="en">
-  <context>
-    <name>PyConsole_Console</name>
-    <message>
-      <location filename="../PyConsole_Console.cxx" line="216"/>
-      <source>EDIT_COPY_CMD</source>
-      <translation>コピー(&amp;C)</translation>
-    </message>
-    <message>
-      <location filename="../PyConsole_Console.cxx" line="221"/>
-      <source>EDIT_PASTE_CMD</source>
-      <translation>貼り付け(&amp;P)</translation>
-    </message>
-    <message>
-      <location filename="../PyConsole_Console.cxx" line="226"/>
-      <source>EDIT_CLEAR_CMD</source>
-      <translation>削除(&amp;r)</translation>
-    </message>
-    <message>
-      <location filename="../PyConsole_Console.cxx" line="231"/>
-      <source>EDIT_SELECTALL_CMD</source>
-      <translation>すべて選択します。(&amp;A)</translation>
-    </message>
-    <message>
-      <source>EDIT_DUMPCOMMANDS_CMD</source>
-      <translation>スクリプト コマンドを生成します。(&amp;u)</translation>
-    </message>
-    <message>
-      <source>EDIT_STARTLOG_CMD</source>
-      <translation>ログの開始 (&amp;L)</translation>
-    </message>
-    <message>
-      <source>EDIT_STOPLOG_CMD</source>
-      <translation>ログの停止 (&amp;L)</translation>
-    </message>
-  </context>
-  <context>
-    <name>PyConsole_Editor</name>
-    <message>
-      <source>GET_DUMP_COMMANDS_FILENAME</source>
-      <translation type="unfinished">Dump commands to file</translation>
-    </message>
-    <message>
-      <source>GET_PYTHON_TRACE_FILENAME</source>
-      <translation type="unfinished">Save Python trace to file</translation>
-    </message>
-    <message>
-      <source>PYTHON_SCRIPTS</source>
-      <translation type="unfinished">Python scripts</translation>
-    </message>
-    <message>
-      <source>WARNING</source>
-      <translation type="unfinished">Warning!</translation>
-    </message>
-    <message>
-      <source>LOG_FILES</source>
-      <translation type="unfinished">Log files</translation>
-    </message>
-    <message>
-      <source>ERR_FILE_NOT_WRITEABLE</source>
-      <translation type="unfinished">File is not writeable!</translation>
-    </message>
-    <message>
-      <source>TOO_MANY_MATCHES</source>
-      <translation type="unfinished">Too many matches! Displaying first ones only...</translation>
-    </message>
-    <message>
-      <source>NO_DOC_AVAILABLE</source>
-      <translation type="unfinished">no documentation available</translation>
-    </message>
-  </context>
-</TS>
diff --git a/src/PyInterp/CMakeLists.txt b/src/PyInterp/CMakeLists.txt
deleted file mode 100755 (executable)
index d44a73f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (C) 2012-2016  CEA/DEN, EDF R&D, 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
-#
-
-INCLUDE(UseQtExt)
-
-# --- options ---
-
-# additional include directories
-INCLUDE_DIRECTORIES(
-  ${QT_INCLUDES}
-  ${PYTHON_INCLUDE_DIRS}
-)
-
-# additional preprocessor / compiler flags
-ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
-
-# libraries to link to
-SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES})
-
-# --- headers ---
-
-# header files / to be processed by moc
-SET(_moc_HEADERS
-  PyInterp_Dispatcher.h
-)
-
-# header files / no moc processing
-SET(_other_HEADERS
-  PyInterp.h
-  PyInterp_Event.h
-  PyInterp_Interp.h
-  PyInterp_Request.h
-  PyInterp_Utils.h
-)
-
-# header files / to install
-SET(PyInterp_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
-
-# --- sources ---
-
-# sources / moc wrappings
-QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS})
-
-# sources / static
-SET(_other_SOURCES
-  PyInterp_Dispatcher.cxx
-  PyInterp_Event.cxx
-  PyInterp_Interp.cxx
-  PyInterp_Request.cxx
-)
-
-# sources / to compile
-SET(PyInterp_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
-
-# --- rules ---
-
-ADD_LIBRARY(PyInterp ${PyInterp_SOURCES})
-TARGET_LINK_LIBRARIES(PyInterp ${_link_LIBRARIES})
-INSTALL(TARGETS PyInterp EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
-
-INSTALL(FILES ${PyInterp_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
diff --git a/src/PyInterp/PyInterp.h b/src/PyInterp/PyInterp.h
deleted file mode 100755 (executable)
index 08271e0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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   : 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
-# if defined PYINTERP_EXPORTS || defined PyInterp_EXPORTS
-#  define PYINTERP_EXPORT __declspec(dllexport)
-# else
-#  define PYINTERP_EXPORT __declspec(dllimport)
-# endif
-#else   // WIN32
-# define PYINTERP_EXPORT
-#endif  // WIN32
-
-// ========================================================
-
-#include <Python.h>
-
-// avoid warning messages
-#ifdef WIN32
-#pragma warning (disable : 4786)
-#pragma warning (disable : 4251)
-#endif
-
-#endif // PYINTERP_H
diff --git a/src/PyInterp/PyInterp_Dispatcher.cxx b/src/PyInterp/PyInterp_Dispatcher.cxx
deleted file mode 100755 (executable)
index b702144..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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   : PyInterp_Dispatcher.cxx
-//  Author : Sergey Anikin (OPEN CASCADE S.A.S.)
-
-#include "PyInterp_Dispatcher.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
-
-/**
-   \class PyInterp_Dispatcher
-   \brief Dispatcher of Python events; used to serialize requests to Python interpreter.
-*/
-
-PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
-
-PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
-{
-  if ( !myInstance )
-    myInstance = new PyInterp_Dispatcher();
-  return myInstance;
-}
-
-PyInterp_Dispatcher::PyInterp_Dispatcher() 
-: QThread()
-{
-}
-
-PyInterp_Dispatcher::~PyInterp_Dispatcher()
-{
-  // Clear the request queue
-  myQueueMutex.lock();
-
-  QListIterator<RequestPtr> it( myQueue );
-  while ( it.hasNext() )
-    PyInterp_Request::Destroy( it.next() );
-  myQueue.clear();
-
-  myQueueMutex.unlock();
-
-  // Wait for run() to finish
-  wait();
-}
-
-bool PyInterp_Dispatcher::IsBusy() const
-{
-  return isRunning();
-}
-
-void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest )
-{
-  if ( !theRequest )
-    return;
-
-  if ( theRequest->IsSync() /*&& !IsBusy()*/)
-  {
-    // synchronous processing
-    processRequest( theRequest );
-  }
-  else
-  {
-    // asynchronous processing
-    myQueueMutex.lock();
-
-    myQueue.enqueue( theRequest );
-    if ( theRequest->listener() ) {
-      connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ),
-               this, SLOT( objectDestroyed( QObject* ) ) );
-    }
-
-    myQueueMutex.unlock();  
-
-    if ( !IsBusy() )
-      start();
-  }
-}
-
-void PyInterp_Dispatcher::run()
-{
-  PyInterp_Request* aRequest;
-
-  // prepare for queue size check
-  myQueueMutex.lock();
-
-  while ( myQueue.size() )
-  {
-    aRequest = myQueue.head();
-
-    // let other threads append their requests to the end of the queue
-    myQueueMutex.unlock();
-
-    // processRequest() may delete a request, so this pointer must not be used
-    // after request is processed!
-    processRequest( aRequest );
-
-    // 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.head() == aRequest ) // if it is still here --> remove it
-      myQueue.dequeue();
-  }
-
-  myQueueMutex.unlock();
-}
-
-void PyInterp_Dispatcher::processRequest( PyInterp_Request* theRequest )
-{
-  theRequest->process();
-}
-
-void PyInterp_Dispatcher::objectDestroyed( QObject* o )
-{
-  // prepare for modification of the queue
-  myQueueMutex.lock();
-
-  QMutableListIterator<RequestPtr> it( myQueue );
-  while ( it.hasNext() )
-  {
-    RequestPtr r = it.next();
-    if ( o == r->listener() )
-    {
-      r->setListener( 0 ); // to prevent event posting
-      it.remove();
-    }
-  }
-
-  myQueueMutex.unlock();
-}
diff --git a/src/PyInterp/PyInterp_Dispatcher.h b/src/PyInterp/PyInterp_Dispatcher.h
deleted file mode 100755 (executable)
index c9b8384..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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   : PyInterp_Dispatcher.h
-//  Author : Sergey Anikin (OPEN CASCADE S.A.S.)
-
-#ifndef PYINTERP_DISPATCHER_H
-#define PYINTERP_DISPATCHER_H
-
-#include "PyInterp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
-
-#include "PyInterp_Request.h"   // full include instead of forward declaration
-                                // everyone inc'ing the Dispatcher will get the requests for free.
-
-#include <QMutex>
-#include <QThread>
-#include <QQueue>
-
-class PYINTERP_EXPORT PyInterp_Dispatcher : protected QThread
-{
-  PyInterp_Dispatcher(); // private constructor
-  Q_OBJECT
-public:
-  static PyInterp_Dispatcher* Get();
-
-  virtual                     ~PyInterp_Dispatcher();
-
-  bool                        IsBusy() const;  
-  void                        Exec( PyInterp_Request* );
-
-private:
-  virtual void                run();
-  void                        processRequest( PyInterp_Request* );
-
-private slots:
-  void                        objectDestroyed( QObject* );
-
-private:
-  typedef PyInterp_Request*   RequestPtr;
-
-  QQueue<RequestPtr>          myQueue;
-  QMutex                      myQueueMutex;
-
-  static PyInterp_Dispatcher* myInstance;
-};
-
-#endif // PYINTERP_DISPATCHER_H
diff --git a/src/PyInterp/PyInterp_Event.cxx b/src/PyInterp/PyInterp_Event.cxx
deleted file mode 100644 (file)
index 478eb2c..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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   : PyInterp_Event.cxx
-//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
-
-#include "PyInterp_Event.h"
-#include "PyInterp_Request.h"
-
-/**
-   \class PyInterp_Event
-   \brief Events thrown by the interpreter having executed a command and indicating
-   the return status.
-*/
-
-PyInterp_Event::PyInterp_Event( int type, PyInterp_Request* request )
-  : QEvent( (QEvent::Type)type ), myRequest( request )
-{
-}
-
-PyInterp_Event::~PyInterp_Event()
-{
-  PyInterp_Request::Destroy( myRequest );
-  myRequest = 0;
-}
-
-PyInterp_Request* PyInterp_Event::GetRequest() const
-{
-  return myRequest;
-}
-
-PyInterp_Event::operator PyInterp_Request*() const
-{
-  return myRequest;
-}
diff --git a/src/PyInterp/PyInterp_Event.h b/src/PyInterp/PyInterp_Event.h
deleted file mode 100644 (file)
index e812adb..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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   : PyInterp_Event.h
-//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
-
-#ifndef PYINTERP_EVENT_H
-#define PYINTERP_EVENT_H
-
-#include "PyInterp.h"
-
-#include <QEvent>
-
-class PyInterp_Request;
-
-class PYINTERP_EXPORT PyInterp_Event : public QEvent
-{
-  PyInterp_Event();
-  PyInterp_Event( const PyInterp_Event& );
-
-public:
-  // Execution state
-  enum {
-    ES_NOTIFY = QEvent::User + 5000,
-    ES_OK,
-    ES_ERROR,
-    ES_INCOMPLETE,
-    ES_LAST };
-
-  PyInterp_Event( int type, PyInterp_Request* request );
-  virtual ~PyInterp_Event();
-
-  PyInterp_Request* GetRequest() const;
-  operator PyInterp_Request*() const;
-
-private:
-  PyInterp_Request* myRequest;
-};
-
-#endif // PYINTERP_EVENT_H
diff --git a/src/PyInterp/PyInterp_Interp.cxx b/src/PyInterp/PyInterp_Interp.cxx
deleted file mode 100644 (file)
index 5946e8d..0000000
+++ /dev/null
@@ -1,607 +0,0 @@
-// 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   : PyInterp_Interp.cxx
-//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
-
-#include "PyInterp_Interp.h"  // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
-#include "PyInterp_Utils.h"
-
-#include <pythread.h>
-#include <cStringIO.h>
-#include <structmember.h>
-#include <string>
-#include <vector>
-#include <map>
-#include <iostream>
-#include <sstream>
-#include <algorithm>
-
-#include <QRegExp>
-
-#define TOP_HISTORY_PY   "--- top of history ---"
-#define BEGIN_HISTORY_PY "--- begin of history ---"
-
-/*
-  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 PyObject*
-PyStdOut_flush(PyStdOut *self)
-{
-  Py_INCREF(Py_None);
-  return Py_None;
-}
-
-static PyMethodDef PyStdOut_methods[] = {
-  {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS, PyDoc_STR("write(string) -> None")},
-  {"flush",  (PyCFunction)PyStdOut_flush,  METH_NOARGS,  PyDoc_STR("flush() -> None")},
-  {NULL,    NULL}   /* sentinel */
-};
-
-static PyMemberDef PyStdOut_memberlist[] = {
-  {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
-   (char*)"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[] = {(char*)""};
-
-/*!
-  \brief Basic constructor.
-
-  After construction the interpreter instance successor classes
-  must call virtual method initalize().
-*/
-PyInterp_Interp::PyInterp_Interp():
-  _vout(0), _verr(0), _local_context(0), _global_context(0), _initialized(false)
-{
-}
-
-/*!
-  \brief Destructor.
-*/
-PyInterp_Interp::~PyInterp_Interp()
-{
-  destroy();
-}
-
-/*!
-  \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
-  - 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()
-{
-  if ( initialized() )
-    return; // prevent repeating intitialization
-
-  _initialized = true;
-
-  _history.clear();       // start a new list of user's commands
-  _ith = _history.begin();
-
-  initPython();  // This also inits the multi-threading for Python (but w/o acquiring GIL)
-
-  // ---- The rest of the initialisation process is done hodling the GIL
-  PyLockWrapper lck;
-
-  initContext();
-
-  // used to interpret & compile commands - this is really imported here
-  // and only added again (with PyImport_AddModule) later on
-  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();
-}
-
-void PyInterp_Interp::destroy()
-{
-  PyLockWrapper lck;
-  closeContext();
-}
-
-/*!
-  \brief Initialize Python interpreter.
-
-  In case if Python is not initialized, it sets program name, initializes the single true Python
-  interpreter, sets program arguments, and initializes threads.
-  Otherwise, does nothing. This is important for light SALOME configuration,
-  as in full SALOME this is done at SalomeApp level.
-  \sa SalomeApp_PyInterp class and main() in SALOME_Session_Server
- */
-void PyInterp_Interp::initPython()
-{
-  if (!Py_IsInitialized()){
-    // Python is not initialized
-    Py_SetProgramName(_argv[0]);
-    Py_Initialize(); // Initialize the interpreter
-    PySys_SetArgv(_argc, _argv);
-
-    PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
-    PyEval_ReleaseLock();
-  }
-}
-
-/*!
-  \brief Get embedded Python interpreter banner.
-  \return banner string
- */
-std::string PyInterp_Interp::getBanner() const
-{
-  PyLockWrapper lck;
-  std::string aBanner("Python ");
-  aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
-  aBanner = aBanner + "\ntype help to get general information on environment\n";
-  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()
-{
-  return true;
-}
-
-/*!
- * 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 PyInterp_Interp::initContext()
-{
-  PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
-  if(!m){
-    PyErr_Print();
-    return false;
-  }
-  _global_context = PyModule_GetDict(m);          // get interpreter global variable context
-  Py_INCREF(_global_context);
-  _local_context = _global_context;
-
-  int ret = PyRun_SimpleString("import salome_iapp;salome_iapp.IN_SALOME_GUI=True");
-
-  return ret == 0;
-}
-
-/*!
- * Destroy context dictionaries. GIL is held already.
- */
-void PyInterp_Interp::closeContext()
-{
-  Py_XDECREF(_global_context);
-  // both _global_context and _local_context may point to the same Python object
-  if ( _global_context != _local_context)
-    Py_XDECREF(_local_context);
-}
-
-/*!
-  \brief Compile Python command and evaluate it in the
-         python dictionary contexts if possible. This is not thread-safe.
-         This is the caller's responsability to make this thread-safe.
-  \internal
-  \param command Python command string
-  \return -1 on fatal error, 1 if command is incomplete and 0
-         if command is executed successfully
- */
-static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
-{
-  PyObject *m = PyImport_AddModule("codeop");
-  if(!m) {
-    // Fatal error. No way to go on.
-    PyErr_Print();
-    return -1;
-  }
-
-  PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"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 {
-    PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,global_ctxt, local_ctxt));
-    if(!r) {
-      // Execution error. We return -1
-      PyErr_Print();
-      return -1;
-    }
-    // The command has been successfully executed. Return 0
-    return 0;
-  }
-}
-
-void replaceAll(std::string& str, const std::string& from, const std::string& to) {
-    if(from.empty())
-        return;
-    size_t start_pos = 0;
-    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
-        str.replace(start_pos, from.length(), to);
-        start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
-    }
-}
-
-std::vector<std::string>
-__split(const std::string& str, char delimiter)
-{
-  std::vector<std::string> internal;
-  std::stringstream ss(str); // Turn the string into a stream.
-  std::string tok;
-
-  while (getline(ss, tok, delimiter)) {
-    internal.push_back(tok);
-  }
-
-  return internal;
-}
-
-std::string
-__join(const std::vector<std::string>& v, int begin=0, int end=-1)
-{
-  if (end == -1)
-    end = v.size();
-  std::stringstream ss;
-  for (size_t i = begin; i < end; ++i) {
-    if (i != begin)
-      ss << ",";
-    ss << v[i];
-  }
-  return ss.str();
-}
-
-std::vector<std::string>
-__getArgsList(std::string argsString)
-{
-  // Special process if some items of 'args:' list are themselves lists
-  // Note that an item can be a list, but not a list of lists...
-  // So we can have something like this:
-  // myscript.py args:[\'file1\',\'file2\'],\'val1\',\"done\",[1,2,3],[True,False],\"ok\",kwarg1=\'kwarg1\',kwarg2=\'kwarg2\',\'fin\'
-  // With such a call, argsString variable contains the string representing ['file1','file2'],'val1','done',[1,2,3],[True,False],'ok',kwarg1='kwarg1',kwarg2='kwarg2','fin'
-  // We have to split argsString to obtain a 9 string elements list
-  std::vector<std::string> x = __split(argsString, ',');
-  bool containsList = (argsString.find('[') != std::string::npos);
-  if (containsList) {
-    std::vector<int> listBeginIndices, listEndIndices;
-    for (int pos = 0; pos < x.size(); ++pos) {
-      if (x[pos][0] == '[')
-        listBeginIndices.push_back(pos);
-      else if (x[pos][x[pos].size()-1] == ']')
-        listEndIndices.push_back(pos);
-    }
-    std::vector<std::string> extractedArgs;
-    int start = 0;
-    for (int pos = 0; pos < listBeginIndices.size(); ++pos) {
-      int lbeg = listBeginIndices[pos];
-      int lend = listEndIndices[pos];
-      if (lbeg > start)
-        for (int k = start; k < lbeg; ++k)
-          extractedArgs.push_back(x[k]);
-      extractedArgs.push_back(__join(x, lbeg, lend+1));
-      start = lend+1;
-    }
-    if (start < x.size())
-      for (int k = start; k < x.size(); ++k)
-        extractedArgs.push_back(x[k]);
-    return extractedArgs;
-  }
-  else {
-    return x;
-  }
-}
-
-/*!
-  \brief Compile Python command and evaluate it in the
-         python dictionary context if possible. Command might correspond to
-         the execution of a script with optional arguments.
-         In this case, command is:
-         execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
-  \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 * global_ctxt, PyObject * local_ctxt)
-{
-  // First guess if command is execution of a script with args, or a simple Python command
-  std::string singleCommand = command;
-  std::string commandArgs = "";
-
-  QRegExp rx("execfile\\s*\\(.*(args:.*)\"\\s*\\)");
-  if (rx.indexIn(command) != -1) {
-    commandArgs = rx.cap(1).remove(0,5).toStdString(); // arguments of command
-    singleCommand = rx.cap().remove(rx.cap(1)).remove(" ").toStdString(); // command for execution without arguments
-  }
-
-  if (commandArgs.empty()) {
-    // process command: expression
-    // process command: execfile(r"/absolute/path/to/script.py") (no args)
-    return run_command(singleCommand.c_str(), global_ctxt, local_ctxt);
-  }
-  else {
-    // process command: execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
-    std::string script = singleCommand.substr(11); // remove leading execfile(r"
-    script = script.substr(0, script.length()-2); // remove trailing ")
-    std::vector<std::string> argList = __getArgsList(commandArgs);
-
-    std::string preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=[";
-    std::string preCommandEnd = "];";
-    std::string completeCommand = preCommandBegin+"\""+script+"\",";
-    for (std::vector<std::string>::iterator itr = argList.begin(); itr != argList.end(); ++itr) {
-      if (itr != argList.begin())
-        completeCommand += ",";
-      completeCommand = completeCommand + "\"" + *itr + "\"";
-    }
-    completeCommand = completeCommand+preCommandEnd+singleCommand+";sys.argv=save_argv";
-    return run_command(completeCommand.c_str(), global_ctxt, local_ctxt);
-  }
-}
-
-/*!
-  \brief Run Python command - the command has to fit on a single line (no \n!).
-  Use ';' if you need multiple statements evaluated at once.
-  \param command Python command
-  \return command status
-*/
-int PyInterp_Interp::run(const char *command)
-{
-  beforeRun();
-  int ret = simpleRun(command);
-  afterRun();
-  return ret;
-}
-
-/**
- * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability
- * to acquire GIL if needed.
- */
-int PyInterp_Interp::beforeRun()
-{
-  return 0;
-}
-
-/**
- * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsability
- * to acquire GIL if needed.
- */
-int PyInterp_Interp::afterRun()
-{
-  return 0;
-}
-
-/*!
-  \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability.
-  \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();
-  }
-
-  // Current stdout and stderr are saved
-  PyObject * oldOut = PySys_GetObject((char*)"stdout");
-  PyObject * oldErr = PySys_GetObject((char*)"stderr");
-  // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
-  Py_INCREF(oldOut);
-  Py_INCREF(oldErr);
-
-  // Redirect outputs to SALOME Python console before treatment
-  PySys_SetObject((char*)"stderr",_verr);
-  PySys_SetObject((char*)"stdout",_vout);
-
-  int ier = compile_command(command, _global_context, _local_context);
-
-  // Outputs are redirected to what they were before
-  PySys_SetObject((char*)"stdout",oldOut);
-  PySys_SetObject((char*)"stderr",oldErr);
-
-  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;
-}
-
-/*!
-  \bried Check if the interpreter is initialized
-  \internal
-*/
-bool PyInterp_Interp::initialized() const
-{
-  return _initialized;
-}
diff --git a/src/PyInterp/PyInterp_Interp.h b/src/PyInterp/PyInterp_Interp.h
deleted file mode 100644 (file)
index 88e5519..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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   : PyInterp_Interp.h
-//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
-
-#ifndef PYINTERP_INTERP_H
-#define PYINTERP_INTERP_H
-
-#include "PyInterp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
-#include "PyInterp_Utils.h"
-
-#include <list>
-#include <string>
-
-typedef void PyOutChanged(void* data,char * c);
-
-typedef struct {
-  PyObject_HEAD
-  int softspace;
-  PyOutChanged* _cb;
-  void* _data;
-  bool _iscerr;
-} PyStdOut;
-
-/**
- * Main class representing a *virtual* Python interpreter. There is really only one true
- * Python interpreter in the whole application (no call to Py_NewInterpreter),
- * but the use of different execution contexts allow
- * to split the execution lines, and hence to emulate (relatively) independent interpreters.
- * This has some consequences: modules imported in one context are not re-imported in another context
- * (only there namespace is made available when importing in another context).
- * See also class PyConsole_Interp.
- */
-class PYINTERP_EXPORT PyInterp_Interp
-{
-public:
-  static int _argc;
-  static char* _argv[];
-  
-  PyInterp_Interp();
-  virtual ~PyInterp_Interp();
-  
-  void initialize();
-  void destroy();
-
-  virtual int run(const char *command); 
-  virtual void initStudy() {};
-
-  std::string getBanner() const;
-  void setverrcb(PyOutChanged*, void*);
-  void setvoutcb(PyOutChanged*, void*);
-
-  const char* getPrevious();
-  const char* getNext();
-
-protected:
-  /** Redirection of stdout and stderr */
-  PyObject* _vout;
-  PyObject* _verr;
-  /** Execution context (local and global variables) */
-  PyObject* _global_context;
-  PyObject* _local_context;
-
-  std::list<std::string> _history;
-  std::list<std::string>::iterator _ith;
-
-  virtual int beforeRun();
-  virtual int afterRun();
-  int simpleRun(const char* command, const bool addToHistory = true);
-
-  virtual void initPython();
-
-  /** Initialize execution context. */
-  virtual bool initContext();
-  virtual bool initRun();
-  virtual void closeContext();
-
-  bool initialized() const;
-
-private:
-  bool _initialized;
-};
-
-#endif // PYINTERP_INTERP_H
diff --git a/src/PyInterp/PyInterp_Request.cxx b/src/PyInterp/PyInterp_Request.cxx
deleted file mode 100644 (file)
index f8227f0..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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   : PyInterp_Request.h
-//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
-
-#include "PyInterp_Request.h"
-#include "PyInterp_Utils.h"
-
-#include <QCoreApplication>
-
-void PyInterp_Request::process()
-{
-  safeExecute();
-
-  bool isSync = IsSync();
-
-  if ( !isSync )
-    myMutex.lock();
-
-  if ( listener() )
-    processEvent( listener() );
-
-  if ( !isSync )
-    myMutex.unlock();
-}
-
-void PyInterp_Request::safeExecute()
-{
-  execute();
-}
-
-void PyInterp_Request::Destroy( PyInterp_Request* request )
-{
-  // Lock and unlock the mutex to avoid errors on its deletion
-  request->myMutex.lock();
-  request->myMutex.unlock();
-  delete request;
-}
-
-QEvent* PyInterp_Request::createEvent()
-{
-  return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, this );
-}
-
-void PyInterp_Request::processEvent( QObject* o )
-{
-  if ( !o )
-    return;
-
-  QEvent* e = createEvent();
-  if ( !e )
-    return;
-
-  if ( !IsSync() )
-    QCoreApplication::postEvent( o, e );
-  else
-  {
-    QCoreApplication::sendEvent( o, e );
-    delete e;
-  }
-}
-
-void PyInterp_Request::setListener( QObject* o )
-{
-  myMutex.lock();
-  myListener = o;
-  myMutex.unlock();
-}
-
-void PyInterp_LockRequest::safeExecute()
-{
-  PyLockWrapper aLock; // Acquire GIL
-  execute();
-}
diff --git a/src/PyInterp/PyInterp_Request.h b/src/PyInterp/PyInterp_Request.h
deleted file mode 100644 (file)
index cabb3d6..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-// 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   : PyInterp_Request.h
-//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
-
-#ifndef PYINTERP_REQUEST_H
-#define PYINTERP_REQUEST_H
-
-#include "PyInterp.h"
-#include "PyInterp_Event.h"
-
-#include <QMutex>
-
-class QObject;
-class PyInterp_Interp;
-
-/**
-   \class PyInterp_Request
-   \brief Base Python interpreter request; does not not acquire GIL during execution.
- */
-class PYINTERP_EXPORT PyInterp_Request
-{
-  friend class PyInterp_Dispatcher;
-
-private:
-  PyInterp_Request();
-  PyInterp_Request( const PyInterp_Request& );
-
-protected:
-  // protected destructor - to control deletion of requests
-  virtual ~PyInterp_Request() {};
-
-public:
-  // Constructor
-  PyInterp_Request( QObject* listener, bool sync = true )
-    : myIsSync( sync ), myListener( listener ) {};
-
-  // Deletes a request
-  static void     Destroy( PyInterp_Request* );
-
-  // Returns true if this request should be processed synchronously,
-  // without putting it to a queue
-  bool            IsSync() const { return myIsSync; }
-
-protected:
-  // Performs safe execution of the request
-  virtual void    safeExecute();
-
-  // Should be redefined in successors, contains actual request code
-  virtual void    execute() = 0;
-
-  // This method can be overridden to customize notification event creation
-  virtual QEvent* createEvent();
-
-  virtual void    processEvent( QObject* );
-
-  // Provide access to the listener of this request
-  QObject*        listener() const { return myListener; }
-  void            setListener( QObject* );
-
-private:
-  // Process request, invoked from Dispatcher
-  void            process();
-
-private:
-  QMutex          myMutex;
-  bool            myIsSync;
-  QObject*        myListener;
-};
-
-/**
-   \class PyInterp_LockRequest
-   \brief Python interpreter request; automatically acquires GIL during execution.
- */
-class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request
-{
-public:
-  // Constructor
-  PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener=0, bool sync=true )
-    : PyInterp_Request( listener, sync ), myInterp( interp )
-  {}
-
-protected:
-  // Get interpreter
-  PyInterp_Interp*  getInterp() const { return myInterp; }
-
-  // Performs safe execution of the request
-  virtual void      safeExecute();
-
-private:
-  PyInterp_Interp*  myInterp;
-};
-
-#endif // PYINTERP_REQUEST_H
diff --git a/src/PyInterp/PyInterp_Utils.h b/src/PyInterp/PyInterp_Utils.h
deleted file mode 100644 (file)
index 8d6ce8c..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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   : PyInterp_Utils.h
-//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
-
-#ifndef PYINTERP_UTILS_H
-#define PYINTERP_UTILS_H
-
-#include "PyInterp.h"
-
-#ifdef _DEBUG_
-  #include <iostream>
-#endif
-
-/**
- * \class PyLockWrapper
- * \brief Python GIL wrapper.
- *
- * Utility class wrapping the Python GIL acquisition. This makes use of the high level
- * API (PyGILState_Ensure and PyGILState_Release), and is hence compatible with only
- * one running Python interpreter (no call to Py_NewInterpreter()).
- * When the class is instanciated the lock is acquired. It is released at destruction time.
- * Copy construction (and hence assignation) is forbidden.
- */
-class PYINTERP_EXPORT PyLockWrapper
-{
-public:
-  /**
-   * \brief Constructor. Automatically acquires GIL.
-   */
-  PyLockWrapper()
-  {
-    _gil_state = PyGILState_Ensure();
-    // Save current thread state for later comparison
-    _state = PyGILState_GetThisThreadState();
-  }
-
-  /**
-   * \brief Destructor. Automatically releases GIL.
-   */
-  ~PyLockWrapper()
-  {
-    PyThreadState* _currState = PyGILState_GetThisThreadState();
-#ifdef _DEBUG_
-    if (_currState != _state)
-    {
-      std::cout << "!!!!!!!!! PyLockWrapper inconsistency - now entering infinite loop for debugging\n";
-      while(1);
-    }
-#endif
-    PyGILState_Release(_gil_state);
-  }
-
-private:
-  PyGILState_STATE _gil_state;
-  PyThreadState* _state;
-
-  // "Rule of 3" - Forbid usage of copy operator and copy-constructor
-  PyLockWrapper(const PyLockWrapper & another);
-  const PyLockWrapper & operator=(const PyLockWrapper & another);
-};
-
-/**
- * \class PyObjWrapper
- * \brief Utility class to properly handle the reference counting required on Python objects.
- */
-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;
-  }
-};
-
-#endif // PYINTERP_UTILS_H
index a9d20317bce020747a3b4089dbaa726ce2f71916..ded75b88fcc4052e14f2997cdbb6ca21cb0ca351 100755 (executable)
@@ -35,12 +35,12 @@ INCLUDE_DIRECTORIES(
   ${OMNIORB_INCLUDE_DIR}
   ${PROJECT_SOURCE_DIR}/src/CAM
   ${PROJECT_SOURCE_DIR}/src/LightApp
-  ${PROJECT_SOURCE_DIR}/src/PyInterp
   ${PROJECT_SOURCE_DIR}/src/Qtx
   ${PROJECT_SOURCE_DIR}/src/SALOME_PYQT/SALOME_PYQT_GUILight
   ${PROJECT_SOURCE_DIR}/src/STD
   ${PROJECT_SOURCE_DIR}/src/SUIT
   ${PROJECT_SOURCE_DIR}/src/SalomeApp
+  ${PROJECT_SOURCE_DIR}/tools/PyInterp/src
 )
 
 # additional preprocessor / compiler flags
@@ -85,7 +85,6 @@ SET(_other_SOURCES SALOME_PYQT_Module.cxx)
 SET(SalomePyQtGUI_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
 
 # --- rules ---
-
 ADD_LIBRARY(SalomePyQtGUI ${SalomePyQtGUI_SOURCES})
 TARGET_LINK_LIBRARIES(SalomePyQtGUI ${_link_LIBRARIES})
 INSTALL(TARGETS SalomePyQtGUI DESTINATION ${SALOME_INSTALL_LIBS})
index ec02263954a7a38bba97fd31e004204dc987d0c8..5c452c83f8c84aa9746d4fd650ae5a4e2b7425da 100755 (executable)
@@ -39,13 +39,13 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/LightApp
   ${PROJECT_SOURCE_DIR}/src/OCCViewer
   ${PROJECT_SOURCE_DIR}/src/Plot2d
-  ${PROJECT_SOURCE_DIR}/src/PyConsole
-  ${PROJECT_SOURCE_DIR}/src/PyInterp
   ${PROJECT_SOURCE_DIR}/src/Qtx
   ${PROJECT_SOURCE_DIR}/src/STD
   ${PROJECT_SOURCE_DIR}/src/SUIT
   ${PROJECT_SOURCE_DIR}/src/SUITApp
   ${PROJECT_SOURCE_DIR}/src/ObjBrowser
+  ${PROJECT_SOURCE_DIR}/tools/PyConsole/src
+  ${PROJECT_SOURCE_DIR}/tools/PyInterp/src
 )
 
 # additional preprocessor / compiler flags
index 3b2114600aa0004a20750fe6198f7275e43817e3..3756b7ce8fd74023f79de270194886035112c048 100755 (executable)
@@ -40,12 +40,12 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/LogWindow
   ${PROJECT_SOURCE_DIR}/src/OBJECT
   ${PROJECT_SOURCE_DIR}/src/ObjBrowser
-  ${PROJECT_SOURCE_DIR}/src/PyInterp
-  ${PROJECT_SOURCE_DIR}/src/PyConsole
   ${PROJECT_SOURCE_DIR}/src/Qtx
   ${PROJECT_SOURCE_DIR}/src/SALOME_PYQT/SALOME_PYQT_GUILight
   ${PROJECT_SOURCE_DIR}/src/STD
   ${PROJECT_SOURCE_DIR}/src/SUIT
+  ${PROJECT_SOURCE_DIR}/tools/PyInterp/src
+  ${PROJECT_SOURCE_DIR}/tools/PyConsole/src
 )
 
 IF(SALOME_USE_OCCVIEWER)
index bf2fd39116c8ef2d5547608c09af1e1cae89e0f9..d65ba0b38f2ad862a34100d2819091114cf510bb 100755 (executable)
@@ -56,8 +56,8 @@ INCLUDE_DIRECTORIES(
 IF(SALOME_USE_PYCONSOLE)
   INCLUDE_DIRECTORIES(
     ${PYTHON_INCLUDE_DIRS}
-    ${PROJECT_SOURCE_DIR}/src/PyConsole
-    ${PROJECT_SOURCE_DIR}/src/PyInterp
+    ${PROJECT_SOURCE_DIR}/tools/PyConsole/src
+    ${PROJECT_SOURCE_DIR}/tools/PyInterp/src
   )
 ENDIF()
 
diff --git a/tools/PyConsole/CMakeLists.txt b/tools/PyConsole/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a2ce72f
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (C) 2015-2016  CEA/DEN, EDF 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, 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
+#
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
+PROJECT(PyConsole C CXX)
+
+# Versioning
+# ===========
+# Project name, upper case
+STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC)
+
+###################
+# To be changed once externalized CMake procedure:
+SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL")
+IF(EXISTS ${KERNEL_ROOT_DIR})
+  LIST(APPEND CMAKE_MODULE_PATH "${KERNEL_ROOT_DIR}/salome_adm/cmake_files")
+  INCLUDE(SalomeMacros)
+ELSE(EXISTS ${KERNEL_ROOT_DIR})
+  MESSAGE(FATAL_ERROR "We absolutely need a Salome KERNEL, please define KERNEL_ROOT_DIR")
+ENDIF(EXISTS ${KERNEL_ROOT_DIR})
+# From GUI - again to be changed once externalized:
+LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../adm_local/cmake_files")
+###################
+
+# Platform setup
+# ==============
+INCLUDE(SalomeSetupPlatform)
+
+#
+# Set list of prerequisites
+# =========================
+
+FIND_PACKAGE(SalomePythonInterp REQUIRED)
+FIND_PACKAGE(SalomePythonLibs REQUIRED)
+FIND_PACKAGE(SalomeQt4 REQUIRED)
+
+# Detection report
+SALOME_PACKAGE_REPORT_AND_CHECK()
+
+# Directories
+#
+# Directories have to be given after prerequisites (to be able to use
+# Python version string for example).
+# ===========
+SET(PYCONSOLE_INSTALL_LIBS lib CACHE PATH "Install path: PyConsole libs")
+SET(PYCONSOLE_INSTALL_HEADERS include CACHE PATH "Install path: PyConsole headers")
+
+SET(PYCONSOLE_INSTALL_RES share/resources CACHE PATH "Install path: PyConsole resources")
+
+# Tool dependencies
+# =================
+# PyConsole depends on PyInterp:
+SET(PYINTERP_INSTALL_LIBS "${PYCONSOLE_INSTALL_LIBS}")
+SET(PYINTERP_INSTALL_HEADERS "${PYCONSOLE_INSTALL_HEADERS}")
+SET(PYINTERP_INSTALL_RES "${PYCONSOLE_INSTALL_RES}")
+
+ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/../PyInterp ${PROJECT_BINARY_DIR}/PyInterp)
+INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/../PyInterp/src)
+
+# Sources
+# ========
+ADD_SUBDIRECTORY(src)
+
diff --git a/tools/PyConsole/src/CMakeLists.txt b/tools/PyConsole/src/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..113f808
--- /dev/null
@@ -0,0 +1,89 @@
+# Copyright (C) 2012-2016  CEA/DEN, EDF R&D, 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
+#
+
+INCLUDE(UseQtExt)
+
+# --- options ---
+
+# additional include directories
+INCLUDE_DIRECTORIES(
+  ${QT_INCLUDES}
+  ${PYTHON_INCLUDE_DIRS}
+  ${PROJECT_SOURCE_DIR}/src/PyInterp
+)
+
+# additional preprocessor / compiler flags
+ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
+
+# libraries to link to
+SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} PyInterp)
+
+# --- headers ---
+
+# header files / to be processed by moc
+SET(_moc_HEADERS
+  PyConsole_Console.h
+  PyConsole_Editor.h
+)
+
+# header files / no moc processing
+SET(_other_HEADERS
+  PyConsole.h
+  PyConsole_Event.h
+  PyConsole_Interp.h
+  PyConsole_Request.h
+)
+
+# header files / to install
+SET(PyConsole_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
+
+# --- resources ---
+
+# resource files / to be processed by lrelease
+SET(_ts_RESOURCES
+  resources/PyConsole_msg_en.ts
+  resources/PyConsole_msg_fr.ts
+  resources/PyConsole_msg_ja.ts
+)
+
+# --- sources ---
+
+# sources / moc wrappings
+QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS})
+
+# sources / static
+SET(_other_SOURCES
+  PyConsole_Console.cxx
+  PyConsole_Event.cxx
+  PyConsole_Interp.cxx
+  PyConsole_Request.cxx
+  PyConsole_Editor.cxx
+)
+
+# sources / to compile
+SET(PyConsole_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
+
+# --- rules ---
+
+ADD_LIBRARY(PyConsole ${PyConsole_SOURCES})
+TARGET_LINK_LIBRARIES(PyConsole ${_link_LIBRARIES})
+INSTALL(TARGETS PyConsole EXPORT ${TOOLS_EXPORT_NAME}TargetGroup DESTINATION ${PYCONSOLE_INSTALL_LIBS})
+
+INSTALL(FILES ${PyConsole_HEADERS} DESTINATION ${PYCONSOLE_INSTALL_HEADERS})
+QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${PYCONSOLE_INSTALL_RES}")
diff --git a/tools/PyConsole/src/PyConsole.h b/tools/PyConsole/src/PyConsole.h
new file mode 100644 (file)
index 0000000..4c72bdf
--- /dev/null
@@ -0,0 +1,47 @@
+// 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   : 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
+#  if defined PYCONSOLE_EXPORTS || defined PyConsole_EXPORTS
+#    define PYCONSOLE_EXPORT __declspec(dllexport)
+#  else
+#    define PYCONSOLE_EXPORT __declspec(dllimport)
+#  endif
+#else   // WIN32
+#  define PYCONSOLE_EXPORT
+#endif  // WIN32
+
+// ========================================================
+// avoid warning messages
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#pragma warning (disable : 4251)
+#endif
+
+#endif // PYCONSOLE_H
diff --git a/tools/PyConsole/src/PyConsole_Console.cxx b/tools/PyConsole/src/PyConsole_Console.cxx
new file mode 100644 (file)
index 0000000..3aaa52c
--- /dev/null
@@ -0,0 +1,383 @@
+// 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   : PyConsole_Console.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+
+#include "PyConsole_Console.h"
+#include "PyConsole_Interp.h"
+#include "PyConsole_Editor.h"
+
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
+#include <QContextMenuEvent>
+#include <QMenu>
+#include <QVBoxLayout>
+
+/*!
+  \class PyConsole_Console
+  \brief Python console widget.
+
+  To create a Python console, just use default contstructor, specifying only a parent widget:
+  \code
+  PyConsole_Console c(myWindow);
+  \endcode
+
+  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:
+  \code
+  PyConsole_Interp* interp = new PyConsole_Interp();
+  interp->initialize();
+  PyConsole_Console c(myWindow, new MyEditor(interp));
+  \endcode
+*/  
+
+/*!
+  \brief Constructor.
+
+  Creates new python console widget.
+  \param parent parent widget
+  \param interp python interpreter
+*/
+PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Editor* editor )
+: QWidget( parent )
+{
+  // initialize Python interpretator
+  PyConsole_Interp* interp = editor ? editor->getInterp() : new PyConsole_Interp();
+  interp->initialize();
+  
+  // create editor console
+  QVBoxLayout* lay = new QVBoxLayout( this );
+  lay->setMargin( 0 );
+  myEditor = editor ? editor : new PyConsole_Editor( interp, this );
+  myEditor->setContextMenuPolicy( Qt::NoContextMenu );
+  lay->addWidget( myEditor );
+
+  // force synchronous mode
+  QString synchronous = qgetenv( "PYTHON_CONSOLE_SYNC" );
+  if ( !synchronous.isEmpty() && synchronous.toInt() > 0 )
+    setIsSync( true );
+
+  // create actions
+  createActions();
+}
+
+/*!
+  \brief Destructor.
+*/
+PyConsole_Console::~PyConsole_Console()
+{
+}
+
+/*!
+  \brief Get Python interpreter
+  \return pointer to Python interpreter
+*/
+PyConsole_Interp* PyConsole_Console::getInterp() const
+{
+  return myEditor ? myEditor->getInterp() : 0;
+}
+
+/*!
+  \brief Execute python command in the interpreter.
+  \param command string with command and arguments
+*/
+void PyConsole_Console::exec( const QString& command )
+{
+  if ( myEditor )
+    myEditor->exec( command );
+}
+
+/*!
+  \brief Execute python command in the interpreter 
+         and wait until it is finished.
+  
+  Block execution of main application until the python command is executed.
+  \param command string with command and arguments
+*/
+void PyConsole_Console::execAndWait( const QString& command )
+{
+  if ( myEditor )
+    myEditor->execAndWait( command );
+}
+
+/*!
+  \brief Get synchronous mode flag value.
+  
+  \sa setIsSync()
+  \return \c true if python console works in synchronous mode
+*/
+bool PyConsole_Console::isSync() const
+{
+  return myEditor ? myEditor->isSync() : false;
+}
+
+/*!
+  \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 )
+{
+  if ( myEditor ) 
+    myEditor->setIsSync( on );
+}
+
+/*!
+  \brief Get suppress output flag value.
+  
+  \sa setIsSuppressOutput()
+  \return \c true if python console output is suppressed.
+*/
+bool PyConsole_Console::isSuppressOutput() const
+{
+  return myEditor ? myEditor->isSuppressOutput() : false;
+}
+
+/*!
+  \brief Set suppress output flag value.
+
+  In case if suppress output flag is \c true, the python 
+  console output suppressed.
+
+  \param on suppress output flag
+*/
+void PyConsole_Console::setIsSuppressOutput( const bool on )
+{
+  if ( myEditor )
+    myEditor->setIsSuppressOutput( on );
+}
+
+/*!
+  \brief Get 'show banner' flag value.
+  
+  \sa setIsShowBanner()
+  \return \c true if python console shows banner
+*/
+bool PyConsole_Console::isShowBanner() const
+{
+  return myEditor ? myEditor->isShowBanner() : false;
+}
+
+/*!
+  \brief Set 'show banner' flag value.
+
+  The banner is shown in the top of the python console window.
+
+  \sa isShowBanner()
+  \param on 'show banner' flag
+*/
+void PyConsole_Console::setIsShowBanner( const bool on )
+{
+  if ( myEditor )
+    myEditor->setIsShowBanner( on );
+}
+
+/*!
+  \brief Returns \c true if auto-completion feature is switched on
+  or \c false otherwise
+  \sa setAutoCompletion()
+*/
+bool PyConsole_Console::autoCompletion() const
+{
+  return myEditor ? myEditor->autoCompletion() : false;
+}
+
+/*!
+  \brief Switch on/off commands auto-completion feature
+  \sa autoCompletion()
+*/
+void PyConsole_Console::setAutoCompletion( const bool on )
+{
+  if ( myEditor )
+    myEditor->setAutoCompletion( on );
+}
+
+/*!
+  \brief Change the python console's font.
+  \param f new font
+*/
+void PyConsole_Console::setFont( const QFont& f )
+{
+  if ( myEditor )
+    myEditor->setFont( f );
+}
+
+/*!
+  \brief Get python console font.
+  \return current python console font
+*/
+QFont PyConsole_Console::font() const
+{
+  return myEditor ? myEditor->font() : QFont();
+}
+
+/*!
+  \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 )
+{
+  myActions[CopyId]->setVisible( flags & CopyId );
+  myActions[PasteId]->setVisible( flags & PasteId );
+  myActions[ClearId]->setVisible( flags & ClearId );
+  myActions[SelectAllId]->setVisible( flags & SelectAllId );
+  myActions[DumpCommandsId]->setVisible( flags & DumpCommandsId );
+  myActions[StartLogId]->setVisible( flags & StartLogId );
+  myActions[StopLogId]->setVisible( flags & StopLogId );
+}
+
+/*!
+  \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 );
+  ret = ret | ( myActions[DumpCommandsId]->isVisible() ? DumpCommandsId : 0 );
+  ret = ret | ( myActions[StartLogId]->isVisible() ? StartLogId : 0 );
+  ret = ret | ( myActions[StopLogId]->isVisible() ? StopLogId : 0 );
+  return ret;
+}
+
+/*!
+  \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 );
+
+  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 );
+  
+  a = new QAction( tr( "EDIT_DUMPCOMMANDS_CMD" ), this );
+  a->setStatusTip( tr( "EDIT_DUMPCOMMANDS_CMD" ) );
+  connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( dump() ) );
+  myActions.insert( DumpCommandsId, a );
+
+  a = new QAction( tr( "EDIT_STARTLOG_CMD" ), this );
+  a->setStatusTip( tr( "EDIT_STARTLOG_CMD" ) );
+  connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( startLog() ) );
+  myActions.insert( StartLogId, a );
+
+  a = new QAction( tr( "EDIT_STOPLOG_CMD" ), this );
+  a->setStatusTip( tr( "EDIT_STOPLOG_CMD" ) );
+  connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( stopLog() ) );
+  myActions.insert( StopLogId, a );
+}
+
+/*!
+  \brief Update menu actions.
+
+  Update context popup menu action state.
+*/
+void PyConsole_Console::updateActions()
+{
+  myActions[CopyId]->setEnabled( myEditor && myEditor->textCursor().hasSelection() );
+  myActions[PasteId]->setEnabled( myEditor && !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
+  myActions[SelectAllId]->setEnabled( myEditor && !myEditor->document()->isEmpty() );
+}
+
+/*!
+  \brief Start python trace logging
+  \param fileName the path to the log file
+*/
+void PyConsole_Console::startLog( const QString& fileName )
+{
+  if ( myEditor ) 
+    myEditor->startLog( fileName );
+}
+
+/*!
+  \brief Stop python trace logging
+*/
+void PyConsole_Console::stopLog()
+{
+  if ( myEditor ) 
+    myEditor->stopLog();
+}
+
+/*!
+  \brief Process context popup menu request
+
+  Show the context popup menu.
+
+  \param event context popup menu event
+*/
+void PyConsole_Console::contextMenuEvent( QContextMenuEvent* event )
+{
+  if ( !myEditor || myEditor->isReadOnly() )
+    return;
+
+  QMenu* menu = new QMenu( this );
+  menu->addAction( myActions[CopyId] );
+  menu->addAction( myActions[PasteId] );
+  menu->addAction( myActions[ClearId] );
+  menu->addSeparator();
+  menu->addAction( myActions[SelectAllId] );
+  menu->addSeparator();
+  menu->addAction( myActions[DumpCommandsId] );
+  if ( !myEditor->isLogging() )
+    menu->addAction( myActions[StartLogId] );
+  else
+    menu->addAction( myActions[StopLogId] );
+
+  updateActions();
+
+  menu->exec( event->globalPos());
+
+  delete menu;
+}
diff --git a/tools/PyConsole/src/PyConsole_Console.h b/tools/PyConsole/src/PyConsole_Console.h
new file mode 100644 (file)
index 0000000..e0b111e
--- /dev/null
@@ -0,0 +1,97 @@
+// 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   : 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 <QWidget>
+#include <QMap>
+
+class QMenu;
+
+class PyConsole_Interp;
+class PyConsole_Editor;
+
+class PYCONSOLE_EXPORT PyConsole_Console : public QWidget
+{
+  Q_OBJECT
+
+public:
+  //! Context popup menu actions flags
+  enum
+  {
+    CopyId         = 0x01,  //!< "Copy" menu action
+    PasteId        = 0x02,  //!< "Paste" menu action
+    ClearId        = 0x04,  //!< "Clear" menu action
+    SelectAllId    = 0x08,  //!< "Select All" menu action
+    DumpCommandsId = 0x10,  //!< "DumpCommands" menu action
+    StartLogId     = 0x20,  //!< "Start log" menu action
+    StopLogId      = 0x40,  //!< "Stop log" menu action
+    All            = 0xFF,  //!< all menu actions 
+  };
+
+public:
+  PyConsole_Console( QWidget* parent, PyConsole_Editor* editor = 0 );
+  virtual ~PyConsole_Console();
+
+  PyConsole_Interp*   getInterp() const;
+
+  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:
+  void                createActions();
+  void                updateActions();
+
+  virtual void        contextMenuEvent( QContextMenuEvent* );
+
+protected:
+  PyConsole_Editor*   myEditor;    //!< python console editor widget
+  QMap<int, QAction*> myActions;   //!< menu actions list
+};
+
+#endif // PYCONSOLE_CONSOLE_H
diff --git a/tools/PyConsole/src/PyConsole_Editor.cxx b/tools/PyConsole/src/PyConsole_Editor.cxx
new file mode 100644 (file)
index 0000000..7d540f6
--- /dev/null
@@ -0,0 +1,1700 @@
+// 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   : PyConsole_Editor.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+
+/*!
+  \class PyConsole_Editor
+  \brief Python command line interpreter front-end GUI widget.
+  
+  This class provides simple GUI interface to the Python interpreter, including basic 
+  navigation operations, executing commands (both interactively and programmatically), 
+  copy-paste operations, history of the commands and so on.
+
+  Here below is the shortcut keyboard boundings used for navigation and other operations:
+  - <Enter>              : execute current command
+  - <Ctrl><Break>        : clear current command
+  - <Escape>             : clear current command
+  - <Up>                 : previous command in the history
+  - <Shift><Up>          : move cursor one row up with selection
+  - <Ctrl><Up>           : move cursor one row up without selection
+  - <Ctrl><Shift><Up>    : move cursor one row up with selection
+  - <Down>               : next command in the history
+  - <Shift><Down>        : move cursor one row down with selection
+  - <Ctrl><Down>         : move cursor one row down without selection
+  - <Ctrl><Shift><Down>  : move cursor one row down with selection
+  - <Left>               : move one symbol left without selection
+  - <Shift><Left>        : move one symbol left with selection
+  - <Ctrl><Left>         : move one word left without selection
+  - <Ctrl><Shift><Left>  : move one word left with selection
+  - <Right>              : move one symbol right without selection
+  - <Shift><Right>       : move one symbol right with selection
+  - <Ctrl><Right>        : move one word right without selection
+  - <Ctrl><Shift><Right> : move one word right with selection
+  - <PgUp>               : first command in the history
+  - <Shift><PgUp>        : move one page up with selection
+  - <Ctrl><PgUp>         : move one page up without selection
+  - <Ctrl><Shift><PgUp>  : scroll one page up
+  - <PgDn>               : last command in the history
+  - <Shift><PgDn>        : move one page down with selection
+  - <Ctrl><PgDn>         : move one page down without selection
+  - <Ctrl><Shift><PgDn>  : scroll one page down
+  - <Home>               : move to the beginning of the line without selection
+  - <Shift><Home>        : move to the beginning of the line with selection
+  - <Ctrl><Home>         : move to the very first symbol without selection
+  - <Ctrl><Shift><Home>  : move to the very first symbol with selection
+  - <End>                : move to the end of the line without selection
+  - <Shift><End>         : move to the end of the line with selection
+  - <Ctrl><End>          : move to the very last symbol without selection
+  - <Ctrl><Shift><End>   : move to the very last symbol with selection
+  - <Backspace>          : delete symbol before the cursor
+                           / remove selected text and put it to the clipboard (cut)
+  - <Shift><Backspace>   : delete previous word
+                           / remove selected text and put it to the clipboard (cut)
+  - <Ctrl><Backspace>    : delete text from the cursor to the beginning of the line 
+                           / remove selected text and put it to the clipboard (cut)
+  - <Delete>             : delete symbol after the cursor 
+                           / remove selected text and put it to the clipboard (cut)
+  - <Shift><Delete>      : delete next word
+                           / remove selected text and put it to the clipboard (cut)
+  - <Ctrl><Delete>       : delete text from the cursor to the end of the line
+                           / remove selected text and put it to the clipboard (cut)
+  - <Ctrl><Insert>       : copy
+  - <Shift><Insert>      : paste
+  - <Ctrl><V>            : paste
+  - <Ctrl><C>            : copy
+  - <Ctrl><X>            : cut
+  - <Ctrl><V>            : paste
+  - <Tab>                : performs auto-completion
+  - <Ctrl><Tab>          : undoes auto-completion
+*/
+
+#include "PyConsole_Editor.h"
+#include "PyConsole_Interp.h"
+#include "PyConsole_Event.h"
+#include "PyInterp_Dispatcher.h"
+#include "PyConsole_Request.h"
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDropEvent>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMimeData>
+#include <QMouseEvent>
+#include <QScrollBar>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextStream>
+#include <QChar>
+#include <QFileDialog>
+#include <QMessageBox>
+
+//VSR: uncomment below macro to support unicode text properly in SALOME
+//     current commented out due to regressions
+//#define PAL22528_UNICODE
+
+namespace
+{
+  QString fromUtf8( const char* txt )
+  {
+#ifdef PAL22528_UNICODE
+    return QString::fromUtf8( txt );
+#else
+    return QString( txt );
+#endif
+  }
+}
+
+static QString READY_PROMPT = ">>> ";
+static QString DOTS_PROMPT  = "... ";
+
+void staticCallbackStdout( void* data, char* c )
+{
+  if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
+    PyConsole_Editor* e = (PyConsole_Editor*)data;
+    QApplication::postEvent( e, new PyConsole_PrintEvent( fromUtf8(c), false ) );
+  }
+}
+
+void staticCallbackStderr( void* data, char* c )
+{
+  if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
+    PyConsole_Editor* e = (PyConsole_Editor*)data;
+    QApplication::postEvent( e, new PyConsole_PrintEvent( fromUtf8(c), true ) );
+  }
+}
+
+/*!
+  \brief 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 )
+{
+  setFont( QFont( "Courier", 11 ) ); // default font
+  setUndoRedoEnabled( false );
+
+  myPrompt = READY_PROMPT;
+  setLineWrapMode( QTextEdit::WidgetWidth );
+  setWordWrapMode( QTextOption::WrapAnywhere );
+  setAcceptRichText( false );
+
+  // set callbacks to interpeter
+  myInterp->setvoutcb( staticCallbackStdout, this );
+  myInterp->setverrcb( staticCallbackStderr, this );
+  // print banner
+  if ( isShowBanner() )
+    addText( banner() );
+  // clear command buffer
+  myCommandBuffer.truncate(0);
+  // unset read-only state
+  setReadOnly( false );
+  // unset history browsing mode
+  myCmdInHistory = -1;
+  // add prompt
+  addText( myPrompt );
+  // unset busy cursor
+  viewport()->unsetCursor();
+}
+
+/*!
+  \brief Destructor.
+*/
+PyConsole_Editor::~PyConsole_Editor()
+{
+  myInterp = 0;
+}
+
+/*!
+  \brief Get Python interpreter
+*/
+PyConsole_Interp* PyConsole_Editor::getInterp() const
+{
+  return myInterp;
+}
+
+/*!
+  \brief Get synchronous mode flag value.
+  
+  \sa setIsSync()
+  \return \c true if python console works in synchronous mode
+*/
+bool PyConsole_Editor::isSync() const
+{
+  return myIsSync;
+}
+
+/*!
+  \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 = on;
+}
+
+/*!
+  \brief Get suppress output flag value.
+  
+  \sa setIsSuppressOutput()
+  \return \c true if python console output is suppressed.
+*/
+bool PyConsole_Editor::isSuppressOutput() const
+{
+  return myIsSuppressOutput;
+}
+
+/*!
+  \brief Set suppress output flag value.
+
+  In case if suppress output flag is \c true, the python 
+  console output suppressed.
+
+  \param on suppress output flag
+*/
+void PyConsole_Editor::setIsSuppressOutput( const bool on )
+{
+  myIsSuppressOutput = on;
+}
+
+/*!
+  \brief Get 'show banner' flag value.
+  
+  \sa setIsShowBanner()
+  \return \c true if python console shows banner
+*/
+bool PyConsole_Editor::isShowBanner() const
+{
+  return myShowBanner;
+}
+
+/*!
+  \brief Set 'show banner' flag value.
+
+  The banner is shown in the top of the python console window.
+
+  \sa isShowBanner()
+  \param on 'show banner' flag
+*/
+void PyConsole_Editor::setIsShowBanner( const bool on )
+{
+  if ( myShowBanner != on ) {
+    myShowBanner = on;
+    clear();
+  }
+}
+
+/*!
+  \brief Switch on/off commands auto-completion feature
+  \sa autoCompletion()
+*/
+void PyConsole_Editor::setAutoCompletion( bool on )
+{
+  myAutoCompletion = on;
+  document()->setUndoRedoEnabled( myAutoCompletion );
+}
+  
+/*!
+  \brief Returns \c true if auto-completion feature is switched on
+  or \c false otherwise
+  \sa setAutoCompletion()
+*/
+bool PyConsole_Editor::autoCompletion() const
+{
+  return myAutoCompletion;
+}
+
+/*!
+  \brief Check if trace logging is switched on.
+  
+  \sa startLog(), stopLog()
+  \return \c true if trace logging is switched on
+*/
+bool PyConsole_Editor::isLogging() const
+{
+  return !myLogFile.isEmpty();
+}
+
+/*!
+  \brief Get size hint for the Python console window
+  \return size hint value
+*/
+QSize PyConsole_Editor::sizeHint() const
+{
+  QFontMetrics fm( font() );
+  int nbLines = ( isShowBanner() ? banner().split("\n").count() : 0 ) + 1;
+  QSize s(100, fm.lineSpacing()*nbLines);
+  return s;
+}
+
+/*!
+  \brief Put the string \a str to the python editor.
+  \param str string to be put in the command line of the editor
+  \param newBlock if \c true, then the string is printed on a new line
+  \param isError if \c true, the text is printed in dark red
+*/
+void PyConsole_Editor::addText( const QString& str, 
+                                const bool     newBlock,
+                                const bool     isError )
+{
+  QTextCursor aCursor = textCursor();
+  QTextCharFormat cf;
+
+  moveCursor( QTextCursor::End );
+  if ( newBlock )
+    aCursor.insertBlock();
+  if ( isError )
+    cf.setForeground( QBrush( Qt::red ) );
+  else
+    cf.setForeground( QBrush( Qt::black ) );
+  aCursor.insertText( str, cf );
+  moveCursor( QTextCursor::End );
+  ensureCursorVisible();
+}
+
+/*!
+  \brief Convenient method for executing a Python command,
+  as if the user typed it manually.
+  \param command python command to be executed
+
+  !!! WARNING: doesn't work properly with multi-line commands. !!!
+*/
+void PyConsole_Editor::exec( const QString& command )
+{
+  if ( isReadOnly() ) {
+    // some interactive command is being executed in this editor...
+    // shedule the command to the queue
+    myQueue.push_back( command );
+    return;
+  }
+
+  // remove last line
+  moveCursor( QTextCursor::End );
+  moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+  textCursor().removeSelectedText();
+
+  // set "ready" prompt
+  myPrompt = READY_PROMPT;
+
+  // clear command buffer
+  myCommandBuffer.truncate( 0 );
+
+  // unset history browsing mode
+  myCmdInHistory = -1;
+
+  // print command line by line
+  QString cmd = command;
+  if ( !cmd.endsWith( "\n" ) ) cmd += "\n";
+  QStringList lines = command.split( "\n" );
+  for ( int i = 0; i < lines.size(); i++ ) {
+    if ( !lines[i].trimmed().isEmpty() )
+      myHistory.push_back( lines[i] );
+    addText( ( i == 0 ? READY_PROMPT : DOTS_PROMPT ) + lines[i], i != 0 );
+    putLog( QString( "%1%2\n" ).arg( i == 0 ? READY_PROMPT : DOTS_PROMPT ).arg( lines[i] ) );
+  }
+
+  // IPAL20182
+  addText( "", true );
+
+  // set read-only mode
+  setReadOnly( true );
+
+  // set busy cursor
+  setCursor( Qt::BusyCursor );
+  
+  // post a request to execute Python command;
+  // editor will be informed via a custom event that execution has been completed
+  PyInterp_Dispatcher::Get()->Exec( createCmdRequest( cmd ) );
+}
+
+/*!
+  \brief Create request to the python dispatcher for the command execution.
+  \param command python command to be executed
+ */
+PyInterp_Request* PyConsole_Editor::createCmdRequest( const QString& command )
+{
+  return new PyConsole_ExecCommand( myInterp, command, this, isSync() );
+}
+
+/*!
+  \brief Create the Python request that will be posted to the interpreter to
+  get the completions.
+  \param input line entered by the user at the time <TAB> was pressed
+  \return completion command
+  \sa CompletionCommand
+*/
+PyInterp_Request* PyConsole_Editor::createTabRequest( const QString& input )
+{
+  // valid separators
+  static QStringList separators;
+  if ( separators.isEmpty() ) {
+    separators << " " << "(" << "[" << "+" << "-" << "*" << "/" << ";" << "^" << "=";
+  }
+
+  // parse input to extract on what part the dir() has to be executed
+
+  QString input2( input );
+
+  // split up to the last syntaxical separator
+  int lastSp = -1;
+  foreach ( QString separator, separators ) {
+    int j = input2.lastIndexOf( separator );
+    if ( j > lastSp )
+      lastSp = j;
+  }
+  if ( lastSp >= 0 )
+    input2 = input.mid( lastSp + 1 );
+
+  // detect a qualified name (with a point)
+  int lastPt = input2.lastIndexOf( "." );
+
+  if ( lastPt != -1 ) {
+    // split the 2 surrounding parts of the qualified name
+    myComplBeforePoint = input2.left( lastPt );
+    myComplAfterPoint = input2.mid( lastPt+1 );
+  }
+  else {
+    // no point found - do a global matching
+    // (the following will call dir() with an empty string)
+    myComplAfterPoint = input2;
+    myComplBeforePoint = "";
+  }
+
+  return new PyConsole_CompletionCommand( myInterp, myComplBeforePoint,
+                                          myComplAfterPoint, 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 )
+{
+  // already running ?
+  if ( myEventLoop )
+    return;
+
+  // create new event loop
+  bool sync = isSync();
+  if ( !sync ) {
+    myEventLoop = new QEventLoop( this );
+  }
+
+  // execute command
+  exec( command );
+
+  if ( !sync ) {
+    // run event loop
+    myEventLoop->exec();
+    // delete event loop after command is processed
+    delete myEventLoop;
+    myEventLoop = 0;
+  }
+}
+
+/*!
+  \brief Process <Enter> key press event. 
+  
+  Execute the command entered by the user.
+*/
+void PyConsole_Editor::handleReturn()
+{
+  // Position cursor at the end
+  QTextCursor aCursor = textCursor();
+  aCursor.movePosition( QTextCursor::End );
+  setTextCursor( aCursor );
+
+  // get last line
+  QTextBlock par = document()->end().previous();
+  if ( !par.isValid() ) return;
+
+  // get command
+  QString cmd = par.text().remove( 0, promptSize() );
+
+  // extend the command buffer with the current command 
+  myCommandBuffer.append( cmd );
+
+  // add command to the history
+  if ( !cmd.trimmed().isEmpty() )
+    myHistory.push_back( cmd );
+  putLog( QString( "%1%2\n" ).arg( myPrompt ).arg( cmd ) );
+
+  // IPAL19397
+  addText( "", true ); 
+  
+  // set read-only mode
+  setReadOnly( true );
+
+  // set busy cursor
+  setCursor( Qt::BusyCursor );
+  
+  // post a request to execute Python command;
+  // editor will be informed via a custom event that execution has been completed
+  PyInterp_Dispatcher::Get()->Exec( createCmdRequest( myCommandBuffer ) );
+}
+
+/*!
+  \brief Process <Tab> key press event. 
+  
+  Perform auto-completion of the currently entered command, if this feature is enabled
+*/
+void PyConsole_Editor::handleTab()
+{
+  if ( !autoCompletion() )
+    return; // auto-completion feature is disabled
+
+  if ( myTabMode )
+    return; // already in tab mode
+
+  QTextCursor aCursor = textCursor();
+
+  // move cursor to the end of input
+  aCursor.movePosition( QTextCursor::End );
+  setTextCursor( aCursor );
+
+  // save cursor position if needed
+  if ( myComplCursorPos == -1 )
+    myComplCursorPos = textCursor().position();
+
+  // get last line
+  QTextBlock par = document()->end().previous();
+  if ( !par.isValid() ) return; // empty line
+
+  // switch to completion mode
+  myTabMode = true;
+
+  // get currently entered command
+  QString cmd = par.text().mid( promptSize() );
+
+  // post completion request
+  // editor will be informed that completion has been done via a custom event 
+  PyInterp_Dispatcher::Get()->Exec( createTabRequest( cmd ) );
+}
+
+/*!
+  \brief Process <Ctrl><Tab> key press event. 
+  
+  Undoe last auto-completion
+*/
+void PyConsole_Editor::handleBackTab()
+{
+  if ( !autoCompletion() )
+    return; // auto-completion feature is disabled
+
+  QTextCursor aCursor = textCursor();
+
+  if ( myComplCursorPos == -1 )
+    return; // invalid cursor position
+
+  // ensure cursor is at the end of command line
+  aCursor.setPosition( myComplCursorPos );
+  aCursor.movePosition( QTextCursor::EndOfLine );
+  //setCursor( aCursor );
+
+  // delete last completed text
+  int i = aCursor.position() - myComplCursorPos;
+  aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, i );
+  aCursor.removeSelectedText();
+  myComplCursorPos = -1;
+}
+
+/*!
+  \brief Process drop event.
+
+  Paste dragged text.
+  \param event drop event
+*/
+void PyConsole_Editor::dropEvent( QDropEvent* event )
+{
+  // get the initial drop position
+  QPoint pos = event->pos();
+  QTextCursor aCursor = cursorForPosition( event->pos() );
+
+  // if the position is not in the last line move it to the end of the command line
+  if ( aCursor.position() < document()->end().previous().position() + promptSize() ) {
+    moveCursor( QTextCursor::End );
+    pos = cursorRect().center();
+  }
+
+  // create new drop event and use it instead of the original
+  QDropEvent de( pos,
+                 event->possibleActions(),
+                 event->mimeData(),
+                 event->mouseButtons(),
+                 event->keyboardModifiers(),
+                 event->type() );
+  QTextEdit::dropEvent( &de );
+
+  // accept the original event
+  event->acceptProposedAction();
+}
+
+/*!
+  \brief Process mouse press event
+
+  Clear the completion when any mouse button is pressed.
+
+  \param e mouse press event
+*/
+void PyConsole_Editor::mousePressEvent( QMouseEvent* event )
+{
+  if ( autoCompletion() ) {
+    clearCompletion();
+    myComplCursorPos = -1;
+  }
+  QTextEdit::mousePressEvent( event );
+}
+
+/*!
+  \brief Process mouse button release event.
+
+  Left mouse button: copy selection to the clipboard.
+  Middle mouse button: paste clipboard's contents.
+
+  \param event mouse event
+*/
+void PyConsole_Editor::mouseReleaseEvent( QMouseEvent* event )
+{
+  if ( event->button() == Qt::LeftButton ) {
+    QTextEdit::mouseReleaseEvent( event );
+  }
+  else if ( event->button() == Qt::MidButton ) {
+    QTextCursor aCursor = cursorForPosition( event->pos() );
+    // if the position is not in the last line move it to the end of the command line
+    if ( aCursor.position() < document()->end().previous().position() + promptSize() ) {
+      moveCursor( QTextCursor::End );
+    }
+    else {
+      setTextCursor( aCursor );
+    }
+    const QMimeData* md = QApplication::clipboard()->mimeData( QApplication::clipboard()->supportsSelection() ? 
+                                                              QClipboard::Selection : QClipboard::Clipboard );
+    if ( md )
+      insertFromMimeData( md );
+  }
+  else {
+    QTextEdit::mouseReleaseEvent( event );
+  }
+}
+
+/*!
+  \brief Check if the string is command.
+  
+  Return \c true if the string \a str is likely to be the command
+  (i.e. it is started from the '>>>' or '...').
+  \param str string to be checked
+*/
+bool PyConsole_Editor::isCommand( const QString& str ) const
+{
+  return str.startsWith( READY_PROMPT ) || str.startsWith( DOTS_PROMPT );
+}
+
+/*!
+  \brief Handle keyboard event.
+
+  Implement navigation, history browsing, copy/paste and other common
+  operations.
+
+  \param event keyboard event
+*/
+void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
+{
+  // get cursor position
+  QTextCursor aCursor = textCursor();
+  int curLine = aCursor.blockNumber();
+  int curCol  = aCursor.columnNumber();
+
+  // get last edited line
+  int endLine = document()->blockCount()-1;
+
+  // get pressed key code
+  int aKey = event->key();
+
+  // check if <Ctrl> is pressed
+  bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
+  // check if <Shift> is pressed
+  bool shftPressed = event->modifiers() & Qt::ShiftModifier;
+
+  if ( autoCompletion() ) {
+    // auto-completion support
+    if ( aKey == Qt::Key_Tab && !shftPressed ) {
+      // process <Tab> key
+      if ( !ctrlPressed ) {
+        handleTab();
+      }
+      else {
+        clearCompletion();
+        handleBackTab();
+      }
+      return;
+    }
+
+    // If <Ctrl> is not pressed (or if something else is pressed with <Ctrl>),
+    // or if <Ctrl> is not pressed alone, we have to clear completion
+    if ( !ctrlPressed || ( ctrlPressed && aKey != Qt::Key_Control ) ) {
+      clearCompletion();
+      myComplCursorPos = -1;
+    }
+    
+    // Discard <Ctrl> pressed alone:
+    if ( aKey == Qt::Key_Control )
+      return;
+  }
+
+  if ( aKey == Qt::Key_Escape || ( ctrlPressed && aKey == -1 ) ) {
+    // process <Ctrl>+<Break> key-binding and <Escape> key: clear current command
+    myCommandBuffer.truncate( 0 );
+    myPrompt = READY_PROMPT;
+    addText( myPrompt, true );
+    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+    return;
+  }
+  else if ( ctrlPressed && aKey == Qt::Key_C ) {
+    // process <Ctrl>+<C> key-binding : copy
+    copy();
+    return;
+  }
+  else if ( ctrlPressed && aKey == Qt::Key_X ) {
+    // process <Ctrl>+<X> key-binding : cut
+    cut();
+    return;
+  }
+  else if ( ctrlPressed && aKey == Qt::Key_V ) {
+    // process <Ctrl>+<V> key-binding : paste
+    paste();
+    return;
+  }
+
+  // check for printed key
+  // #### aKey = ( aKey < Qt::Key_Space || aKey > Qt::Key_ydiaeresis ) ? aKey : 0;
+  // Better:
+  aKey = !(QChar(aKey).isPrint()) ? aKey : 0;
+
+  switch ( aKey ) {
+  case 0 :
+    // any printed key: just print it
+    {
+      if ( curLine < endLine || curCol < promptSize() ) {
+        moveCursor( QTextCursor::End );
+      }
+      QTextEdit::keyPressEvent( event );
+      break;
+    }
+  case Qt::Key_Return:
+  case Qt::Key_Enter:
+    // <Enter> key: process the current command
+    {
+      handleReturn();
+      break;
+    }
+  case Qt::Key_Up:
+    // <Up> arrow key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: previous command in history
+    // - with <Ctrl> modifier key pressed:  move cursor one row up without selection
+    // - with <Shift> modifier key pressed: move cursor one row up with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row up
+    {
+      if ( ctrlPressed && shftPressed ) {
+        int value   = verticalScrollBar()->value();
+        int spacing = fontMetrics().lineSpacing();
+        verticalScrollBar()->setValue( value > spacing ? value-spacing : 0 );
+      }
+      else if ( shftPressed || ctrlPressed ) {
+        if ( curLine > 0 )
+          moveCursor( QTextCursor::Up, 
+                      shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+      }
+      else { 
+        if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
+          // set history browsing mode
+          myCmdInHistory = myHistory.count();
+          // remember current command
+          QTextBlock par = document()->end().previous();
+          myCurrentCommand = par.text().remove( 0, promptSize() );
+        }
+        if ( myCmdInHistory > 0 ) {
+          myCmdInHistory--;
+          // get previous command in the history
+          QString previousCommand = myHistory.at( myCmdInHistory );
+          // print previous command
+          moveCursor( QTextCursor::End );
+          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+          addText( myPrompt + previousCommand ); 
+          // move cursor to the end
+          moveCursor( QTextCursor::End );
+        }
+      }
+      break;
+    }
+  case Qt::Key_Down:
+    // <Down> arrow key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: next command in history
+    // - with <Ctrl> modifier key pressed:  move cursor one row down without selection
+    // - with <Shift> modifier key pressed: move cursor one row down with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row down
+    {
+      if ( ctrlPressed && shftPressed ) {
+        int value   = verticalScrollBar()->value();
+        int maxval  = verticalScrollBar()->maximum();
+        int spacing = fontMetrics().lineSpacing();
+        verticalScrollBar()->setValue( value+spacing < maxval ? value+spacing : maxval );
+      }
+      else if ( shftPressed || ctrlPressed) {
+        if ( curLine < endLine )
+          moveCursor( QTextCursor::Down, 
+                      shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+      }
+      else { 
+        if ( myCmdInHistory >= 0 ) {
+          // get next command in the history
+          myCmdInHistory++;
+          QString nextCommand;
+          if ( myCmdInHistory < myHistory.count() ) {
+            // next command in history
+            nextCommand = myHistory.at( myCmdInHistory );
+          }
+          else {
+            // end of history is reached
+            // last printed command
+            nextCommand = myCurrentCommand;
+            // unset history browsing mode
+            myCmdInHistory = -1;
+          }
+          // print next or current command
+          moveCursor( QTextCursor::End );
+          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+          addText( myPrompt + nextCommand );
+          // move cursor to the end
+          moveCursor( QTextCursor::End );
+        }
+      }
+      break;
+    }
+  case Qt::Key_Left:
+    // <Left> arrow key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: move one symbol left (taking into account prompt)
+    // - with <Ctrl> modifier key pressed:  move one word left (taking into account prompt)
+    // - with <Shift> modifier key pressed: move one symbol left with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: move one word left with selection
+    {
+      QString txt = textCursor().block().text();
+      if ( !shftPressed && isCommand( txt ) && curCol <= promptSize() ) {
+        moveCursor( QTextCursor::Up );
+        moveCursor( QTextCursor::EndOfBlock );
+      }
+      else {
+        QTextEdit::keyPressEvent( event );
+      }
+      break;
+    }
+  case Qt::Key_Right:
+    // <Right> arrow key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: move one symbol right (taking into account prompt)
+    // - with <Ctrl> modifier key pressed:  move one word right (taking into account prompt)
+    // - with <Shift> modifier key pressed: move one symbol right with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: move one word right with selection
+    {
+      QString txt = textCursor().block().text();
+      if ( !shftPressed ) {
+        if ( curCol < txt.length() ) {
+          if ( isCommand( txt ) && curCol < promptSize() ) {
+            aCursor.setPosition( aCursor.block().position() + promptSize() );
+            setTextCursor( aCursor );
+            break;
+          }
+        }
+        else {
+          if ( curLine < endLine && isCommand( textCursor().block().next().text() ) ) {
+            aCursor.setPosition( aCursor.position() + promptSize()+1 );
+            setTextCursor( aCursor );
+            horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+            break;
+          }
+        }
+      }
+      QTextEdit::keyPressEvent( event );
+      break;
+    }
+  case Qt::Key_PageUp:
+    // <PageUp> key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: first command in history
+    // - with <Ctrl> modifier key pressed:  move cursor one page up without selection
+    // - with <Shift> modifier key pressed: move cursor one page up with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page up
+    {
+      if ( ctrlPressed && shftPressed ) {
+        verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub);
+      }
+      else if ( shftPressed || ctrlPressed ) {
+        bool moved = false;
+        qreal lastY = cursorRect( aCursor ).top();
+        qreal distance = 0;
+        // move using movePosition to keep the cursor's x
+        do {
+          qreal y = cursorRect( aCursor ).top();
+          distance += qAbs( y - lastY );
+          lastY = y;
+          moved = aCursor.movePosition( QTextCursor::Up, 
+                                        shftPressed ? QTextCursor::KeepAnchor : 
+                                        QTextCursor::MoveAnchor );
+        } while ( moved && distance < viewport()->height() );
+        if ( moved ) {
+          aCursor.movePosition( QTextCursor::Down, 
+                                shftPressed ? QTextCursor::KeepAnchor : 
+                                QTextCursor::MoveAnchor );
+          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
+        }
+        setTextCursor( aCursor );
+      }
+      else { 
+        if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
+          // set history browsing mode
+          myCmdInHistory = myHistory.count();
+          // remember current command
+          QTextBlock par = document()->end().previous();
+          myCurrentCommand = par.text().remove( 0, promptSize() );
+        }
+        if ( myCmdInHistory > 0 ) {
+          myCmdInHistory = 0;
+          // get very first command in the history
+          QString firstCommand = myHistory.at( myCmdInHistory );
+          // print first command
+          moveCursor( QTextCursor::End );
+          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+          addText( myPrompt + firstCommand ); 
+          // move cursor to the end
+          moveCursor( QTextCursor::End );
+        }
+      }
+      break;
+    }
+  case Qt::Key_PageDown:
+    // <PageDown> key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: last command in history
+    // - with <Ctrl> modifier key pressed:  move cursor one page down without selection
+    // - with <Shift> modifier key pressed: move cursor one page down with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page down
+    {
+      if ( ctrlPressed && shftPressed ) {
+        verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd);
+      }
+      else if ( shftPressed || ctrlPressed ) {
+        bool moved = false;
+        qreal lastY = cursorRect( aCursor ).top();
+        qreal distance = 0;
+        // move using movePosition to keep the cursor's x
+        do {
+          qreal y = cursorRect( aCursor ).top();
+          distance += qAbs( y - lastY );
+          lastY = y;
+          moved = aCursor.movePosition( QTextCursor::Down, 
+                                        shftPressed ? QTextCursor::KeepAnchor : 
+                                        QTextCursor::MoveAnchor );
+        } while ( moved && distance < viewport()->height() );
+        if ( moved ) {
+          aCursor.movePosition( QTextCursor::Up, 
+                                shftPressed ? QTextCursor::KeepAnchor : 
+                                QTextCursor::MoveAnchor );
+          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
+        }
+        setTextCursor( aCursor );
+      }
+      else { 
+        if ( myCmdInHistory >= 0 ) {
+          // unset history browsing mode
+          myCmdInHistory = -1;
+          // print current command
+          moveCursor( QTextCursor::End );
+          moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+          addText( myPrompt + myCurrentCommand ); 
+          // move cursor to the end
+          moveCursor( QTextCursor::End );
+        }
+      }
+      break;
+    }
+  case Qt::Key_Home: 
+    // <Home> key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: move cursor to the beginning of the current line without selection
+    // - with <Ctrl> modifier key pressed:  move cursor to the very first symbol without selection
+    // - with <Shift> modifier key pressed: move cursor to the beginning of the current line with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very first symbol with selection
+    {
+      if ( ctrlPressed ) { 
+        moveCursor( QTextCursor::Start, 
+                    shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+      }
+      else {
+        QString txt = textCursor().block().text();
+        if ( isCommand( txt ) ) {
+          if ( shftPressed ) {
+            if ( curCol > promptSize() ) {
+              aCursor.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
+              aCursor.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
+            }
+          }
+          else {
+            aCursor.movePosition( QTextCursor::StartOfLine );
+            aCursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
+          }
+          setTextCursor( aCursor );
+        }
+        else {
+          moveCursor( QTextCursor::StartOfBlock, 
+                      shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+        }
+        horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+      }
+      break;
+    }
+  case Qt::Key_End:
+    // <End> key: process as follows:
+    // - without <Ctrl>, <Shift> modifiers: move cursor to the end of the current line without selection
+    // - with <Ctrl> modifier key pressed:  move cursor to the very last symbol without selection
+    // - with <Shift> modifier key pressed: move cursor to the end of the current line with selection
+    // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very last symbol with selection
+    {
+      moveCursor( ctrlPressed ? QTextCursor::End : QTextCursor::EndOfBlock, 
+                  shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+      break;
+    }  
+  case Qt::Key_Backspace :
+    // <Backspace> key: process as follows
+    // - without any modifiers : delete symbol before the cursor / selection (taking into account prompt)
+    // - with <Shift> modifier key pressed: delete previous word
+    // - with <Ctrl> modifier key pressed: delete text from the cursor to the line beginning
+    // works only for last (command) line
+    {
+      if ( aCursor.hasSelection() ) {
+        cut();
+      }
+      else if ( aCursor.position() > document()->end().previous().position() + promptSize() ) {
+        if ( shftPressed ) {
+          moveCursor( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+        }
+        else if ( ctrlPressed ) {
+          aCursor.setPosition( document()->end().previous().position() + promptSize(),
+                               QTextCursor::KeepAnchor );
+          setTextCursor( aCursor );
+          textCursor().removeSelectedText();
+        }
+        else {
+          QTextEdit::keyPressEvent( event );
+        }
+      }
+      else {
+        aCursor.setPosition( document()->end().previous().position() + promptSize() );
+        setTextCursor( aCursor );
+        horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+      }
+      break;
+    }
+  case Qt::Key_Delete :
+    // <Delete> key: process as follows
+    // - without any modifiers : delete symbol after the cursor / selection (taking into account prompt)
+    // - with <Shift> modifier key pressed: delete next word
+    // - with <Ctrl> modifier key pressed: delete text from the cursor to the end of line
+    // works only for last (command) line
+    {
+      if ( aCursor.hasSelection() ) {
+        cut();
+      }
+      else if ( aCursor.position() > document()->end().previous().position() + promptSize()-1 ) {
+        if ( shftPressed ) {
+          moveCursor( QTextCursor::NextWord, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+        }
+        else if ( ctrlPressed ) {
+          moveCursor( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+        }
+        else {
+          QTextEdit::keyPressEvent( event );
+        }
+      }
+      else {
+        aCursor.setPosition( document()->end().previous().position() + promptSize() );
+        setTextCursor( aCursor );
+        horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+      }
+      break;
+    }
+  case Qt::Key_Insert :
+    // <Insert> key: process as follows
+    // - with <Ctrl> modifier key pressed:  copy()
+    // - with <Shift> modifier key pressed: paste() to the command line
+    {
+      if ( ctrlPressed ) {
+        copy();
+      }
+      else if ( shftPressed ) {
+        paste();
+      }
+      else
+        QTextEdit::keyPressEvent( event );
+      break;
+    }
+  default:
+    break;
+  }
+}
+
+/*!
+  \brief Handle notification event coming from Python dispatcher.
+  \param event notification event
+*/
+void PyConsole_Editor::customEvent( QEvent* event )
+{
+  switch( event->type() )
+  {
+  case PyConsole_PrintEvent::EVENT_ID:
+  {
+    PyConsole_PrintEvent* pe = (PyConsole_PrintEvent*)event;
+    putLog( pe->text());
+    addText( pe->text(), false, pe->isError() );
+    return;
+  }
+  case PyConsole_CompletionEvent::EVENT_ID:
+  {
+    PyConsole_CompletionEvent* ce = (PyConsole_CompletionEvent*)event;
+    bool status = ce->status();
+    QStringList matches = ce->matches();
+    QString doc = ce->doc();
+
+    if ( status ) {
+      // completion was successful
+      QTextCursor aCursor = textCursor();
+
+      if ( matches.isEmpty() ) {
+       // completion successful but there are no matches.
+        myTabMode = false;
+        myComplCursorPos = -1;
+        return;
+      }
+      
+      if ( matches.size() == 1 ) {
+        // there's only one match - complete directly and update doc string window
+        aCursor.insertText( matches[0].mid( myComplAfterPoint.size() ) );
+        myTabMode = false;
+        if ( doc.isEmpty() )
+          emit updateDoc( formatDocHTML( QString( "(%1)\n" ).arg( tr( "NO_DOC_AVAILABLE" ) ) ) );
+        else
+          emit updateDoc( formatDocHTML( doc ) );
+      }
+      else {
+        // there are several matches
+        
+        // detect if there is a common base to all available completion
+        // in this case append this base to the text
+        QString base = extractCommon( matches );
+        aCursor.insertText( base.mid( myComplAfterPoint.size() ) );
+        
+        // if this happens to match exactly the first completion
+        // also provide doc
+        if ( base == matches[0] )
+          emit updateDoc( formatDocHTML( doc ) );
+        
+        // print all matching completion in a "undo-able" block
+        int cursorPos = aCursor.position();
+        aCursor.insertBlock();
+        aCursor.beginEditBlock();
+        
+        // insert all matches
+        QTextCharFormat cf;
+        cf.setForeground( QBrush( Qt::darkGreen ) );
+        aCursor.setCharFormat( cf );
+        aCursor.insertText( formatCompletion( matches ) );
+        aCursor.endEditBlock();
+        
+        // position cursor where it was before inserting the completion list
+        aCursor.setPosition( cursorPos );
+        setTextCursor( aCursor );
+      }
+    }
+    else {
+      // completion failed
+      myTabMode = false;
+      myComplCursorPos = -1;
+    }
+    return;
+  }
+  case PyInterp_Event::ES_OK:
+  case PyInterp_Event::ES_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 );
+    // unset busy cursor
+    unsetCursor();
+    // stop event loop (if running)
+    if ( myEventLoop )
+      myEventLoop->exit();
+    // if we are in multi_paste_mode, process the next item
+    multiLineProcessNextLine();
+    break;
+  }
+  case PyInterp_Event::ES_INCOMPLETE:
+  {
+    // 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*/ ); // IPAL19397
+    // unset busy cursor
+    unsetCursor();
+    // stop event loop (if running)
+    if ( myEventLoop )
+      myEventLoop->exit();
+    // if we are in multi_paste_mode, process the next item
+    multiLineProcessNextLine();
+    break;
+  }
+  default:
+    QTextEdit::customEvent( event );
+  }
+  
+  // unset read-only state
+  setReadOnly( false );
+  // unset history browsing mode
+  myCmdInHistory = -1;
+
+  if ( (int)event->type() == (int)PyInterp_Event::ES_OK && myQueue.count() > 0 )
+  {
+    // process the next sheduled command from the queue (if there is any)
+    QString nextcmd = myQueue[0];
+    myQueue.pop_front();
+    exec( nextcmd );
+  }
+}
+
+/*!
+  \brief "Copy" operation.
+  
+  Reimplemented from Qt.
+  Warning! In Qt this method is not virtual.
+*/
+void PyConsole_Editor::cut()
+{
+  QTextCursor aCursor = textCursor();
+  if ( aCursor.hasSelection() ) {
+    QApplication::clipboard()->setText( aCursor.selectedText() );
+    int startSelection = aCursor.selectionStart();
+    if ( startSelection < document()->end().previous().position() + promptSize() )
+      startSelection = document()->end().previous().position() + promptSize();
+    int endSelection = aCursor.selectionEnd();
+    if ( endSelection < document()->end().previous().position() + promptSize() )
+      endSelection = document()->end().previous().position() + promptSize();
+    aCursor.setPosition( startSelection );
+    aCursor.setPosition( endSelection, QTextCursor::KeepAnchor );
+    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+    setTextCursor( aCursor );
+    textCursor().removeSelectedText();
+  }
+}
+
+/*!
+  \brief "Paste" operation.
+
+  Reimplemented from Qt.
+  Warning! In Qt this method is not virtual.
+*/
+void PyConsole_Editor::paste()
+{
+  QTextCursor aCursor = textCursor();
+  if ( aCursor.hasSelection() ) {
+    int startSelection = aCursor.selectionStart();
+    if ( startSelection < document()->end().previous().position() + promptSize() )
+      startSelection = document()->end().previous().position() + promptSize();
+    int endSelection = aCursor.selectionEnd();
+    if ( endSelection < document()->end().previous().position() + promptSize() )
+      endSelection = document()->end().previous().position() + promptSize();
+    aCursor.setPosition( startSelection );
+    aCursor.setPosition( endSelection, QTextCursor::KeepAnchor );
+    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+    setTextCursor( aCursor );
+    textCursor().removeSelectedText();
+  }
+  if ( textCursor().position() < document()->end().previous().position() + promptSize() )
+    moveCursor( QTextCursor::End );
+  QTextEdit::paste();
+}
+
+/*!
+  \brief "Clear" operation.
+
+  Reimplemented from Qt.
+  Warning! In Qt this method is not virtual.
+*/
+void PyConsole_Editor::clear()
+{
+  QTextEdit::clear();
+  if ( isShowBanner() )
+    addText( banner() );
+  myPrompt = READY_PROMPT;
+  addText( myPrompt );
+}
+
+/*!
+  \brief Dumps recorded Python commands to the file
+  \param fileName path to the dump file
+  \return \c true if dump operation succeeded or \c false otherwise
+*/
+bool PyConsole_Editor::dump( const QString& fileName )
+{
+  bool ok = false;
+  if ( !fileName.isEmpty() ) {
+    QFile file( fileName ); 
+    if ( file.open( QFile::WriteOnly ) ) {
+      QTextStream out( &file );
+      for ( int i = 0; i < myHistory.count(); i++ ) {
+        out << myHistory[i] << endl;
+      }
+      file.close();
+      ok = true;
+    }
+  }
+  return ok;
+}
+
+/*!
+  \brief Dump menu action slot
+*/
+void PyConsole_Editor::dump()
+{
+  forever {
+    // get file name
+    QString fileName = getDumpFileName();
+
+    if ( fileName.isEmpty() )
+      break; // cancelled
+    
+    if ( dump( fileName ) )
+      break;
+    else
+      QMessageBox::warning( this,
+                            tr( "WARNING" ),
+                            tr( "ERR_FILE_NOT_WRITEABLE" ) );
+  }
+}
+
+/*!
+  \brief Get file name for Dump commands operation.
+  
+  This function can be redefined in successor classes to show application
+  specific dialog box.
+
+  \return path to the dump file
+*/
+QString PyConsole_Editor::getDumpFileName()
+{
+  return QFileDialog::getSaveFileName( this,
+                                       tr( "GET_DUMP_COMMANDS_FILENAME" ),
+                                       QString(),
+                                       QString( "%1 (*.py)" ).arg( tr( "PYTHON_SCRIPTS" ) ) );
+}
+
+/*!
+  \brief Get file name for Log Python trace operation.
+  
+  This function can be redefined in successor classes to show application
+  specific dialog box.
+
+  \return path to the log file
+*/
+QString PyConsole_Editor::getLogFileName()
+{
+  return QFileDialog::getSaveFileName( this,
+                                       tr( "GET_PYTHON_TRACE_FILENAME" ),
+                                       QString(),
+                                       QString( "%1 (*.log *.txt)" ).arg( tr( "LOG_FILES" ) ) );
+}
+
+/*!
+  \brief Start python trace logging
+  \param fileName the path to the log file
+  \return \c true if operation succeeded or \c false otherwise
+          (for example, if file is not writeable)
+  \sa stopLog()
+ */
+bool PyConsole_Editor::startLog( const QString& fileName )
+{
+  // stop possibly already running logging
+  if ( isLogging() )
+    stopLog();
+
+  bool ok = false;
+  if ( !fileName.isEmpty() ) {
+    QFile file( fileName );
+    if ( file.open( QFile::WriteOnly ) ) {
+      file.close();
+      myLogFile = fileName;
+      ok = true;
+    }
+  }
+  return ok;
+}
+
+/*!
+  \brief Start log action slot
+*/
+void PyConsole_Editor::startLog()
+{
+  forever {
+    // get file name
+    QString fileName = getLogFileName();
+
+    if ( fileName.isEmpty() )
+      break; // cancelled
+    
+    if ( startLog( fileName ) )
+      break;
+    else
+      QMessageBox::warning( this,
+                            tr( "WARNING" ),
+                            tr( "File is not writable" ) );
+  }
+}
+
+/*!
+  \brief Stop log action slot
+  
+  Stops Python trace logging.
+*/
+void PyConsole_Editor::stopLog()
+{
+  myLogFile = QString();
+}
+
+/*!
+  \brief Put data to the log file
+*/
+void PyConsole_Editor::putLog( const QString& s )
+{
+  if ( !myLogFile.isEmpty() ) {
+    QFile file( myLogFile );
+    if ( !file.open( QFile::Append ) )
+      return;
+    
+    QTextStream out( &file );
+    out << s;
+    
+    file.close();
+  }
+}
+
+/*!
+  \brief Handle properly multi-line pasting. Qt documentation recommends overriding this function.
+  If the pasted text doesn't contain a line return, no special treatment is done.
+  \param source
+*/
+void PyConsole_Editor::insertFromMimeData(const QMimeData* source)
+{
+  if ( myMultiLinePaste )
+    return;
+
+  if ( source->hasText() ) {
+    QString s = source->text();
+    if ( s.contains( "\n" ) )
+      multilinePaste( s );
+    else
+      QTextEdit::insertFromMimeData( source );
+  }
+  else {
+    QTextEdit::insertFromMimeData( source );
+  }
+}
+
+/*!
+  Start multi-line paste operation
+  \internal
+*/
+void PyConsole_Editor::multilinePaste( const QString& s )
+{
+  // Turn on multi line pasting mode
+  myMultiLinePaste = true;
+
+  // Split string data to lines
+  QString s2 = s;
+  s2.replace( "\r", "" ); // Windows string format converted to Unix style
+  QStringList lst = s2.split( QChar('\n'), QString::KeepEmptyParts );
+
+  // Perform the proper paste operation for the first line to handle the case where
+  // something was already there
+  QMimeData source;
+  source.setText( lst[0] );
+  QTextEdit::insertFromMimeData( &source );
+
+  // Prepare what will have to be executed after the first line
+  myMultiLineContent.clear();
+  for ( int i = 1; i < lst.size(); ++i )
+    myMultiLineContent.enqueue( lst[i] );
+
+  // Trigger the execution of the first (mixed) line
+  handleReturn();
+
+  // See customEvent() and multiLineProcessNext() for the rest of the handling.
+}
+
+/*!
+  \brief Process the next line in the queue of multi-line paste operation; called
+  from customEvent() function
+  \internal
+*/
+void PyConsole_Editor::multiLineProcessNextLine()
+{
+  // not in multi-line paste mode
+  if ( !myMultiLinePaste || myMultiLineContent.isEmpty() )
+    return;
+
+  QString line = myMultiLineContent.dequeue();
+  if ( myMultiLineContent.empty() )
+  {
+    // this isa last line in the queue, just paste it
+    addText( line, false, false );
+    myMultiLinePaste = false;
+  }
+  else
+  {
+    // paste the line and simulate a <RETURN> key stroke
+    addText( line, false, false );
+    handleReturn();
+  }
+}
+
+/*!
+  \brief Clear results of completion
+*/
+void PyConsole_Editor::clearCompletion()
+{
+  // delete completion text if present
+  if ( myTabMode ) {
+    // remove completion display
+    document()->undo();
+    // remove trailing line return:
+    QTextCursor tc( textCursor() );
+    tc.setPosition( document()->characterCount()-1 );
+    setTextCursor( tc );
+    textCursor().deletePreviousChar();
+    // TODO: before wait for any <Tab> event to be completed
+  }
+  myTabMode = false;
+}
+
+/*!
+ \brief Format completion results - this is where we should create 3 columns etc ...
+ \param matches list of possible completions
+ \return result string
+*/
+QString PyConsole_Editor::formatCompletion( const QStringList& matches ) const
+{
+  static const int MAX_COMPLETIONS = 70;
+
+  QStringList result;
+  int sz = matches.size();
+
+  if ( sz > MAX_COMPLETIONS )
+    result.append( QString( "[%1]" ).arg( tr( "TOO_MANY_MATCHES" ) ) );
+
+  for ( int i = 0; i < qMin( sz, MAX_COMPLETIONS); ++i )
+    result.append( matches[i] );
+
+  return result.join( "\n" );
+}
+
+/*!
+  \brief Format the doc string in HTML format with the first line in bold blue
+  \param doc initial doc string
+  \return HTML string
+*/
+QString PyConsole_Editor::formatDocHTML( const QString& doc ) const
+{
+  static const char* templ = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " \
+    "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" \
+    "<html><head><meta name=\"qrichtext\" content=\"1\" /> " \
+    "<style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style> " \
+    "</head><body style=\" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;\">\n" \
+    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> " \
+    "<span style=\" font-weight:600; color:#0000ff;\">%1</span></p> " \
+    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%2</p> " \
+    "</body></html>";
+  
+  QString fst, rest("");
+
+  // Extract first line of doc
+  int idx = doc.indexOf( "\n" );
+  if ( idx > 0 ) {
+    fst = doc.left( idx );
+    rest = doc.mid( idx+1 );
+  }
+  else {
+    fst = doc;
+  }
+
+  fst = fst.replace( "\n", " " );
+  rest = rest.replace(" \n", " " );
+  return QString( templ ).arg( fst ).arg( rest );
+}
+
+/*!
+  \fn void PyConsole_Editor::updateDoc( const QString& doc);
+  \brief Signal emitted by the editor widget when the doc string should be updated.
+  \param doc a HTML block with the formatted doc string.
+  \todo currently this signal is left uncaught.
+*/
+
+/*!
+ \brief Extract the common leading part of all strings in matches.
+ \param matches
+ \param result
+*/
+QString PyConsole_Editor::extractCommon( const QStringList& matches ) const
+{
+  QString result = "";
+  
+  if ( matches.size() > 1 ) {
+    int l = 0;
+    bool ok = true;
+    while ( ok && l+1 < matches[0].size() ) {
+      QString match = matches[0].left( l+1 );
+      for ( int j = 1; j < matches.size() && ok; j++ )
+        ok = matches[j].startsWith( match );
+      if ( ok )
+        l++;
+    }
+    result = matches[0].left( l );
+  }
+
+  return result;
+}
+
+/*!
+  \brief Useful method to get banner from Python interpreter
+  \return banner
+*/
+QString PyConsole_Editor::banner() const
+{
+  return myInterp->getBanner().c_str();
+}
diff --git a/tools/PyConsole/src/PyConsole_Editor.h b/tools/PyConsole/src/PyConsole_Editor.h
new file mode 100644 (file)
index 0000000..774e101
--- /dev/null
@@ -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   : 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.h"
+
+#include <QTextEdit>
+#include <QQueue>
+
+class PyConsole_Interp;
+class PyInterp_Request;
+class QEventLoop;
+
+class PYCONSOLE_EXPORT PyConsole_Editor : public QTextEdit
+{
+  Q_OBJECT;
+
+public:
+  PyConsole_Editor( PyConsole_Interp*, QWidget* = 0 );
+  ~PyConsole_Editor();
+
+  PyConsole_Interp* getInterp() const;
+  
+  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:
+  void           multilinePaste( const QString& );
+  void           multiLineProcessNextLine();
+
+  void           handleReturn();
+  void           handleTab();
+  void           handleBackTab();
+  void           clearCompletion();
+  QString        formatCompletion( const QStringList& ) const;
+  QString        formatDocHTML( const QString& ) const;
+  QString        extractCommon( const QStringList& ) const;
+
+  PyInterp_Request* createCmdRequest( const QString& );
+  PyInterp_Request* createTabRequest( const QString& );
+
+  QString        banner() const;
+  inline int     promptSize() const { return myPrompt.size(); }
+
+  PyConsole_Interp* myInterp;           //!< python interpreter
+  QString           myCommandBuffer;    //!< python command buffer
+  QString           myCurrentCommand;   //!< currently being printed command
+  QString           myPrompt;           //!< current command line prompt
+  int               myCmdInHistory;     //!< current history command index
+  QString           myLogFile;          //!< current output log
+  QStringList       myHistory;          //!< commands history buffer
+  QEventLoop*       myEventLoop;        //!< internal event loop
+  bool              myShowBanner;       //!< 'show banner' flag
+  QStringList       myQueue;            //!< python commands queue
+  bool              myIsSync;           //!< synchronous mode flag
+  bool              myIsSuppressOutput; //!< suppress output flag
+  bool              myMultiLinePaste;   //!< true when pasting several lines
+  QQueue<QString>   myMultiLineContent; //!< queue of lines being pasted
+  bool              myAutoCompletion;   //!< auto-completion mode flag
+  bool              myTabMode;          //!< flag that is \c true when editor performs completion
+  QString           myComplBeforePoint; //!< string on which the dir() command is executed
+  QString           myComplAfterPoint;  //!< string on which the results of the dir() are matched
+  int               myComplCursorPos;   //!< cursor position when <TAB> is hit
+
+};
+
+#endif // PYCONSOLE_EDITOR_H
diff --git a/tools/PyConsole/src/PyConsole_Event.cxx b/tools/PyConsole/src/PyConsole_Event.cxx
new file mode 100644 (file)
index 0000000..5c3f1fd
--- /dev/null
@@ -0,0 +1,107 @@
+// 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   : PyConsole_Event.cxx
+// Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
+
+#include "PyConsole_Event.h"
+
+/*!
+  \class PyConsole_PrintEvent
+  \brief Python command output backend event.
+  \internal
+*/
+
+/*!
+  \brief Constructor
+  \param message message text (python trace)
+  \param isError default to \c false - if \c true indicates that an error is being printed.
+*/
+PyConsole_PrintEvent::PyConsole_PrintEvent( const QString& message, bool isError )
+  : QEvent( (QEvent::Type)EVENT_ID ), myText( message ), myError( isError )
+{
+}
+
+/*!
+  \brief Get message
+  \return message text (python trace)
+*/
+QString PyConsole_PrintEvent::text() const
+{
+  return myText;
+}
+
+/*!
+  \brief Get error flag
+  \return \c true if this is an error message
+*/
+bool PyConsole_PrintEvent::isError() const
+{
+  return myError;
+}
+
+/*!
+  \class PyConsole_CompletionEvent
+  \brief Python command completion event.
+  \internal
+*/
+
+/*!
+  \brief Constructor
+  \param request python request
+  \param s status of execution of completion command
+  \param ms command matches (completions)
+  \param d docstring of the match (in case if there is sinlge match)
+*/
+PyConsole_CompletionEvent::PyConsole_CompletionEvent( PyInterp_Request* request,
+                                                      bool s,
+                                                      const QStringList& ms,
+                                                      const QString& d )
+  : PyInterp_Event( (QEvent::Type)EVENT_ID, request ),
+    myStatus( s ), myMatches( ms ), myDoc( d )
+{}
+
+/*!
+  \brief Get status of execution of completion command
+  \return execution status
+*/
+bool PyConsole_CompletionEvent::status() const
+{
+  return myStatus;
+}
+
+/*!
+  \brief Get matches (completions)
+  \return detected command matches (completions)
+*/
+QStringList PyConsole_CompletionEvent::matches() const
+{
+  return myMatches;
+}
+
+/*!
+  \brief Get docstring
+  \return docstring of the match (in case if there is sinlge match)
+*/
+QString PyConsole_CompletionEvent::doc() const
+{
+  return myDoc;
+}
diff --git a/tools/PyConsole/src/PyConsole_Event.h b/tools/PyConsole/src/PyConsole_Event.h
new file mode 100644 (file)
index 0000000..d22b78b
--- /dev/null
@@ -0,0 +1,67 @@
+// 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   : PyConsole_Event.h
+// Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
+
+#ifndef PYCONSOLE_EVENT_H
+#define PYCONSOLE_EVENT_H
+
+#include "PyConsole.h"
+#include "PyInterp_Event.h"
+
+#include <QEvent>
+#include <QString>
+#include <QStringList>
+
+class PyConsole_PrintEvent : public QEvent
+{
+public:
+  static const int EVENT_ID = 65432;
+
+  PyConsole_PrintEvent( const QString&, bool = false );
+
+  QString text() const;
+  bool isError() const;
+
+private:
+  QString myText;  //!< Event message (python trace)
+  bool    myError; //!< Set to \c true if an error msg is to be displayed
+};
+
+class PyConsole_CompletionEvent : public PyInterp_Event
+{
+public:
+  static const int EVENT_ID = 65433;
+  
+  PyConsole_CompletionEvent( PyInterp_Request*, bool, const QStringList&, const QString& );
+
+  bool status() const;
+  QStringList matches() const;
+  QString doc() const;
+
+protected:
+  bool        myStatus;  //!< Status of execution
+  QStringList myMatches; //!< Command matches (completions)
+  QString     myDoc;     //!< Docstring of the match (in case if there is sinlge match)
+};
+
+#endif // PYCONSOLE_EVENT_H
diff --git a/tools/PyConsole/src/PyConsole_Interp.cxx b/tools/PyConsole/src/PyConsole_Interp.cxx
new file mode 100644 (file)
index 0000000..7224136
--- /dev/null
@@ -0,0 +1,198 @@
+// 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   : PyConsole_Interp.cxx
+// Author : Nicolas REJNERI (OPEN CASCADE), Adrien BRUNETON (CEA/DEN), Vadim SANDLER (OPEN CASCADE)
+
+#include "PyConsole_Interp.h"
+
+/*!
+  \class PyConsole_Interp
+  \brief Python interpreter to be embedded to the SALOME study's GUI.
+
+  There is only one Python interpreter for the whole SALOME environment.
+
+  Call the initialize() method defined in the base class PyInterp_Interp,
+  to initialize the interpreter after instance creation.
+
+  The method initialize() calls virtuals methods
+  - initPython()  to initialize global Python interpreter
+  - initContext() to initialize interpreter internal context
+  - initRun()     to prepare interpreter for running commands
+
+  See PyInterp_Interp class for more details.
+*/
+
+/*!
+  \brief Constructor.
+
+  Creates new python interpreter.
+*/
+PyConsole_Interp::PyConsole_Interp()
+  : PyInterp_Interp()
+{
+}
+
+/*!
+  \brief Destructor.
+*/
+PyConsole_Interp::~PyConsole_Interp()
+{
+}
+
+/*!
+  \brief Performs specific actions before each Python command
+  
+  Sets the variable "__IN_SALOME_GUI_CONSOLE" to True.
+  This is not attached to a module (like salome_iapp.IN_SALOME_GUI_CONSOLE)
+  since modules are shared across all interpreters in SALOME.
+
+  \note GIL is already acquired here.
+*/
+int PyConsole_Interp::beforeRun()
+{
+  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=True");
+}
+/*!
+  \brief Performs specific actions after each Python command
+
+  Sets the variable "__IN_SALOME_GUI_CONSOLE" to False.
+  \sa beforeRun()
+
+  \note GIL is already acquired here.
+*/
+int PyConsole_Interp::afterRun()
+{
+  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=False");
+}
+
+/*!
+  \brief Run Python dir() command to get matches.
+  \internal
+  \param dirArgument Python expression to pass to the dir command. The parsing of what the
+  user actually started typing is dedicated to the caller
+  \param startMatch string representing the begining of the patter to be completed. For example, when
+  the user types "a_string_variable.rsp <TAB>", this is "rsp".
+  \param[out] matches resulting list of matches
+  \param[out] docString resulting docstring of single match
+  \return \true if completion succeeded, \c false otherwise
+*/
+bool PyConsole_Interp::runDirCommand( const QString& dirArgument, const QString& startMatch, 
+                                      QStringList& matches, QString& docString )
+{
+  static QStringList keywords;
+  if ( keywords.isEmpty() ) {
+    keywords << "and" << "as" << "assert" << "break" << "class" << "continue"
+             << "def" << "del" << "elif" << "else" << "except" << "exec"
+             << "finally" << "for" << "from" << "global" << "if" << "import"
+             << "in" << "is" << "lambda" << "not" << "or" << "pass" << "print" << "raise"
+             << "return" << "try" << "while" << "with" << "yield";
+  }
+  
+  // run dir() command and extract completions
+  if ( !runDirAndExtract( dirArgument, startMatch, matches ) )
+    return false;
+  
+  // If dirArgument is empty, we append the __builtins__
+  if ( dirArgument.isEmpty() ) {
+    if ( !runDirAndExtract( QString( "__builtins__" ), startMatch, matches, false ) )
+      return false;
+    
+    // ... and we match on Python's keywords as well
+    foreach( QString keyword, keywords ) {
+      if ( keyword.startsWith( startMatch ) )
+        matches.append( keyword );
+    }
+  }
+  
+  // Try to get doc string of the first match
+  if ( matches.size() > 0 ) {
+    QString cmd = QString( "%1.__doc__" ).arg( matches[0] );
+    if ( !dirArgument.trimmed().isEmpty() )
+      cmd.prepend( QString( "%1." ).arg( dirArgument ) );
+    
+    PyObject* str = PyRun_String( cmd.toStdString().c_str(), Py_eval_input, _global_context, _local_context );
+    if ( !str || str == Py_None || !PyString_Check( str ) )
+      {
+        if ( !str )
+          PyErr_Clear();
+      }
+    else {
+      docString = QString( PyString_AsString( str ) );
+    }
+    Py_XDECREF( str );
+  }
+  return true;
+}
+
+/*!
+  \internal
+  \sa runDirCommand()
+  \param dirArgument see runDirCommand()
+  \param startMatch  see runDirCommand()
+  \param[out] result resulting list of matches
+  \param discardSwig if \c true, a regular expression is used to discard all static method generated
+  by SWIG. Typically: MEDCouplingUMesh_Blabla
+  \return \c true if the call to dir() and parsing of the result succeeded, \false otherwise.
+*/
+bool PyConsole_Interp::runDirAndExtract( const QString& dirArgument,
+                                         const QString& startMatch,
+                                         QStringList& result,
+                                         bool discardSwig ) const
+{
+  QRegExp re( "^[A-Z].+_[A-Z]+[a-z]+.+$" ); // REX to discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
+
+  // Execute dir() command
+  QString command( "dir(" + dirArgument + ")" );
+  PyObject* plst = PyRun_String( command.toStdString().c_str(), Py_eval_input, _global_context, _local_context );
+  if ( !plst || plst == Py_None ) {
+    if ( !plst )
+      PyErr_Clear();
+    Py_XDECREF( plst );
+    return false;
+  }
+
+  // Check result
+  if ( !PySequence_Check( plst ) ) {
+    // Should never happen ...
+    Py_XDECREF( plst );
+    return false;
+  }
+
+  // Extract the returned list
+  int n = PySequence_Length( plst );
+  for ( int i = 0; i < n; i++ ) {
+    PyObject* it;
+    it = PySequence_GetItem( plst, i );
+    QString s( PyString_AsString( it ) );
+    // if the method is not from swig, not static (guessed from the reg exp) and matches
+    // what is already there
+    if ( s.startsWith( startMatch ) ) {
+      if ( !discardSwig || ( !re.exactMatch( s ) && !s.contains( "swig" ) ) )
+        result.append( s );
+    }
+    Py_DECREF( it );
+  }
+  Py_DECREF( plst );
+  
+  return true;
+}
diff --git a/tools/PyConsole/src/PyConsole_Interp.h b/tools/PyConsole/src/PyConsole_Interp.h
new file mode 100644 (file)
index 0000000..4275c35
--- /dev/null
@@ -0,0 +1,49 @@
+// 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   : PyConsole_Interp.h
+// Author : Nicolas REJNERI (OPEN CASCADE), Adrien BRUNETON (CEA/DEN), Vadim SANDLER (OPEN CASCADE)
+
+#ifndef PYCONSOLE_INTERP_H
+#define PYCONSOLE_INTERP_H
+
+#include "PyConsole.h"
+#include "PyInterp_Interp.h"
+
+#include <QStringList>
+
+class PYCONSOLE_EXPORT PyConsole_Interp : public PyInterp_Interp
+{
+  friend class PyConsole_CompletionCommand;
+
+public:
+  PyConsole_Interp();
+  ~PyConsole_Interp();
+
+  virtual int afterRun();
+  virtual int beforeRun();
+
+private:
+  bool runDirCommand( const QString&, const QString&, QStringList&, QString& );
+  bool runDirAndExtract( const QString&, const QString&, QStringList&, bool = true ) const;
+};
+
+#endif // PYCONSOLE_INTERP_H
diff --git a/tools/PyConsole/src/PyConsole_Request.cxx b/tools/PyConsole/src/PyConsole_Request.cxx
new file mode 100644 (file)
index 0000000..aa41c25
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, 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
+//
+// File   : PyConsole_Request.cxx
+// Author : Vadim SANDLER (OPEN CASCADE), Adrien Bruneton (CEA/DEN)
+
+#include "PyConsole_Request.h"
+#include "PyConsole_Interp.h"
+#include "PyConsole_Event.h"
+
+#include <QCoreApplication>
+
+/*!
+  \class PyConsole_ExecCommand
+  \brief Python command execution request.
+  \internal
+*/
+
+/*!
+  \brief Constructor.
+  
+  Creates new python command execution request.
+
+  \param theInterp   python interpreter
+  \param theCommand  python command
+  \param theListener widget to get the notification messages
+  \param theSync     if \c true, the request is processed synchronously
+*/
+PyConsole_ExecCommand::PyConsole_ExecCommand( PyInterp_Interp*        theInterp,
+                                              const QString&          theCommand,
+                                              QObject*                theListener,
+                                              bool                    theSync )
+  : PyInterp_LockRequest( theInterp, theListener, theSync ),
+    myCommand( theCommand ), myState( PyInterp_Event::ES_OK )
+{}
+
+/*!
+  \brief Execute the python command in the interpreter and
+  get its execution status.
+*/
+void PyConsole_ExecCommand::execute()
+{
+  if ( myCommand != "" ) {
+    int ret = getInterp()->run( myCommand.toLatin1().data() );
+    if ( ret < 0 )
+      myState = PyInterp_Event::ES_ERROR;
+    else if ( ret > 0 )
+      myState = PyInterp_Event::ES_INCOMPLETE;
+  }
+}
+
+/*!
+  \brief Create and return a notification event.
+  \return new notification event
+*/
+QEvent* PyConsole_ExecCommand::createEvent()
+{
+  if ( IsSync() )
+    QCoreApplication::sendPostedEvents( listener(), PyConsole_PrintEvent::EVENT_ID );
+  return new PyInterp_Event( myState, this );
+}
+
+/*!
+  \class PyConsole_CompletionCommand
+  \brief Python command completion request.
+  \internal
+*/
+
+/*!
+  \brief Constructor.
+
+  Creates a new python completion request.
+
+  \param theInterp python interpreter
+  \param theInput  string containing the dir() command to be executed
+  \param theStartMatch part to be matched with the results of the dir() command
+  \param theListener widget to get the notification messages
+  \param theSync if \c true the request is processed synchronously
+*/
+PyConsole_CompletionCommand::PyConsole_CompletionCommand( PyInterp_Interp*   theInterp,
+                                                          const QString&     theInput,
+                                                          const QString&     theStartMatch,
+                                                          QObject*           theListener,
+                                                          bool               theSync )
+  : PyInterp_LockRequest( theInterp, theListener, theSync ),
+    myDirArg( theInput ), myStartMatch( theStartMatch ), myStatus( false )
+{}
+
+/*!
+  \brief Execute the completion command by invoking runDirCommand() function
+  of interpreter.
+*/
+void PyConsole_CompletionCommand::execute()
+{
+  myStatus = static_cast<PyConsole_Interp*>( getInterp() )->runDirCommand( myDirArg,  myStartMatch, myMatches, myDoc );
+}
+
+/*!
+ \brief Create and return completion event
+  \return new completion event
+ */
+QEvent* PyConsole_CompletionCommand::createEvent()
+{
+  return new PyConsole_CompletionEvent( this, myStatus, myMatches, myDoc );
+}
diff --git a/tools/PyConsole/src/PyConsole_Request.h b/tools/PyConsole/src/PyConsole_Request.h
new file mode 100644 (file)
index 0000000..827823b
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, 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
+//
+// File   : PyConsole_Request.h
+// Author : Vadim SANDLER (OPEN CASCADE), Adrien Bruneton (CEA/DEN)
+
+#ifndef PYCONSOLE_REQUEST_H
+#define PYCONSOLE_REQUEST_H
+
+#include "PyInterp_Request.h"
+
+#include <QString>
+#include <QStringList>
+
+class QEvent;
+class PyInterp_Interp;
+
+class PyConsole_ExecCommand : public PyInterp_LockRequest
+{
+public:
+  PyConsole_ExecCommand( PyInterp_Interp*, const QString&, QObject*, bool = false );
+
+protected:
+  virtual void execute();
+  virtual QEvent* createEvent();
+
+private:
+  QString myCommand;   //!< Python command
+  int     myState;     //!< Python command execution status
+};
+
+class PyConsole_CompletionCommand : public PyInterp_LockRequest
+{
+public:
+  PyConsole_CompletionCommand( PyInterp_Interp*, const QString&, const QString&, QObject*, bool = false );
+
+protected:
+  virtual void execute();
+  virtual QEvent* createEvent();
+
+private:
+  QString     myDirArg;       //!< String to be passed to the dir() comman
+  QString     myStartMatch;   //!< Begining of the command (as typed by the user)
+  bool        myStatus;       //!< Status of completion command execution
+  QStringList myMatches;      //!< Matches
+  QString     myDoc;          //!< Docstring of single match
+};
+
+#endif // PYCONSOLE_REQUEST_H
diff --git a/tools/PyConsole/src/resources/PyConsole_msg_en.ts b/tools/PyConsole/src/resources/PyConsole_msg_en.ts
new file mode 100644 (file)
index 0000000..7fac57c
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="en_US">
+<context>
+    <name>PyConsole_Console</name>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="216"/>
+        <source>EDIT_COPY_CMD</source>
+        <translation>&amp;Copy</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="221"/>
+        <source>EDIT_PASTE_CMD</source>
+        <translation>&amp;Paste</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="226"/>
+        <source>EDIT_CLEAR_CMD</source>
+        <translation>Clea&amp;r</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="231"/>
+        <source>EDIT_SELECTALL_CMD</source>
+        <translation>Select &amp;All</translation>
+    </message>
+    <message>
+        <source>EDIT_DUMPCOMMANDS_CMD</source>
+        <translation>D&amp;ump Commands</translation>
+    </message>
+    <message>
+        <source>EDIT_STARTLOG_CMD</source>
+        <translation>Start &amp;Log</translation>
+    </message>
+    <message>
+      <source>EDIT_STOPLOG_CMD</source>
+        <translation>Stop &amp;Log</translation>
+    </message>
+</context>
+<context>
+    <name>PyConsole_Editor</name>
+    <message>
+        <source>GET_DUMP_COMMANDS_FILENAME</source>
+        <translation>Dump commands to file</translation>
+    </message>
+    <message>
+        <source>GET_PYTHON_TRACE_FILENAME</source>
+        <translation>Save Python trace to file</translation>
+    </message>
+    <message>
+        <source>PYTHON_SCRIPTS</source>
+        <translation>Python scripts</translation>
+    </message>
+    <message>
+        <source>WARNING</source>
+        <translation>Warning!</translation>
+    </message>
+    <message>
+        <source>LOG_FILES</source>
+        <translation>Log files</translation>
+    </message>
+    <message>
+        <source>ERR_FILE_NOT_WRITEABLE</source>
+        <translation>File is not writeable!</translation>
+    </message>
+    <message>
+        <source>TOO_MANY_MATCHES</source>
+        <translation>Too many matches! Displaying first ones only...</translation>
+    </message>
+    <message>
+        <source>NO_DOC_AVAILABLE</source>
+        <translation>no documentation available</translation>
+    </message>
+</context>
+</TS>
diff --git a/tools/PyConsole/src/resources/PyConsole_msg_fr.ts b/tools/PyConsole/src/resources/PyConsole_msg_fr.ts
new file mode 100644 (file)
index 0000000..9eaf244
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+<context>
+    <name>PyConsole_Console</name>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="216"/>
+        <source>EDIT_COPY_CMD</source>
+        <translation>&amp;Copier</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="221"/>
+        <source>EDIT_PASTE_CMD</source>
+        <translation>C&amp;oller</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="226"/>
+        <source>EDIT_CLEAR_CMD</source>
+        <translation>&amp;Effacer</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_Console.cxx" line="231"/>
+        <source>EDIT_SELECTALL_CMD</source>
+        <translation>&amp;Tout sélectionner</translation>
+    </message>
+    <message>
+        <source>EDIT_DUMPCOMMANDS_CMD</source>
+        <translation>&amp;Générer le script des commandes</translation>
+    </message>
+    <message>
+        <source>EDIT_STARTLOG_CMD</source>
+        <translation>Démarrer une &amp;trace</translation>
+    </message>
+    <message>
+        <source>EDIT_STOPLOG_CMD</source>
+        <translation>Arrêter la &amp;trace</translation>
+    </message>
+</context>
+<context>
+    <name>PyConsole_Editor</name>
+    <message>
+        <source>GET_DUMP_COMMANDS_FILENAME</source>
+        <translation>Choisissez un fichier python où sauver le dump</translation>
+    </message>
+    <message>
+        <source>GET_PYTHON_TRACE_FILENAME</source>
+        <translation>Choisissez un fichier où sauver le log</translation>
+    </message>
+    <message>
+        <source>PYTHON_SCRIPTS</source>
+        <translation>Scripts Python</translation>
+    </message>
+    <message>
+        <source>WARNING</source>
+        <translation>Attention !</translation>
+    </message>
+    <message>
+        <source>LOG_FILES</source>
+        <translation>Fichiers log</translation>
+    </message>
+    <message>
+        <source>ERR_FILE_NOT_WRITEABLE</source>
+        <translation>Le fichier n'a pas été écrit !</translation>
+    </message>
+    <message>
+        <source>TOO_MANY_MATCHES</source>
+        <translation type="unfinished">Too many matches! Displaying first ones only...</translation>
+    </message>
+    <message>
+        <source>NO_DOC_AVAILABLE</source>
+        <translation type="unfinished">no documentation available</translation>
+    </message>
+</context>
+</TS>
diff --git a/tools/PyConsole/src/resources/PyConsole_msg_ja.ts b/tools/PyConsole/src/resources/PyConsole_msg_ja.ts
new file mode 100644 (file)
index 0000000..8861d5e
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="ja" sourcelanguage="en">
+  <context>
+    <name>PyConsole_Console</name>
+    <message>
+      <location filename="../PyConsole_Console.cxx" line="216"/>
+      <source>EDIT_COPY_CMD</source>
+      <translation>コピー(&amp;C)</translation>
+    </message>
+    <message>
+      <location filename="../PyConsole_Console.cxx" line="221"/>
+      <source>EDIT_PASTE_CMD</source>
+      <translation>貼り付け(&amp;P)</translation>
+    </message>
+    <message>
+      <location filename="../PyConsole_Console.cxx" line="226"/>
+      <source>EDIT_CLEAR_CMD</source>
+      <translation>削除(&amp;r)</translation>
+    </message>
+    <message>
+      <location filename="../PyConsole_Console.cxx" line="231"/>
+      <source>EDIT_SELECTALL_CMD</source>
+      <translation>すべて選択します。(&amp;A)</translation>
+    </message>
+    <message>
+      <source>EDIT_DUMPCOMMANDS_CMD</source>
+      <translation>スクリプト コマンドを生成します。(&amp;u)</translation>
+    </message>
+    <message>
+      <source>EDIT_STARTLOG_CMD</source>
+      <translation>ログの開始 (&amp;L)</translation>
+    </message>
+    <message>
+      <source>EDIT_STOPLOG_CMD</source>
+      <translation>ログの停止 (&amp;L)</translation>
+    </message>
+  </context>
+  <context>
+    <name>PyConsole_Editor</name>
+    <message>
+      <source>GET_DUMP_COMMANDS_FILENAME</source>
+      <translation type="unfinished">Dump commands to file</translation>
+    </message>
+    <message>
+      <source>GET_PYTHON_TRACE_FILENAME</source>
+      <translation type="unfinished">Save Python trace to file</translation>
+    </message>
+    <message>
+      <source>PYTHON_SCRIPTS</source>
+      <translation type="unfinished">Python scripts</translation>
+    </message>
+    <message>
+      <source>WARNING</source>
+      <translation type="unfinished">Warning!</translation>
+    </message>
+    <message>
+      <source>LOG_FILES</source>
+      <translation type="unfinished">Log files</translation>
+    </message>
+    <message>
+      <source>ERR_FILE_NOT_WRITEABLE</source>
+      <translation type="unfinished">File is not writeable!</translation>
+    </message>
+    <message>
+      <source>TOO_MANY_MATCHES</source>
+      <translation type="unfinished">Too many matches! Displaying first ones only...</translation>
+    </message>
+    <message>
+      <source>NO_DOC_AVAILABLE</source>
+      <translation type="unfinished">no documentation available</translation>
+    </message>
+  </context>
+</TS>
diff --git a/tools/PyInterp/CMakeLists.txt b/tools/PyInterp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6b24505
--- /dev/null
@@ -0,0 +1,69 @@
+# Copyright (C) 2015-2016  CEA/DEN, EDF 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, 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
+#
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
+PROJECT(PyInterp C CXX)
+
+# Versioning
+# ===========
+# Project name, upper case
+STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC)
+
+# To be changed once externalized CMake procedure:
+###################
+SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL")
+IF(EXISTS ${KERNEL_ROOT_DIR})
+  LIST(APPEND CMAKE_MODULE_PATH "${KERNEL_ROOT_DIR}/salome_adm/cmake_files")
+  INCLUDE(SalomeMacros)
+ELSE(EXISTS ${KERNEL_ROOT_DIR})
+  MESSAGE(FATAL_ERROR "We absolutely need a Salome KERNEL, please define KERNEL_ROOT_DIR")
+ENDIF(EXISTS ${KERNEL_ROOT_DIR})
+# From GUI - again to be changed once externalized:
+LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../adm_local/cmake_files")
+###################
+
+# Platform setup
+# ==============
+INCLUDE(SalomeSetupPlatform)
+
+#
+# Set list of prerequisites
+# =========================
+
+FIND_PACKAGE(SalomePythonInterp REQUIRED)
+FIND_PACKAGE(SalomePythonLibs REQUIRED)
+FIND_PACKAGE(SalomeQt4 REQUIRED)
+
+# Detection report
+SALOME_PACKAGE_REPORT_AND_CHECK()
+
+# Directories
+#
+# Directories have to be given after prerequisites (to be able to use
+# Python version string for example).
+# ===========
+SET(PYINTERP_INSTALL_LIBS lib CACHE PATH "Install path: PyInterp libs")
+SET(PYINTERP_INSTALL_HEADERS include CACHE PATH "Install path: PyInterp headers")
+
+SET(PYINTERP_INSTALL_RES share/resources CACHE PATH "Install path: PyInterp resources")
+
+# Sources
+# ========
+ADD_SUBDIRECTORY(src)
+
diff --git a/tools/PyInterp/src/CMakeLists.txt b/tools/PyInterp/src/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..c29e7e5
--- /dev/null
@@ -0,0 +1,77 @@
+# Copyright (C) 2012-2016  CEA/DEN, EDF R&D, 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
+#
+
+INCLUDE(UseQtExt)
+
+# --- options ---
+
+# additional include directories
+INCLUDE_DIRECTORIES(
+  ${QT_INCLUDES}
+  ${PYTHON_INCLUDE_DIRS}
+)
+
+# additional preprocessor / compiler flags
+ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
+
+# libraries to link to
+SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES})
+
+# --- headers ---
+
+# header files / to be processed by moc
+SET(_moc_HEADERS
+  PyInterp_Dispatcher.h
+)
+
+# header files / no moc processing
+SET(_other_HEADERS
+  PyInterp.h
+  PyInterp_Event.h
+  PyInterp_Interp.h
+  PyInterp_Request.h
+  PyInterp_Utils.h
+)
+
+# header files / to install
+SET(PyInterp_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
+
+# --- sources ---
+
+# sources / moc wrappings
+QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS})
+
+# sources / static
+SET(_other_SOURCES
+  PyInterp_Dispatcher.cxx
+  PyInterp_Event.cxx
+  PyInterp_Interp.cxx
+  PyInterp_Request.cxx
+)
+
+# sources / to compile
+SET(PyInterp_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
+
+# --- rules ---
+
+ADD_LIBRARY(PyInterp ${PyInterp_SOURCES})
+TARGET_LINK_LIBRARIES(PyInterp ${_link_LIBRARIES})
+INSTALL(TARGETS PyInterp EXPORT ${TOOLS_EXPORT_NAME}TargetGroup DESTINATION ${PYINTERP_INSTALL_LIBS})
+
+INSTALL(FILES ${PyInterp_HEADERS} DESTINATION ${PYINTERP_INSTALL_HEADERS})
diff --git a/tools/PyInterp/src/PyInterp.h b/tools/PyInterp/src/PyInterp.h
new file mode 100755 (executable)
index 0000000..08271e0
--- /dev/null
@@ -0,0 +1,50 @@
+// 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   : 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
+# if defined PYINTERP_EXPORTS || defined PyInterp_EXPORTS
+#  define PYINTERP_EXPORT __declspec(dllexport)
+# else
+#  define PYINTERP_EXPORT __declspec(dllimport)
+# endif
+#else   // WIN32
+# define PYINTERP_EXPORT
+#endif  // WIN32
+
+// ========================================================
+
+#include <Python.h>
+
+// avoid warning messages
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#pragma warning (disable : 4251)
+#endif
+
+#endif // PYINTERP_H
diff --git a/tools/PyInterp/src/PyInterp_Dispatcher.cxx b/tools/PyInterp/src/PyInterp_Dispatcher.cxx
new file mode 100755 (executable)
index 0000000..b702144
--- /dev/null
@@ -0,0 +1,146 @@
+// 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   : PyInterp_Dispatcher.cxx
+//  Author : Sergey Anikin (OPEN CASCADE S.A.S.)
+
+#include "PyInterp_Dispatcher.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+
+/**
+   \class PyInterp_Dispatcher
+   \brief Dispatcher of Python events; used to serialize requests to Python interpreter.
+*/
+
+PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
+
+PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
+{
+  if ( !myInstance )
+    myInstance = new PyInterp_Dispatcher();
+  return myInstance;
+}
+
+PyInterp_Dispatcher::PyInterp_Dispatcher() 
+: QThread()
+{
+}
+
+PyInterp_Dispatcher::~PyInterp_Dispatcher()
+{
+  // Clear the request queue
+  myQueueMutex.lock();
+
+  QListIterator<RequestPtr> it( myQueue );
+  while ( it.hasNext() )
+    PyInterp_Request::Destroy( it.next() );
+  myQueue.clear();
+
+  myQueueMutex.unlock();
+
+  // Wait for run() to finish
+  wait();
+}
+
+bool PyInterp_Dispatcher::IsBusy() const
+{
+  return isRunning();
+}
+
+void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest )
+{
+  if ( !theRequest )
+    return;
+
+  if ( theRequest->IsSync() /*&& !IsBusy()*/)
+  {
+    // synchronous processing
+    processRequest( theRequest );
+  }
+  else
+  {
+    // asynchronous processing
+    myQueueMutex.lock();
+
+    myQueue.enqueue( theRequest );
+    if ( theRequest->listener() ) {
+      connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ),
+               this, SLOT( objectDestroyed( QObject* ) ) );
+    }
+
+    myQueueMutex.unlock();  
+
+    if ( !IsBusy() )
+      start();
+  }
+}
+
+void PyInterp_Dispatcher::run()
+{
+  PyInterp_Request* aRequest;
+
+  // prepare for queue size check
+  myQueueMutex.lock();
+
+  while ( myQueue.size() )
+  {
+    aRequest = myQueue.head();
+
+    // let other threads append their requests to the end of the queue
+    myQueueMutex.unlock();
+
+    // processRequest() may delete a request, so this pointer must not be used
+    // after request is processed!
+    processRequest( aRequest );
+
+    // 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.head() == aRequest ) // if it is still here --> remove it
+      myQueue.dequeue();
+  }
+
+  myQueueMutex.unlock();
+}
+
+void PyInterp_Dispatcher::processRequest( PyInterp_Request* theRequest )
+{
+  theRequest->process();
+}
+
+void PyInterp_Dispatcher::objectDestroyed( QObject* o )
+{
+  // prepare for modification of the queue
+  myQueueMutex.lock();
+
+  QMutableListIterator<RequestPtr> it( myQueue );
+  while ( it.hasNext() )
+  {
+    RequestPtr r = it.next();
+    if ( o == r->listener() )
+    {
+      r->setListener( 0 ); // to prevent event posting
+      it.remove();
+    }
+  }
+
+  myQueueMutex.unlock();
+}
diff --git a/tools/PyInterp/src/PyInterp_Dispatcher.h b/tools/PyInterp/src/PyInterp_Dispatcher.h
new file mode 100755 (executable)
index 0000000..c9b8384
--- /dev/null
@@ -0,0 +1,65 @@
+// 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   : PyInterp_Dispatcher.h
+//  Author : Sergey Anikin (OPEN CASCADE S.A.S.)
+
+#ifndef PYINTERP_DISPATCHER_H
+#define PYINTERP_DISPATCHER_H
+
+#include "PyInterp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+
+#include "PyInterp_Request.h"   // full include instead of forward declaration
+                                // everyone inc'ing the Dispatcher will get the requests for free.
+
+#include <QMutex>
+#include <QThread>
+#include <QQueue>
+
+class PYINTERP_EXPORT PyInterp_Dispatcher : protected QThread
+{
+  PyInterp_Dispatcher(); // private constructor
+  Q_OBJECT
+public:
+  static PyInterp_Dispatcher* Get();
+
+  virtual                     ~PyInterp_Dispatcher();
+
+  bool                        IsBusy() const;  
+  void                        Exec( PyInterp_Request* );
+
+private:
+  virtual void                run();
+  void                        processRequest( PyInterp_Request* );
+
+private slots:
+  void                        objectDestroyed( QObject* );
+
+private:
+  typedef PyInterp_Request*   RequestPtr;
+
+  QQueue<RequestPtr>          myQueue;
+  QMutex                      myQueueMutex;
+
+  static PyInterp_Dispatcher* myInstance;
+};
+
+#endif // PYINTERP_DISPATCHER_H
diff --git a/tools/PyInterp/src/PyInterp_Event.cxx b/tools/PyInterp/src/PyInterp_Event.cxx
new file mode 100644 (file)
index 0000000..478eb2c
--- /dev/null
@@ -0,0 +1,53 @@
+// 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   : PyInterp_Event.cxx
+//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
+
+#include "PyInterp_Event.h"
+#include "PyInterp_Request.h"
+
+/**
+   \class PyInterp_Event
+   \brief Events thrown by the interpreter having executed a command and indicating
+   the return status.
+*/
+
+PyInterp_Event::PyInterp_Event( int type, PyInterp_Request* request )
+  : QEvent( (QEvent::Type)type ), myRequest( request )
+{
+}
+
+PyInterp_Event::~PyInterp_Event()
+{
+  PyInterp_Request::Destroy( myRequest );
+  myRequest = 0;
+}
+
+PyInterp_Request* PyInterp_Event::GetRequest() const
+{
+  return myRequest;
+}
+
+PyInterp_Event::operator PyInterp_Request*() const
+{
+  return myRequest;
+}
diff --git a/tools/PyInterp/src/PyInterp_Event.h b/tools/PyInterp/src/PyInterp_Event.h
new file mode 100644 (file)
index 0000000..e812adb
--- /dev/null
@@ -0,0 +1,58 @@
+// 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   : PyInterp_Event.h
+//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
+
+#ifndef PYINTERP_EVENT_H
+#define PYINTERP_EVENT_H
+
+#include "PyInterp.h"
+
+#include <QEvent>
+
+class PyInterp_Request;
+
+class PYINTERP_EXPORT PyInterp_Event : public QEvent
+{
+  PyInterp_Event();
+  PyInterp_Event( const PyInterp_Event& );
+
+public:
+  // Execution state
+  enum {
+    ES_NOTIFY = QEvent::User + 5000,
+    ES_OK,
+    ES_ERROR,
+    ES_INCOMPLETE,
+    ES_LAST };
+
+  PyInterp_Event( int type, PyInterp_Request* request );
+  virtual ~PyInterp_Event();
+
+  PyInterp_Request* GetRequest() const;
+  operator PyInterp_Request*() const;
+
+private:
+  PyInterp_Request* myRequest;
+};
+
+#endif // PYINTERP_EVENT_H
diff --git a/tools/PyInterp/src/PyInterp_Interp.cxx b/tools/PyInterp/src/PyInterp_Interp.cxx
new file mode 100644 (file)
index 0000000..5946e8d
--- /dev/null
@@ -0,0 +1,607 @@
+// 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   : PyInterp_Interp.cxx
+//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
+
+#include "PyInterp_Interp.h"  // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "PyInterp_Utils.h"
+
+#include <pythread.h>
+#include <cStringIO.h>
+#include <structmember.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+
+#include <QRegExp>
+
+#define TOP_HISTORY_PY   "--- top of history ---"
+#define BEGIN_HISTORY_PY "--- begin of history ---"
+
+/*
+  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 PyObject*
+PyStdOut_flush(PyStdOut *self)
+{
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static PyMethodDef PyStdOut_methods[] = {
+  {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS, PyDoc_STR("write(string) -> None")},
+  {"flush",  (PyCFunction)PyStdOut_flush,  METH_NOARGS,  PyDoc_STR("flush() -> None")},
+  {NULL,    NULL}   /* sentinel */
+};
+
+static PyMemberDef PyStdOut_memberlist[] = {
+  {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
+   (char*)"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[] = {(char*)""};
+
+/*!
+  \brief Basic constructor.
+
+  After construction the interpreter instance successor classes
+  must call virtual method initalize().
+*/
+PyInterp_Interp::PyInterp_Interp():
+  _vout(0), _verr(0), _local_context(0), _global_context(0), _initialized(false)
+{
+}
+
+/*!
+  \brief Destructor.
+*/
+PyInterp_Interp::~PyInterp_Interp()
+{
+  destroy();
+}
+
+/*!
+  \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
+  - 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()
+{
+  if ( initialized() )
+    return; // prevent repeating intitialization
+
+  _initialized = true;
+
+  _history.clear();       // start a new list of user's commands
+  _ith = _history.begin();
+
+  initPython();  // This also inits the multi-threading for Python (but w/o acquiring GIL)
+
+  // ---- The rest of the initialisation process is done hodling the GIL
+  PyLockWrapper lck;
+
+  initContext();
+
+  // used to interpret & compile commands - this is really imported here
+  // and only added again (with PyImport_AddModule) later on
+  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();
+}
+
+void PyInterp_Interp::destroy()
+{
+  PyLockWrapper lck;
+  closeContext();
+}
+
+/*!
+  \brief Initialize Python interpreter.
+
+  In case if Python is not initialized, it sets program name, initializes the single true Python
+  interpreter, sets program arguments, and initializes threads.
+  Otherwise, does nothing. This is important for light SALOME configuration,
+  as in full SALOME this is done at SalomeApp level.
+  \sa SalomeApp_PyInterp class and main() in SALOME_Session_Server
+ */
+void PyInterp_Interp::initPython()
+{
+  if (!Py_IsInitialized()){
+    // Python is not initialized
+    Py_SetProgramName(_argv[0]);
+    Py_Initialize(); // Initialize the interpreter
+    PySys_SetArgv(_argc, _argv);
+
+    PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
+    PyEval_ReleaseLock();
+  }
+}
+
+/*!
+  \brief Get embedded Python interpreter banner.
+  \return banner string
+ */
+std::string PyInterp_Interp::getBanner() const
+{
+  PyLockWrapper lck;
+  std::string aBanner("Python ");
+  aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
+  aBanner = aBanner + "\ntype help to get general information on environment\n";
+  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()
+{
+  return true;
+}
+
+/*!
+ * 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 PyInterp_Interp::initContext()
+{
+  PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
+  if(!m){
+    PyErr_Print();
+    return false;
+  }
+  _global_context = PyModule_GetDict(m);          // get interpreter global variable context
+  Py_INCREF(_global_context);
+  _local_context = _global_context;
+
+  int ret = PyRun_SimpleString("import salome_iapp;salome_iapp.IN_SALOME_GUI=True");
+
+  return ret == 0;
+}
+
+/*!
+ * Destroy context dictionaries. GIL is held already.
+ */
+void PyInterp_Interp::closeContext()
+{
+  Py_XDECREF(_global_context);
+  // both _global_context and _local_context may point to the same Python object
+  if ( _global_context != _local_context)
+    Py_XDECREF(_local_context);
+}
+
+/*!
+  \brief Compile Python command and evaluate it in the
+         python dictionary contexts if possible. This is not thread-safe.
+         This is the caller's responsability to make this thread-safe.
+  \internal
+  \param command Python command string
+  \return -1 on fatal error, 1 if command is incomplete and 0
+         if command is executed successfully
+ */
+static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
+{
+  PyObject *m = PyImport_AddModule("codeop");
+  if(!m) {
+    // Fatal error. No way to go on.
+    PyErr_Print();
+    return -1;
+  }
+
+  PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"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 {
+    PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,global_ctxt, local_ctxt));
+    if(!r) {
+      // Execution error. We return -1
+      PyErr_Print();
+      return -1;
+    }
+    // The command has been successfully executed. Return 0
+    return 0;
+  }
+}
+
+void replaceAll(std::string& str, const std::string& from, const std::string& to) {
+    if(from.empty())
+        return;
+    size_t start_pos = 0;
+    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
+        str.replace(start_pos, from.length(), to);
+        start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
+    }
+}
+
+std::vector<std::string>
+__split(const std::string& str, char delimiter)
+{
+  std::vector<std::string> internal;
+  std::stringstream ss(str); // Turn the string into a stream.
+  std::string tok;
+
+  while (getline(ss, tok, delimiter)) {
+    internal.push_back(tok);
+  }
+
+  return internal;
+}
+
+std::string
+__join(const std::vector<std::string>& v, int begin=0, int end=-1)
+{
+  if (end == -1)
+    end = v.size();
+  std::stringstream ss;
+  for (size_t i = begin; i < end; ++i) {
+    if (i != begin)
+      ss << ",";
+    ss << v[i];
+  }
+  return ss.str();
+}
+
+std::vector<std::string>
+__getArgsList(std::string argsString)
+{
+  // Special process if some items of 'args:' list are themselves lists
+  // Note that an item can be a list, but not a list of lists...
+  // So we can have something like this:
+  // myscript.py args:[\'file1\',\'file2\'],\'val1\',\"done\",[1,2,3],[True,False],\"ok\",kwarg1=\'kwarg1\',kwarg2=\'kwarg2\',\'fin\'
+  // With such a call, argsString variable contains the string representing ['file1','file2'],'val1','done',[1,2,3],[True,False],'ok',kwarg1='kwarg1',kwarg2='kwarg2','fin'
+  // We have to split argsString to obtain a 9 string elements list
+  std::vector<std::string> x = __split(argsString, ',');
+  bool containsList = (argsString.find('[') != std::string::npos);
+  if (containsList) {
+    std::vector<int> listBeginIndices, listEndIndices;
+    for (int pos = 0; pos < x.size(); ++pos) {
+      if (x[pos][0] == '[')
+        listBeginIndices.push_back(pos);
+      else if (x[pos][x[pos].size()-1] == ']')
+        listEndIndices.push_back(pos);
+    }
+    std::vector<std::string> extractedArgs;
+    int start = 0;
+    for (int pos = 0; pos < listBeginIndices.size(); ++pos) {
+      int lbeg = listBeginIndices[pos];
+      int lend = listEndIndices[pos];
+      if (lbeg > start)
+        for (int k = start; k < lbeg; ++k)
+          extractedArgs.push_back(x[k]);
+      extractedArgs.push_back(__join(x, lbeg, lend+1));
+      start = lend+1;
+    }
+    if (start < x.size())
+      for (int k = start; k < x.size(); ++k)
+        extractedArgs.push_back(x[k]);
+    return extractedArgs;
+  }
+  else {
+    return x;
+  }
+}
+
+/*!
+  \brief Compile Python command and evaluate it in the
+         python dictionary context if possible. Command might correspond to
+         the execution of a script with optional arguments.
+         In this case, command is:
+         execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
+  \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 * global_ctxt, PyObject * local_ctxt)
+{
+  // First guess if command is execution of a script with args, or a simple Python command
+  std::string singleCommand = command;
+  std::string commandArgs = "";
+
+  QRegExp rx("execfile\\s*\\(.*(args:.*)\"\\s*\\)");
+  if (rx.indexIn(command) != -1) {
+    commandArgs = rx.cap(1).remove(0,5).toStdString(); // arguments of command
+    singleCommand = rx.cap().remove(rx.cap(1)).remove(" ").toStdString(); // command for execution without arguments
+  }
+
+  if (commandArgs.empty()) {
+    // process command: expression
+    // process command: execfile(r"/absolute/path/to/script.py") (no args)
+    return run_command(singleCommand.c_str(), global_ctxt, local_ctxt);
+  }
+  else {
+    // process command: execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
+    std::string script = singleCommand.substr(11); // remove leading execfile(r"
+    script = script.substr(0, script.length()-2); // remove trailing ")
+    std::vector<std::string> argList = __getArgsList(commandArgs);
+
+    std::string preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=[";
+    std::string preCommandEnd = "];";
+    std::string completeCommand = preCommandBegin+"\""+script+"\",";
+    for (std::vector<std::string>::iterator itr = argList.begin(); itr != argList.end(); ++itr) {
+      if (itr != argList.begin())
+        completeCommand += ",";
+      completeCommand = completeCommand + "\"" + *itr + "\"";
+    }
+    completeCommand = completeCommand+preCommandEnd+singleCommand+";sys.argv=save_argv";
+    return run_command(completeCommand.c_str(), global_ctxt, local_ctxt);
+  }
+}
+
+/*!
+  \brief Run Python command - the command has to fit on a single line (no \n!).
+  Use ';' if you need multiple statements evaluated at once.
+  \param command Python command
+  \return command status
+*/
+int PyInterp_Interp::run(const char *command)
+{
+  beforeRun();
+  int ret = simpleRun(command);
+  afterRun();
+  return ret;
+}
+
+/**
+ * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability
+ * to acquire GIL if needed.
+ */
+int PyInterp_Interp::beforeRun()
+{
+  return 0;
+}
+
+/**
+ * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsability
+ * to acquire GIL if needed.
+ */
+int PyInterp_Interp::afterRun()
+{
+  return 0;
+}
+
+/*!
+  \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability.
+  \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();
+  }
+
+  // Current stdout and stderr are saved
+  PyObject * oldOut = PySys_GetObject((char*)"stdout");
+  PyObject * oldErr = PySys_GetObject((char*)"stderr");
+  // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
+  Py_INCREF(oldOut);
+  Py_INCREF(oldErr);
+
+  // Redirect outputs to SALOME Python console before treatment
+  PySys_SetObject((char*)"stderr",_verr);
+  PySys_SetObject((char*)"stdout",_vout);
+
+  int ier = compile_command(command, _global_context, _local_context);
+
+  // Outputs are redirected to what they were before
+  PySys_SetObject((char*)"stdout",oldOut);
+  PySys_SetObject((char*)"stderr",oldErr);
+
+  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;
+}
+
+/*!
+  \bried Check if the interpreter is initialized
+  \internal
+*/
+bool PyInterp_Interp::initialized() const
+{
+  return _initialized;
+}
diff --git a/tools/PyInterp/src/PyInterp_Interp.h b/tools/PyInterp/src/PyInterp_Interp.h
new file mode 100644 (file)
index 0000000..88e5519
--- /dev/null
@@ -0,0 +1,103 @@
+// 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   : PyInterp_Interp.h
+//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
+
+#ifndef PYINTERP_INTERP_H
+#define PYINTERP_INTERP_H
+
+#include "PyInterp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "PyInterp_Utils.h"
+
+#include <list>
+#include <string>
+
+typedef void PyOutChanged(void* data,char * c);
+
+typedef struct {
+  PyObject_HEAD
+  int softspace;
+  PyOutChanged* _cb;
+  void* _data;
+  bool _iscerr;
+} PyStdOut;
+
+/**
+ * Main class representing a *virtual* Python interpreter. There is really only one true
+ * Python interpreter in the whole application (no call to Py_NewInterpreter),
+ * but the use of different execution contexts allow
+ * to split the execution lines, and hence to emulate (relatively) independent interpreters.
+ * This has some consequences: modules imported in one context are not re-imported in another context
+ * (only there namespace is made available when importing in another context).
+ * See also class PyConsole_Interp.
+ */
+class PYINTERP_EXPORT PyInterp_Interp
+{
+public:
+  static int _argc;
+  static char* _argv[];
+  
+  PyInterp_Interp();
+  virtual ~PyInterp_Interp();
+  
+  void initialize();
+  void destroy();
+
+  virtual int run(const char *command); 
+  virtual void initStudy() {};
+
+  std::string getBanner() const;
+  void setverrcb(PyOutChanged*, void*);
+  void setvoutcb(PyOutChanged*, void*);
+
+  const char* getPrevious();
+  const char* getNext();
+
+protected:
+  /** Redirection of stdout and stderr */
+  PyObject* _vout;
+  PyObject* _verr;
+  /** Execution context (local and global variables) */
+  PyObject* _global_context;
+  PyObject* _local_context;
+
+  std::list<std::string> _history;
+  std::list<std::string>::iterator _ith;
+
+  virtual int beforeRun();
+  virtual int afterRun();
+  int simpleRun(const char* command, const bool addToHistory = true);
+
+  virtual void initPython();
+
+  /** Initialize execution context. */
+  virtual bool initContext();
+  virtual bool initRun();
+  virtual void closeContext();
+
+  bool initialized() const;
+
+private:
+  bool _initialized;
+};
+
+#endif // PYINTERP_INTERP_H
diff --git a/tools/PyInterp/src/PyInterp_Request.cxx b/tools/PyInterp/src/PyInterp_Request.cxx
new file mode 100644 (file)
index 0000000..f8227f0
--- /dev/null
@@ -0,0 +1,93 @@
+// 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   : PyInterp_Request.h
+//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
+
+#include "PyInterp_Request.h"
+#include "PyInterp_Utils.h"
+
+#include <QCoreApplication>
+
+void PyInterp_Request::process()
+{
+  safeExecute();
+
+  bool isSync = IsSync();
+
+  if ( !isSync )
+    myMutex.lock();
+
+  if ( listener() )
+    processEvent( listener() );
+
+  if ( !isSync )
+    myMutex.unlock();
+}
+
+void PyInterp_Request::safeExecute()
+{
+  execute();
+}
+
+void PyInterp_Request::Destroy( PyInterp_Request* request )
+{
+  // Lock and unlock the mutex to avoid errors on its deletion
+  request->myMutex.lock();
+  request->myMutex.unlock();
+  delete request;
+}
+
+QEvent* PyInterp_Request::createEvent()
+{
+  return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, this );
+}
+
+void PyInterp_Request::processEvent( QObject* o )
+{
+  if ( !o )
+    return;
+
+  QEvent* e = createEvent();
+  if ( !e )
+    return;
+
+  if ( !IsSync() )
+    QCoreApplication::postEvent( o, e );
+  else
+  {
+    QCoreApplication::sendEvent( o, e );
+    delete e;
+  }
+}
+
+void PyInterp_Request::setListener( QObject* o )
+{
+  myMutex.lock();
+  myListener = o;
+  myMutex.unlock();
+}
+
+void PyInterp_LockRequest::safeExecute()
+{
+  PyLockWrapper aLock; // Acquire GIL
+  execute();
+}
diff --git a/tools/PyInterp/src/PyInterp_Request.h b/tools/PyInterp/src/PyInterp_Request.h
new file mode 100644 (file)
index 0000000..cabb3d6
--- /dev/null
@@ -0,0 +1,113 @@
+// 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   : PyInterp_Request.h
+//  Author : Sergey Anikin (OPEN CASCADE S.A.S.), Adrien Bruneton (CEA/DEN)
+
+#ifndef PYINTERP_REQUEST_H
+#define PYINTERP_REQUEST_H
+
+#include "PyInterp.h"
+#include "PyInterp_Event.h"
+
+#include <QMutex>
+
+class QObject;
+class PyInterp_Interp;
+
+/**
+   \class PyInterp_Request
+   \brief Base Python interpreter request; does not not acquire GIL during execution.
+ */
+class PYINTERP_EXPORT PyInterp_Request
+{
+  friend class PyInterp_Dispatcher;
+
+private:
+  PyInterp_Request();
+  PyInterp_Request( const PyInterp_Request& );
+
+protected:
+  // protected destructor - to control deletion of requests
+  virtual ~PyInterp_Request() {};
+
+public:
+  // Constructor
+  PyInterp_Request( QObject* listener, bool sync = true )
+    : myIsSync( sync ), myListener( listener ) {};
+
+  // Deletes a request
+  static void     Destroy( PyInterp_Request* );
+
+  // Returns true if this request should be processed synchronously,
+  // without putting it to a queue
+  bool            IsSync() const { return myIsSync; }
+
+protected:
+  // Performs safe execution of the request
+  virtual void    safeExecute();
+
+  // Should be redefined in successors, contains actual request code
+  virtual void    execute() = 0;
+
+  // This method can be overridden to customize notification event creation
+  virtual QEvent* createEvent();
+
+  virtual void    processEvent( QObject* );
+
+  // Provide access to the listener of this request
+  QObject*        listener() const { return myListener; }
+  void            setListener( QObject* );
+
+private:
+  // Process request, invoked from Dispatcher
+  void            process();
+
+private:
+  QMutex          myMutex;
+  bool            myIsSync;
+  QObject*        myListener;
+};
+
+/**
+   \class PyInterp_LockRequest
+   \brief Python interpreter request; automatically acquires GIL during execution.
+ */
+class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request
+{
+public:
+  // Constructor
+  PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener=0, bool sync=true )
+    : PyInterp_Request( listener, sync ), myInterp( interp )
+  {}
+
+protected:
+  // Get interpreter
+  PyInterp_Interp*  getInterp() const { return myInterp; }
+
+  // Performs safe execution of the request
+  virtual void      safeExecute();
+
+private:
+  PyInterp_Interp*  myInterp;
+};
+
+#endif // PYINTERP_REQUEST_H
diff --git a/tools/PyInterp/src/PyInterp_Utils.h b/tools/PyInterp/src/PyInterp_Utils.h
new file mode 100644 (file)
index 0000000..8d6ce8c
--- /dev/null
@@ -0,0 +1,108 @@
+// 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   : PyInterp_Utils.h
+//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
+
+#ifndef PYINTERP_UTILS_H
+#define PYINTERP_UTILS_H
+
+#include "PyInterp.h"
+
+#ifdef _DEBUG_
+  #include <iostream>
+#endif
+
+/**
+ * \class PyLockWrapper
+ * \brief Python GIL wrapper.
+ *
+ * Utility class wrapping the Python GIL acquisition. This makes use of the high level
+ * API (PyGILState_Ensure and PyGILState_Release), and is hence compatible with only
+ * one running Python interpreter (no call to Py_NewInterpreter()).
+ * When the class is instanciated the lock is acquired. It is released at destruction time.
+ * Copy construction (and hence assignation) is forbidden.
+ */
+class PYINTERP_EXPORT PyLockWrapper
+{
+public:
+  /**
+   * \brief Constructor. Automatically acquires GIL.
+   */
+  PyLockWrapper()
+  {
+    _gil_state = PyGILState_Ensure();
+    // Save current thread state for later comparison
+    _state = PyGILState_GetThisThreadState();
+  }
+
+  /**
+   * \brief Destructor. Automatically releases GIL.
+   */
+  ~PyLockWrapper()
+  {
+    PyThreadState* _currState = PyGILState_GetThisThreadState();
+#ifdef _DEBUG_
+    if (_currState != _state)
+    {
+      std::cout << "!!!!!!!!! PyLockWrapper inconsistency - now entering infinite loop for debugging\n";
+      while(1);
+    }
+#endif
+    PyGILState_Release(_gil_state);
+  }
+
+private:
+  PyGILState_STATE _gil_state;
+  PyThreadState* _state;
+
+  // "Rule of 3" - Forbid usage of copy operator and copy-constructor
+  PyLockWrapper(const PyLockWrapper & another);
+  const PyLockWrapper & operator=(const PyLockWrapper & another);
+};
+
+/**
+ * \class PyObjWrapper
+ * \brief Utility class to properly handle the reference counting required on Python objects.
+ */
+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;
+  }
+};
+
+#endif // PYINTERP_UTILS_H