]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Merge from V6_main 12/04/2013
authorvsr <vsr@opencascade.com>
Fri, 12 Apr 2013 13:59:43 +0000 (13:59 +0000)
committervsr <vsr@opencascade.com>
Fri, 12 Apr 2013 13:59:43 +0000 (13:59 +0000)
31 files changed:
src/LightApp/LightApp_Application.cxx
src/LightApp/LightApp_PyInterp.cxx
src/LightApp/LightApp_PyInterp.h
src/PyConsole/CMakeLists.txt
src/PyConsole/Makefile.am
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 [new file with mode: 0644]
src/PyConsole/PyConsole_EnhEditor.h [new file with mode: 0644]
src/PyConsole/PyConsole_EnhInterp.cxx [new file with mode: 0644]
src/PyConsole/PyConsole_EnhInterp.h [new file with mode: 0644]
src/PyConsole/PyConsole_Event.cxx [new file with mode: 0644]
src/PyConsole/PyConsole_Event.h [new file with mode: 0644]
src/PyConsole/PyConsole_Request.cxx [new file with mode: 0644]
src/PyConsole/PyConsole_Request.h [new file with mode: 0644]
src/PyInterp/CMakeLists.txt
src/PyInterp/Makefile.am
src/PyInterp/PyInterp_Dispatcher.cxx
src/PyInterp/PyInterp_Dispatcher.h
src/PyInterp/PyInterp_Event.cxx [new file with mode: 0644]
src/PyInterp/PyInterp_Event.h [new file with mode: 0644]
src/PyInterp/PyInterp_Request.cxx [new file with mode: 0644]
src/PyInterp/PyInterp_Request.h [new file with mode: 0644]
src/SALOME_PYQT/SALOME_PYQT_GUILight/CMakeLists.txt
src/SALOME_PYQT/SALOME_PYQT_GUILight/Makefile.am
src/SVTK/SVTK_ViewModel.cxx
src/SalomeApp/SalomeApp_Application.cxx
src/SalomeApp/SalomeApp_PyInterp.cxx
src/SalomeApp/SalomeApp_PyInterp.h

index 9142c8da6e1802f267d8b2f98137e2f57ad0d656..8dd648f27aa78e305caa0e07ca06acdecb3d2d1f 100644 (file)
@@ -1839,7 +1839,7 @@ QWidget* LightApp_Application::createWindow( const int flag )
 #ifndef DISABLE_PYCONSOLE
   else  if ( flag == WT_PyConsole )
   {
-    PyConsole_Console* pyCons = new PyConsole_Console( desktop(),new LightApp_PyInterp());
+    PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(),new LightApp_PyInterp());
     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
index d6179eca30248175b63defeb5a8accad1585bc5a..5bc90b951807659edf253527aeb71eab865a73c1 100644 (file)
@@ -32,7 +32,7 @@
  * calls initialize method defined in base class, which calls virtual methods
  * initstate & initcontext redefined here.
  */
-LightApp_PyInterp::LightApp_PyInterp(): PyConsole_Interp()
+LightApp_PyInterp::LightApp_PyInterp(): PyConsole_EnhInterp()
 {
 }
 
index 22fdb87f0d0b8ca6a6f5e8855f64d03c17ff8a9a..d13d6bd85ccc04c0410510f74d66347e9b243692 100644 (file)
@@ -23,9 +23,9 @@
 #ifndef _LIGHTAPP_PYINTERP_H_
 #define _LIGHTAPP_PYINTERP_H_
 
-#include <PyConsole_Interp.h> // this include must be first (see PyInterp_base.h)!
+#include <PyConsole_EnhInterp.h> // this include must be first (see PyInterp_base.h)!
 
-class LightApp_PyInterp : public PyConsole_Interp
+class LightApp_PyInterp : public PyConsole_EnhInterp
 {
 public:
   LightApp_PyInterp();
index 2079551060a402730a67da9fb359a2f2c5a26ff0..00d0f49ca7047993fc9059bcae5a72ab285a19f7 100755 (executable)
@@ -27,12 +27,14 @@ INCLUDE_DIRECTORIES(
   ${CMAKE_CURRENT_SOURCE_DIR}/../Qtx
   ${CMAKE_CURRENT_SOURCE_DIR}/../SUIT
   ${CMAKE_CURRENT_SOURCE_DIR}/../PyInterp
+  ${CMAKE_CURRENT_SOURCE_DIR}/../Event
 )
 
-SET(COMMON_LIBS ${PYTHON_LIBRARIES} ${QT_LIBRARIES} ${SALOMELocalTrace} qtx suit PyInterp)
+SET(COMMON_LIBS ${PYTHON_LIBRARIES} ${QT_LIBRARIES} ${SALOMELocalTrace} qtx suit PyInterp Event)
 
 SET(GUI_HEADERS   
   PyConsole_Editor.h
+  PyConsole_EnhEditor.h
   PyConsole_Console.h
 )
 QT4_WRAP_CPP(GUI_HEADERS_MOC ${GUI_HEADERS})
@@ -40,7 +42,11 @@ QT4_WRAP_CPP(GUI_HEADERS_MOC ${GUI_HEADERS})
 SET(PyConsole_SOURCES
   PyConsole_Console.cxx
   PyConsole_Editor.cxx
+  PyConsole_EnhEditor.cxx
   PyConsole_Interp.cxx
+  PyConsole_EnhInterp.cxx
+  PyConsole_Event.cxx
+  PyConsole_Request.cxx
 )
 
 SET(GUITS_SOURCES
@@ -58,7 +64,11 @@ SET(COMMON_HEADERS_H
   PyConsole.h
   PyConsole_Console.h
   PyConsole_Editor.h
+  PyConsole_EnhEditor.h
   PyConsole_Interp.h
+  PyConsole_EnhInterp.h
+  PyConsole_Event.h
+  PyConsole_Request.h
 )
 INSTALL(FILES ${COMMON_HEADERS_H} DESTINATION ${GUI_salomeinclude_HEADERS})
 QT4_INSTALL_TS_RESOURCES("${GUITS_SOURCES}" "${GUI_salomeres_DATA}")
index 5ae4afbc91706fd061cedc5d14ced39025f67f61..4bba60a39690560d64d79880547ede33228a3d04 100755 (executable)
@@ -29,15 +29,24 @@ salomeinclude_HEADERS =             \
        PyConsole.h             \
        PyConsole_Console.h     \
        PyConsole_Editor.h      \
-       PyConsole_Interp.h
+       PyConsole_EnhEditor.h   \
+       PyConsole_EnhInterp.h   \
+       PyConsole_Event.h       \
+       PyConsole_Request.h     \
+       PyConsole_Interp.h  
 
 dist_libPyConsole_la_SOURCES = \
        PyConsole_Console.cxx   \
        PyConsole_Editor.cxx    \
-       PyConsole_Interp.cxx            
+       PyConsole_EnhEditor.cxx \
+       PyConsole_Event.cxx     \
+       PyConsole_Request.cxx   \
+       PyConsole_Interp.cxx    \
+       PyConsole_EnhInterp.cxx
 
 MOC_FILES =                            \
        PyConsole_Editor_moc.cxx        \
+       PyConsole_EnhEditor_moc.cxx     \
        PyConsole_Console_moc.cxx
 
 nodist_libPyConsole_la_SOURCES = $(MOC_FILES)
@@ -47,7 +56,7 @@ nodist_salomeres_DATA = \
        PyConsole_msg_fr.qm
 
 libPyConsole_la_CPPFLAGS = $(PYTHON_INCLUDES) $(QT_INCLUDES) \
-       -I$(srcdir)/../PyInterp -I$(srcdir)/../SUIT -I$(srcdir)/../Qtx
+       -I$(srcdir)/../PyInterp -I$(srcdir)/../SUIT -I$(srcdir)/../Qtx -I$(srcdir)/../Event
 
 libPyConsole_la_LDFLAGS  = $(PYTHON_LIBS) $(QT_MT_LIBS) $(KERNEL_LDFLAGS) -lSALOMELocalTrace
-libPyConsole_la_LIBADD   = ../Qtx/libqtx.la ../SUIT/libsuit.la ../PyInterp/libPyInterp.la
+libPyConsole_la_LIBADD   = ../Qtx/libqtx.la ../SUIT/libsuit.la ../Event/libEvent.la ../PyInterp/libPyInterp.la 
index 8fbd17296af79e3396940da98bb5728a37f5c8b9..131055a0036894890a0e746c47b435687e1fc52c 100644 (file)
@@ -30,7 +30,8 @@
 
 #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 <Qtx.h>
 
@@ -49,8 +50,7 @@
   \param interp python interpreter
 */
 PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* interp )
-: QWidget( parent ),
-  myEditor( 0 )
+: QWidget( parent )
 {
   // create python interpreter
   myInterp = interp;
@@ -75,6 +75,13 @@ PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* interp
   createActions();
 }
 
+/**
+ * Protected constructor.
+ */
+PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* i,  PyConsole_Editor* e)
+  : QWidget (parent), myEditor(e), myInterp(i)
+{}
+
 /*!
   \brief Destructor.
 
@@ -324,3 +331,35 @@ void PyConsole_Console::updateActions()
   myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
   myActions[SelectAllId]->setEnabled( !myEditor->document()->isEmpty() );
 }
+
+/**
+ * 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_EnhConsole::PyConsole_EnhConsole( QWidget* parent, PyConsole_EnhInterp* interp)
+  : PyConsole_Console(parent, interp, 0)
+{
+  // create python interpreter
+  myInterp = interp;
+  if ( !myInterp )
+    myInterp = new PyConsole_EnhInterp();
+
+  // initialize Python interpretator
+  myInterp->initialize();
+
+  // create editor console
+  QVBoxLayout* lay = new QVBoxLayout( this );
+  lay->setMargin( 0 );
+  myEditor = new PyConsole_EnhEditor( static_cast<PyConsole_EnhInterp*>(myInterp), this );
+  char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
+  if (synchronous && atoi(synchronous))
+  {
+      myEditor->setIsSync(true);
+  }
+  myEditor->viewport()->installEventFilter( this );
+  lay->addWidget( myEditor );
+
+  createActions();
+}
index 6258ee97f1eff3d1019d208a47e98057a4e4836c..e7b02ad196792021cc146992b8adcde53a2d5964 100644 (file)
@@ -34,6 +34,7 @@
 
 class PyConsole_Interp;
 class PyConsole_Editor;
+class PyConsole_EnhInterp;
 
 class PYCONSOLE_EXPORT PyConsole_Console : public QWidget, public SUIT_PopupClient
 {
@@ -81,14 +82,30 @@ public:
   void                setMenuActions( const int );
   int                 menuActions() const;
 
-private:
+protected:
   void                createActions();
   void                updateActions();
 
-private:
+  PyConsole_Console( QWidget* parent, PyConsole_Interp*,  PyConsole_Editor*);
+
+
   PyConsole_Interp*   myInterp;    //!< python interpreter
   PyConsole_Editor*   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 PYCONSOLE_EXPORT PyConsole_EnhConsole: public PyConsole_Console
+{
+  Q_OBJECT
+
+public:
+  PyConsole_EnhConsole( QWidget* parent, PyConsole_EnhInterp* interp = 0);
+  virtual ~PyConsole_EnhConsole() {}
+};
+
 #endif // PYCONSOLE_CONSOLE_H
index 3414e26a62b56da147bc90712864a82c07231fdc..636ee54a7c2667537f86cdd68d4795c542a937b6 100644 (file)
   - <Ctrl><C>            : copy
   - <Ctrl><X>            : cut
   - <Ctrl><V>            : paste
-
-  TODO:
-  - paste multiline text: process each line as separate command
-    (including mouse middle-button click pasting)
-  - the same for drag-n-drop of multiline text
 */
 
 #include "PyConsole_Interp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
 #include "PyConsole_Editor.h"
-#include <PyInterp_Dispatcher.h>
+#include "PyConsole_Event.h"
+#include "PyInterp_Event.h"
+#include "PyInterp_Dispatcher.h"
+#include "PyConsole_Request.h"
 
 #include <SUIT_Tools.h>
 #include <SUIT_FileDlg.h>
 #include <QTextCursor>
 #include <QTextDocument>
 #include <QTextStream>
+#include <QChar>
 
 static QString READY_PROMPT = ">>> ";
 static QString DOTS_PROMPT  = "... ";
-#define PROMPT_SIZE myPrompt.length()
-
-#define PRINT_EVENT 65432
-
 
 class DumpCommandsFileValidator : public SUIT_FileValidator
 {
@@ -141,95 +136,19 @@ bool DumpCommandsFileValidator::canSave(const QString& file, bool permissions)
   return SUIT_FileValidator::canSave( file, permissions);
 }
 
-/*!
-  \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,
-               PyConsole_Editor*       theListener, 
-               bool                    sync = false )
-    : PyInterp_LockRequest( theInterp, theListener, sync ),
-      myCommand( theCommand ), myState( PyInterp_Event::ES_OK )
-  {}
-
-protected:
-  /*!
-    \brief Execute the python command in the interpreter and 
-           get its execution status.
-  */
-  virtual void execute()
-  {
-    if ( myCommand != "" )
-    {
-      int ret = getInterp()->run( myCommand.toUtf8().data() );
-      if ( ret < 0 )
-        myState = PyInterp_Event::ES_ERROR;
-      else if ( ret > 0 )
-        myState = PyInterp_Event::ES_INCOMPLETE;
-    } 
-  }
-
-  /*!
-    \brief Create and return a notification event.
-    \return new notification event
-  */
-  virtual QEvent* createEvent() const
-  {
-    if ( IsSync() )
-      QCoreApplication::sendPostedEvents( listener(), PRINT_EVENT );
-    return new PyInterp_Event( myState, (PyInterp_Request*)this );    
-  }
-
-private:
-  QString myCommand;   //!< Python command
-  int     myState;     //!< Python command execution status
-};
-
-/*!
-  \class PrintEvent
-  \brief Python command output backend event.
-  \internal
-*/
-
-class PrintEvent : public QEvent
+void staticCallbackStdout( void* data, char* c )
 {
-public:
-  /*!
-    \brief Constructor
-    \param c message text (python trace)
-  */
-  PrintEvent( const char* c ) : QEvent( (QEvent::Type)PRINT_EVENT ), myText( c ) {}
-  /*!
-    \brief Get message
-    \return message text (python trace)
-  */
-  QString text() const { return myText; }
-
-private:
-  QString myText; //!< Event message (python trace)
-};
+  if(!((PyConsole_Editor*)data)->isSuppressOutput())
+    QApplication::postEvent( (PyConsole_Editor*)data, new PrintEvent( c, false ) );
+}
 
-void staticCallback( void* data, char* c )
+void staticCallbackStderr( void* data, char* c )
 {
   if(!((PyConsole_Editor*)data)->isSuppressOutput())
-    QApplication::postEvent( (PyConsole_Editor*)data, new PrintEvent( c ) ); 
+    QApplication::postEvent( (PyConsole_Editor*)data, new PrintEvent( c, true ) );
 }
 
+
 /*!
   \brief Constructor. 
   
@@ -257,8 +176,8 @@ PyConsole_Editor::PyConsole_Editor( PyConsole_Interp* theInterp,
   setWordWrapMode( QTextOption::WrapAnywhere );
   setAcceptRichText( false );
 
-  theInterp->setvoutcb( staticCallback, this );
-  theInterp->setverrcb( staticCallback, this );
+  theInterp->setvoutcb( staticCallbackStdout, this );
+  theInterp->setverrcb( staticCallbackStderr, this );
 
   // san - This is necessary for troubleless initialization
   onPyInterpChanged( theInterp );
@@ -366,14 +285,23 @@ QSize PyConsole_Editor::sizeHint() const
   \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     newBlock,
+                                const bool    isError)
 {
+  QTextCursor theCursor(textCursor());
+  QTextCharFormat cf;
+
   moveCursor( QTextCursor::End );
   if ( newBlock )
-    textCursor().insertBlock();
-  textCursor().insertText( str );
+    theCursor.insertBlock();
+  if (isError)
+      cf.setForeground(QBrush(Qt::red));
+  else
+      cf.setForeground(QBrush(Qt::black));
+  theCursor.insertText( str, cf);
   moveCursor( QTextCursor::End );
   ensureCursorVisible();
 }
@@ -382,6 +310,8 @@ void PyConsole_Editor::addText( const QString& str,
   \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 )
 {
@@ -462,12 +392,17 @@ void PyConsole_Editor::execAndWait( const QString& command )
 */
 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, PROMPT_SIZE );
+  QString cmd = par.text().remove( 0, promptSize() );
   // extend the command buffer with the current command 
   myCommandBuffer.append( cmd );
   // add command to the history
@@ -499,7 +434,7 @@ void PyConsole_Editor::dropEvent( QDropEvent* event )
   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() + PROMPT_SIZE ) {
+  if ( cur.position() < document()->end().previous().position() + promptSize() ) {
     moveCursor( QTextCursor::End );
     pos = cursorRect().center();
   }
@@ -529,21 +464,18 @@ void PyConsole_Editor::mouseReleaseEvent( QMouseEvent* event )
     //copy();
   }
   else if ( event->button() == Qt::MidButton ) {
-    QString text;
-    if ( QApplication::clipboard()->supportsSelection() )
-      text = QApplication::clipboard()->text( QClipboard::Selection );
-    if ( text.isEmpty() )
-      text = QApplication::clipboard()->text( QClipboard::Clipboard );
     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() + PROMPT_SIZE ) {
+    if ( cur.position() < document()->end().previous().position() + promptSize() ) {
       moveCursor( QTextCursor::End );
     }
     else {
       setTextCursor( cur );
     }
-    textCursor().clearSelection();
-    textCursor().insertText( text );
+    const QMimeData* md = QApplication::clipboard()->mimeData( QApplication::clipboard()->supportsSelection() ? 
+                                                              QClipboard::Selection : QClipboard::Clipboard );
+    if ( md )
+      insertFromMimeData( md );
   }
   else {
     QTextEdit::mouseReleaseEvent( event );
@@ -612,13 +544,15 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
   }
 
   // check for printed key
-  aKey = ( aKey < Qt::Key_Space || aKey > Qt::Key_ydiaeresis ) ? aKey : 0;
+  // #### 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 < PROMPT_SIZE ) {
+      if ( curLine < endLine || curCol < promptSize() ) {
         moveCursor( QTextCursor::End );
       }
       QTextEdit::keyPressEvent( event );
@@ -654,7 +588,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
           myCmdInHistory = myHistory.count();
           // remember current command
           QTextBlock par = document()->end().previous();
-          myCurrentCommand = par.text().remove( 0, PROMPT_SIZE );
+          myCurrentCommand = par.text().remove( 0, promptSize() );
         }
         if ( myCmdInHistory > 0 ) {
           myCmdInHistory--;
@@ -724,7 +658,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
     // - with <Ctrl>+<Shift> modifier keys pressed: move one word left with selection
     {
       QString txt = textCursor().block().text();
-      if ( !shftPressed && isCommand( txt ) && curCol <= PROMPT_SIZE ) {
+      if ( !shftPressed && isCommand( txt ) && curCol <= promptSize() ) {
         moveCursor( QTextCursor::Up );
         moveCursor( QTextCursor::EndOfBlock );
       }
@@ -743,15 +677,15 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
       QString txt = textCursor().block().text();
       if ( !shftPressed ) {
         if ( curCol < txt.length() ) {
-          if ( isCommand( txt ) && curCol < PROMPT_SIZE ) {
-            cur.setPosition( cur.block().position() + PROMPT_SIZE );
+          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() + PROMPT_SIZE+1 );
+            cur.setPosition( cur.position() + promptSize()+1 );
             setTextCursor( cur );
             horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
             break;
@@ -798,7 +732,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
           myCmdInHistory = myHistory.count();
           // remember current command
           QTextBlock par = document()->end().previous();
-          myCurrentCommand = par.text().remove( 0, PROMPT_SIZE );
+          myCurrentCommand = par.text().remove( 0, promptSize() );
         }
         if ( myCmdInHistory > 0 ) {
           myCmdInHistory = 0;
@@ -876,14 +810,14 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
         QString txt = textCursor().block().text();
         if ( isCommand( txt ) ) {
           if ( shftPressed ) {
-            if ( curCol > PROMPT_SIZE ) {
+            if ( curCol > promptSize() ) {
               cur.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
-              cur.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, PROMPT_SIZE );
+              cur.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
             }
           }
           else {
             cur.movePosition( QTextCursor::StartOfLine );
-            cur.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PROMPT_SIZE );
+            cur.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
           }
           setTextCursor( cur );
         }
@@ -916,13 +850,13 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
       if ( cur.hasSelection() ) {
         cut();
       }
-      else if ( cur.position() > document()->end().previous().position() + PROMPT_SIZE ) {
+      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() + PROMPT_SIZE, 
+          cur.setPosition( document()->end().previous().position() + promptSize(),
                            QTextCursor::KeepAnchor );
           setTextCursor( cur );
           textCursor().removeSelectedText();
@@ -932,7 +866,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
         }
       }
       else {
-        cur.setPosition( document()->end().previous().position() + PROMPT_SIZE );
+        cur.setPosition( document()->end().previous().position() + promptSize() );
         setTextCursor( cur );
         horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
       }
@@ -948,7 +882,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
       if ( cur.hasSelection() ) {
         cut();
       }
-      else if ( cur.position() > document()->end().previous().position() + PROMPT_SIZE-1 ) {
+      else if ( cur.position() > document()->end().previous().position() + promptSize()-1 ) {
         if ( shftPressed ) {
           moveCursor( QTextCursor::NextWord, QTextCursor::KeepAnchor );
           textCursor().removeSelectedText();
@@ -962,7 +896,7 @@ void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
         }
       }
       else {
-        cur.setPosition( document()->end().previous().position() + PROMPT_SIZE );
+        cur.setPosition( document()->end().previous().position() + promptSize() );
         setTextCursor( cur );
         horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
       }
@@ -994,10 +928,10 @@ void PyConsole_Editor::customEvent( QEvent* event )
 {
   switch( event->type() )
   {
-  case PRINT_EVENT:
+  case PrintEvent::EVENT_ID:
     {
       PrintEvent* pe=(PrintEvent*)event;
-      addText( pe->text() );
+      addText( pe->text(), false, pe->isError());
       return;
     }
   case PyInterp_Event::ES_OK:
@@ -1115,11 +1049,11 @@ void PyConsole_Editor::cut()
   if ( cur.hasSelection() ) {
     QApplication::clipboard()->setText( cur.selectedText() );
     int startSelection = cur.selectionStart();
-    if ( startSelection < document()->end().previous().position() + PROMPT_SIZE )
-      startSelection = document()->end().previous().position() + PROMPT_SIZE;
+    if ( startSelection < document()->end().previous().position() + promptSize() )
+      startSelection = document()->end().previous().position() + promptSize();
     int endSelection = cur.selectionEnd();
-    if ( endSelection < document()->end().previous().position() + PROMPT_SIZE )
-      endSelection = document()->end().previous().position() + PROMPT_SIZE;
+    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() );
@@ -1139,18 +1073,18 @@ void PyConsole_Editor::paste()
   QTextCursor cur = textCursor();
   if ( cur.hasSelection() ) {
     int startSelection = cur.selectionStart();
-    if ( startSelection < document()->end().previous().position() + PROMPT_SIZE )
-      startSelection = document()->end().previous().position() + PROMPT_SIZE;
+    if ( startSelection < document()->end().previous().position() + promptSize() )
+      startSelection = document()->end().previous().position() + promptSize();
     int endSelection = cur.selectionEnd();
-    if ( endSelection < document()->end().previous().position() + PROMPT_SIZE )
-      endSelection = document()->end().previous().position() + PROMPT_SIZE;
+    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() + PROMPT_SIZE )
+  if ( textCursor().position() < document()->end().previous().position() + promptSize() )
     moveCursor( QTextCursor::End );
   QTextEdit::paste();
 }
index 6bcc53a55445c28350ee0176736d1b427b862d62..2e1c80630a427efaee43996ca34930c93f0d61b6 100644 (file)
@@ -43,7 +43,7 @@ public:
   PyConsole_Editor( PyConsole_Interp* theInterp, QWidget *theParent = 0 );
   ~PyConsole_Editor();
   
-  virtual void   addText( const QString& str, const bool newBlock = false ); 
+  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 );
@@ -60,6 +60,14 @@ public:
 
   virtual QSize  sizeHint() const;
 
+public slots:
+    void           cut();
+    void           paste();
+    void           clear();
+    void           handleReturn();
+    void           onPyInterpChanged( PyConsole_Interp* );
+    void           dump();
+
 protected:
   virtual void   dropEvent( QDropEvent* event );
   virtual void   mouseReleaseEvent( QMouseEvent* event );
@@ -68,15 +76,9 @@ protected:
 
   virtual PyInterp_Request* createRequest( const QString& );
 
-public slots:
-  void           cut();
-  void           paste();
-  void           clear();
-  void           handleReturn();
-  void           onPyInterpChanged( PyConsole_Interp* );
-  void           dump();
-  
-private:
+  /** Convenience function */
+  inline int promptSize() const { return myPrompt.size(); }
+
   PyConsole_Interp* myInterp;           //!< python interpreter
 
   QString           myCommandBuffer;    //!< python command buffer
diff --git a/src/PyConsole/PyConsole_EnhEditor.cxx b/src/PyConsole/PyConsole_EnhEditor.cxx
new file mode 100644 (file)
index 0000000..c3bbbf4
--- /dev/null
@@ -0,0 +1,482 @@
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
+//
+// 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 <Python.h>
+
+#include <QKeyEvent>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextCharFormat>
+#include <QRegExp>
+
+#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]));
+
+/**
+ * Constructor.
+ * @param interp the interpreter linked to the editor
+ * @param parent parent widget
+ */
+PyConsole_EnhEditor::PyConsole_EnhEditor(PyConsole_EnhInterp * 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
+      static_cast<PyConsole_EnhInterp *>(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( static_cast<PyConsole_EnhInterp *>(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 std::vector<QString> & 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_EnhEditor::customEvent( QEvent* event )
+{
+  std::vector<QString> matches;
+  QString first_match, comple_text, doc, base;
+  QTextCursor cursor(textCursor());
+  QTextBlockFormat bf;
+  QTextCharFormat cf;
+  PyConsole_EnhInterp * interp = static_cast<PyConsole_EnhInterp *>(myInterp);
+  int cursorPos;
+
+  switch( event->type() )
+  {
+    case PyInterp_Event::ES_TAB_COMPLETE_OK:
+      // Extract corresponding matches from the interpreter
+      matches = interp->getLastMatches();
+
+      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
+      doc = interp->getDocStr();
+      if (matches.size() == 1)
+        {
+          first_match = matches[0].mid(_compl_after_point.size());
+          cursor.insertText(first_match);
+          _tab_mode = false;
+          if (doc == QString(""))
+            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;
+  }
+}
+
+/**
+ * Extract the common leading part of all strings in matches.
+ * @param matches
+ * @param result
+ */
+void PyConsole_EnhEditor::extractCommon(const std::vector<QString> & 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_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();
+    }
+}
diff --git a/src/PyConsole/PyConsole_EnhEditor.h b/src/PyConsole/PyConsole_EnhEditor.h
new file mode 100644 (file)
index 0000000..f52dc82
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
+//
+// 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_ENHEDITOR_H_
+#define PYCONSOLE_ENHEDITOR_H_
+
+#include "PyConsole.h"
+
+#include "PyConsole_Editor.h"
+#include <QObject>
+#include <queue>
+
+class PyConsole_EnhInterp;
+
+/**
+ * Enhanced Python editor handling tab completion.
+ */
+class PYCONSOLE_EXPORT PyConsole_EnhEditor: public PyConsole_Editor
+{
+  Q_OBJECT;
+
+public:
+  PyConsole_EnhEditor(PyConsole_EnhInterp * 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 std::vector<QString> & matches, QString & result) const;
+  virtual QString formatDocHTML(const QString & doc) const;
+
+  virtual void multilinePaste(const QString & s);
+  virtual void multiLineProcessNextLine();
+
+private:
+  void extractCommon(const std::vector<QString> & matches, QString & result) const;
+
+};
+
+#endif /* PYCONSOLE_ENHEDITOR_H_ */
diff --git a/src/PyConsole/PyConsole_EnhInterp.cxx b/src/PyConsole/PyConsole_EnhInterp.cxx
new file mode 100644 (file)
index 0000000..c648086
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
+//
+// 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 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, _g, _g);
+      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, std::vector<QString> & 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, _g, _g);
+  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.resize(0);
+  _doc_str = QString("");
+}
+
+
+
diff --git a/src/PyConsole/PyConsole_EnhInterp.h b/src/PyConsole/PyConsole_EnhInterp.h
new file mode 100644 (file)
index 0000000..113f84a
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
+//
+// 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()
+    : PyConsole_Interp(), _last_matches(0), _doc_str("")
+    {}
+
+  virtual ~PyConsole_EnhInterp() {}
+
+  const std::vector<QString>& getLastMatches() const { return _last_matches; }
+  const QString & getDocStr() const                  { return _doc_str; }
+
+  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 */
+  std::vector<QString> _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,
+      std::vector<QString> & result, bool discardSwig=true) const;
+
+};
+
+#endif /* PYCONSOLE_ENHINTERP_H_ */
diff --git a/src/PyConsole/PyConsole_Event.cxx b/src/PyConsole/PyConsole_Event.cxx
new file mode 100644 (file)
index 0000000..ae0b665
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) 2007-2013  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.
+//
+// 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
new file mode 100644 (file)
index 0000000..ac6a75f
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (C) 2007-2013  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.
+//
+// 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 char* 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_Request.cxx b/src/PyConsole/PyConsole_Request.cxx
new file mode 100644 (file)
index 0000000..bac6a38
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
+//
+// 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 "PyInterp_Event.h"
+#include "PyConsole_Event.h"
+#include "PyConsole_EnhInterp.h"
+#include "PyConsole_EnhEditor.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,
+               PyConsole_Editor*       theListener,
+               bool                    sync )
+    : PyInterp_LockRequest( theInterp, theListener, sync ),
+      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.toUtf8().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( PyConsole_EnhInterp*  theInterp,
+               const QString&          input,
+               const QString&         startMatch,
+               PyConsole_EnhEditor*           theListener,
+               bool                    sync)
+     : PyInterp_LockRequest( theInterp, theListener, sync ),
+       _tabSuccess(false), _dirArg(input), _startMatch(startMatch)
+{}
+
+/**
+ * Execute the completion command by wrapping the runDirCommand() of the
+ * embedded enhanced interpreter.
+ */
+void CompletionCommand::execute()
+{
+  PyConsole_EnhInterp * interp = static_cast<PyConsole_EnhInterp *>(getInterp());
+    int ret = interp->runDirCommand( _dirArg,  _startMatch);
+    if (ret == 0)
+      _tabSuccess = true;
+    else
+      _tabSuccess = false;
+}
+
+/**
+ * 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
new file mode 100644 (file)
index 0000000..ccfea0c
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
+//
+// 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 "PyConsole.h"
+#include "PyInterp_Request.h"
+
+#include <vector>
+#include <QString>
+#include <QEvent>
+
+class PyInterp_Interp;
+class PyConsole_Editor;
+
+/*!
+  \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,
+               PyConsole_Editor*       theListener,
+               bool                    sync = 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 PyConsole_EnhInterp;
+class PyConsole_EnhEditor;
+
+class CompletionCommand : public PyInterp_LockRequest
+{
+public:
+  CompletionCommand( PyConsole_EnhInterp*      theInterp,
+               const QString&          input,
+               const QString&          startMatch,
+               PyConsole_EnhEditor*    theListener,
+               bool                    sync = 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 425fa8b051d604b59f50145c58c5e4ce57f4e8fa..3267a4d93f30c5cecb1166d120ddd942a6caaf25 100755 (executable)
@@ -34,6 +34,8 @@ QT4_WRAP_CPP(GUI_HEADERS_MOC ${GUI_HEADERS})
 SET(PyInterp_SOURCES
   PyInterp_Interp.cxx
   PyInterp_Dispatcher.cxx
+  PyInterp_Event.cxx
+  PyInterp_Request.cxx
 )
 
 ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
@@ -46,5 +48,7 @@ SET(COMMON_HEADERS_H
   PyInterp.h
   PyInterp_Interp.h
   PyInterp_Dispatcher.h
+  PyInterp_Event.h
+  PyInterp_Request.h
 )
 INSTALL(FILES ${COMMON_HEADERS_H} DESTINATION ${GUI_salomeinclude_HEADERS})
index d19ed4e891092d407762a63dca80b6cdf586ce44..4bb400560f9b172bb196f4e671c1d11a3b43174f 100755 (executable)
@@ -31,10 +31,14 @@ lib_LTLIBRARIES = libPyInterp.la
 salomeinclude_HEADERS =                \
        PyInterp.h              \
        PyInterp_Interp.h       \
+       PyInterp_Event.h        \
+       PyInterp_Request.h      \
        PyInterp_Dispatcher.h
 
 dist_libPyInterp_la_SOURCES =  \
        PyInterp_Interp.cxx     \
+       PyInterp_Event.cxx      \
+       PyInterp_Request.cxx    \
        PyInterp_Dispatcher.cxx
 
 MOC_FILES = PyInterp_Watcher_moc.cxx
index 5e7643547b2589d56ec2d05c7e3b6d2608c65b3c..44052093a3817c796828949e20e23c39fa0a38ae 100755 (executable)
 #include "PyInterp_Dispatcher.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
 #include "PyInterp_Interp.h"
 #include "PyInterp_Watcher.h"
-#include <SALOME_Event.h>
+#include "PyInterp_Request.h"
 
 #include <QObject>
 #include <QCoreApplication>
 
-class PyInterp_ExecuteEvent: public SALOME_Event
-{
-public:
-  PyInterp_Request* myRequest;
-  PyInterp_ExecuteEvent( PyInterp_Request* r )
-    : myRequest( r ) {}
-  virtual void Execute()
-  {
-    myRequest->execute();
-  }
-};
-
 PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
 
 void PyInterp_Request::process()
@@ -76,9 +64,9 @@ void PyInterp_Request::Destroy( PyInterp_Request* request )
   delete request;
 }
 
-QEvent* PyInterp_Request::createEvent() const
+QEvent* PyInterp_Request::createEvent()
 {
-  return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, (PyInterp_Request*)this );
+  return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, this );
 }
 
 void PyInterp_Request::processEvent( QObject* o )
index 793124d2b3c62380df9a4a6149d7e419d050ce8f..4cc9a55f3ad5deaf7f62ba84c61db4775309c03d 100755 (executable)
 
 //  File   : PyInterp_Dispatcher.h
 //  Author : Sergey Anikin, OCC
-//  Module : SALOME
+//  Module : GUI
 //
 #ifndef PYINTERP_DISPATCHER_H
 #define PYINTERP_DISPATCHER_H
 
 #include "PyInterp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
 
+#include "PyInterp_Request.h"   // full include instead of forward declaration
+                                // everyone inc'ing the Dispatcher will get the requests for free.
+
 #include <QMutex>
 #include <QThread>
-#include <QEvent>
 #include <QQueue>
 
 class QObject;
-
-class PyInterp_Interp;
 class PyInterp_Watcher;
-class PyInterp_Dispatcher;
-class PyInterp_ExecuteEvent;
-
-class PYINTERP_EXPORT PyInterp_Request
-{
-  friend class PyInterp_Dispatcher;
-  friend class PyInterp_ExecuteEvent;
-
-  PyInterp_Request();
-  PyInterp_Request( const PyInterp_Request& );
-
-protected:
-  virtual ~PyInterp_Request() {};
-  // protected destructor - to control deletion of requests
-
-public:
-  PyInterp_Request( QObject* listener, bool sync = false )
-    : myIsSync( sync ), myListener( listener ) {};
-
-  static void     Destroy( PyInterp_Request* );
-  // Deletes a request
-
-  bool            IsSync() const { return myIsSync; }
-  // Returns true if this request should be processed synchronously,
-  // without putting it to a queue
-
-protected:
-  virtual void    safeExecute();
-
-  virtual void    execute() = 0;
-  // Should be redefined in successors, contains actual request code
-
-  virtual QEvent* createEvent() const;
-  // This method can be overridden to customize notification event creation
-
-  virtual void    processEvent( QObject* );
-
-  QObject*        listener() const { return myListener; }
-  void            setListener( QObject* );
-
-private:
-  void            process();
-
-private:
-  QMutex          myMutex;
-  bool            myIsSync;
-  QObject*        myListener;
-};
-
-class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request
-{
-public:
-  PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener = 0, bool sync = false )
-    : PyInterp_Request( listener, sync ), myInterp( interp ) {}
-
-protected:
-  PyInterp_Interp*  getInterp() const { return myInterp; }
-
-  virtual void      safeExecute();
-
-private:
-  PyInterp_Interp*  myInterp;
-};
-
-class PYINTERP_EXPORT PyInterp_Event : public QEvent
-{
-  PyInterp_Event();
-  PyInterp_Event( const PyInterp_Event& );
-
-public:
-  //Execution state
-  enum { ES_NOTIFY = QEvent::User + 5000, ES_OK, ES_ERROR, ES_INCOMPLETE, ES_LAST };
-
-  PyInterp_Event( int type, PyInterp_Request* request )
-    : QEvent( (QEvent::Type)type ), myRequest( request ) {}
-
-  virtual ~PyInterp_Event();
-
-  PyInterp_Request* GetRequest() const { return myRequest; }
-  operator PyInterp_Request*() const { return myRequest; }
-
-private:
-  PyInterp_Request* myRequest;
-};
 
 class PYINTERP_EXPORT PyInterp_Dispatcher : protected QThread
 {
diff --git a/src/PyInterp/PyInterp_Event.cxx b/src/PyInterp/PyInterp_Event.cxx
new file mode 100644 (file)
index 0000000..7027f6e
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (C) 2007-2013  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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : PyInterp_Request.h
+//  Author : Sergey Anikin, OCC, Adrien Bruneton (CEA/DEN)
+//  Module : GUI
+
+#include "PyInterp_Event.h"
+#include "PyInterp_Request.h"
+
+void PyInterp_ExecuteEvent::Execute()
+{
+  myRequest->execute();
+}
diff --git a/src/PyInterp/PyInterp_Event.h b/src/PyInterp/PyInterp_Event.h
new file mode 100644 (file)
index 0000000..3a16400
--- /dev/null
@@ -0,0 +1,76 @@
+
+// Copyright (C) 2007-2013  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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : PyInterp_Request.h
+//  Author : Sergey Anikin, OCC, Adrien Bruneton (CEA/DEN)
+//  Module : GUI
+
+#ifndef PYINTERP_EVENT_H
+#define PYINTERP_EVENT_H
+
+#include "PyInterp.h"
+
+#include <SALOME_Event.h>
+
+#include <QEvent>
+
+class PyInterp_Request;
+
+class PyInterp_ExecuteEvent: public SALOME_Event
+{
+public:
+  PyInterp_ExecuteEvent( PyInterp_Request* r )
+    : myRequest( r ) {}
+
+  virtual void Execute();
+
+protected:
+  PyInterp_Request* myRequest;
+};
+
+/**
+ * Events thrown by the interpreter having executed a command and indicating
+ * the return status.
+ */
+class PYINTERP_EXPORT PyInterp_Event : public QEvent
+{
+  PyInterp_Event();
+  PyInterp_Event( const PyInterp_Event& );
+
+public:
+  //Execution state
+  enum { ES_NOTIFY = QEvent::User + 5000, ES_OK, ES_ERROR, ES_INCOMPLETE,
+         ES_TAB_COMPLETE_OK, ES_TAB_COMPLETE_ERR, ES_LAST };
+
+  PyInterp_Event( int type, PyInterp_Request* request )
+    : QEvent( (QEvent::Type)type ), myRequest( request ) {}
+
+  virtual ~PyInterp_Event();
+
+  PyInterp_Request* GetRequest() const { return myRequest; }
+  operator PyInterp_Request*() const { return myRequest; }
+
+private:
+  PyInterp_Request* myRequest;
+};
+
+#endif // PYINTERP_EVENT_H
diff --git a/src/PyInterp/PyInterp_Request.cxx b/src/PyInterp/PyInterp_Request.cxx
new file mode 100644 (file)
index 0000000..e8032c1
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (C) 2007-2013  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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : PyInterp_Request.h
+//  Author : Sergey Anikin, OCC, Adrien Bruneton (CEA/DEN)
+//  Module : GUI
+
+#include "PyInterp_Request.h"
+
diff --git a/src/PyInterp/PyInterp_Request.h b/src/PyInterp/PyInterp_Request.h
new file mode 100644 (file)
index 0000000..9a4291b
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright (C) 2007-2013  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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : PyInterp_Request.h
+//  Author : Sergey Anikin (OCC), Adrien Bruneton (CEA/DEN)
+//  Module : GUI
+
+#ifndef PYINTERP_REQUEST_H
+#define PYINTERP_REQUEST_H
+
+#include "PyInterp.h"
+#include "PyInterp_Event.h"
+
+#include <QMutex>
+#include <QObject>
+
+class PyInterp_Interp;
+class PyInterp_Watcher;
+class PyInterp_Dispatcher;
+class PyInterp_ExecuteEvent;
+class PyConsole_Editor;
+
+class PYINTERP_EXPORT PyInterp_Request
+{
+  friend class PyInterp_Dispatcher;
+  friend class PyInterp_ExecuteEvent;
+
+  PyInterp_Request();
+  PyInterp_Request( const PyInterp_Request& );
+
+protected:
+  virtual ~PyInterp_Request() {};
+  // protected destructor - to control deletion of requests
+
+public:
+  PyInterp_Request( QObject* listener, bool sync = false )
+    : myIsSync( sync ), myListener( listener ) {};
+
+  static void     Destroy( PyInterp_Request* );
+  // Deletes a request
+
+  bool            IsSync() const { return myIsSync; }
+  // Returns true if this request should be processed synchronously,
+  // without putting it to a queue
+
+protected:
+  virtual void    safeExecute();
+
+  virtual void    execute() = 0;
+  // Should be redefined in successors, contains actual request code
+
+  virtual QEvent* createEvent();
+  // This method can be overridden to customize notification event creation
+
+  virtual void    processEvent( QObject* );
+
+  QObject*        listener() const { return myListener; }
+  void            setListener( QObject* );
+
+private:
+  void            process();
+
+private:
+  QMutex          myMutex;
+  bool            myIsSync;
+  QObject*        myListener;
+};
+
+class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request
+{
+public:
+
+  PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener = 0, bool sync = false )
+    : PyInterp_Request( listener, sync ), myInterp( interp )
+  {}
+
+protected:
+  PyInterp_Interp*  getInterp() const { return myInterp; }
+
+  virtual void      safeExecute();
+
+private:
+  PyInterp_Interp*  myInterp;
+};
+
+#endif // PYINTERP_REQUEST_H
index e1e3919f951036aea4902590bcf0e1b1fd2f8a8e..b8765efa2c97a66d16cfbb9f3272ec1095ec231b 100755 (executable)
@@ -40,6 +40,7 @@ INCLUDE_DIRECTORIES(
   ${CMAKE_CURRENT_SOURCE_DIR}/../../SUITApp
   ${CMAKE_CURRENT_SOURCE_DIR}/../../CAM
   ${CMAKE_CURRENT_SOURCE_DIR}/../../STD
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../Event
 )
 
 SET(COMMON_LIBS ${PYTHON_LIBRARIES} ${PYQT_LIBRARIES} ${VTK_LIBRARIES} ${OPENGL_LIBRARIES} PyInterp LightApp) 
index 08c264dcbb9fe2475a23f2d444d0d9a994875e31..cfa541401171868bc6af9950e1f775f72b0789c1 100644 (file)
@@ -74,7 +74,7 @@ libSalomePyQtGUILight_la_CPPFLAGS =  $(QT_INCLUDES) $(SIP_INCLUDES) $(PYTHON_INC
        -I$(srcdir)/../../Plot2d -I$(srcdir)/../../OCCViewer                            \
        -I$(srcdir)/../../CAM -I$(srcdir)/../../STD                                     \
        -I$(srcdir)/../../SUITApp                                                       \
-       -I$(srcdir)/../../CAM -I$(srcdir)/../../STD
+       -I$(srcdir)/../../CAM -I$(srcdir)/../../STD -I$(srcdir)/../../Event
 
 if GUI_ENABLE_CORBA
 libSalomePyQtGUILight_la_CPPFLAGS += -I$(srcdir)/../../SalomeApp \
index d0e2556d1624648f56ca4a7ebdd1dbde58e52ab1..d89674a8a08d10ce2b8fbca722d70349e4ebc252 100644 (file)
@@ -666,10 +666,10 @@ void SVTK_Viewer::EraseAll( const bool forced )
             //Handle(SALOME_InteractiveObject) anObj = anAct->getIO();
             //if(!anObj.IsNull() && anObj->hasEntry() && aStudy)
             //  ToolsGUI::SetVisibility(aStudy,anObj->getEntry(),false,this);
-            if(forced) 
+            if(forced){
               if(SVTK_Renderer* aRnd = aView->GetRenderer())
                 aRnd->RemoveActor(anAct);
-            else{
+            }else{
               // just erase actor
               anAct->SetVisibility( false );
               // erase dependent actors
index 159997416d7fc7d30dc1f4c6496a18a2a889a422..33d73927d0de0388cd8409a853deddb1deecab31 100644 (file)
@@ -929,7 +929,7 @@ QWidget* SalomeApp_Application::createWindow( const int flag )
   }
   else if ( flag == WT_PyConsole )
   {
-    PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new SalomeApp_PyInterp() );
+    PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
index 185b01f30f02f1419e8cf19b71cfbf3f5ff4058f..a0301b6ca6b84c81bcfb283b9eaf43691c0f4254 100755 (executable)
@@ -37,7 +37,7 @@
  * initstate & initcontext redefined here.
  */
 SalomeApp_PyInterp::SalomeApp_PyInterp(): 
-  PyConsole_Interp(), myFirstRun( true )
+  PyConsole_EnhInterp(), myFirstRun( true )
 {
 }
 
index 84c7906fe6fc6df908e628a5930aaa487fdb6d82..d457cf763e88af2d739341e7913cf1b43b5472da 100755 (executable)
@@ -27,9 +27,9 @@
 #ifndef _SalomeApp_PYINTERP_H_
 #define _SalomeApp_PYINTERP_H_
 
-#include <PyConsole_Interp.h> // this include must be first (see PyInterp_base.h)!
+#include <PyConsole_EnhInterp.h> // this include must be first (see PyInterp_base.h)!
 
-class SalomeApp_PyInterp : public PyConsole_Interp
+class SalomeApp_PyInterp : public PyConsole_EnhInterp
 {
 public:
   SalomeApp_PyInterp();