# 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()
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)
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)
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)
##
IF(SALOME_USE_PYCONSOLE)
ADD_SUBDIRECTORY(PyInterp)
+ ADD_SUBDIRECTORY(PyConsoleBase)
ADD_SUBDIRECTORY(PyConsole)
ADD_SUBDIRECTORY(SALOME_PYQT)
ENDIF(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
)
<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"/>
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
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 ---
# 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
# --- 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
QT_WRAP_MOC(_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
INSTALL(FILES ${PyConsole_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}")
-
#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.
{
}
-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);
}
/*!
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.
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);
}
#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
};
/**
* 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 );
#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
{
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.
*/
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 );
}
/*!
*/
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") );
}
}
/*!
- \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);
}
#define PYCONSOLE_EDITOR_H
#include "PyConsole.h"
+#include "PyConsole_EditorBase.h"
#include <QTextEdit>
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
#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.
* @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);
}
#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_ */
+++ /dev/null
-// 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 = "";
-}
+++ /dev/null
-// 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_ */
+++ /dev/null
-// 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"
+++ /dev/null
-// 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
+++ /dev/null
-// 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()
-{
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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);
-}
+++ /dev/null
-// 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_ */
<?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>&Copy</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="221"/>
- <source>EDIT_PASTE_CMD</source>
- <translation>&Paste</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="226"/>
- <source>EDIT_CLEAR_CMD</source>
- <translation>Clea&r</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="231"/>
- <source>EDIT_SELECTALL_CMD</source>
- <translation>Select &All</translation>
- </message>
- <message>
- <source>EDIT_DUMPCOMMANDS_CMD</source>
- <translation>D&ump Commands</translation>
- </message>
- <message>
- <source>EDIT_STARTLOG_CMD</source>
- <translation>Start &Log</translation>
- </message>
- <message>
- <source>EDIT_STOPLOG_CMD</source>
- <translation>Stop &Log</translation>
- </message>
-</context>
<context>
<name>PyConsole_Editor</name>
<message>
<?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>&Copier</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="221"/>
- <source>EDIT_PASTE_CMD</source>
- <translation>C&oller</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="226"/>
- <source>EDIT_CLEAR_CMD</source>
- <translation>&Effacer</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="231"/>
- <source>EDIT_SELECTALL_CMD</source>
- <translation>&Tout sélectionner</translation>
- </message>
- <message>
- <source>EDIT_DUMPCOMMANDS_CMD</source>
- <translation>&Générer le script des commandes</translation>
- </message>
- <message>
- <source>EDIT_STARTLOG_CMD</source>
- <translation>Démarrer une &trace</translation>
- </message>
- <message>
- <source>EDIT_STOPLOG_CMD</source>
- <translation>Arrêter la &trace</translation>
- </message>
-</context>
<context>
<name>PyConsole_Editor</name>
<message>
<?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>コピー(&C)</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="221"/>
- <source>EDIT_PASTE_CMD</source>
- <translation>貼り付け(&P)</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="226"/>
- <source>EDIT_CLEAR_CMD</source>
- <translation>削除(&r)</translation>
- </message>
- <message>
- <location filename="../PyConsole_Console.cxx" line="231"/>
- <source>EDIT_SELECTALL_CMD</source>
- <translation>すべて選択します。(&A)</translation>
- </message>
- <message>
- <source>EDIT_DUMPCOMMANDS_CMD</source>
- <translation>スクリプト コマンドを生成します。(&u)</translation>
- </message>
- <message>
- <source>EDIT_STARTLOG_CMD</source>
- <translation>ログの開始 (&L)</translation>
- </message>
- <message>
- <source>EDIT_STOPLOG_CMD</source>
- <translation>ログの停止 (&L)</translation>
- </message>
- </context>
<context>
<name>PyConsole_Editor</name>
<message>
--- /dev/null
+# 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}")
+
--- /dev/null
+// 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
--- /dev/null
+// 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();
+}
--- /dev/null
+// 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
--- /dev/null
+// 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();
+ }
+}
--- /dev/null
+// 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
--- /dev/null
+// 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();
+ }
+}
--- /dev/null
+// 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_ */
--- /dev/null
+// 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 = "";
+}
--- /dev/null
+// 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_ */
--- /dev/null
+// 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"
--- /dev/null
+// 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
--- /dev/null
+// 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()
+{
+}
--- /dev/null
+// 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
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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_ */
--- /dev/null
+<?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>&Copy</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
+ <source>EDIT_PASTE_CMD</source>
+ <translation>&Paste</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
+ <source>EDIT_CLEAR_CMD</source>
+ <translation>Clea&r</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="231"/>
+ <source>EDIT_SELECTALL_CMD</source>
+ <translation>Select &All</translation>
+ </message>
+ <message>
+ <source>EDIT_DUMPCOMMANDS_CMD</source>
+ <translation>D&ump Commands</translation>
+ </message>
+ <message>
+ <source>EDIT_STARTLOG_CMD</source>
+ <translation>Start &Log</translation>
+ </message>
+ <message>
+ <source>EDIT_STOPLOG_CMD</source>
+ <translation>Stop &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>
--- /dev/null
+<?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>&Copier</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
+ <source>EDIT_PASTE_CMD</source>
+ <translation>C&oller</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
+ <source>EDIT_CLEAR_CMD</source>
+ <translation>&Effacer</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="231"/>
+ <source>EDIT_SELECTALL_CMD</source>
+ <translation>&Tout sélectionner</translation>
+ </message>
+ <message>
+ <source>EDIT_DUMPCOMMANDS_CMD</source>
+ <translation>&Générer le script des commandes</translation>
+ </message>
+ <message>
+ <source>EDIT_STARTLOG_CMD</source>
+ <translation>Démarrer une &trace</translation>
+ </message>
+ <message>
+ <source>EDIT_STOPLOG_CMD</source>
+ <translation>Arrêter la &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>
--- /dev/null
+<?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>コピー(&C)</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
+ <source>EDIT_PASTE_CMD</source>
+ <translation>貼り付け(&P)</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
+ <source>EDIT_CLEAR_CMD</source>
+ <translation>削除(&r)</translation>
+ </message>
+ <message>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="231"/>
+ <source>EDIT_SELECTALL_CMD</source>
+ <translation>すべて選択します。(&A)</translation>
+ </message>
+ <message>
+ <source>EDIT_DUMPCOMMANDS_CMD</source>
+ <translation>スクリプト コマンドを生成します。(&u)</translation>
+ </message>
+ <message>
+ <source>EDIT_STARTLOG_CMD</source>
+ <translation>ログの開始 (&L)</translation>
+ </message>
+ <message>
+ <source>EDIT_STOPLOG_CMD</source>
+ <translation>ログの停止 (&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>
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>
#include <QString>
#include <QList>
+#include <QFont>
#include <QColor>
#include <QImage>
#include <QPixmap>
static QString qtDir( const QString& = QString());
+ static QFont stringToFont( const QString& fontDescription );
+
#ifndef WIN32
static void* getDisplay();
static Qt::HANDLE getVisual();
${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
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
*/
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 );
};
INCLUDE_DIRECTORIES(
${PYTHON_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/src/PyConsole
+ ${PROJECT_SOURCE_DIR}/src/PyConsoleBase
${PROJECT_SOURCE_DIR}/src/PyInterp
)
ENDIF()