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