Salome HOME
Split PyConsole in order to be used easily outside GUI of SALOME.
authorAnthony Geay <anthony.geay@edf.fr>
Mon, 22 Feb 2016 13:44:49 +0000 (14:44 +0100)
committerAnthony Geay <anthony.geay@edf.fr>
Mon, 14 Mar 2016 09:44:20 +0000 (10:44 +0100)
Conflicts:
src/PyConsole/CMakeLists.txt

50 files changed:
CMakeLists.txt
SalomeGUIConfig.cmake.in
adm_local/cmake_files/FindGUI.cmake
adm_local/cmake_files/deprecated/FindGUI.cmake
src/CMakeLists.txt
src/LightApp/CMakeLists.txt
src/LightApp/resources/LightApp.xml
src/PyConsole/CMakeLists.txt
src/PyConsole/PyConsole_Console.cxx
src/PyConsole/PyConsole_Console.h
src/PyConsole/PyConsole_Editor.cxx
src/PyConsole/PyConsole_Editor.h
src/PyConsole/PyConsole_EnhEditor.cxx
src/PyConsole/PyConsole_EnhEditor.h
src/PyConsole/PyConsole_EnhInterp.cxx [deleted file]
src/PyConsole/PyConsole_EnhInterp.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
src/PyConsole/resources/PyConsole_msg_fr.ts [changed mode: 0755->0644]
src/PyConsole/resources/PyConsole_msg_ja.ts
src/PyConsoleBase/CMakeLists.txt [new file with mode: 0755]
src/PyConsoleBase/PyConsoleBase.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_ConsoleBase.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_ConsoleBase.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_EditorBase.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_EditorBase.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_EnhEditorBase.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_EnhEditorBase.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_EnhInterp.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_EnhInterp.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_Event.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_Event.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_Interp.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_Interp.h [new file with mode: 0644]
src/PyConsoleBase/PyConsole_Request.cxx [new file with mode: 0644]
src/PyConsoleBase/PyConsole_Request.h [new file with mode: 0644]
src/PyConsoleBase/resources/PyConsoleBase_msg_en.ts [new file with mode: 0644]
src/PyConsoleBase/resources/PyConsoleBase_msg_fr.ts [new file with mode: 0644]
src/PyConsoleBase/resources/PyConsoleBase_msg_ja.ts [new file with mode: 0644]
src/Qtx/Qtx.cxx
src/Qtx/Qtx.h
src/SALOME_PYQT/SalomePyQt/CMakeLists.txt
src/SUIT/SUIT_Tools.cxx
src/SUIT/SUIT_Tools.h
src/SalomeApp/CMakeLists.txt

index 347ee31e5e5a562ea988e53468693ebc77ca836b..2afecb5e2525108fc3e94e9bd8b3ffb035a5aa0a 100755 (executable)
@@ -377,7 +377,7 @@ ENDIF()
 # Python-based packages specific targets:
 IF(SALOME_USE_PYCONSOLE)
   LIST(APPEND _${PROJECT_NAME}_exposed_targets 
-       PyInterp PyConsole  SalomePyQtGUILight)
+       PyInterp PyConsoleBase PyConsole SalomePyQtGUILight)
   IF(SALOME_USE_PLOT2DVIEWER)
     LIST(APPEND _${PROJECT_NAME}_exposed_targets SalomePyQt)
   ENDIF()
index 9b5b44472a8da92e8fcbbc22bbfe3a2481038941..82a895b374a6fdab3318b29cf77f07f8c67c7844 100644 (file)
@@ -192,6 +192,7 @@ SET(GUI_ObjBrowser ObjBrowser)
 SET(GUI_OCCViewer OCCViewer)
 SET(GUI_OpenGLUtils OpenGLUtils)
 SET(GUI_Plot2d Plot2d)
+SET(GUI_PyConsoleBase PyConsoleBase)
 SET(GUI_PyConsole PyConsole)
 SET(GUI_PyInterp PyInterp)
 SET(GUI_PyEditor PyEditor)
index 7a185c84a2d71eb653b208ed6e7413251835a511..ef6ffa9c456456e9cc1b2b0f66c4ec73ae62256d 100644 (file)
@@ -36,6 +36,7 @@ FIND_LIBRARY(OCCViewer OCCViewer ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(OpenGLUtils OpenGLUtils ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(Plot2d Plot2d ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(PyConsole PyConsole ${GUI_ROOT_DIR}/lib/salome)
+FIND_LIBRARY(PyConsoleBase PyConsoleBase ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(PyInterp PyInterp ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(QDS QDS ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(qtx qtx ${GUI_ROOT_DIR}/lib/salome)
index cf4277198855d6513868a5464fdc3d76219cac09..ff29e7b16fad72b3008e1b09a5e6bdff7534b335 100644 (file)
@@ -32,6 +32,7 @@ FIND_LIBRARY(OCCViewer OCCViewer ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(OpenGLUtils OpenGLUtils ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(Plot2d Plot2d ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(PyConsole PyConsole ${GUI_ROOT_DIR}/lib/salome)
+FIND_LIBRARY(PyConsoleBase PyConsoleBase ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(PyInterp PyInterp ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(QDS QDS ${GUI_ROOT_DIR}/lib/salome)
 FIND_LIBRARY(qtx qtx ${GUI_ROOT_DIR}/lib/salome)
index 6435a1ccfc526556a126ea66364d8818b3ae237c..ba919fa87f1378548731b20d79fc23324194a602 100755 (executable)
@@ -124,6 +124,7 @@ ENDIF(SALOME_USE_PYVIEWER)
 ##
 IF(SALOME_USE_PYCONSOLE) 
   ADD_SUBDIRECTORY(PyInterp)
+  ADD_SUBDIRECTORY(PyConsoleBase)
   ADD_SUBDIRECTORY(PyConsole)
   ADD_SUBDIRECTORY(SALOME_PYQT)
 ENDIF(SALOME_USE_PYCONSOLE)
index 9b39c65e80202d549ee302f54f26c2b910ff2a2c..ce4553dae3f1016432b8412ba42476412edfa007 100755 (executable)
@@ -82,6 +82,7 @@ IF(SALOME_USE_PYCONSOLE)
   INCLUDE_DIRECTORIES(
     ${PYTHON_INCLUDE_DIRS}
     ${PROJECT_SOURCE_DIR}/src/PyConsole
+    ${PROJECT_SOURCE_DIR}/src/PyConsoleBase
     ${PROJECT_SOURCE_DIR}/src/PyInterp
     ${PROJECT_SOURCE_DIR}/src/SUITApp
   )
index 37c53bb808bc9344ece413c40475ce1d73dda349..86757736467b1a9fbb34fdd784d6db82f4f51fa0 100644 (file)
@@ -73,6 +73,7 @@
     <parameter name="PyEditor"      value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
     <parameter name="PyViewer"      value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
     <parameter name="PyConsole"     value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
+    <parameter name="PyConsoleBase" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
     <parameter name="SalomeApp"     value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
     <parameter name="OB"            value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
     <parameter name="CAM"           value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
index 36904dd3cd8dc71256a84e6fc37f805dba5cfaf7..e7fb30e4cb7d480fd3abb4293daed3627d67894f 100755 (executable)
@@ -25,6 +25,8 @@ INCLUDE(UseQt4Ext)
 INCLUDE_DIRECTORIES(
   ${QT_INCLUDES}
   ${PYTHON_INCLUDE_DIRS}
+  ${PROJECT_SOURCE_DIR}/src/PyConsole
+  ${PROJECT_SOURCE_DIR}/src/PyConsoleBase
   ${PROJECT_SOURCE_DIR}/src/Qtx
   ${PROJECT_SOURCE_DIR}/src/SUIT
   ${PROJECT_SOURCE_DIR}/src/Event
@@ -35,7 +37,7 @@ INCLUDE_DIRECTORIES(
 ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
 
 # libraries to link to
-SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} qtx suit PyInterp Event)
+SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} qtx suit PyConsoleBase)
 
 # --- headers ---
 
@@ -49,10 +51,6 @@ SET(_moc_HEADERS
 # header files / no moc processing
 SET(_other_HEADERS
   PyConsole.h
-  PyConsole_EnhInterp.h
-  PyConsole_Event.h
-  PyConsole_Interp.h
-  PyConsole_Request.h
 )
 
 # header files / to install
@@ -60,27 +58,23 @@ SET(PyConsole_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
 
 # --- resources ---
 
+# --- sources ---
 # 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
 QT4_WRAP_CPP(_moc_SOURCES ${_moc_HEADERS})
 
 # sources / static
 SET(_other_SOURCES
   PyConsole_Console.cxx
-  PyConsole_Editor.cxx
   PyConsole_EnhEditor.cxx
-  PyConsole_EnhInterp.cxx
-  PyConsole_Event.cxx
-  PyConsole_Interp.cxx
-  PyConsole_Request.cxx
+  PyConsole_Editor.cxx
 )
 
 # sources / to compile
@@ -94,4 +88,3 @@ INSTALL(TARGETS PyConsole EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME
 
 INSTALL(FILES ${PyConsole_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
 QT4_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}")
-
index e684bf1e6c11cdc1d1aa4b9f331d4343448daf62..43e9cb6a49333557d3ca3c2053f9a47444951b7b 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "PyConsole_Interp.h"   /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
 #include "PyConsole_Console.h"
+#include "PyConsole_Editor.h"
 #include "PyConsole_EnhEditor.h"
 #include "PyConsole_EnhInterp.h"
 
 #include <QMenu>
 #include <QVBoxLayout>
 
+PyConsole_EditorBase *PyConsole_Console::PyConsole_Interp_Creator::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new PyConsole_Editor(interp,console); }
+
+PyConsole_Interp *PyConsole_Console::PyConsole_Interp_Creator::createInterp( ) const
+{ return new PyConsole_Interp; }
+
 /*!
   \brief Constructor.
 
   \param interp python interpreter
 */
 PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* interp )
-: QWidget( parent )
+  : PyConsole_ConsoleBase( parent, interp, 0 )
 {
-  PyConsole_Interp* anInterp = interp ? interp : new PyConsole_Interp();
-  
-  // initialize Python interpretator
-  anInterp->initialize();
-  
-  // create editor console
-  QVBoxLayout* lay = new QVBoxLayout( this );
-  lay->setMargin( 0 );
-  myEditor = new PyConsole_Editor( anInterp, this );
-  char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
-  if (synchronous && atoi(synchronous))
-  {
-      myEditor->setIsSync(true);
-  }
-  myEditor->viewport()->installEventFilter( this );
-  lay->addWidget( myEditor );
-
-  createActions();
+  PyConsole_Interp_Creator crea;
+  defaultConstructor(interp,crea);
 }
 
 /**
  * Protected constructor.
  */
-PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* /*i*/,  PyConsole_Editor* e )
-  : QWidget (parent), myEditor(e)
-{}
+PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* i,  PyConsole_Editor* e )
+  : PyConsole_ConsoleBase(parent,i,e)
+{  
+}
 
 /*!
   \brief Destructor.
@@ -88,128 +80,16 @@ PyConsole_Console::~PyConsole_Console()
 {
 }
 
-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 True if python console works in synchronous mode
-*/
-bool PyConsole_Console::isSync() const
-{
-  return myEditor->isSync();
-}
-
-/*!
-  \brief Set synchronous mode flag value.
-
-  In synhronous mode the Python commands are executed in the GUI thread
-  and the GUI is blocked until the command is finished. In the asynchronous
-  mode each Python command is executed in the separate thread that does not
-  block the main GUI loop.
-
-  \param on synhronous mode flag
-*/
-void PyConsole_Console::setIsSync( const bool on )
-{
-  myEditor->setIsSync( on );
-}
-
-/*!
-  \brief Get suppress output flag value.
-  
-  \sa setIsSuppressOutput()
-  \return True if python console output is suppressed.
-*/
-bool PyConsole_Console::isSuppressOutput() const
-{
-  return myEditor->isSuppressOutput();
-}
-
-/*!
-  \brief Set suppress output flag value.
-
-  In case if suppress output flag is true, the python 
-  console output suppressed.
-
-  \param on suppress output flag
-*/
-void PyConsole_Console::setIsSuppressOutput( const bool on )
-{
-  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->isShowBanner();
-}
-
-/*!
-  \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 )
-{
-  myEditor->setIsShowBanner( on );
-}
+  \brief Create the context popup menu.
 
-/*!
-  \brief Change the python console's font.
-  \param f new font
-*/
-void PyConsole_Console::setFont( const QFont& f )
-{
-  if( myEditor )
-    myEditor->setFont( f );
-}
+  Fill in the popup menu with the commands.
 
-/*!
-  \brief Get python console font.
-  \return current python console's font
+  \param menu context popup menu
 */
-QFont PyConsole_Console::font() const
+void PyConsole_Console::contextMenuPopup( QMenu *menu )
 {
-  QFont res;
-  if( myEditor )
-    res = myEditor->font();
-  return res;
+  PyConsole_ConsoleBase::contextMenuPopup(menu);
 }
 
 /*!
@@ -231,143 +111,11 @@ bool PyConsole_Console::eventFilter( QObject* o, QEvent* e )
   return QWidget::eventFilter( o, e );
 }
 
-/*!
-  \brief Create the context popup menu.
+PyConsole_EditorBase *PyConsole_EnhConsole::PyConsole_Interp_EnhCreator::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new PyConsole_EnhEditor(interp,console); }
 
-  Fill in the popup menu with the commands.
-
-  \param menu context popup menu
-*/
-void PyConsole_Console::contextMenuPopup( QMenu* menu )
-{
-  if ( myEditor->isReadOnly() )
-    return;
-
-  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] );
-
-  Qtx::simplifySeparators( menu );
-
-  updateActions();
-}
-
-/*!
-  \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->textCursor().hasSelection() );
-  myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
-  myActions[SelectAllId]->setEnabled( !myEditor->document()->isEmpty() );
-}
-
-/*!
-  \brief Start python trace logging
-  \param fileName the path to the log file
-*/
-void PyConsole_Console::startLog( const QString& fileName )
-{
-  myEditor->startLog( fileName );
-}
-
-/*!
-  \brief Stop python trace logging
-*/
-void PyConsole_Console::stopLog()
-{
-  myEditor->stopLog();
-}
+PyConsole_Interp *PyConsole_EnhConsole::PyConsole_Interp_EnhCreator::createInterp( ) const
+{ return new PyConsole_EnhInterp; }
 
 /**
  * Similar to constructor of the base class but using enhanced objects.
@@ -378,22 +126,6 @@ void PyConsole_Console::stopLog()
 PyConsole_EnhConsole::PyConsole_EnhConsole( QWidget* parent, PyConsole_Interp* interp )
   : PyConsole_Console( parent, interp, 0 )
 {
-  PyConsole_Interp* anInterp = interp ? interp : new PyConsole_EnhInterp();
-
-  // initialize Python interpretator
-  anInterp->initialize();
-
-  // create editor console
-  QVBoxLayout* lay = new QVBoxLayout( this );
-  lay->setMargin( 0 );
-  myEditor = new PyConsole_EnhEditor( anInterp, this );
-  char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
-  if (synchronous && atoi(synchronous))
-  {
-      myEditor->setIsSync(true);
-  }
-  myEditor->viewport()->installEventFilter( this );
-  lay->addWidget( myEditor );
-
-  createActions();
+  PyConsole_Interp_EnhCreator crea;
+  defaultConstructor(interp,crea);
 }
index ce8f36467170f50b9fa0ae653d0906393df40bc8..1aa68a4d68f4c82e6bcfbe81c2b9a89be804a863 100644 (file)
@@ -27,7 +27,7 @@
 #define PYCONSOLE_CONSOLE_H
 
 #include "PyConsole.h"
-
+#include <PyConsole_ConsoleBase.h>
 #include <SUIT_PopupClient.h>
 #include <QWidget>
 #include <QMap>
 class PyConsole_Interp;
 class PyConsole_Editor;
 
-class PYCONSOLE_EXPORT PyConsole_Console : public QWidget, public SUIT_PopupClient
+class PYCONSOLE_EXPORT PyConsole_Console : public PyConsole_ConsoleBase, public SUIT_PopupClient
 {
   Q_OBJECT
-
 public:
-  //! Context popup menu actions flags
-  enum
+
+  struct PyConsole_Interp_Creator : public PyConsole_Interp_CreatorBase
   {
-    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 
+    virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+    virtual PyConsole_Interp *createInterp( ) const;
   };
 
 public:
   PyConsole_Console( QWidget* parent, PyConsole_Interp* interp = 0 );
   virtual ~PyConsole_Console();
-
-  //! \brief Get python interperter
-  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                exec( const QString& );
-  void                execAndWait( const QString& );
-
-  virtual bool        eventFilter( QObject*, QEvent* );
-
   //! \brief Get popup client symbolic name
   virtual QString     popupClientType() const { return QString( "PyConsole" ); }
   virtual void        contextMenuPopup( QMenu* );
-
-  void                setMenuActions( const int );
-  int                 menuActions() const;
-
-  void                startLog( const QString& );
-  void                stopLog();
-
+  virtual bool        eventFilter( QObject*, QEvent* );
 protected:
-  void                createActions();
-  void                updateActions();
-
   PyConsole_Console( QWidget* parent, PyConsole_Interp*,  PyConsole_Editor*);
-
-  PyConsole_Editor*   myEditor;    //!< python console editor widget
-  QMap<int, QAction*> myActions;   //!< menu actions list
 };
 
 /**
@@ -101,9 +62,16 @@ protected:
  * Similar to PyConsole_Console except that an enhanced interpreter and enhanced editor
  * are encapsulated.
  */
-class PYCONSOLE_EXPORT PyConsole_EnhConsole: public PyConsole_Console
+class PYCONSOLE_EXPORT PyConsole_EnhConsole : public PyConsole_Console
 {
   Q_OBJECT
+public:
+
+  struct PyConsole_Interp_EnhCreator : public PyConsole_Interp_CreatorBase
+  {
+    virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+    virtual PyConsole_Interp *createInterp( ) const;
+  };
 
 public:
   PyConsole_EnhConsole( QWidget* parent, PyConsole_Interp* interp = 0 );
index 2311b58d46bb29a3e2b48be8b4b7cd2020572401..2371eecae54b961e162795ca7e0d697e85f6e7a9 100644 (file)
 #include "PyInterp_Dispatcher.h"
 #include "PyConsole_Request.h"
 
-#include <SUIT_Tools.h>
-#include <SUIT_FileDlg.h>
-#include <SUIT_MessageBox.h>
-#include <SUIT_FileValidator.h>
+#include "SUIT_FileValidator.h"
+#include "SUIT_MessageBox.h"
+#include "SUIT_FileDlg.h"
 
 #include <QApplication>
 #include <QClipboard>
 #include <QTextDocument>
 #include <QTextStream>
 #include <QChar>
-
-//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  = "... ";
+#include <QFileInfo>
 
 class DumpCommandsFileValidator : public SUIT_FileValidator
 {
@@ -152,25 +133,6 @@ bool DumpCommandsFileValidator::canSave(const QString& file, bool permissions)
   return SUIT_FileValidator::canSave( file, permissions);
 }
 
-void staticCallbackStdout( void* data, char* c )
-{
-  if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
-    PyConsole_Editor* e = (PyConsole_Editor*)data;
-    e->putLog( fromUtf8(c) );
-    QApplication::postEvent( e, new PrintEvent( fromUtf8(c), false ) );
-  }
-}
-
-void staticCallbackStderr( void* data, char* c )
-{
-  if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
-    PyConsole_Editor* e = (PyConsole_Editor*)data;
-    e->putLog( fromUtf8(c) );
-    QApplication::postEvent( e, new PrintEvent( fromUtf8(c), true ) );
-  }
-}
-
-
 /*!
   \brief Constructor. 
   
@@ -180,29 +142,8 @@ void staticCallbackStderr( void* data, char* c )
 */
 PyConsole_Editor::PyConsole_Editor( PyConsole_Interp* theInterp, 
                                     QWidget*          theParent )
-: QTextEdit( theParent ),
-  myInterp( 0 ),
-  myCmdInHistory( -1 ),
-  myEventLoop( 0 ),
-  myShowBanner( true ),
-  myIsSync( true ),
-  myIsSuppressOutput( false )
+  : PyConsole_EditorBase(theInterp,theParent)
 {
-  QString fntSet( "" );
-  QFont aFont = SUIT_Tools::stringToFont( fntSet );
-  setFont( aFont );
-  setUndoRedoEnabled( false );
-
-  myPrompt = READY_PROMPT;
-  setLineWrapMode( QTextEdit::WidgetWidth );
-  setWordWrapMode( QTextOption::WrapAnywhere );
-  setAcceptRichText( false );
-
-  theInterp->setvoutcb( staticCallbackStdout, this );
-  theInterp->setverrcb( staticCallbackStderr, this );
-
-  // san - This is necessary for troubleless initialization
-  onPyInterpChanged( theInterp );
 }
 
 /*!
@@ -210,991 +151,43 @@ PyConsole_Editor::PyConsole_Editor( PyConsole_Interp* theInterp,
 */
 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 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 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 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() ? myBanner.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 True, then the string is printed on a new line
-  \param isError if true, the text is printed in dark red
-*/
-void PyConsole_Editor::addText( const QString& str, 
-                                const bool     newBlock,
-                                const bool    isError)
-{
-  QTextCursor theCursor(textCursor());
-  QTextCharFormat cf;
-
-  moveCursor( QTextCursor::End );
-  if ( newBlock )
-    theCursor.insertBlock();
-  if (isError)
-      cf.setForeground(QBrush(Qt::red));
-  else
-      cf.setForeground(QBrush(Qt::black));
-  theCursor.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( createRequest( cmd ) );
-}
-
-/*!
-  \brief Create request to the python dispatcher for the command execution.
-
-  \param command python command to be executed
- */
-PyInterp_Request* PyConsole_Editor::createRequest( const QString& command )
-{
-  return new ExecCommand( myInterp, command, this, isSync() );
-}
-
-/*!
-  \brief Execute command in the python interpreter
-  and wait until it is finished.
-
-  \param command python command to be executed
- */
-void PyConsole_Editor::execAndWait( const QString& command )
-{
-  // 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 curs(textCursor());
-  curs.movePosition(QTextCursor::End);
-  setTextCursor(curs);
-
-  // 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( createRequest( myCommandBuffer ) );
-}
-
-/*!
-  \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 cur = cursorForPosition( event->pos() );
-  // if the position is not in the last line move it to the end of the command line
-  if ( cur.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 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 );
-    //copy();
-  }
-  else if ( event->button() == Qt::MidButton ) {
-    QTextCursor cur = cursorForPosition( event->pos() );
-    // if the position is not in the last line move it to the end of the command line
-    if ( cur.position() < document()->end().previous().position() + promptSize() ) {
-      moveCursor( QTextCursor::End );
-    }
-    else {
-      setTextCursor( cur );
-    }
-    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 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 cur = textCursor();
-  int curLine = cur.blockNumber();
-  int curCol  = cur.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 ( 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() ) {
-            cur.setPosition( cur.block().position() + promptSize() );
-            setTextCursor( cur );
-            break;
-          }
-        }
-        else {
-          if ( curLine < endLine && isCommand( textCursor().block().next().text() ) ) {
-            cur.setPosition( cur.position() + promptSize()+1 );
-            setTextCursor( cur );
-            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( cur ).top();
-        qreal distance = 0;
-        // move using movePosition to keep the cursor's x
-        do {
-          qreal y = cursorRect( cur ).top();
-          distance += qAbs( y - lastY );
-          lastY = y;
-          moved = cur.movePosition( QTextCursor::Up, 
-                                    shftPressed ? QTextCursor::KeepAnchor : 
-                                                  QTextCursor::MoveAnchor );
-        } while ( moved && distance < viewport()->height() );
-        if ( moved ) {
-          cur.movePosition( QTextCursor::Down, 
-                            shftPressed ? QTextCursor::KeepAnchor : 
-                                          QTextCursor::MoveAnchor );
-          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
-        }
-        setTextCursor( cur );
-      }
-      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( cur ).top();
-        qreal distance = 0;
-        // move using movePosition to keep the cursor's x
-        do {
-          qreal y = cursorRect( cur ).top();
-          distance += qAbs( y - lastY );
-          lastY = y;
-          moved = cur.movePosition( QTextCursor::Down, 
-                                    shftPressed ? QTextCursor::KeepAnchor : 
-                                                  QTextCursor::MoveAnchor );
-        } while ( moved && distance < viewport()->height() );
-        if ( moved ) {
-          cur.movePosition( QTextCursor::Up, 
-                            shftPressed ? QTextCursor::KeepAnchor : 
-                                          QTextCursor::MoveAnchor );
-          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
-        }
-        setTextCursor( cur );
-      }
-      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() ) {
-              cur.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
-              cur.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
-            }
-          }
-          else {
-            cur.movePosition( QTextCursor::StartOfLine );
-            cur.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
-          }
-          setTextCursor( cur );
-        }
-        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 ( cur.hasSelection() ) {
-        cut();
-      }
-      else if ( cur.position() > document()->end().previous().position() + promptSize() ) {
-        if ( shftPressed ) {
-          moveCursor( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
-          textCursor().removeSelectedText();
-        }
-        else if ( ctrlPressed ) {
-          cur.setPosition( document()->end().previous().position() + promptSize(),
-                           QTextCursor::KeepAnchor );
-          setTextCursor( cur );
-          textCursor().removeSelectedText();
-        }
-        else {
-          QTextEdit::keyPressEvent( event );
-        }
-      }
-      else {
-        cur.setPosition( document()->end().previous().position() + promptSize() );
-        setTextCursor( cur );
-        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 ( cur.hasSelection() ) {
-        cut();
-      }
-      else if ( cur.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 {
-        cur.setPosition( document()->end().previous().position() + promptSize() );
-        setTextCursor( cur );
-        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;
-    }
-  }
-}
-
-/*!
-  \brief Handle notification event coming from Python dispatcher.
-  \param event notification event
-*/
-void PyConsole_Editor::customEvent( QEvent* event )
-{
-  switch( event->type() )
-  {
-  case PrintEvent::EVENT_ID:
-    {
-      PrintEvent* pe=(PrintEvent*)event;
-      addText( pe->text(), false, pe->isError());
-      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();
-    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();
-    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 Handle Python interpreter change.
 
-  Perform initialization actions if the interpreter is changed.
-  \param interp python interpreter is being set
-*/
-void PyConsole_Editor::onPyInterpChanged( PyConsole_Interp* interp )
+void PyConsole_Editor::StaticDumpSlot(PyConsole_EditorBase *base)
 {
-  if ( myInterp != interp 
-       // Force read-only state and wait cursor when myInterp is NULL
-      || !myInterp ) {
-    myInterp = interp;
-    if ( myInterp ) {
-      // print banner
-      myBanner = myInterp->getbanner().c_str();
-      if ( isShowBanner() )
-       addText( myBanner );
-      // 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();
-      // stop event loop (if running)
-      if( myEventLoop)
-        myEventLoop->exit();
-    }
-    else {
-      // clear contents
-      clear();
-      // set read-only state
-      setReadOnly( true );
-      // set busy cursor
-      setCursor( Qt::WaitCursor );
-    }
-  }
-}
-
-/*!
-  \brief "Copy" operation.
+  QStringList aFilters;
+  aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
   
-  Reimplemented from Qt.
-  Warning! In Qt4 this method is not virtual.
- */
-void PyConsole_Editor::cut()
-{
-  QTextCursor cur = textCursor();
-  if ( cur.hasSelection() ) {
-    QApplication::clipboard()->setText( cur.selectedText() );
-    int startSelection = cur.selectionStart();
-    if ( startSelection < document()->end().previous().position() + promptSize() )
-      startSelection = document()->end().previous().position() + promptSize();
-    int endSelection = cur.selectionEnd();
-    if ( endSelection < document()->end().previous().position() + promptSize() )
-      endSelection = document()->end().previous().position() + promptSize();
-    cur.setPosition( startSelection );
-    cur.setPosition( endSelection, QTextCursor::KeepAnchor );
-    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-    setTextCursor( cur );
-    textCursor().removeSelectedText();
-  }
-}
-
-/*!
-  \brief "Paste" operation.
-
-  Reimplemented from Qt.
-  Warning! In Qt4 this method is not virtual.
- */
-void PyConsole_Editor::paste()
-{
-  QTextCursor cur = textCursor();
-  if ( cur.hasSelection() ) {
-    int startSelection = cur.selectionStart();
-    if ( startSelection < document()->end().previous().position() + promptSize() )
-      startSelection = document()->end().previous().position() + promptSize();
-    int endSelection = cur.selectionEnd();
-    if ( endSelection < document()->end().previous().position() + promptSize() )
-      endSelection = document()->end().previous().position() + promptSize();
-    cur.setPosition( startSelection );
-    cur.setPosition( endSelection, QTextCursor::KeepAnchor );
-    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
-    setTextCursor( cur );
-    textCursor().removeSelectedText();
-  }
-  if ( textCursor().position() < document()->end().previous().position() + promptSize() )
-    moveCursor( QTextCursor::End );
-  QTextEdit::paste();
-}
-
-/*!
-  \brief "Clear" operation.
-
-  Reimplemented from Qt.
-  Warning! In Qt4 this method is not virtual.
- */
-void PyConsole_Editor::clear()
-{
-  QTextEdit::clear();
-  if ( isShowBanner() )
-    addText( myBanner );
-  myPrompt = READY_PROMPT;
-  addText( myPrompt );
+  QString fileName = SUIT_FileDlg::getFileName( base, QString(),
+                                               aFilters, tr( "TOT_DUMP_PYCOMMANDS" ),
+                                               false, true, new DumpCommandsFileValidator( base ) );
+  base->dumpImpl(fileName);
 }
 
 /*!
   \brief "Dump commands" operation.
  */
-void PyConsole_Editor::dump()
+void PyConsole_Editor::dumpSlot()
 {
-  QStringList aFilters;
-  aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
-  
-  QString fileName = SUIT_FileDlg::getFileName( this, QString(),
-                                               aFilters, tr( "TOT_DUMP_PYCOMMANDS" ),
-                                               false, true, new DumpCommandsFileValidator( this ) );
-  if ( !fileName.isEmpty() ) {
-    QFile file( fileName ); 
-    if ( !file.open( QFile::WriteOnly ) )
-      return;
-
-    QTextStream out (&file);
-  
-    for ( int i=0; i<myHistory.count(); i++ ) {
-      out << myHistory[i] << endl;
-    }
-    file.close();
-  }
+  PyConsole_Editor::StaticDumpSlot(this);
 }
-/*!
-  \brief "Start log" operation.
- */
-void PyConsole_Editor::startLog()
+
+void PyConsole_Editor::StaticStartLogSlot(PyConsole_EditorBase *base)
 {
   QStringList aFilters;
   aFilters.append( tr( "LOG_FILES_FILTER" ) );
 
   while (1) {
-    QString fileName = SUIT_FileDlg::getFileName( this, QString(),
+    QString fileName = SUIT_FileDlg::getFileName( base, QString(),
                                                  aFilters, tr( "TOT_SAVE_PYLOG" ),
                                                  false, true );
     if ( !fileName.isEmpty() ) {
-      if ( startLog( fileName ) ) {
+      if ( base->startLogImpl( fileName ) ) {
        break;
       }
       else {
-       SUIT_MessageBox::critical( this,
+       SUIT_MessageBox::critical( base,
                                   QObject::tr("ERR_ERROR"),
                                   QObject::tr("ERR_FILE_NOT_WRITABLE") );
       }
@@ -1206,46 +199,9 @@ void PyConsole_Editor::startLog()
 }
 
 /*!
-  \brief Start python trace logging
-  \param fileName the path to the log file
-  \sa stopLog()
- */
-bool PyConsole_Editor::startLog( const QString& fileName )
-{
-  bool ok = false;
-  if ( !fileName.isEmpty() ) {
-    QFile file( fileName );
-    if ( file.open( QFile::WriteOnly ) ) {
-      file.close();
-      myLogFile = fileName;
-      ok = true;
-    }
-  }
-  return ok;
-}
-
-/*!
-  \brief "Stop log" operation.
-  \sa startLog()
- */
-void PyConsole_Editor::stopLog()
-{
-  myLogFile = QString();
-}
-
-/*!
-  \brief Put string to the log file
+  \brief "Start log" operation.
  */
-void PyConsole_Editor::putLog( const QString& s )
+void PyConsole_Editor::startLogSlot()
 {
-  if ( !myLogFile.isEmpty() ) {
-    QFile file( myLogFile );
-    if ( !file.open( QFile::Append ) )
-      return;
-    
-    QTextStream out (&file);
-    out << s;
-    
-    file.close();
-  }
+  StaticStartLogSlot(this);
 }
index 5dbc8d15e3636b2f876dfc91a75f6879c0ab7d77..a8821992ed798a913c04238bff092cc830da0676 100644 (file)
@@ -28,6 +28,7 @@
 #define PYCONSOLE_EDITOR_H
 
 #include "PyConsole.h"
+#include "PyConsole_EditorBase.h"
 
 #include <QTextEdit>
 
@@ -35,72 +36,17 @@ class PyConsole_Interp;
 class PyInterp_Request;
 class QEventLoop;
 
-class PYCONSOLE_EXPORT PyConsole_Editor : public QTextEdit
+class PYCONSOLE_EXPORT PyConsole_Editor : public PyConsole_EditorBase
 {
   Q_OBJECT;
-
 public:
   PyConsole_Editor( PyConsole_Interp* theInterp, QWidget *theParent = 0 );
   ~PyConsole_Editor();
-
-  PyConsole_Interp* getInterp() const;
-  
-  virtual void   addText( const QString& str, const bool newBlock = false, const bool isError = false );
-  bool           isCommand( const QString& str ) const;
-
-  virtual void   exec( const QString& command );
-  void           execAndWait( const QString& command );
-
-  bool           isSync() const;
-  void           setIsSync( const bool );
-
-  bool           isSuppressOutput() const;
-  void           setIsSuppressOutput(const bool);
-
-  bool           isShowBanner() const;
-  void           setIsShowBanner( const bool );
-
-  bool           isLogging() const;
-
-  virtual QSize  sizeHint() const;
-
-public slots:
-    void           cut();
-    void           paste();
-    void           clear();
-    void           handleReturn();
-    void           onPyInterpChanged( PyConsole_Interp* );
-    void           dump();
-    bool           startLog( const QString& );
-    void           startLog();
-    void           stopLog();
-    void           putLog( const QString& );
-
+  static void StaticDumpSlot(PyConsole_EditorBase *base);
+  static void StaticStartLogSlot(PyConsole_EditorBase *base);
 protected:
-  virtual void   dropEvent( QDropEvent* event );
-  virtual void   mouseReleaseEvent( QMouseEvent* event );
-  virtual void   keyPressEvent ( QKeyEvent* event);
-  virtual void   customEvent( QEvent* event);
-
-  virtual PyInterp_Request* createRequest( const QString& );
-
-  /** Convenience function */
-  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
-  QString           myBanner;           //!< current banner
-  bool              myShowBanner;       //!< 'show banner' flag
-  QStringList       myQueue;            //!< python commands queue
-  bool              myIsSync;           //!< synchronous mode flag
-  bool              myIsSuppressOutput; //!< suppress output flag
+  virtual void dumpSlot();
+  virtual void startLogSlot();
 };
 
 #endif // PYCONSOLE_EDITOR_H
index d4cf274a222026cdc66ea393d2d9c784ab95f88b..dd4619b1e419eed400db71c2aa72c1320da92b3c 100644 (file)
 #include <QMimeData>
 
 #include "PyConsole_EnhEditor.h"
-#include "PyConsole_EnhInterp.h"
-#include "PyConsole_Request.h"
-#include "PyInterp_Dispatcher.h"
-
-// Initialize list of valid separators
-static const char * tmp_a[] = {" ", "(", "[","+", "-", "*", "/", ";", "^", "="};
-const std::vector<QString> PyConsole_EnhEditor::SEPARATORS = \
-    std::vector<QString>(tmp_a, tmp_a + sizeof(tmp_a)/sizeof(tmp_a[0]));
+#include "PyConsole_Editor.h"
 
 /**
  * Constructor.
@@ -45,447 +38,16 @@ const std::vector<QString> PyConsole_EnhEditor::SEPARATORS = \
  * @param parent parent widget
  */
 PyConsole_EnhEditor::PyConsole_EnhEditor(PyConsole_Interp* interp, QWidget* parent) :
-     PyConsole_Editor(interp, parent),
-     _tab_mode(false),
-     _cursor_pos(-1),
-     _multi_line_paste(false),
-     _multi_line_content()
-{
-  document()->setUndoRedoEnabled(true);
-}
-
-/**
- * Overrides. Catches the TAB and Ctrl+TAB combinations.
- * @param event
- */
-void PyConsole_EnhEditor::keyPressEvent ( QKeyEvent* event)
-{
-  // check if <Ctrl> is pressed
-  bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
-  // check if <Shift> is pressed
-  bool shftPressed = event->modifiers() & Qt::ShiftModifier;
-
-  if (event->key() == Qt::Key_Tab && !shftPressed)
-    {
-      if (!ctrlPressed)
-        handleTab();
-      else
-        {
-          clearCompletion();
-          handleBackTab();
-        }
-      PyConsole_Editor::keyPressEvent(event);
-    }
-  else
-    {
-      // If ctrl is not pressed (and sth else is pressed with it),
-      // or if ctrl is not pressed alone
-      if (!ctrlPressed || (ctrlPressed && event->key() != Qt::Key_Control))
-        {
-          clearCompletion();
-          _cursor_pos = -1;
-        }
-      // Discard ctrl pressed alone:
-      if (event->key() != Qt::Key_Control)
-        PyConsole_Editor::keyPressEvent(event);
-    }
-}
-
-/**
- * Whenever the mouse is clicked, clear the completion.
- * @param e
- */
-void PyConsole_EnhEditor::mousePressEvent(QMouseEvent* e)
-{
-  clearCompletion();
-  _cursor_pos = -1;
-  PyConsole_Editor::mousePressEvent(e);
-}
-
-/**
- * Clear in the editor the block of text displayed after having hit <TAB>.
- */
-void PyConsole_EnhEditor::clearCompletion()
-{
-  // Delete completion text if present
-  if (_tab_mode)
-    {
-      // 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
-      if ( myInterp ) 
-       myInterp->clearCompletion();
-    }
-  _tab_mode = false;
-}
-
-/**
- * Handle the sequence of events after having hit <TAB>
- */
-void PyConsole_EnhEditor::handleTab()
-{
-  if (_tab_mode)
-    {
-      // Already tab mode - nothing to do !
-      return;
-    }
-
-  QTextCursor cursor(textCursor());
-
-  // Cursor at end of input
-  cursor.movePosition(QTextCursor::End);
-  setTextCursor(cursor);
-
-  // Save cursor position if needed
-  if (_cursor_pos == -1)
-    _cursor_pos = textCursor().position();
-
-  // get last line
-  QTextBlock par = document()->end().previous();
-  if ( !par.isValid() ) return;
-
-  // Switch to completion mode
-  _tab_mode = true;
-
-  QString cmd = par.text().mid(promptSize());
-
-  // Post completion request
-  // Editor will be informed via a custom event that completion has been run
-  PyInterp_Request* req = createTabRequest(cmd);
-  PyInterp_Dispatcher::Get()->Exec(req);
-}
-
-/**
- * Handles what happens after hitting Ctrl-TAB
- */
-void PyConsole_EnhEditor::handleBackTab()
-{
-  QTextCursor cursor(textCursor());
-
-  if (_cursor_pos == -1)
-    {
-      // Invalid cursor position - we can't do anything:
-      return;
-    }
-  // Ensure cursor is at the end of command line
-  cursor.setPosition(_cursor_pos);
-  cursor.movePosition(QTextCursor::EndOfLine);
-  //setCursor(cursor);
-
-  // Delete last completed text
-  int i = cursor.position() - _cursor_pos;
-  cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, i);
-  cursor.removeSelectedText();
-  _cursor_pos = -1;
-}
-
-/**
- * Create the Python requested that will be posted to the interpreter to
- * get the completions.
- * @param input line typed by the user at the time TAB was hit
- * @return a CompletionCommand
- * @sa CompletionCommand
- */
-PyInterp_Request* PyConsole_EnhEditor::createTabRequest( const QString& input )
-{
-  // 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;
-  for (std::vector<QString>::const_iterator i = SEPARATORS.begin(); i != SEPARATORS.end(); i++)
-    {
-      int j = input2.lastIndexOf(*i);
-      if (j > lastSp)
-        lastSp = j;
-    }
-  if (lastSp >= 0)
-    input2 = input.mid(lastSp+1);
-
-  // Detect a qualified name (with a point)
-  int lastPt = input2.lastIndexOf(QString("."));
-
-  // Split the 2 surrounding parts of the qualified name
-  if (lastPt != -1)
-    {
-      _compl_before_point = input2.left(lastPt);
-      _compl_after_point = input2.mid(lastPt+1);
-    }
-  else
-    {
-      // No point found - do a global matching -
-      // (the following will call dir() with an empty string)
-      _compl_after_point = input2;
-      _compl_before_point = QString("");
-    }
-
-  return new CompletionCommand( myInterp, _compl_before_point,
-                               _compl_after_point, this, isSync() );
-}
-
-/**
- * Format completion results - this is where we should create 3 columns etc ...
- * @param matches list of possible completions
- * @param result return value
- */
-void PyConsole_EnhEditor::formatCompletion(const QStringList& matches, QString& result) const
+     PyConsole_EnhEditorBase(interp, parent)
 {
-  int sz = matches.size();
-
-  if (sz > MAX_COMPLETIONS)
-    {
-      sz = MAX_COMPLETIONS;
-      result.append("[Too many matches! Displaying first ones only ...]\n");
-    }
-
-  for (int i = 0; i < sz; ++i)
-    {
-      result.append(matches[i]);
-      result.append("\n");
-    }
 }
 
-/**
- * Override. Catches the events generated by the enhanced interpreter after the execution
- * of a completion request.
- * @param event
- */
-void PyConsole_EnhEditor::customEvent( QEvent* event )
+void PyConsole_EnhEditor::dumpSlot()
 {
-  QStringList matches;
-  QString first_match, comple_text, doc, base;
-  QTextCursor cursor(textCursor());
-  QTextBlockFormat bf;
-  QTextCharFormat cf;
-  int cursorPos;
-
-  switch( event->type() )
-  {
-    case PyInterp_Event::ES_TAB_COMPLETE_OK:
-    {
-      // Extract corresponding matches from the interpreter
-      matches = getInterp()->getLastMatches();
-      doc = getInterp()->getDocStr();
-
-      if (matches.size() == 0)
-      {
-       // Completion successful but nothing returned.
-       _tab_mode = false;
-       _cursor_pos = -1;
-       return;
-      }
-      
-      // Only one match - complete directly and update doc string window
-      if (matches.size() == 1)
-      {
-       first_match = matches[0].mid(_compl_after_point.size());
-       cursor.insertText(first_match);
-       _tab_mode = false;
-       if (doc.isEmpty())
-         emit updateDoc(formatDocHTML("(no documentation available)\n"));
-       else
-         emit updateDoc(formatDocHTML(doc));
-      }
-      else
-      {
-       // Detect if there is a common base to all available completion
-       // In this case append this base to the text already
-       extractCommon(matches, base);
-       first_match = base.mid(_compl_after_point.size());
-       cursor.insertText(first_match);
-       
-       // If this happens to match exaclty the first completion
-       // also provide doc
-       if (base == matches[0])
-       {
-         doc = formatDocHTML(doc);
-         emit updateDoc(doc);
-       }
-       
-       // Print all matching completion in a "undo-able" block
-       cursorPos = cursor.position();
-       cursor.insertBlock();
-       cursor.beginEditBlock();
-       
-       // Insert all matches
-       QTextCharFormat cf;
-       cf.setForeground(QBrush(Qt::darkGreen));
-       cursor.setCharFormat(cf);
-       formatCompletion(matches, comple_text);
-       cursor.insertText(comple_text);
-       cursor.endEditBlock();
-       
-       // Position cursor where it was before inserting the completion list:
-       cursor.setPosition(cursorPos);
-       setTextCursor(cursor);
-      }
-      break;
-    }
-    case PyInterp_Event::ES_TAB_COMPLETE_ERR:
-    {
-      // Tab completion was unsuccessful, switch off mode:
-      _tab_mode = false;
-      _cursor_pos = -1;
-      break;
-    }
-    case PyInterp_Event::ES_OK:
-    case PyInterp_Event::ES_ERROR:
-    case PyInterp_Event::ES_INCOMPLETE:
-    {
-      // Before everything else, call super()
-      PyConsole_Editor::customEvent(event);
-      // If we are in multi_paste_mode, process the next item:
-      multiLineProcessNextLine();
-      break;
-    }
-    default:
-    {
-      PyConsole_Editor::customEvent( event );
-      break;
-    }
-  }
+  PyConsole_Editor::StaticDumpSlot(this);
 }
 
-/**
- * Extract the common leading part of all strings in matches.
- * @param matches
- * @param result
- */
-void PyConsole_EnhEditor::extractCommon(const QStringList& matches, QString& result) const
+void PyConsole_EnhEditor::startLogSlot()
 {
-  result = "";
-  int charIdx = 0;
-
-  if (matches.size() < 2)
-    return;
-
-  while (true)
-    {
-      if (charIdx >= matches[0].size())
-        return;
-      QChar ch = matches[0][charIdx];
-      for (int j = 1; j < matches.size(); j++)
-        if (charIdx >= matches[j].size() || matches[j][charIdx] != ch)
-          return;
-      result += ch;
-      charIdx++;
-    }
-}
-
-/**
- * Format the doc string in HTML format with the first line in bold blue
- * @param doc initial doc string
- * @return HTML string
- */
-QString PyConsole_EnhEditor::formatDocHTML(const QString & doc) const
-{
-  QString templ = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" ") +
-      QString(" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n ") +
-      QString("<html><head><meta name=\"qrichtext\" content=\"1\" /> ") +
-      QString("<style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style> ") +
-      QString("</head><body style=\" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;\">\n") +
-      QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">") +
-      QString("<span style=\" font-weight:600; color:#0000ff;\">%1</span></p>") +
-      QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%2</p>") +
-      QString("</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 templ.arg(fst).arg(rest);
-}
-
-/**
- * Handle properly multi-line pasting. Qt4 doc recommends overriding this function.
- * If the pasted text doesn't contain a line return, no special treatment is done.
- * @param source
- */
-void PyConsole_EnhEditor::insertFromMimeData(const QMimeData* source)
-{
-  if (_multi_line_paste)
-    return;
-
-  if (source->hasText())
-    {
-      QString s = source->text();
-      if (s.contains("\n"))
-        multilinePaste(s);
-      else
-        PyConsole_Editor::insertFromMimeData(source);
-    }
-  else
-    {
-      PyConsole_Editor::insertFromMimeData(source);
-    }
-}
-
-
-void PyConsole_EnhEditor::multilinePaste(const QString & s)
-{
-  // Turn on multi line pasting mode
-  _multi_line_paste = true;
-
-  // Split the string:
-  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
-  // sth was already there:
-  QMimeData source;
-  source.setText(lst[0]);
-  PyConsole_Editor::insertFromMimeData(&source);
-
-  // Prepare what will have to be executed after the first line:
-  _multi_line_content = std::queue<QString>();
-  for (int i = 1; i < lst.size(); ++i)
-    _multi_line_content.push(lst[i]);
-
-  // Trigger the execution of the first (mixed) line
-  handleReturn();
-
-  // See customEvent() and multiLineProcessNext() for the rest of the handling.
-}
-
-/**
- * Process the next line in the queue of a multiple copy/paste:
- */
-void PyConsole_EnhEditor::multiLineProcessNextLine()
-{
-  if (!_multi_line_paste)
-    return;
-
-  QString line(_multi_line_content.front());
-  _multi_line_content.pop();
-  if (!_multi_line_content.size())
-    {
-      // last line in the queue, just paste it
-      addText(line, false, false);
-      _multi_line_paste = false;
-    }
-  else
-    {
-      // paste the line and simulate a <RETURN> key stroke
-      addText(line, false, false);
-      handleReturn();
-    }
+  PyConsole_Editor::StaticStartLogSlot(this);
 }
index f505066d32aa1f94a792fa773f7f2974868a38b7..f14402e3be099222d714c705d70e9024e27cc3c1 100644 (file)
@@ -23,7 +23,7 @@
 #define PYCONSOLE_ENHEDITOR_H_
 
 #include "PyConsole.h"
-#include "PyConsole_Editor.h"
+#include "PyConsole_EnhEditorBase.h"
 
 #include <QObject>
 #include <queue>
 /**
  * Enhanced Python editor handling tab completion.
  */
-class PYCONSOLE_EXPORT PyConsole_EnhEditor: public PyConsole_Editor
+class PYCONSOLE_EXPORT PyConsole_EnhEditor : public PyConsole_EnhEditorBase
 {
   Q_OBJECT;
-
 public:
   PyConsole_EnhEditor(PyConsole_Interp* interp, QWidget* parent = 0);
   virtual ~PyConsole_EnhEditor() {}
-
-signals:
-  /**
-   * Signal emitted by the editor widget when the doc string should be updated.
-   * @param doc a HTML block with the formatted doc string.
-   * TODO: for now this signal is left uncaught.
-   */
-  void updateDoc(QString doc);
-
 protected:
-  /** List of separators identifying the last parsable token for completion */
-  static const std::vector<QString> SEPARATORS;
-
-  /** Maximum number of completions shown at once */
-  static const int MAX_COMPLETIONS = 70;
-
-  /** Are we in completion mode */
-  bool _tab_mode;
-
-  /** String on which the dir() comamnd is executed */
-  QString _compl_before_point;
-  /** String on which the results of the dir() are matched */
-  QString _compl_after_point;
-
-  /** Cursor position when <TAB> is hit */
-  int _cursor_pos;
-
-  /** Are we currently pasting several lines */
-  bool _multi_line_paste;
-
-  /** Queue of lines being pasted */
-  std::queue<QString> _multi_line_content;
-
-  // Overrides:
-  virtual void   keyPressEvent ( QKeyEvent* event);
-  virtual void   customEvent( QEvent* event);
-  virtual void   mousePressEvent( QMouseEvent* event );
-  virtual void   insertFromMimeData(const QMimeData* source);
-
-  virtual PyInterp_Request* createTabRequest( const QString& input );
-  virtual void handleTab();
-  virtual void handleBackTab();
-  virtual void clearCompletion();
-  virtual void formatCompletion(const QStringList& matches, QString& result) const;
-  virtual QString formatDocHTML(const QString & doc) const;
-
-  virtual void multilinePaste(const QString & s);
-  virtual void multiLineProcessNextLine();
-
-private:
-  void extractCommon(const QStringList& matches, QString& result) const;
-
+  virtual void dumpSlot();
+  virtual void startLogSlot();
 };
 
 #endif /* PYCONSOLE_ENHEDITOR_H_ */
diff --git a/src/PyConsole/PyConsole_EnhInterp.cxx b/src/PyConsole/PyConsole_EnhInterp.cxx
deleted file mode 100644 (file)
index bb32304..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (C) 2007-2015  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
-//
-// Author : Adrien Bruneton (CEA/DEN)
-// Created on: 4 avr. 2013
-
-
-#include "PyConsole.h"
-
-#include "PyConsole_EnhInterp.h"
-
-#include <pythonrun.h>
-#include <string>
-#include <QRegExp>
-
-static const char * tmp_k[] = {"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"};
-
-const std::vector<QString> PyConsole_EnhInterp::PYTHON_KEYWORDS = \
-      std::vector<QString>(tmp_k, tmp_k+sizeof(tmp_k)/sizeof(tmp_k[0]));
-
-/*!
-  \brief Constructor
-*/
-PyConsole_EnhInterp::PyConsole_EnhInterp()
-  : PyConsole_Interp()
-{
-}
-
-/*!
-  \brief Destructor
-*/
-PyConsole_EnhInterp::~PyConsole_EnhInterp()
-{
-}
-
-QStringList PyConsole_EnhInterp::getLastMatches() const
-{
-  return _last_matches;
-}
-
-QString PyConsole_EnhInterp::getDocStr() const
-{
-  return _doc_str;
-}
-
-/*!
-  \brief Run Python dir() command and saves the result internally in _lastPy
-  \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".
-  \return command exit status - 0 = success
-*/
-int PyConsole_EnhInterp::runDirCommand(const QString& dirArgument, const QString& startMatch)
-{
-  int ret;
-  std::vector<QString> v;
-
-  clearCompletion();
-  if ( (ret = runDirAndExtract(dirArgument, startMatch, _last_matches)) )
-      return ret;
-
-  // If dirArgument is empty, we append the __builtins__
-  if (dirArgument.isEmpty())
-    {
-      if ( (ret = runDirAndExtract(QString("__builtins__"), startMatch, _last_matches, false)) )
-            return ret;
-
-      // ... and we match on Python's keywords as well:
-      for (std::vector<QString>::const_iterator it = PYTHON_KEYWORDS.begin(); it != PYTHON_KEYWORDS.end(); it++)
-          if ((*it).startsWith(startMatch))
-            _last_matches.push_back(*it);
-    }
-
-  // Try to get doc string of the first match
-  if (_last_matches.size() > 0)
-    {
-      QString cmd("");
-      if (dirArgument.trimmed() != "")
-        cmd = dirArgument + ".";
-      cmd += _last_matches[0] + ".__doc__";
-      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();
-          _doc_str = "";
-        }
-      else
-        _doc_str = QString(PyString_AsString(str));
-      Py_XDECREF(str);
-    }
-
-  // The command has been successfully executed
-  return 0;
-}
-
-/**
- * See runDirCommand().
- * @param dirArgument see runDirCommand()
- * @param startMatch  see runDirCommand()
- * @param[out] result the list of matches
- * @param discardSwig if true a regular expression is used to discard all static method generated
- * by SWIG. typically: MEDCouplingUMesh_Blabla
- * @return -1 if the call to dir() or the parsing of the result failed, 0 otherwise.
- */
-int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument,
-                                         const QString& startMatch,
-                                         QStringList& result,
-                                         bool discardSwig) const
-{
-  QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$");  // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
-  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 -1;
-  }
-
-  // Extract the returned list and convert it to a vector<>
-  if (!PySequence_Check(plst))
-    {
-      // Should never happen ...
-      //std::cerr << "not a list!" << std::endl;
-      Py_XDECREF(plst);
-      return -1;
-    }
-
-  // Convert plst to a vector of QString
-  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.push_back(s);
-      Py_DECREF(it);
-    }
-  Py_DECREF(plst);
-
-  return 0;
-}
-
-/**
- * Clear internal members containing the last completion results.
- */
-void PyConsole_EnhInterp::clearCompletion()
-{
-  _last_matches.clear();
-  _doc_str = "";
-}
diff --git a/src/PyConsole/PyConsole_EnhInterp.h b/src/PyConsole/PyConsole_EnhInterp.h
deleted file mode 100644 (file)
index b8fb04a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2007-2015  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
-//
-// Author : Adrien Bruneton (CEA/DEN)
-// Created on: 4 avr. 2013
-
-
-#ifndef PYCONSOLE_ENHINTERP_H_
-#define PYCONSOLE_ENHINTERP_H_
-
-#include "PyConsole.h"
-
-#include <Python.h>
-#include "PyConsole_Interp.h"
-
-#include <vector>
-#include <QString>
-
-/**
- * Enhanced Python interpreter used for auto-completion.
- * This extends PyConsole_Interp with an API wrapping the Python dir() command nicely.
- */
-class PYCONSOLE_EXPORT PyConsole_EnhInterp: public PyConsole_Interp
-{
-public:
-  PyConsole_EnhInterp();
-  virtual ~PyConsole_EnhInterp();
-
-  virtual QStringList getLastMatches() const;
-  virtual QString getDocStr() const;
-
-  virtual int runDirCommand(const QString& dirArgument, const QString& startMatch);
-  virtual void clearCompletion();
-
-protected:
-  /** Hard coded list of Python keywords */
-  static const std::vector<QString> PYTHON_KEYWORDS;
-
-  /** Last computed matches */
-  QStringList _last_matches;
-  /** Doc string of the first match - when only one match it will be displayed by the Editor*/
-  QString _doc_str;
-
-  virtual int runDirAndExtract(const QString& dirArgument, const QString& startMatch,
-                              QStringList& result, bool discardSwig=true) const;
-};
-
-#endif /* PYCONSOLE_ENHINTERP_H_ */
diff --git a/src/PyConsole/PyConsole_Event.cxx b/src/PyConsole/PyConsole_Event.cxx
deleted file mode 100644 (file)
index aaeb257..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2007-2015  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
-//
-//  Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
-
-#include "PyConsole_Event.h"
diff --git a/src/PyConsole/PyConsole_Event.h b/src/PyConsole/PyConsole_Event.h
deleted file mode 100644 (file)
index 6ec1d51..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2007-2015  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
-//
-//  Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
-
-#ifndef PYCONSOLE_EVENT_H
-#define PYCONSOLE_EVENT_H
-
-#include "PyConsole.h"
-
-#include <QEvent>
-#include <QString>
-
-/*!
-  \class PrintEvent
-  \brief Python command output backend event.
-  \internal
-*/
-class PrintEvent : public QEvent
-{
-public:
-  static const int EVENT_ID = 65432;
-
-  /*!
-    \brief Constructor
-    \param c message text (python trace)
-    \param isError default to false - if true indicates that an error is being printed.
-  */
-  PrintEvent( const QString& c, bool isError = false) :
-    QEvent( (QEvent::Type)EVENT_ID ), myText( c ), errorFlag(isError)
-  {}
-
-  /*!
-    \brief Get message
-    \return message text (python trace)
-  */
-  QString text() const { return myText; }
-
-  /**
-   * @return true if this is an error message
-   */
-  bool isError() const { return errorFlag; }
-
-protected:
-  QString myText; //!< Event message (python trace)
-
-  /** Set to true if an error msg is to be displayed */
-  bool errorFlag;
-};
-
-#endif // PYCONSOLE_EVENT_H
diff --git a/src/PyConsole/PyConsole_Interp.cxx b/src/PyConsole/PyConsole_Interp.cxx
deleted file mode 100644 (file)
index ca459b5..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2007-2015  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, Adrien BRUNETON
-
-#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
-*/
-
-/*!
-  \brief Constructor.
-
-  Creates new python interpreter.
-*/
-PyConsole_Interp::PyConsole_Interp(): PyInterp_Interp()
-{
-}
-
-/*!
-  \brief Destructor.
-
-  Does nothing for the moment.
-*/
-PyConsole_Interp::~PyConsole_Interp()
-{
-}
-
-/*! 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.
-*
-* (GIL is already acquired here)
-*/
-int PyConsole_Interp::beforeRun()
-{
-  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=True");
-}
-int PyConsole_Interp::afterRun()
-{
-  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=False");
-}
-
-QStringList PyConsole_Interp::getLastMatches() const
-{
-  return QStringList();
-}
-
-QString PyConsole_Interp::getDocStr() const
-{
-  return QString();
-}
-
-int PyConsole_Interp::runDirCommand(const QString&, const QString& )
-{
-  return 0;
-}
-
-void PyConsole_Interp::clearCompletion()
-{
-}
diff --git a/src/PyConsole/PyConsole_Interp.h b/src/PyConsole/PyConsole_Interp.h
deleted file mode 100644 (file)
index 1aac736..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2007-2015  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, Adrien BRUNETON
-
-#ifndef PYCONSOLE_INTERP_H
-#define PYCONSOLE_INTERP_H
-
-#include "PyConsole.h"
-#include "PyInterp_Interp.h"   /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
-
-#include <QStringList>
-
-class PYCONSOLE_EXPORT PyConsole_Interp : public PyInterp_Interp
-{
-public:
-  PyConsole_Interp();
-  ~PyConsole_Interp();
-
-  virtual int afterRun();
-  virtual int beforeRun();
-
-  virtual QStringList getLastMatches() const;
-  virtual QString getDocStr() const;
-
-  virtual int runDirCommand(const QString&, const QString&);
-  virtual void clearCompletion();
-};
-
-#endif // PYCONSOLE_INTERP_H
diff --git a/src/PyConsole/PyConsole_Request.cxx b/src/PyConsole/PyConsole_Request.cxx
deleted file mode 100644 (file)
index 5c67b8b..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (C) 2007-2015  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
-//
-// Author : Adrien Bruneton (CEA/DEN)
-// Created on: 3 avr. 2013
-
-#include "PyConsole_Request.h"
-#include "PyConsole_Interp.h"
-#include "PyConsole_Event.h"
-#include "PyInterp_Event.h"
-
-#include <QCoreApplication>
-
-/**
- * Constructor.
- * @param theInterp interpreter that will execute the command
- * @param theCommand command text
- * @param theListener editor object that will receive the response events after execution
- * of the request
- * @param sync
- */
-ExecCommand::ExecCommand( PyInterp_Interp*        theInterp,
-                         const QString&          theCommand,
-                         QObject*                theListener,
-                         bool                    theSync )
-  : PyInterp_LockRequest( theInterp, theListener, theSync ),
-    myCommand( theCommand ), myState( PyInterp_Event::ES_OK )
-{}
-
-/**
- * Execute the command by calling the run() method of the embedded interpreter.
- */
-void 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;
-  }
-}
-
-/**
- * Create the event indicating the status of the request execution.
- * @return a QEvent
- */
-QEvent* ExecCommand::createEvent()
-{
-  if ( IsSync() )
-    QCoreApplication::sendPostedEvents( listener(), PrintEvent::EVENT_ID );
-  return new PyInterp_Event( myState, this );
-}
-
-
-/*!
-  Constructor.
-  Creates a new python completion request.
-  \param theInterp   python interpreter
-  \param input  string containing the dir() command to be executed
-  \param startMatch  part to be matched with the results of the dir() command
-  \param theListener widget to get the notification messages
-  \param sync        if True the request is processed synchronously
-*/
-CompletionCommand::CompletionCommand( PyInterp_Interp*   theInterp,
-                                     const QString&     theInput,
-                                     const QString&     theStartMatch,
-                                     QObject*           theListener,
-                                     bool               theSync )
-  : PyInterp_LockRequest( theInterp, theListener, theSync ),
-    _tabSuccess(false), _dirArg(theInput), _startMatch(theStartMatch)
-{}
-
-/**
- * Execute the completion command by wrapping the runDirCommand() of the
- * embedded enhanced interpreter.
- */
-void CompletionCommand::execute()
-{
-  int ret = static_cast<PyConsole_Interp*>(getInterp())->runDirCommand( _dirArg,  _startMatch );
-  _tabSuccess = ret == 0;
-}
-
-/**
- * Create the event indicating the return value of the completion command.
- * @return
- */
-QEvent* CompletionCommand::createEvent()
-{
-  int typ = _tabSuccess ? PyInterp_Event::ES_TAB_COMPLETE_OK : PyInterp_Event::ES_TAB_COMPLETE_ERR;
-  return new PyInterp_Event( typ, this);
-}
diff --git a/src/PyConsole/PyConsole_Request.h b/src/PyConsole/PyConsole_Request.h
deleted file mode 100644 (file)
index a0ed598..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (C) 2007-2015  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
-//
-// Author : Adrien Bruneton (CEA/DEN)
-// Created on: 3 avr. 2013
-
-
-#ifndef PYCONSOLE_REQUEST_H_
-#define PYCONSOLE_REQUEST_H_
-
-#include "PyInterp_Request.h"
-
-#include <vector>
-#include <QString>
-#include <QEvent>
-
-class PyInterp_Interp;
-
-/*!
-  \class ExecCommand
-  \brief Python command execution request.
-  \internal
-*/
-class ExecCommand : public PyInterp_LockRequest
-{
-public:
-  /*!
-    \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 sync        if True the request is processed synchronously
-  */
-  ExecCommand( PyInterp_Interp*        theInterp,
-               const QString&          theCommand,
-               QObject*                theListener,
-               bool                    theSync = false );
-
-protected:
-  /*!
-    \brief Execute the python command in the interpreter and
-           get its execution status.
-  */
-  virtual void execute();
-
-  /*!
-    \brief Create and return a notification event.
-    \return new notification event
-  */
-  virtual QEvent* createEvent();
-
-private:
-  QString myCommand;   //!< Python command
-  int     myState;     //!< Python command execution status
-};
-
-class CompletionCommand : public PyInterp_LockRequest
-{
-public:
-  CompletionCommand( PyInterp_Interp*     theInterp,
-                    const QString&       theInput,
-                    const QString&       theStartMatch,
-                    QObject*             theListener,
-                    bool                 theSync = false );
-
-
-protected:
-  /** List of separators identifying the last parsable token for completion */
-  static const std::vector<QString> SEPARATORS;
-
-  /** String to be passed to the dir() command */
-  QString _dirArg;
-  /** Begining of the command (as typed by the user) */
-  QString _startMatch;
-  /** was the completion command successful */
-  bool _tabSuccess;
-
-  virtual void execute();
-  virtual QEvent* createEvent();
-};
-
-#endif /* PYCONSOLE_REQUEST_H_ */
index 3a3b89bd94a077e4af5f6f7e2b2a10674d86dfbf..a2d4aae3928597979134c1a7ae86da4fcd8c3281 100644 (file)
@@ -1,41 +1,6 @@
 <?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>
old mode 100755 (executable)
new mode 100644 (file)
index b4f16bd..905d68f
@@ -1,41 +1,6 @@
 <?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>
index 85e2cc732c46ca0f769a218ec0ce240d0bbf650e..dd8b48e3e5a300c457f8beb3a65825d4e76a6eaf 100644 (file)
@@ -1,41 +1,6 @@
 <?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>
diff --git a/src/PyConsoleBase/CMakeLists.txt b/src/PyConsoleBase/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..3e06a3f
--- /dev/null
@@ -0,0 +1,97 @@
+# Copyright (C) 2012-2015  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/Qtx
+  ${PROJECT_SOURCE_DIR}/src/PyConsoleBase
+  ${PROJECT_SOURCE_DIR}/src/Event
+  ${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 Event qtx)
+
+# --- headers ---
+
+# header files / to be processed by moc
+SET(_moc_HEADERS
+  PyConsole_ConsoleBase.h
+  PyConsole_EditorBase.h
+  PyConsole_EnhEditorBase.h
+)
+
+# header files / no moc processing
+SET(_other_HEADERS
+  PyConsoleBase.h
+  PyConsole_EnhInterp.h
+  PyConsole_Event.h
+  PyConsole_Interp.h
+  PyConsole_Request.h
+)
+
+# header files / to install
+SET(PyConsoleBase_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
+
+# --- resources ---
+
+# resource files / to be processed by lrelease
+SET(_ts_RESOURCES
+  resources/PyConsoleBase_msg_en.ts
+  resources/PyConsoleBase_msg_fr.ts
+  resources/PyConsoleBase_msg_ja.ts
+)
+
+# --- sources ---
+
+# sources / moc wrappings
+QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS})
+
+# sources / static
+SET(_other_SOURCES
+  PyConsole_ConsoleBase.cxx
+  PyConsole_EnhInterp.cxx
+  PyConsole_Event.cxx
+  PyConsole_Interp.cxx
+  PyConsole_Request.cxx
+  PyConsole_EditorBase.cxx
+  PyConsole_EnhEditorBase.cxx
+)
+
+# sources / to compile
+SET(PyConsoleBase_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
+
+# --- rules ---
+
+ADD_LIBRARY(PyConsoleBase ${PyConsoleBase_SOURCES})
+TARGET_LINK_LIBRARIES(PyConsoleBase ${_link_LIBRARIES})
+INSTALL(TARGETS PyConsoleBase EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
+
+INSTALL(FILES ${PyConsoleBase_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
+QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}")
+
diff --git a/src/PyConsoleBase/PyConsoleBase.h b/src/PyConsoleBase/PyConsoleBase.h
new file mode 100644 (file)
index 0000000..fcef126
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2007-2015  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   : PyConsoleBase.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#if !defined ( PYCONSOLEBASE_H )
+#define PYCONSOLEBASE_H
+
+// ========================================================
+// set dllexport type for Win platform 
+#ifdef WIN32
+#  if defined PYCONSOLEBASE_EXPORTS || defined PyConsoleBase_EXPORTS
+#    define PYCONSOLEBASE_EXPORT __declspec(dllexport)
+#  else
+#    define PYCONSOLEBASE_EXPORT __declspec(dllimport)
+#  endif
+#else   // WIN32
+#  define PYCONSOLEBASE_EXPORT
+#endif  // WIN32
+
+// ========================================================
+// avoid warning messages
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#pragma warning (disable : 4251)
+#endif
+
+#endif // PYCONSOLEBASE_H
diff --git a/src/PyConsoleBase/PyConsole_ConsoleBase.cxx b/src/PyConsoleBase/PyConsole_ConsoleBase.cxx
new file mode 100644 (file)
index 0000000..306dd99
--- /dev/null
@@ -0,0 +1,413 @@
+// Copyright (C) 2007-2015  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_ConsoleBase.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+/*!
+  \class PyConsole_Console
+  \brief Python console widget.
+*/  
+
+#include "PyConsole_Interp.h"   /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
+#include "PyConsole_ConsoleBase.h"
+#include "PyConsole_EnhEditorBase.h"
+#include "PyConsole_EnhInterp.h"
+
+#include "Qtx.h"
+
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
+#include <QEvent>
+#include <QMenu>
+#include <QContextMenuEvent>
+#include <QVBoxLayout>
+
+PyConsole_EditorBase *PyConsole_ConsoleBase::PyConsole_Interp_CreatorBase::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new PyConsole_EditorBase(interp,console); }
+
+PyConsole_Interp *PyConsole_ConsoleBase::PyConsole_Interp_CreatorBase::createInterp( ) const
+{ return new PyConsole_Interp; }
+
+/*!
+  \brief Constructor.
+
+  Creates new python console widget.
+  \param parent parent widget
+  \param interp python interpreter
+*/
+PyConsole_ConsoleBase::PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp* interp )
+: QWidget( parent )
+{
+  PyConsole_ConsoleBase::PyConsole_Interp_CreatorBase crea;
+  defaultConstructor(interp,crea);
+}
+
+/*!
+ * MUST BE NON VIRTUAL ! (called from constructor !!!!)
+ */
+void PyConsole_ConsoleBase::defaultConstructor( PyConsole_Interp* interp, const PyConsole_Interp_CreatorBase& crea )
+{
+  PyConsole_Interp *anInterp = interp ? interp : crea.createInterp();
+  
+  // initialize Python interpretator
+  anInterp->initialize();
+  
+  // create editor console
+  QVBoxLayout* lay = new QVBoxLayout( this );
+  lay->setMargin( 0 );
+  myEditor = crea.createEditor( anInterp, this );
+  char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
+  if (synchronous && atoi(synchronous))
+  {
+      myEditor->setIsSync(true);
+  }
+  myEditor->viewport()->installEventFilter( this );
+  lay->addWidget( myEditor );
+
+  createActions();
+}
+
+/**
+ * Protected constructor.
+ */
+PyConsole_ConsoleBase::PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp* /*i*/,  PyConsole_EditorBase* e )
+  : QWidget (parent), myEditor(e)
+{}
+
+/*!
+  \brief Destructor.
+
+  Does nothing for the moment.
+*/
+PyConsole_ConsoleBase::~PyConsole_ConsoleBase()
+{
+}
+
+PyConsole_Interp* PyConsole_ConsoleBase::getInterp() const
+{
+  return myEditor ? myEditor->getInterp() : 0;
+} 
+
+/*!
+  \brief Execute python command in the interpreter.
+  \param command string with command and arguments
+*/
+void PyConsole_ConsoleBase::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_ConsoleBase::execAndWait( const QString& command )
+{
+  if ( myEditor )
+    myEditor->execAndWait( command );
+}
+
+/*!
+  \brief Get synchronous mode flag value.
+  
+  \sa setIsSync()
+  \return True if python console works in synchronous mode
+*/
+bool PyConsole_ConsoleBase::isSync() const
+{
+  return myEditor->isSync();
+}
+
+/*!
+  \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_ConsoleBase::setIsSync( const bool on )
+{
+  myEditor->setIsSync( on );
+}
+
+/*!
+  \brief Get suppress output flag value.
+  
+  \sa setIsSuppressOutput()
+  \return True if python console output is suppressed.
+*/
+bool PyConsole_ConsoleBase::isSuppressOutput() const
+{
+  return myEditor->isSuppressOutput();
+}
+
+/*!
+  \brief Set suppress output flag value.
+
+  In case if suppress output flag is true, the python 
+  console output suppressed.
+
+  \param on suppress output flag
+*/
+void PyConsole_ConsoleBase::setIsSuppressOutput( const bool on )
+{
+  myEditor->setIsSuppressOutput(on);
+}
+
+/*!
+  \brief Get 'show banner' flag value.
+  
+  \sa setIsShowBanner()
+  \return \c true if python console shows banner
+*/
+bool PyConsole_ConsoleBase::isShowBanner() const
+{
+  return myEditor->isShowBanner();
+}
+
+/*!
+  \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_ConsoleBase::setIsShowBanner( const bool on )
+{
+  myEditor->setIsShowBanner( on );
+}
+
+/*!
+  \brief Change the python console's font.
+  \param f new font
+*/
+void PyConsole_ConsoleBase::setFont( const QFont& f )
+{
+  if( myEditor )
+    myEditor->setFont( f );
+}
+
+/*!
+  \brief Get python console font.
+  \return current python console's font
+*/
+QFont PyConsole_ConsoleBase::font() const
+{
+  QFont res;
+  if( myEditor )
+    res = myEditor->font();
+  return res;
+}
+
+/*!
+  \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_ConsoleBase::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_ConsoleBase::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_ConsoleBase::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_ConsoleBase::updateActions()
+{
+  myActions[CopyId]->setEnabled( myEditor->textCursor().hasSelection() );
+  myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
+  myActions[SelectAllId]->setEnabled( !myEditor->document()->isEmpty() );
+}
+
+/*!
+  \brief Start python trace logging
+  \param fileName the path to the log file
+*/
+void PyConsole_ConsoleBase::startLog( const QString& fileName )
+{
+  myEditor->startLog( fileName );
+}
+
+/*!
+  \brief Stop python trace logging
+*/
+void PyConsole_ConsoleBase::stopLog()
+{
+  myEditor->stopLog();
+}
+
+/*!
+  \brief Create the context popup menu.
+
+  Fill in the popup menu with the commands.
+
+  \param menu context popup menu
+*/
+void PyConsole_ConsoleBase::contextMenuPopup( QMenu *menu )
+{
+  if ( myEditor->isReadOnly() )
+    return;
+
+  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] );
+
+  Qtx::simplifySeparators( menu );
+
+  updateActions();
+}
+
+PyConsole_EditorBase *PyConsole_EnhConsoleBase::PyConsole_Interp_EnhCreatorBase::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new PyConsole_EnhEditorBase(interp,console); }
+
+PyConsole_Interp *PyConsole_EnhConsoleBase::PyConsole_Interp_EnhCreatorBase::createInterp( ) const
+{ return new PyConsole_EnhInterp; }
+
+/**
+ * Similar to constructor of the base class but using enhanced objects.
+ * TODO: this should really be done in a factory to avoid code duplication.
+ * @param parent
+ * @param interp
+ */
+PyConsole_EnhConsoleBase::PyConsole_EnhConsoleBase( QWidget* parent, PyConsole_Interp* interp )
+  : PyConsole_ConsoleBase( parent, interp, 0 )
+{
+  PyConsole_Interp_EnhCreatorBase crea;
+  defaultConstructor(interp,crea);
+}
+
+/*!
+  \brief Event handler.
+
+  Handles context menu request event.
+
+  \param o object
+  \param e event
+  \return True if the event is processed and further processing should be stopped
+*/
+bool PyConsole_EnhConsoleBase::eventFilter( QObject* o, QEvent* e )
+{
+  if ( o == myEditor->viewport() && e->type() == QEvent::ContextMenu )
+  {
+    contextMenuRequest( (QContextMenuEvent*)e );
+    return true;
+  }
+  return QWidget::eventFilter( o, e );
+}
+
+void PyConsole_EnhConsoleBase::contextMenuRequest( QContextMenuEvent * e )
+{
+  QMenu *menu(new QMenu(this));
+  contextMenuPopup(menu);
+  menu->move(e->globalPos());
+  menu->show();
+}
diff --git a/src/PyConsoleBase/PyConsole_ConsoleBase.h b/src/PyConsoleBase/PyConsole_ConsoleBase.h
new file mode 100644 (file)
index 0000000..b0a0727
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright (C) 2007-2015  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_CONSOLEBASE_H
+#define PYCONSOLE_CONSOLEBASE_H
+
+#include "PyConsoleBase.h"
+
+#include <QWidget>
+#include <QMenu>
+#include <QMap>
+
+class PyConsole_Interp;
+class PyConsole_EditorBase;
+
+class PYCONSOLEBASE_EXPORT PyConsole_ConsoleBase : public QWidget
+{
+  Q_OBJECT
+
+public:
+
+  struct PyConsole_Interp_CreatorBase
+  {
+    virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+    virtual PyConsole_Interp *createInterp( ) const;
+  };
+
+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_ConsoleBase( QWidget* parent, PyConsole_Interp* interp = 0 );
+  virtual ~PyConsole_ConsoleBase();
+
+  //! \brief Get python interperter
+  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                exec( const QString& );
+  void                execAndWait( const QString& );
+
+  void                setMenuActions( const int );
+  int                 menuActions() const;
+
+  void                startLog( const QString& );
+  void                stopLog();
+
+  virtual void        contextMenuPopup( QMenu* );
+
+protected:
+  void                createActions();
+  void                updateActions();
+  //!  MUST BE NON VIRTUAL ! (called from constructor !!!!)
+  void defaultConstructor( PyConsole_Interp* interp, const PyConsole_Interp_CreatorBase& crea );
+  PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp*,  PyConsole_EditorBase*);
+
+  PyConsole_EditorBase*   myEditor;    //!< python console editor widget
+  QMap<int, QAction*> myActions;   //!< menu actions list
+};
+
+/**
+ * Enhance console object providing auto-completion.
+ * Similar to PyConsole_Console except that an enhanced interpreter and enhanced editor
+ * are encapsulated.
+ */
+class PYCONSOLEBASE_EXPORT PyConsole_EnhConsoleBase : public PyConsole_ConsoleBase
+{
+  Q_OBJECT
+public:
+
+  struct PyConsole_Interp_EnhCreatorBase : public PyConsole_Interp_CreatorBase
+  {
+    virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+    virtual PyConsole_Interp *createInterp( ) const;
+  };
+
+public:
+  PyConsole_EnhConsoleBase( QWidget* parent, PyConsole_Interp* interp = 0 );
+  virtual ~PyConsole_EnhConsoleBase() {}
+  virtual bool eventFilter( QObject * o, QEvent * e );
+  virtual void contextMenuRequest( QContextMenuEvent * e ) ;
+};
+
+#endif // PYCONSOLE_CONSOLEBASE_H
diff --git a/src/PyConsoleBase/PyConsole_EditorBase.cxx b/src/PyConsoleBase/PyConsole_EditorBase.cxx
new file mode 100644 (file)
index 0000000..a8bdd05
--- /dev/null
@@ -0,0 +1,1260 @@
+// Copyright (C) 2007-2015  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
+//
+
+//  SALOME SALOMEGUI : implementation of desktop and GUI kernel
+// 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
+*/
+
+#include "PyConsole_Interp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "PyConsole_EditorBase.h"
+#include "PyConsole_Event.h"
+#include "PyInterp_Event.h"
+#include "PyInterp_Dispatcher.h"
+#include "PyConsole_Request.h"
+
+#include <Qtx.h>
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDropEvent>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMouseEvent>
+#include <QScrollBar>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextDocument>
+#include <QTextStream>
+#include <QChar>
+#include <QFileInfo>
+#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_EditorBase*)data)->isSuppressOutput()) {
+    PyConsole_EditorBase* e = (PyConsole_EditorBase*)data;
+    e->putLog( fromUtf8(c) );
+    QApplication::postEvent( e, new PrintEvent( fromUtf8(c), false ) );
+  }
+}
+
+void staticCallbackStderr( void* data, char* c )
+{
+  if(!((PyConsole_EditorBase*)data)->isSuppressOutput()) {
+    PyConsole_EditorBase* e = (PyConsole_EditorBase*)data;
+    e->putLog( fromUtf8(c) );
+    QApplication::postEvent( e, new PrintEvent( fromUtf8(c), true ) );
+  }
+}
+
+
+/*!
+  \brief Constructor. 
+  
+  Creates python editor window.
+  \param theInterp python interper
+  \param theParent parent widget
+*/
+PyConsole_EditorBase::PyConsole_EditorBase( PyConsole_Interp* theInterp, 
+                                            QWidget*          theParent )
+: QTextEdit( theParent ),
+  myInterp( 0 ),
+  myCmdInHistory( -1 ),
+  myEventLoop( 0 ),
+  myShowBanner( true ),
+  myIsSync( true ),
+  myIsSuppressOutput( false )
+{
+  QString fntSet( "" );
+  QFont aFont ( Qtx::stringToFont(fntSet) );
+  setFont( aFont );
+  setUndoRedoEnabled( false );
+
+  myPrompt = READY_PROMPT;
+  setLineWrapMode( QTextEdit::WidgetWidth );
+  setWordWrapMode( QTextOption::WrapAnywhere );
+  setAcceptRichText( false );
+
+  theInterp->setvoutcb( staticCallbackStdout, this );
+  theInterp->setverrcb( staticCallbackStderr, this );
+
+  // san - This is necessary for troubleless initialization
+  onPyInterpChanged( theInterp );
+}
+
+/*!
+  \brief Destructor.
+*/
+PyConsole_EditorBase::~PyConsole_EditorBase()
+{
+  myInterp = 0;
+}
+
+/*!
+  \brief Get Python interpreter
+*/
+PyConsole_Interp* PyConsole_EditorBase::getInterp() const
+{
+  return myInterp;
+}
+
+/*!
+  \brief Get synchronous mode flag value.
+  
+  \sa setIsSync()
+  \return True if python console works in synchronous mode
+*/
+bool PyConsole_EditorBase::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_EditorBase::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_EditorBase::isSuppressOutput() const
+{
+  return myIsSuppressOutput;
+}
+
+/*!
+  \brief Set suppress output flag value.
+
+  In case if suppress output flag is true, the python 
+  console output suppressed.
+
+  \param on suppress output flag
+*/
+void PyConsole_EditorBase::setIsSuppressOutput( const bool on )
+{
+  myIsSuppressOutput = on;
+}
+
+/*!
+  \brief Get 'show banner' flag value.
+  
+  \sa setIsShowBanner()
+  \return \c true if python console shows banner
+*/
+bool PyConsole_EditorBase::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_EditorBase::setIsShowBanner( const bool on )
+{
+  if ( myShowBanner != on ) {
+    myShowBanner = on;
+    clear();
+  }
+}
+
+/*!
+  \brief Check if trace logging is switched on.
+  
+  \sa startLog(), stopLog()
+  \return \c true if trace logging is switched on
+*/
+bool PyConsole_EditorBase::isLogging() const
+{
+  return !myLogFile.isEmpty();
+}
+
+/*!
+  \brief Get size hint for the Python console window
+  \return size hint value
+*/
+QSize PyConsole_EditorBase::sizeHint() const
+{
+  QFontMetrics fm( font() );
+  int nbLines = ( isShowBanner() ? myBanner.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 True, then the string is printed on a new line
+  \param isError if true, the text is printed in dark red
+*/
+void PyConsole_EditorBase::addText( const QString& str, 
+                                const bool     newBlock,
+                                const bool    isError)
+{
+  QTextCursor theCursor(textCursor());
+  QTextCharFormat cf;
+
+  moveCursor( QTextCursor::End );
+  if ( newBlock )
+    theCursor.insertBlock();
+  if (isError)
+      cf.setForeground(QBrush(Qt::red));
+  else
+      cf.setForeground(QBrush(Qt::black));
+  theCursor.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_EditorBase::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( createRequest( cmd ) );
+}
+
+/*!
+  \brief Create request to the python dispatcher for the command execution.
+
+  \param command python command to be executed
+ */
+PyInterp_Request* PyConsole_EditorBase::createRequest( const QString& command )
+{
+  return new ExecCommand( myInterp, command, this, isSync() );
+}
+
+/*!
+  \brief Execute command in the python interpreter
+  and wait until it is finished.
+
+  \param command python command to be executed
+ */
+void PyConsole_EditorBase::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_EditorBase::handleReturn()
+{
+  // Position cursor at the end
+  QTextCursor curs(textCursor());
+  curs.movePosition(QTextCursor::End);
+  setTextCursor(curs);
+
+  // 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( createRequest( myCommandBuffer ) );
+}
+
+/*!
+  \brief Process drop event.
+
+  Paste dragged text.
+  \param event drop event
+*/
+void PyConsole_EditorBase::dropEvent( QDropEvent* event )
+{
+  // get the initial drop position
+  QPoint pos = event->pos();
+  QTextCursor cur = cursorForPosition( event->pos() );
+  // if the position is not in the last line move it to the end of the command line
+  if ( cur.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 button release event.
+
+  Left mouse button: copy selection to the clipboard.
+  Middle mouse button: paste clipboard's contents.
+  \param event mouse event
+*/
+void PyConsole_EditorBase::mouseReleaseEvent( QMouseEvent* event )
+{
+  if ( event->button() == Qt::LeftButton ) {
+    QTextEdit::mouseReleaseEvent( event );
+    //copy();
+  }
+  else if ( event->button() == Qt::MidButton ) {
+    QTextCursor cur = cursorForPosition( event->pos() );
+    // if the position is not in the last line move it to the end of the command line
+    if ( cur.position() < document()->end().previous().position() + promptSize() ) {
+      moveCursor( QTextCursor::End );
+    }
+    else {
+      setTextCursor( cur );
+    }
+    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 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_EditorBase::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_EditorBase::keyPressEvent( QKeyEvent* event )
+{
+  // get cursor position
+  QTextCursor cur = textCursor();
+  int curLine = cur.blockNumber();
+  int curCol  = cur.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 ( 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() ) {
+            cur.setPosition( cur.block().position() + promptSize() );
+            setTextCursor( cur );
+            break;
+          }
+        }
+        else {
+          if ( curLine < endLine && isCommand( textCursor().block().next().text() ) ) {
+            cur.setPosition( cur.position() + promptSize()+1 );
+            setTextCursor( cur );
+            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( cur ).top();
+        qreal distance = 0;
+        // move using movePosition to keep the cursor's x
+        do {
+          qreal y = cursorRect( cur ).top();
+          distance += qAbs( y - lastY );
+          lastY = y;
+          moved = cur.movePosition( QTextCursor::Up, 
+                                    shftPressed ? QTextCursor::KeepAnchor : 
+                                                  QTextCursor::MoveAnchor );
+        } while ( moved && distance < viewport()->height() );
+        if ( moved ) {
+          cur.movePosition( QTextCursor::Down, 
+                            shftPressed ? QTextCursor::KeepAnchor : 
+                                          QTextCursor::MoveAnchor );
+          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
+        }
+        setTextCursor( cur );
+      }
+      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( cur ).top();
+        qreal distance = 0;
+        // move using movePosition to keep the cursor's x
+        do {
+          qreal y = cursorRect( cur ).top();
+          distance += qAbs( y - lastY );
+          lastY = y;
+          moved = cur.movePosition( QTextCursor::Down, 
+                                    shftPressed ? QTextCursor::KeepAnchor : 
+                                                  QTextCursor::MoveAnchor );
+        } while ( moved && distance < viewport()->height() );
+        if ( moved ) {
+          cur.movePosition( QTextCursor::Up, 
+                            shftPressed ? QTextCursor::KeepAnchor : 
+                                          QTextCursor::MoveAnchor );
+          verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
+        }
+        setTextCursor( cur );
+      }
+      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() ) {
+              cur.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
+              cur.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
+            }
+          }
+          else {
+            cur.movePosition( QTextCursor::StartOfLine );
+            cur.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
+          }
+          setTextCursor( cur );
+        }
+        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 ( cur.hasSelection() ) {
+        cut();
+      }
+      else if ( cur.position() > document()->end().previous().position() + promptSize() ) {
+        if ( shftPressed ) {
+          moveCursor( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
+          textCursor().removeSelectedText();
+        }
+        else if ( ctrlPressed ) {
+          cur.setPosition( document()->end().previous().position() + promptSize(),
+                           QTextCursor::KeepAnchor );
+          setTextCursor( cur );
+          textCursor().removeSelectedText();
+        }
+        else {
+          QTextEdit::keyPressEvent( event );
+        }
+      }
+      else {
+        cur.setPosition( document()->end().previous().position() + promptSize() );
+        setTextCursor( cur );
+        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 ( cur.hasSelection() ) {
+        cut();
+      }
+      else if ( cur.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 {
+        cur.setPosition( document()->end().previous().position() + promptSize() );
+        setTextCursor( cur );
+        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;
+    }
+  }
+}
+
+/*!
+  \brief Handle notification event coming from Python dispatcher.
+  \param event notification event
+*/
+void PyConsole_EditorBase::customEvent( QEvent* event )
+{
+  switch( event->type() )
+  {
+  case PrintEvent::EVENT_ID:
+    {
+      PrintEvent* pe=(PrintEvent*)event;
+      addText( pe->text(), false, pe->isError());
+      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();
+    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();
+    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 Handle Python interpreter change.
+
+  Perform initialization actions if the interpreter is changed.
+  \param interp python interpreter is being set
+*/
+void PyConsole_EditorBase::onPyInterpChanged( PyConsole_Interp* interp )
+{
+  if ( myInterp != interp 
+       // Force read-only state and wait cursor when myInterp is NULL
+      || !myInterp ) {
+    myInterp = interp;
+    if ( myInterp ) {
+      // print banner
+      myBanner = myInterp->getbanner().c_str();
+      if ( isShowBanner() )
+       addText( myBanner );
+      // 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();
+      // stop event loop (if running)
+      if( myEventLoop)
+        myEventLoop->exit();
+    }
+    else {
+      // clear contents
+      clear();
+      // set read-only state
+      setReadOnly( true );
+      // set busy cursor
+      setCursor( Qt::WaitCursor );
+    }
+  }
+}
+
+/*!
+  \brief "Copy" operation.
+  
+  Reimplemented from Qt.
+  Warning! In Qt4 this method is not virtual.
+ */
+void PyConsole_EditorBase::cut()
+{
+  QTextCursor cur = textCursor();
+  if ( cur.hasSelection() ) {
+    QApplication::clipboard()->setText( cur.selectedText() );
+    int startSelection = cur.selectionStart();
+    if ( startSelection < document()->end().previous().position() + promptSize() )
+      startSelection = document()->end().previous().position() + promptSize();
+    int endSelection = cur.selectionEnd();
+    if ( endSelection < document()->end().previous().position() + promptSize() )
+      endSelection = document()->end().previous().position() + promptSize();
+    cur.setPosition( startSelection );
+    cur.setPosition( endSelection, QTextCursor::KeepAnchor );
+    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+    setTextCursor( cur );
+    textCursor().removeSelectedText();
+  }
+}
+
+/*!
+  \brief "Paste" operation.
+
+  Reimplemented from Qt.
+  Warning! In Qt4 this method is not virtual.
+ */
+void PyConsole_EditorBase::paste()
+{
+  QTextCursor cur = textCursor();
+  if ( cur.hasSelection() ) {
+    int startSelection = cur.selectionStart();
+    if ( startSelection < document()->end().previous().position() + promptSize() )
+      startSelection = document()->end().previous().position() + promptSize();
+    int endSelection = cur.selectionEnd();
+    if ( endSelection < document()->end().previous().position() + promptSize() )
+      endSelection = document()->end().previous().position() + promptSize();
+    cur.setPosition( startSelection );
+    cur.setPosition( endSelection, QTextCursor::KeepAnchor );
+    horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+    setTextCursor( cur );
+    textCursor().removeSelectedText();
+  }
+  if ( textCursor().position() < document()->end().previous().position() + promptSize() )
+    moveCursor( QTextCursor::End );
+  QTextEdit::paste();
+}
+
+/*!
+  \brief "Clear" operation.
+
+  Reimplemented from Qt.
+  Warning! In Qt4 this method is not virtual.
+ */
+void PyConsole_EditorBase::clear()
+{
+  QTextEdit::clear();
+  if ( isShowBanner() )
+    addText( myBanner );
+  myPrompt = READY_PROMPT;
+  addText( myPrompt );
+}
+
+/*!
+  \brief "Dump commands" operation.
+ */
+void PyConsole_EditorBase::dumpImpl(const QString& fileName)
+{
+  if ( !fileName.isEmpty() ) {
+    QFile file( fileName ); 
+    if ( !file.open( QFile::WriteOnly ) )
+      return;
+
+    QTextStream out (&file);
+  
+    for ( int i=0; i<myHistory.count(); i++ ) {
+      out << myHistory[i] << endl;
+    }
+    file.close();
+  }
+}
+
+/*!
+  \brief "Dump commands" operation.
+ */
+void PyConsole_EditorBase::dump(const QString& fileName)
+{
+  dumpImpl(fileName);
+}
+
+/*!
+  \brief "Dump commands" operation.
+ */
+void PyConsole_EditorBase::dump()
+{
+  dumpSlot();
+}
+
+void PyConsole_EditorBase::dumpSlot()
+{
+  QString fileName(QFileDialog::getSaveFileName(this,tr("Choose python file where to store"),QString(),tr("Python scripts ext (*.py)")));
+  if ( !fileName.isEmpty() )
+    this->dump( fileName );
+  else
+    QMessageBox::warning(this,tr("WARNING"),tr("Python file has not been written"));
+}
+
+/*!
+  \brief Start python trace logging
+  \param fileName the path to the log file
+  \sa stopLog()
+ */
+bool PyConsole_EditorBase::startLogImpl( const QString& fileName )
+{
+  bool ok = false;
+  if ( !fileName.isEmpty() ) {
+    QFile file( fileName );
+    if ( file.open( QFile::WriteOnly ) ) {
+      file.close();
+      myLogFile = fileName;
+      ok = true;
+    }
+  }
+  return ok;
+}
+
+
+/*!
+  \brief Start python trace logging
+  \param fileName the path to the log file
+  \sa stopLog()
+ */
+bool PyConsole_EditorBase::startLog( const QString& fileName )
+{
+  return startLogImpl(fileName);
+}
+
+/*!
+  \brief Start python trace logging
+  \sa stopLog()
+ */
+void PyConsole_EditorBase::startLog()
+{
+  startLogSlot();
+}
+
+void PyConsole_EditorBase::startLogSlot()
+{
+  while (1)
+    {
+      QString fileName(QFileDialog::getSaveFileName(this,tr("Choose python file where to store log"),QString(),tr("Log files ext (*.log *.txt)")));
+      if ( !fileName.isEmpty() )
+        {
+          if ( startLogImpl( fileName ) )
+            break;
+          else
+            QMessageBox::warning(this,tr("WARNING"),tr("Log file is not writable"));
+        }
+      else
+        break;
+    }
+}
+
+/*!
+  \brief "Stop log" operation.
+  \sa startLog()
+ */
+void PyConsole_EditorBase::stopLog()
+{
+  myLogFile = QString();
+}
+
+/*!
+  \brief Put string to the log file
+ */
+void PyConsole_EditorBase::putLog( const QString& s )
+{
+  if ( !myLogFile.isEmpty() ) {
+    QFile file( myLogFile );
+    if ( !file.open( QFile::Append ) )
+      return;
+    
+    QTextStream out (&file);
+    out << s;
+    
+    file.close();
+  }
+}
diff --git a/src/PyConsoleBase/PyConsole_EditorBase.h b/src/PyConsoleBase/PyConsole_EditorBase.h
new file mode 100644 (file)
index 0000000..c875e76
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright (C) 2007-2015  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
+//
+
+//  SALOME SALOMEGUI : implementation of desktop and GUI kernel
+// File   : PyConsole_Editor.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#ifndef PYCONSOLE_EDITORBASE_H
+#define PYCONSOLE_EDITORBASE_H
+
+#include "PyConsoleBase.h"
+
+#include <QTextEdit>
+
+class PyConsole_Interp;
+class PyInterp_Request;
+class QEventLoop;
+
+class PYCONSOLEBASE_EXPORT PyConsole_EditorBase : public QTextEdit
+{
+  Q_OBJECT;
+
+public:
+  PyConsole_EditorBase( PyConsole_Interp* theInterp, QWidget *theParent = 0 );
+  ~PyConsole_EditorBase();
+
+  PyConsole_Interp* getInterp() const;
+  
+  virtual void   addText( const QString& str, const bool newBlock = false, const bool isError = false );
+  bool           isCommand( const QString& str ) const;
+
+  virtual void   exec( const QString& command );
+  void           execAndWait( const QString& command );
+
+  bool           isSync() const;
+  void           setIsSync( const bool );
+
+  bool           isSuppressOutput() const;
+  void           setIsSuppressOutput(const bool);
+
+  bool           isShowBanner() const;
+  void           setIsShowBanner( const bool );
+
+  bool           isLogging() const;
+
+  virtual QSize  sizeHint() const;
+  void           dumpImpl(const QString& fileName);
+  bool           startLogImpl( const QString& );
+public slots:
+    void           cut();
+    void           paste();
+    void           clear();
+    void           handleReturn();
+    void           onPyInterpChanged( PyConsole_Interp* );
+    void           dump(const QString& fileName);
+    void           dump();
+    void           startLog();
+    bool           startLog( const QString& );
+    void           stopLog();
+    void           putLog( const QString& );
+
+protected:
+  virtual void   dropEvent( QDropEvent* event );
+  virtual void   mouseReleaseEvent( QMouseEvent* event );
+  virtual void   keyPressEvent ( QKeyEvent* event);
+  virtual void   customEvent( QEvent* event);
+  virtual void   dumpSlot();
+  virtual void   startLogSlot();
+
+  virtual PyInterp_Request* createRequest( const QString& );
+
+  /** Convenience function */
+  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
+  QString           myBanner;           //!< current banner
+  bool              myShowBanner;       //!< 'show banner' flag
+  QStringList       myQueue;            //!< python commands queue
+  bool              myIsSync;           //!< synchronous mode flag
+  bool              myIsSuppressOutput; //!< suppress output flag
+};
+
+#endif // PYCONSOLE_EDITORBASE_H
diff --git a/src/PyConsoleBase/PyConsole_EnhEditorBase.cxx b/src/PyConsoleBase/PyConsole_EnhEditorBase.cxx
new file mode 100644 (file)
index 0000000..54bf7fd
--- /dev/null
@@ -0,0 +1,491 @@
+// Copyright (C) 2007-2015  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
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+#include "PyConsoleBase.h"
+#include <Python.h>
+
+#include <QKeyEvent>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextCharFormat>
+#include <QRegExp>
+#include <QMimeData>
+
+#include "PyConsole_EnhEditorBase.h"
+#include "PyConsole_EnhInterp.h"
+#include "PyConsole_Request.h"
+#include "PyInterp_Dispatcher.h"
+
+// Initialize list of valid separators
+static const char * tmp_a[] = {" ", "(", "[","+", "-", "*", "/", ";", "^", "="};
+const std::vector<QString> PyConsole_EnhEditorBase::SEPARATORS = \
+    std::vector<QString>(tmp_a, tmp_a + sizeof(tmp_a)/sizeof(tmp_a[0]));
+
+/**
+ * Constructor.
+ * @param interp the interpreter linked to the editor
+ * @param parent parent widget
+ */
+PyConsole_EnhEditorBase::PyConsole_EnhEditorBase(PyConsole_Interp* interp, QWidget* parent) :
+     PyConsole_EditorBase(interp, parent),
+     _tab_mode(false),
+     _cursor_pos(-1),
+     _multi_line_paste(false),
+     _multi_line_content()
+{
+  document()->setUndoRedoEnabled(true);
+}
+
+/**
+ * Overrides. Catches the TAB and Ctrl+TAB combinations.
+ * @param event
+ */
+void PyConsole_EnhEditorBase::keyPressEvent ( QKeyEvent* event)
+{
+  // check if <Ctrl> is pressed
+  bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
+  // check if <Shift> is pressed
+  bool shftPressed = event->modifiers() & Qt::ShiftModifier;
+
+  if (event->key() == Qt::Key_Tab && !shftPressed)
+    {
+      if (!ctrlPressed)
+        handleTab();
+      else
+        {
+          clearCompletion();
+          handleBackTab();
+        }
+      PyConsole_EditorBase::keyPressEvent(event);
+    }
+  else
+    {
+      // If ctrl is not pressed (and sth else is pressed with it),
+      // or if ctrl is not pressed alone
+      if (!ctrlPressed || (ctrlPressed && event->key() != Qt::Key_Control))
+        {
+          clearCompletion();
+          _cursor_pos = -1;
+        }
+      // Discard ctrl pressed alone:
+      if (event->key() != Qt::Key_Control)
+        PyConsole_EditorBase::keyPressEvent(event);
+    }
+}
+
+/**
+ * Whenever the mouse is clicked, clear the completion.
+ * @param e
+ */
+void PyConsole_EnhEditorBase::mousePressEvent(QMouseEvent* e)
+{
+  clearCompletion();
+  _cursor_pos = -1;
+  PyConsole_EditorBase::mousePressEvent(e);
+}
+
+/**
+ * Clear in the editor the block of text displayed after having hit <TAB>.
+ */
+void PyConsole_EnhEditorBase::clearCompletion()
+{
+  // Delete completion text if present
+  if (_tab_mode)
+    {
+      // 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
+      if ( myInterp ) 
+       myInterp->clearCompletion();
+    }
+  _tab_mode = false;
+}
+
+/**
+ * Handle the sequence of events after having hit <TAB>
+ */
+void PyConsole_EnhEditorBase::handleTab()
+{
+  if (_tab_mode)
+    {
+      // Already tab mode - nothing to do !
+      return;
+    }
+
+  QTextCursor cursor(textCursor());
+
+  // Cursor at end of input
+  cursor.movePosition(QTextCursor::End);
+  setTextCursor(cursor);
+
+  // Save cursor position if needed
+  if (_cursor_pos == -1)
+    _cursor_pos = textCursor().position();
+
+  // get last line
+  QTextBlock par = document()->end().previous();
+  if ( !par.isValid() ) return;
+
+  // Switch to completion mode
+  _tab_mode = true;
+
+  QString cmd = par.text().mid(promptSize());
+
+  // Post completion request
+  // Editor will be informed via a custom event that completion has been run
+  PyInterp_Request* req = createTabRequest(cmd);
+  PyInterp_Dispatcher::Get()->Exec(req);
+}
+
+/**
+ * Handles what happens after hitting Ctrl-TAB
+ */
+void PyConsole_EnhEditorBase::handleBackTab()
+{
+  QTextCursor cursor(textCursor());
+
+  if (_cursor_pos == -1)
+    {
+      // Invalid cursor position - we can't do anything:
+      return;
+    }
+  // Ensure cursor is at the end of command line
+  cursor.setPosition(_cursor_pos);
+  cursor.movePosition(QTextCursor::EndOfLine);
+  //setCursor(cursor);
+
+  // Delete last completed text
+  int i = cursor.position() - _cursor_pos;
+  cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, i);
+  cursor.removeSelectedText();
+  _cursor_pos = -1;
+}
+
+/**
+ * Create the Python requested that will be posted to the interpreter to
+ * get the completions.
+ * @param input line typed by the user at the time TAB was hit
+ * @return a CompletionCommand
+ * @sa CompletionCommand
+ */
+PyInterp_Request* PyConsole_EnhEditorBase::createTabRequest( const QString& input )
+{
+  // 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;
+  for (std::vector<QString>::const_iterator i = SEPARATORS.begin(); i != SEPARATORS.end(); i++)
+    {
+      int j = input2.lastIndexOf(*i);
+      if (j > lastSp)
+        lastSp = j;
+    }
+  if (lastSp >= 0)
+    input2 = input.mid(lastSp+1);
+
+  // Detect a qualified name (with a point)
+  int lastPt = input2.lastIndexOf(QString("."));
+
+  // Split the 2 surrounding parts of the qualified name
+  if (lastPt != -1)
+    {
+      _compl_before_point = input2.left(lastPt);
+      _compl_after_point = input2.mid(lastPt+1);
+    }
+  else
+    {
+      // No point found - do a global matching -
+      // (the following will call dir() with an empty string)
+      _compl_after_point = input2;
+      _compl_before_point = QString("");
+    }
+
+  return new CompletionCommand( myInterp, _compl_before_point,
+                               _compl_after_point, this, isSync() );
+}
+
+/**
+ * Format completion results - this is where we should create 3 columns etc ...
+ * @param matches list of possible completions
+ * @param result return value
+ */
+void PyConsole_EnhEditorBase::formatCompletion(const QStringList& matches, QString& result) const
+{
+  int sz = matches.size();
+
+  if (sz > MAX_COMPLETIONS)
+    {
+      sz = MAX_COMPLETIONS;
+      result.append("[Too many matches! Displaying first ones only ...]\n");
+    }
+
+  for (int i = 0; i < sz; ++i)
+    {
+      result.append(matches[i]);
+      result.append("\n");
+    }
+}
+
+/**
+ * Override. Catches the events generated by the enhanced interpreter after the execution
+ * of a completion request.
+ * @param event
+ */
+void PyConsole_EnhEditorBase::customEvent( QEvent* event )
+{
+  QStringList matches;
+  QString first_match, comple_text, doc, base;
+  QTextCursor cursor(textCursor());
+  QTextBlockFormat bf;
+  QTextCharFormat cf;
+  int cursorPos;
+
+  switch( event->type() )
+  {
+    case PyInterp_Event::ES_TAB_COMPLETE_OK:
+    {
+      // Extract corresponding matches from the interpreter
+      matches = getInterp()->getLastMatches();
+      doc = getInterp()->getDocStr();
+
+      if (matches.size() == 0)
+      {
+       // Completion successful but nothing returned.
+       _tab_mode = false;
+       _cursor_pos = -1;
+       return;
+      }
+      
+      // Only one match - complete directly and update doc string window
+      if (matches.size() == 1)
+      {
+       first_match = matches[0].mid(_compl_after_point.size());
+       cursor.insertText(first_match);
+       _tab_mode = false;
+       if (doc.isEmpty())
+         emit updateDoc(formatDocHTML("(no documentation available)\n"));
+       else
+         emit updateDoc(formatDocHTML(doc));
+      }
+      else
+      {
+       // Detect if there is a common base to all available completion
+       // In this case append this base to the text already
+       extractCommon(matches, base);
+       first_match = base.mid(_compl_after_point.size());
+       cursor.insertText(first_match);
+       
+       // If this happens to match exaclty the first completion
+       // also provide doc
+       if (base == matches[0])
+       {
+         doc = formatDocHTML(doc);
+         emit updateDoc(doc);
+       }
+       
+       // Print all matching completion in a "undo-able" block
+       cursorPos = cursor.position();
+       cursor.insertBlock();
+       cursor.beginEditBlock();
+       
+       // Insert all matches
+       QTextCharFormat cf;
+       cf.setForeground(QBrush(Qt::darkGreen));
+       cursor.setCharFormat(cf);
+       formatCompletion(matches, comple_text);
+       cursor.insertText(comple_text);
+       cursor.endEditBlock();
+       
+       // Position cursor where it was before inserting the completion list:
+       cursor.setPosition(cursorPos);
+       setTextCursor(cursor);
+      }
+      break;
+    }
+    case PyInterp_Event::ES_TAB_COMPLETE_ERR:
+    {
+      // Tab completion was unsuccessful, switch off mode:
+      _tab_mode = false;
+      _cursor_pos = -1;
+      break;
+    }
+    case PyInterp_Event::ES_OK:
+    case PyInterp_Event::ES_ERROR:
+    case PyInterp_Event::ES_INCOMPLETE:
+    {
+      // Before everything else, call super()
+      PyConsole_EditorBase::customEvent(event);
+      // If we are in multi_paste_mode, process the next item:
+      multiLineProcessNextLine();
+      break;
+    }
+    default:
+    {
+      PyConsole_EditorBase::customEvent( event );
+      break;
+    }
+  }
+}
+
+/**
+ * Extract the common leading part of all strings in matches.
+ * @param matches
+ * @param result
+ */
+void PyConsole_EnhEditorBase::extractCommon(const QStringList& matches, QString& result) const
+{
+  result = "";
+  int charIdx = 0;
+
+  if (matches.size() < 2)
+    return;
+
+  while (true)
+    {
+      if (charIdx >= matches[0].size())
+        return;
+      QChar ch = matches[0][charIdx];
+      for (int j = 1; j < matches.size(); j++)
+        if (charIdx >= matches[j].size() || matches[j][charIdx] != ch)
+          return;
+      result += ch;
+      charIdx++;
+    }
+}
+
+/**
+ * Format the doc string in HTML format with the first line in bold blue
+ * @param doc initial doc string
+ * @return HTML string
+ */
+QString PyConsole_EnhEditorBase::formatDocHTML(const QString & doc) const
+{
+  QString templ = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" ") +
+      QString(" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n ") +
+      QString("<html><head><meta name=\"qrichtext\" content=\"1\" /> ") +
+      QString("<style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style> ") +
+      QString("</head><body style=\" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;\">\n") +
+      QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">") +
+      QString("<span style=\" font-weight:600; color:#0000ff;\">%1</span></p>") +
+      QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%2</p>") +
+      QString("</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 templ.arg(fst).arg(rest);
+}
+
+/**
+ * Handle properly multi-line pasting. Qt4 doc recommends overriding this function.
+ * If the pasted text doesn't contain a line return, no special treatment is done.
+ * @param source
+ */
+void PyConsole_EnhEditorBase::insertFromMimeData(const QMimeData* source)
+{
+  if (_multi_line_paste)
+    return;
+
+  if (source->hasText())
+    {
+      QString s = source->text();
+      if (s.contains("\n"))
+        multilinePaste(s);
+      else
+        PyConsole_EditorBase::insertFromMimeData(source);
+    }
+  else
+    {
+      PyConsole_EditorBase::insertFromMimeData(source);
+    }
+}
+
+
+void PyConsole_EnhEditorBase::multilinePaste(const QString & s)
+{
+  // Turn on multi line pasting mode
+  _multi_line_paste = true;
+
+  // Split the string:
+  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
+  // sth was already there:
+  QMimeData source;
+  source.setText(lst[0]);
+  PyConsole_EditorBase::insertFromMimeData(&source);
+
+  // Prepare what will have to be executed after the first line:
+  _multi_line_content = std::queue<QString>();
+  for (int i = 1; i < lst.size(); ++i)
+    _multi_line_content.push(lst[i]);
+
+  // Trigger the execution of the first (mixed) line
+  handleReturn();
+
+  // See customEvent() and multiLineProcessNext() for the rest of the handling.
+}
+
+/**
+ * Process the next line in the queue of a multiple copy/paste:
+ */
+void PyConsole_EnhEditorBase::multiLineProcessNextLine()
+{
+  if (!_multi_line_paste)
+    return;
+
+  QString line(_multi_line_content.front());
+  _multi_line_content.pop();
+  if (!_multi_line_content.size())
+    {
+      // last line in the queue, just paste it
+      addText(line, false, false);
+      _multi_line_paste = false;
+    }
+  else
+    {
+      // paste the line and simulate a <RETURN> key stroke
+      addText(line, false, false);
+      handleReturn();
+    }
+}
diff --git a/src/PyConsoleBase/PyConsole_EnhEditorBase.h b/src/PyConsoleBase/PyConsole_EnhEditorBase.h
new file mode 100644 (file)
index 0000000..6c91a3d
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright (C) 2007-2015  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
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+#ifndef PYCONSOLE_ENHEDITORBASE_H_
+#define PYCONSOLE_ENHEDITORBASE_H_
+
+#include "PyConsoleBase.h"
+#include "PyConsole_EditorBase.h"
+
+#include <QObject>
+#include <queue>
+
+/**
+ * Enhanced Python editor handling tab completion.
+ */
+class PYCONSOLEBASE_EXPORT PyConsole_EnhEditorBase : public PyConsole_EditorBase
+{
+  Q_OBJECT;
+
+public:
+  PyConsole_EnhEditorBase(PyConsole_Interp* interp, QWidget* parent = 0);
+  virtual ~PyConsole_EnhEditorBase() {}
+
+signals:
+  /**
+   * Signal emitted by the editor widget when the doc string should be updated.
+   * @param doc a HTML block with the formatted doc string.
+   * TODO: for now this signal is left uncaught.
+   */
+  void updateDoc(QString doc);
+
+protected:
+  /** List of separators identifying the last parsable token for completion */
+  static const std::vector<QString> SEPARATORS;
+
+  /** Maximum number of completions shown at once */
+  static const int MAX_COMPLETIONS = 70;
+
+  /** Are we in completion mode */
+  bool _tab_mode;
+
+  /** String on which the dir() comamnd is executed */
+  QString _compl_before_point;
+  /** String on which the results of the dir() are matched */
+  QString _compl_after_point;
+
+  /** Cursor position when <TAB> is hit */
+  int _cursor_pos;
+
+  /** Are we currently pasting several lines */
+  bool _multi_line_paste;
+
+  /** Queue of lines being pasted */
+  std::queue<QString> _multi_line_content;
+
+  // Overrides:
+  virtual void   keyPressEvent ( QKeyEvent* event);
+  virtual void   customEvent( QEvent* event);
+  virtual void   mousePressEvent( QMouseEvent* event );
+  virtual void   insertFromMimeData(const QMimeData* source);
+
+  virtual PyInterp_Request* createTabRequest( const QString& input );
+  virtual void handleTab();
+  virtual void handleBackTab();
+  virtual void clearCompletion();
+  virtual void formatCompletion(const QStringList& matches, QString& result) const;
+  virtual QString formatDocHTML(const QString & doc) const;
+
+  virtual void multilinePaste(const QString & s);
+  virtual void multiLineProcessNextLine();
+
+private:
+  void extractCommon(const QStringList& matches, QString& result) const;
+
+};
+
+#endif /* PYCONSOLE_ENHEDITORBASE_H_ */
diff --git a/src/PyConsoleBase/PyConsole_EnhInterp.cxx b/src/PyConsoleBase/PyConsole_EnhInterp.cxx
new file mode 100644 (file)
index 0000000..eab44af
--- /dev/null
@@ -0,0 +1,177 @@
+// Copyright (C) 2007-2015  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
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+
+#include "PyConsoleBase.h"
+
+#include "PyConsole_EnhInterp.h"
+
+#include <pythonrun.h>
+#include <string>
+#include <QRegExp>
+
+static const char * tmp_k[] = {"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"};
+
+const std::vector<QString> PyConsole_EnhInterp::PYTHON_KEYWORDS = \
+      std::vector<QString>(tmp_k, tmp_k+sizeof(tmp_k)/sizeof(tmp_k[0]));
+
+/*!
+  \brief Constructor
+*/
+PyConsole_EnhInterp::PyConsole_EnhInterp()
+  : PyConsole_Interp()
+{
+}
+
+/*!
+  \brief Destructor
+*/
+PyConsole_EnhInterp::~PyConsole_EnhInterp()
+{
+}
+
+QStringList PyConsole_EnhInterp::getLastMatches() const
+{
+  return _last_matches;
+}
+
+QString PyConsole_EnhInterp::getDocStr() const
+{
+  return _doc_str;
+}
+
+/*!
+  \brief Run Python dir() command and saves the result internally in _lastPy
+  \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".
+  \return command exit status - 0 = success
+*/
+int PyConsole_EnhInterp::runDirCommand(const QString& dirArgument, const QString& startMatch)
+{
+  int ret;
+  std::vector<QString> v;
+
+  clearCompletion();
+  if ( (ret = runDirAndExtract(dirArgument, startMatch, _last_matches)) )
+      return ret;
+
+  // If dirArgument is empty, we append the __builtins__
+  if (dirArgument.isEmpty())
+    {
+      if ( (ret = runDirAndExtract(QString("__builtins__"), startMatch, _last_matches, false)) )
+            return ret;
+
+      // ... and we match on Python's keywords as well:
+      for (std::vector<QString>::const_iterator it = PYTHON_KEYWORDS.begin(); it != PYTHON_KEYWORDS.end(); it++)
+          if ((*it).startsWith(startMatch))
+            _last_matches.push_back(*it);
+    }
+
+  // Try to get doc string of the first match
+  if (_last_matches.size() > 0)
+    {
+      QString cmd("");
+      if (dirArgument.trimmed() != "")
+        cmd = dirArgument + ".";
+      cmd += _last_matches[0] + ".__doc__";
+      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();
+          _doc_str = "";
+        }
+      else
+        _doc_str = QString(PyString_AsString(str));
+      Py_XDECREF(str);
+    }
+
+  // The command has been successfully executed
+  return 0;
+}
+
+/**
+ * See runDirCommand().
+ * @param dirArgument see runDirCommand()
+ * @param startMatch  see runDirCommand()
+ * @param[out] result the list of matches
+ * @param discardSwig if true a regular expression is used to discard all static method generated
+ * by SWIG. typically: MEDCouplingUMesh_Blabla
+ * @return -1 if the call to dir() or the parsing of the result failed, 0 otherwise.
+ */
+int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument,
+                                         const QString& startMatch,
+                                         QStringList& result,
+                                         bool discardSwig) const
+{
+  QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$");  // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
+  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 -1;
+  }
+
+  // Extract the returned list and convert it to a vector<>
+  if (!PySequence_Check(plst))
+    {
+      // Should never happen ...
+      //std::cerr << "not a list!" << std::endl;
+      Py_XDECREF(plst);
+      return -1;
+    }
+
+  // Convert plst to a vector of QString
+  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.push_back(s);
+      Py_DECREF(it);
+    }
+  Py_DECREF(plst);
+
+  return 0;
+}
+
+/**
+ * Clear internal members containing the last completion results.
+ */
+void PyConsole_EnhInterp::clearCompletion()
+{
+  _last_matches.clear();
+  _doc_str = "";
+}
diff --git a/src/PyConsoleBase/PyConsole_EnhInterp.h b/src/PyConsoleBase/PyConsole_EnhInterp.h
new file mode 100644 (file)
index 0000000..57a483b
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (C) 2007-2015  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
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+
+#ifndef PYCONSOLE_ENHINTERP_H_
+#define PYCONSOLE_ENHINTERP_H_
+
+#include "PyConsoleBase.h"
+
+#include <Python.h>
+#include "PyConsole_Interp.h"
+
+#include <vector>
+#include <QString>
+
+/**
+ * Enhanced Python interpreter used for auto-completion.
+ * This extends PyConsole_Interp with an API wrapping the Python dir() command nicely.
+ */
+class PYCONSOLEBASE_EXPORT PyConsole_EnhInterp: public PyConsole_Interp
+{
+public:
+  PyConsole_EnhInterp();
+  virtual ~PyConsole_EnhInterp();
+
+  virtual QStringList getLastMatches() const;
+  virtual QString getDocStr() const;
+
+  virtual int runDirCommand(const QString& dirArgument, const QString& startMatch);
+  virtual void clearCompletion();
+
+protected:
+  /** Hard coded list of Python keywords */
+  static const std::vector<QString> PYTHON_KEYWORDS;
+
+  /** Last computed matches */
+  QStringList _last_matches;
+  /** Doc string of the first match - when only one match it will be displayed by the Editor*/
+  QString _doc_str;
+
+  virtual int runDirAndExtract(const QString& dirArgument, const QString& startMatch,
+                              QStringList& result, bool discardSwig=true) const;
+};
+
+#endif /* PYCONSOLE_ENHINTERP_H_ */
diff --git a/src/PyConsoleBase/PyConsole_Event.cxx b/src/PyConsoleBase/PyConsole_Event.cxx
new file mode 100644 (file)
index 0000000..aaeb257
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) 2007-2015  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
+//
+//  Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
+
+#include "PyConsole_Event.h"
diff --git a/src/PyConsoleBase/PyConsole_Event.h b/src/PyConsoleBase/PyConsole_Event.h
new file mode 100644 (file)
index 0000000..28db824
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (C) 2007-2015  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
+//
+//  Author : Vadim SANDLER (Open CASCADE S.A.S), Adrien Bruneton (CEA/DEN)
+
+#ifndef PYCONSOLE_EVENT_H
+#define PYCONSOLE_EVENT_H
+
+#include "PyConsoleBase.h"
+
+#include <QEvent>
+#include <QString>
+
+/*!
+  \class PrintEvent
+  \brief Python command output backend event.
+  \internal
+*/
+class PrintEvent : public QEvent
+{
+public:
+  static const int EVENT_ID = 65432;
+
+  /*!
+    \brief Constructor
+    \param c message text (python trace)
+    \param isError default to false - if true indicates that an error is being printed.
+  */
+  PrintEvent( const QString& c, bool isError = false) :
+    QEvent( (QEvent::Type)EVENT_ID ), myText( c ), errorFlag(isError)
+  {}
+
+  /*!
+    \brief Get message
+    \return message text (python trace)
+  */
+  QString text() const { return myText; }
+
+  /**
+   * @return true if this is an error message
+   */
+  bool isError() const { return errorFlag; }
+
+protected:
+  QString myText; //!< Event message (python trace)
+
+  /** Set to true if an error msg is to be displayed */
+  bool errorFlag;
+};
+
+#endif // PYCONSOLE_EVENT_H
diff --git a/src/PyConsoleBase/PyConsole_Interp.cxx b/src/PyConsoleBase/PyConsole_Interp.cxx
new file mode 100644 (file)
index 0000000..ca459b5
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright (C) 2007-2015  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, Adrien BRUNETON
+
+#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
+*/
+
+/*!
+  \brief Constructor.
+
+  Creates new python interpreter.
+*/
+PyConsole_Interp::PyConsole_Interp(): PyInterp_Interp()
+{
+}
+
+/*!
+  \brief Destructor.
+
+  Does nothing for the moment.
+*/
+PyConsole_Interp::~PyConsole_Interp()
+{
+}
+
+/*! 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.
+*
+* (GIL is already acquired here)
+*/
+int PyConsole_Interp::beforeRun()
+{
+  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=True");
+}
+int PyConsole_Interp::afterRun()
+{
+  return PyRun_SimpleString("__builtins__.__IN_SALOME_GUI_CONSOLE=False");
+}
+
+QStringList PyConsole_Interp::getLastMatches() const
+{
+  return QStringList();
+}
+
+QString PyConsole_Interp::getDocStr() const
+{
+  return QString();
+}
+
+int PyConsole_Interp::runDirCommand(const QString&, const QString& )
+{
+  return 0;
+}
+
+void PyConsole_Interp::clearCompletion()
+{
+}
diff --git a/src/PyConsoleBase/PyConsole_Interp.h b/src/PyConsoleBase/PyConsole_Interp.h
new file mode 100644 (file)
index 0000000..34f251d
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (C) 2007-2015  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, Adrien BRUNETON
+
+#ifndef PYCONSOLE_INTERP_H
+#define PYCONSOLE_INTERP_H
+
+#include "PyConsoleBase.h"
+#include "PyInterp_Interp.h"   /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
+
+#include <QStringList>
+
+class PYCONSOLEBASE_EXPORT PyConsole_Interp : public PyInterp_Interp
+{
+public:
+  PyConsole_Interp();
+  ~PyConsole_Interp();
+
+  virtual int afterRun();
+  virtual int beforeRun();
+
+  virtual QStringList getLastMatches() const;
+  virtual QString getDocStr() const;
+
+  virtual int runDirCommand(const QString&, const QString&);
+  virtual void clearCompletion();
+};
+
+#endif // PYCONSOLE_INTERP_H
diff --git a/src/PyConsoleBase/PyConsole_Request.cxx b/src/PyConsoleBase/PyConsole_Request.cxx
new file mode 100644 (file)
index 0000000..5c67b8b
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright (C) 2007-2015  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
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 3 avr. 2013
+
+#include "PyConsole_Request.h"
+#include "PyConsole_Interp.h"
+#include "PyConsole_Event.h"
+#include "PyInterp_Event.h"
+
+#include <QCoreApplication>
+
+/**
+ * Constructor.
+ * @param theInterp interpreter that will execute the command
+ * @param theCommand command text
+ * @param theListener editor object that will receive the response events after execution
+ * of the request
+ * @param sync
+ */
+ExecCommand::ExecCommand( PyInterp_Interp*        theInterp,
+                         const QString&          theCommand,
+                         QObject*                theListener,
+                         bool                    theSync )
+  : PyInterp_LockRequest( theInterp, theListener, theSync ),
+    myCommand( theCommand ), myState( PyInterp_Event::ES_OK )
+{}
+
+/**
+ * Execute the command by calling the run() method of the embedded interpreter.
+ */
+void 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;
+  }
+}
+
+/**
+ * Create the event indicating the status of the request execution.
+ * @return a QEvent
+ */
+QEvent* ExecCommand::createEvent()
+{
+  if ( IsSync() )
+    QCoreApplication::sendPostedEvents( listener(), PrintEvent::EVENT_ID );
+  return new PyInterp_Event( myState, this );
+}
+
+
+/*!
+  Constructor.
+  Creates a new python completion request.
+  \param theInterp   python interpreter
+  \param input  string containing the dir() command to be executed
+  \param startMatch  part to be matched with the results of the dir() command
+  \param theListener widget to get the notification messages
+  \param sync        if True the request is processed synchronously
+*/
+CompletionCommand::CompletionCommand( PyInterp_Interp*   theInterp,
+                                     const QString&     theInput,
+                                     const QString&     theStartMatch,
+                                     QObject*           theListener,
+                                     bool               theSync )
+  : PyInterp_LockRequest( theInterp, theListener, theSync ),
+    _tabSuccess(false), _dirArg(theInput), _startMatch(theStartMatch)
+{}
+
+/**
+ * Execute the completion command by wrapping the runDirCommand() of the
+ * embedded enhanced interpreter.
+ */
+void CompletionCommand::execute()
+{
+  int ret = static_cast<PyConsole_Interp*>(getInterp())->runDirCommand( _dirArg,  _startMatch );
+  _tabSuccess = ret == 0;
+}
+
+/**
+ * Create the event indicating the return value of the completion command.
+ * @return
+ */
+QEvent* CompletionCommand::createEvent()
+{
+  int typ = _tabSuccess ? PyInterp_Event::ES_TAB_COMPLETE_OK : PyInterp_Event::ES_TAB_COMPLETE_ERR;
+  return new PyInterp_Event( typ, this);
+}
diff --git a/src/PyConsoleBase/PyConsole_Request.h b/src/PyConsoleBase/PyConsole_Request.h
new file mode 100644 (file)
index 0000000..a0ed598
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (C) 2007-2015  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
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 3 avr. 2013
+
+
+#ifndef PYCONSOLE_REQUEST_H_
+#define PYCONSOLE_REQUEST_H_
+
+#include "PyInterp_Request.h"
+
+#include <vector>
+#include <QString>
+#include <QEvent>
+
+class PyInterp_Interp;
+
+/*!
+  \class ExecCommand
+  \brief Python command execution request.
+  \internal
+*/
+class ExecCommand : public PyInterp_LockRequest
+{
+public:
+  /*!
+    \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 sync        if True the request is processed synchronously
+  */
+  ExecCommand( PyInterp_Interp*        theInterp,
+               const QString&          theCommand,
+               QObject*                theListener,
+               bool                    theSync = false );
+
+protected:
+  /*!
+    \brief Execute the python command in the interpreter and
+           get its execution status.
+  */
+  virtual void execute();
+
+  /*!
+    \brief Create and return a notification event.
+    \return new notification event
+  */
+  virtual QEvent* createEvent();
+
+private:
+  QString myCommand;   //!< Python command
+  int     myState;     //!< Python command execution status
+};
+
+class CompletionCommand : public PyInterp_LockRequest
+{
+public:
+  CompletionCommand( PyInterp_Interp*     theInterp,
+                    const QString&       theInput,
+                    const QString&       theStartMatch,
+                    QObject*             theListener,
+                    bool                 theSync = false );
+
+
+protected:
+  /** List of separators identifying the last parsable token for completion */
+  static const std::vector<QString> SEPARATORS;
+
+  /** String to be passed to the dir() command */
+  QString _dirArg;
+  /** Begining of the command (as typed by the user) */
+  QString _startMatch;
+  /** was the completion command successful */
+  bool _tabSuccess;
+
+  virtual void execute();
+  virtual QEvent* createEvent();
+};
+
+#endif /* PYCONSOLE_REQUEST_H_ */
diff --git a/src/PyConsoleBase/resources/PyConsoleBase_msg_en.ts b/src/PyConsoleBase/resources/PyConsoleBase_msg_en.ts
new file mode 100644 (file)
index 0000000..1586df2
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="en_US">
+<context>
+    <name>PyConsole_ConsoleBase</name>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.cxx" line="216"/>
+        <source>EDIT_COPY_CMD</source>
+        <translation>&amp;Copy</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
+        <source>EDIT_PASTE_CMD</source>
+        <translation>&amp;Paste</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
+        <source>EDIT_CLEAR_CMD</source>
+        <translation>Clea&amp;r</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.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_EditorBase</name>
+    <message>
+        <source>Choose python file where to store</source>
+        <translation>Choose python file where to store dump</translation>
+    </message>
+    <message>
+        <source>Python scripts ext (*.py)</source>
+        <translation>Python scripts (*.py)</translation>
+    </message>
+    <message>
+        <source>WARNING</source>
+        <translation>WARNING !</translation>
+    </message>
+    <message>
+        <source>Python file has not been written</source>
+        <translation>Python file has not been written !</translation>
+    </message>
+    <message>
+        <source>Choose python file where to store log</source>
+        <translation>Choose python file where to store log</translation>
+    </message>
+    <message>
+        <source>Log files ext (*.log *.txt)</source>
+        <translation>Log files extension (*.log *.txt)</translation>
+    </message>
+    <message>
+        <source>Log file is not writable</source>
+        <translation>Log file is not writable !</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/PyConsoleBase/resources/PyConsoleBase_msg_fr.ts b/src/PyConsoleBase/resources/PyConsoleBase_msg_fr.ts
new file mode 100644 (file)
index 0000000..ff40a32
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+<context>
+    <name>PyConsole_ConsoleBase</name>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.cxx" line="216"/>
+        <source>EDIT_COPY_CMD</source>
+        <translation>&amp;Copier</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
+        <source>EDIT_PASTE_CMD</source>
+        <translation>C&amp;oller</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
+        <source>EDIT_CLEAR_CMD</source>
+        <translation>&amp;Effacer</translation>
+    </message>
+    <message>
+        <location filename="../PyConsole_ConsoleBase.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_EditorBase</name>
+    <message>
+        <source>Choose python file where to store</source>
+        <translation>Choisissez un fichier python où sauver le dump</translation>
+    </message>
+    <message>
+        <source>Python scripts ext (*.py)</source>
+        <translation>Scripts Python (*.py)</translation>
+    </message>
+    <message>
+        <source>WARNING</source>
+        <translation>Attention !</translation>
+    </message>
+    <message>
+        <source>Python file has not been written</source>
+        <translation>Le fichier Python n'a pas été écrit !</translation>
+    </message>
+    <message>
+        <source>Choose python file where to store log</source>
+        <translation>Choisissez un fichier python où sauver le log</translation>
+    </message>
+    <message>
+        <source>Log files ext (*.log *.txt)</source>
+        <translation>Extensions possible des fichiers log (*.log *.txt)</translation>
+    </message>
+    <message>
+        <source>Log file is not writable</source>
+        <translation>Le fichier log sélectionné n'est pas writable !</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/PyConsoleBase/resources/PyConsoleBase_msg_ja.ts b/src/PyConsoleBase/resources/PyConsoleBase_msg_ja.ts
new file mode 100644 (file)
index 0000000..ca1aace
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="ja" sourcelanguage="en">
+  <context>
+    <name>PyConsole_ConsoleBase</name>
+    <message>
+      <location filename="../PyConsole_ConsoleBase.cxx" line="216"/>
+      <source>EDIT_COPY_CMD</source>
+      <translation>コピー(&amp;C)</translation>
+    </message>
+    <message>
+      <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
+      <source>EDIT_PASTE_CMD</source>
+      <translation>貼り付け(&amp;P)</translation>
+    </message>
+    <message>
+      <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
+      <source>EDIT_CLEAR_CMD</source>
+      <translation>削除(&amp;r)</translation>
+    </message>
+    <message>
+      <location filename="../PyConsole_ConsoleBase.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_EditorBase</name>
+    <message>
+        <source>Choose python file where to store</source>
+        <translation>Choose python file where to store dump</translation>
+    </message>
+    <message>
+        <source>Python scripts ext (*.py)</source>
+        <translation>Python scripts (*.py)</translation>
+    </message>
+    <message>
+        <source>WARNING</source>
+        <translation>WARNING !</translation>
+    </message>
+    <message>
+        <source>Python file has not been written</source>
+        <translation>Python file has not been written !</translation>
+    </message>
+    <message>
+        <source>Choose python file where to store log</source>
+        <translation>Choose python file where to store log</translation>
+    </message>
+    <message>
+        <source>Log files ext (*.log *.txt)</source>
+        <translation>Log files extension (*.log *.txt)</translation>
+    </message>
+    <message>
+        <source>Log file is not writable</source>
+        <translation>Log file is not writable !</translation>
+    </message>
+</context>
+</TS>
index cf3dc958f567dd5e3ffb145aede2d4eb737459db..b7e4e775fad26c4939e9cceb6bc6fc600acfcd51 100755 (executable)
@@ -2095,6 +2095,17 @@ QString Qtx::qtDir( const QString& context )
   return qtPath;
 }
 
+/*!
+  Creates font from string description
+*/
+QFont Qtx::stringToFont( const QString& fontDescription )
+{
+  QFont font;
+  if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
+    font = QFont( "Courier", 11 );
+  return font;
+}
+
 #ifndef WIN32
 
 #include <X11/Xlib.h>
index 807002e74db3fb7610ba85124831bec5ba842a38..20eac5f9298c931b92ba9ece201d1662067995dd 100755 (executable)
@@ -44,6 +44,7 @@
 
 #include <QString>
 #include <QList>
+#include <QFont>
 #include <QColor>
 #include <QImage>
 #include <QPixmap>
@@ -276,6 +277,8 @@ public:
 
   static QString     qtDir( const QString& = QString());
 
+  static QFont   stringToFont( const QString& fontDescription );
+
 #ifndef WIN32
   static void*       getDisplay();
   static Qt::HANDLE  getVisual();
index 6fcaba594db7885434d56dd20ed98c2176844653..34f6e9f3a7d81c56b5f3223f610cee71152d4d18 100755 (executable)
@@ -41,6 +41,7 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/OBJECT
   ${PROJECT_SOURCE_DIR}/src/ObjBrowser
   ${PROJECT_SOURCE_DIR}/src/PyInterp
+  ${PROJECT_SOURCE_DIR}/src/PyConsoleBase
   ${PROJECT_SOURCE_DIR}/src/PyConsole
   ${PROJECT_SOURCE_DIR}/src/Qtx
   ${PROJECT_SOURCE_DIR}/src/SALOME_PYQT/SALOME_PYQT_GUILight
index 11a8ddb92d77559bf0a4f3d0af0ec5a5e845d66e..2d5ab0162a14021dab2b2edad9c66be4fc4742f9 100755 (executable)
@@ -62,17 +62,6 @@ QRect SUIT_Tools::makeRect( const int x1, const int y1, const int x2, const int
   return QRect( qMin( x1, x2 ), qMin( y1, y2 ), qAbs( x2 - x1 ), qAbs( y2 - y1 ) );
 }
 
-/*!
-  Creates font from string description
-*/
-QFont SUIT_Tools::stringToFont( const QString& fontDescription )
-{
-  QFont font;
-  if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
-    font = QFont( "Courier", 11 );
-  return font;
-}
-
 /*!
   Creates font's string description
 */
index dbb64a7da650ae405ee805ab5b9a6eed102857c8..40da4718aeabc0a903fe7ecee068569dfd077215 100755 (executable)
@@ -42,7 +42,6 @@ public:
   static QRect   makeRect( const int x1, const int y1, const int x2, const int y2 ); 
 
   static QString fontToString( const QFont& font );
-  static QFont   stringToFont( const QString& fontDescription );
 
   static void    centerWidget( QWidget* src, const QWidget* ref );
 };
index 5335fa4d8b5ac15b08c02bfca290dbe654c65b81..f4b7549331756eaaa299c5a6db9f39716ba34104 100755 (executable)
@@ -57,6 +57,7 @@ IF(SALOME_USE_PYCONSOLE)
   INCLUDE_DIRECTORIES(
     ${PYTHON_INCLUDE_DIRS}
     ${PROJECT_SOURCE_DIR}/src/PyConsole
+    ${PROJECT_SOURCE_DIR}/src/PyConsoleBase
     ${PROJECT_SOURCE_DIR}/src/PyInterp
   )
 ENDIF()