SET(${PROJECT_NAME_UC}_PATCH_VERSION 0)
SET(${PROJECT_NAME_UC}_VERSION
${${PROJECT_NAME_UC}_MAJOR_VERSION}.${${PROJECT_NAME_UC}_MINOR_VERSION}.${${PROJECT_NAME_UC}_PATCH_VERSION})
-SET(${PROJECT_NAME_UC}_VERSION_DEV 0)
+SET(${PROJECT_NAME_UC}_VERSION_DEV 1)
# Find KERNEL
# ===========
# Python-based packages specific targets:
IF(SALOME_USE_PYCONSOLE)
LIST(APPEND _${PROJECT_NAME}_exposed_targets
- PyInterp PyConsole SalomePyQtGUILight)
+ PyInterp PyConsole SalomePyConsole SalomePyQtGUILight)
IF(SALOME_USE_PLOT2DVIEWER)
LIST(APPEND _${PROJECT_NAME}_exposed_targets SalomePyQt)
ENDIF()
SET(GUI_OpenGLUtils OpenGLUtils)
SET(GUI_Plot2d Plot2d)
SET(GUI_PyConsole PyConsole)
+SET(GUI_SalomePyConsole SalomePyConsole)
SET(GUI_PyInterp PyInterp)
SET(GUI_PyEditor PyEditor)
SET(GUI_PyViewer PyViewer)
FIND_LIBRARY(OpenGLUtils OpenGLUtils ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(Plot2d Plot2d ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(PyConsole PyConsole ${GUI_ROOT_DIR}/lib/salome)
+FIND_LIBRARY(SalomePyConsole SalomePyConsole ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(PyInterp PyInterp ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(QDS QDS ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(qtx qtx ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(OpenGLUtils OpenGLUtils ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(Plot2d Plot2d ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(PyConsole PyConsole ${GUI_ROOT_DIR}/lib/salome)
+FIND_LIBRARY(SalomePyConsole SalomePyConsole ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(PyInterp PyInterp ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(QDS QDS ${GUI_ROOT_DIR}/lib/salome)
FIND_LIBRARY(qtx qtx ${GUI_ROOT_DIR}/lib/salome)
the SALOME platform.
- <b>ASCII save</b> - if checked in, your study will be saved in
ASCII format file (or files).
+ - <b>Automatic loading of light modules when opening study</b> - if checked in,
+ Light Modules of the current study will be automatically loaded at the next study
+ opening, allowing completion of object browser.
- <b>Store positions of windows</b> - if checked in, positions of windows
will be saved in a special file at the end of the current session and
then restored for a new session.
IF(SALOME_USE_PYCONSOLE)
ADD_SUBDIRECTORY(PyInterp)
ADD_SUBDIRECTORY(PyConsole)
+ ADD_SUBDIRECTORY(SalomePyConsole)
ADD_SUBDIRECTORY(SALOME_PYQT)
ENDIF(SALOME_USE_PYCONSOLE)
IF(SALOME_USE_PYCONSOLE)
INCLUDE_DIRECTORIES(
${PYTHON_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}/src/SalomePyConsole
${PROJECT_SOURCE_DIR}/src/PyConsole
${PROJECT_SOURCE_DIR}/src/PyInterp
${PROJECT_SOURCE_DIR}/src/SUITApp
LIST(APPEND _link_LIBRARIES PVViewer)
ENDIF()
IF(SALOME_USE_PYCONSOLE)
- LIST(APPEND _link_LIBRARIES PyInterp PyConsole SUITApp)
+ LIST(APPEND _link_LIBRARIES PyInterp SalomePyConsole SUITApp)
ENDIF()
# --- headers ---
#ifndef DISABLE_PYCONSOLE
#include "LightApp_PyInterp.h" // WARNING! This include must be the first!
- #include <PyConsole_Console.h>
+ #include <SalomePyConsole_Console.h>
#endif
#include "LightApp_Application.h"
\param force - if true, the pythonConsole is created if it does not exist yet
\return Python Console
*/
-PyConsole_Console* LightApp_Application::pythonConsole(const bool force)
+SalomePyConsole_Console* LightApp_Application::pythonConsole(const bool force)
{
QWidget* wid = dockWindow( WT_PyConsole );
if ( !wid && force==true) {
wid = getWindow(WT_PyConsole);
}
- return qobject_cast<PyConsole_Console*>( wid );
+ return qobject_cast<SalomePyConsole_Console*>( wid );
}
#endif
#ifndef DISABLE_PYCONSOLE
else if ( flag == WT_PyConsole )
{
- PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
+ SalomePyConsole_Console* pyCons = new SalomePyConsole_EnhConsole( desktop(), getPyInterp() );
pyCons->setObjectName( "pythonConsole" );
pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
// .... -> ascii save mode
pref->addPreference( tr( "PREF_ASCII_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "ascii_file" );
// .... -> store windows geometry
+ pref->addPreference( tr( "PREF_LOAD_LIGHT" ), studyGroup, LightApp_Preferences::Bool, "Study", "autoload_light_modules" );
pref->addPreference( tr( "PREF_STORE_POS" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_positions" );
pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
pref->addPreference( tr( "PREF_STORE_TOOL_POS" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_tool_positions" );
class LogWindow;
#ifndef DISABLE_PYCONSOLE
-class PyConsole_Console;
+class SalomePyConsole_Console;
class PyConsole_Interp;
#endif
class LightApp_WidgetContainer;
LogWindow* logWindow();
SUIT_DataBrowser* objectBrowser();
#ifndef DISABLE_PYCONSOLE
- PyConsole_Console* pythonConsole(const bool force = false);
+ SalomePyConsole_Console* pythonConsole(const bool force = false);
#endif
virtual void updateObjectBrowser( const bool = true );
<parameter name="PyEditor" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
<parameter name="PyViewer" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
<parameter name="PyConsole" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
+ <parameter name="SalomePyConsole" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
<parameter name="SalomeApp" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
<parameter name="OB" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
<parameter name="CAM" value="${GUI_ROOT_DIR}/share/salome/resources/gui"/>
</section>
<section name="Study">
<!-- General study settings -->
+ <parameter name="autoload_light_modules" value="true" />
<parameter name="store_positions" value="true" />
<parameter name="store_tool_positions" value="true" />
<parameter name="auto_save_interval" value="0" />
<source>PREF_GROUP_VTKVIEWER</source>
<translation>VTK 3D Viewer</translation>
</message>
+ <message>
+ <source>PREF_LOAD_LIGHT</source>
+ <translation>Automatic loading of light modules when opening study</translation>
+ </message>
<message>
<source>PREF_STORE_POS</source>
<translation>Store positions of windows</translation>
<source>PREF_GROUP_VTKVIEWER</source>
<translation>Scène VTK 3D</translation>
</message>
+ <message>
+ <source>PREF_LOAD_LIGHT</source>
+ <translation>Chargement automatique des modules Light à l'ouverture d'étude</translation>
+ </message>
<message>
<source>PREF_STORE_POS</source>
<translation>Enregistrer la position des fenêtres</translation>
<source>PREF_GROUP_VTKVIEWER</source>
<translation>VTK 3D Viewer</translation>
</message>
+ <message>
+ <source>PREF_LOAD_LIGHT</source>
+ <translation>Automatic loading of light modules when opening study</translation>
+ </message>
<message>
<source>PREF_STORE_POS</source>
<translation>ウィンドウの位置を保存</translation>
${QT_INCLUDES}
${PYTHON_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/src/Qtx
- ${PROJECT_SOURCE_DIR}/src/SUIT
+ ${PROJECT_SOURCE_DIR}/src/PyConsole
${PROJECT_SOURCE_DIR}/src/Event
${PROJECT_SOURCE_DIR}/src/PyInterp
)
ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
# libraries to link to
-SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} qtx suit PyInterp Event)
+SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} PyInterp Event qtx)
# --- headers ---
# header files / to be processed by moc
SET(_moc_HEADERS
- PyConsole_Console.h
- PyConsole_Editor.h
- PyConsole_EnhEditor.h
+ PyConsole_ConsoleBase.h
+ PyConsole_EditorBase.h
+ PyConsole_EnhEditorBase.h
)
# header files / no moc processing
# sources / static
SET(_other_SOURCES
- PyConsole_Console.cxx
- PyConsole_Editor.cxx
- PyConsole_EnhEditor.cxx
+ PyConsole_ConsoleBase.cxx
PyConsole_EnhInterp.cxx
PyConsole_Event.cxx
PyConsole_Interp.cxx
PyConsole_Request.cxx
+ PyConsole_EditorBase.cxx
+ PyConsole_EnhEditorBase.cxx
)
# sources / to compile
+++ /dev/null
-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-// File : PyConsole_Console.cxx
-// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
-//
-/*!
- \class PyConsole_Console
- \brief Python console widget.
-*/
-
-#include "PyConsole_Interp.h" /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
-#include "PyConsole_Console.h"
-#include "PyConsole_EnhEditor.h"
-#include "PyConsole_EnhInterp.h"
-
-#include <Qtx.h>
-
-#include <QAction>
-#include <QApplication>
-#include <QClipboard>
-#include <QEvent>
-#include <QMenu>
-#include <QVBoxLayout>
-
-/*!
- \brief Constructor.
-
- Creates new python console widget.
- \param parent parent widget
- \param interp python interpreter
-*/
-PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* interp )
-: QWidget( parent )
-{
- PyConsole_Interp* anInterp = interp ? interp : new PyConsole_Interp();
-
- // initialize Python interpretator
- anInterp->initialize();
-
- // create editor console
- QVBoxLayout* lay = new QVBoxLayout( this );
- lay->setMargin( 0 );
- myEditor = new PyConsole_Editor( anInterp, this );
- char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
- if (synchronous && atoi(synchronous))
- {
- myEditor->setIsSync(true);
- }
- myEditor->viewport()->installEventFilter( this );
- lay->addWidget( myEditor );
-
- createActions();
-}
-
-/**
- * Protected constructor.
- */
-PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* /*i*/, PyConsole_Editor* e )
- : QWidget (parent), myEditor(e)
-{}
-
-/*!
- \brief Destructor.
-
- Does nothing for the moment.
-*/
-PyConsole_Console::~PyConsole_Console()
-{
-}
-
-PyConsole_Interp* PyConsole_Console::getInterp() const
-{
- return myEditor ? myEditor->getInterp() : 0;
-}
-
-/*!
- \brief Execute python command in the interpreter.
- \param command string with command and arguments
-*/
-void PyConsole_Console::exec( const QString& command )
-{
- if ( myEditor )
- myEditor->exec( command );
-}
-
-/*!
- \brief Execute python command in the interpreter
- and wait until it is finished.
-
- Block execution of main application until the python command is executed.
- \param command string with command and arguments
-*/
-void PyConsole_Console::execAndWait( const QString& command )
-{
- if ( myEditor )
- myEditor->execAndWait( command );
-}
-
-/*!
- \brief Get synchronous mode flag value.
-
- \sa setIsSync()
- \return True if python console works in synchronous mode
-*/
-bool PyConsole_Console::isSync() const
-{
- return myEditor->isSync();
-}
-
-/*!
- \brief Set synchronous mode flag value.
-
- In synhronous mode the Python commands are executed in the GUI thread
- and the GUI is blocked until the command is finished. In the asynchronous
- mode each Python command is executed in the separate thread that does not
- block the main GUI loop.
-
- \param on synhronous mode flag
-*/
-void PyConsole_Console::setIsSync( const bool on )
-{
- myEditor->setIsSync( on );
-}
-
-/*!
- \brief Get suppress output flag value.
-
- \sa setIsSuppressOutput()
- \return True if python console output is suppressed.
-*/
-bool PyConsole_Console::isSuppressOutput() const
-{
- return myEditor->isSuppressOutput();
-}
-
-/*!
- \brief Set suppress output flag value.
-
- In case if suppress output flag is true, the python
- console output suppressed.
-
- \param on suppress output flag
-*/
-void PyConsole_Console::setIsSuppressOutput( const bool on )
-{
- myEditor->setIsSuppressOutput(on);
-}
-
-/*!
- \brief Get 'show banner' flag value.
-
- \sa setIsShowBanner()
- \return \c true if python console shows banner
-*/
-bool PyConsole_Console::isShowBanner() const
-{
- return myEditor->isShowBanner();
-}
-
-/*!
- \brief Set 'show banner' flag value.
-
- The banner is shown in the top of the python console window.
-
- \sa isShowBanner()
- \param on 'show banner' flag
-*/
-void PyConsole_Console::setIsShowBanner( const bool on )
-{
- myEditor->setIsShowBanner( on );
-}
-
-/*!
- \brief 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's font
-*/
-QFont PyConsole_Console::font() const
-{
- QFont res;
- if( myEditor )
- res = myEditor->font();
- return res;
-}
-
-/*!
- \brief Event handler.
-
- Handles context menu request event.
-
- \param o object
- \param e event
- \return True if the event is processed and further processing should be stopped
-*/
-bool PyConsole_Console::eventFilter( QObject* o, QEvent* e )
-{
- if ( o == myEditor->viewport() && e->type() == QEvent::ContextMenu )
- {
- contextMenuRequest( (QContextMenuEvent*)e );
- return true;
- }
- return QWidget::eventFilter( o, e );
-}
-
-/*!
- \brief Create the context popup menu.
-
- Fill in the popup menu with the commands.
-
- \param menu context popup menu
-*/
-void PyConsole_Console::contextMenuPopup( QMenu* menu )
-{
- if ( myEditor->isReadOnly() )
- return;
-
- menu->addAction( myActions[CopyId] );
- menu->addAction( myActions[PasteId] );
- menu->addAction( myActions[ClearId] );
- menu->addSeparator();
- menu->addAction( myActions[SelectAllId] );
- menu->addSeparator();
- menu->addAction( myActions[DumpCommandsId] );
- if ( !myEditor->isLogging() )
- menu->addAction( myActions[StartLogId] );
- else
- menu->addAction( myActions[StopLogId] );
-
- Qtx::simplifySeparators( menu );
-
- updateActions();
-}
-
-/*!
- \brief Set actions to be visible in the context popup menu.
-
- Actions, which IDs are set in \a flags parameter, will be shown in the
- context popup menu. Other actions will not be shown.
-
- \param flags ORed together actions flags
-*/
-void PyConsole_Console::setMenuActions( const int flags )
-{
- myActions[CopyId]->setVisible( flags & CopyId );
- myActions[PasteId]->setVisible( flags & PasteId );
- myActions[ClearId]->setVisible( flags & ClearId );
- myActions[SelectAllId]->setVisible( flags & SelectAllId );
- myActions[DumpCommandsId]->setVisible( flags & DumpCommandsId );
- myActions[StartLogId]->setVisible( flags & StartLogId );
- myActions[StopLogId]->setVisible( flags & StopLogId );
-}
-
-/*!
- \brief Get menu actions which are currently visible in the context popup menu.
- \return ORed together actions flags
- \sa setMenuActions()
-*/
-int PyConsole_Console::menuActions() const
-{
- int ret = 0;
- ret = ret | ( myActions[CopyId]->isVisible() ? CopyId : 0 );
- ret = ret | ( myActions[PasteId]->isVisible() ? PasteId : 0 );
- ret = ret | ( myActions[ClearId]->isVisible() ? ClearId : 0 );
- ret = ret | ( myActions[SelectAllId]->isVisible() ? SelectAllId : 0 );
- ret = ret | ( myActions[DumpCommandsId]->isVisible() ? DumpCommandsId : 0 );
- ret = ret | ( myActions[StartLogId]->isVisible() ? StartLogId : 0 );
- ret = ret | ( myActions[StopLogId]->isVisible() ? StopLogId : 0 );
- return ret;
-}
-
-/*!
- \brief Create menu actions.
-
- Create context popup menu actions.
-*/
-void PyConsole_Console::createActions()
-{
- QAction* a = new QAction( tr( "EDIT_COPY_CMD" ), this );
- a->setStatusTip( tr( "EDIT_COPY_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) );
- myActions.insert( CopyId, a );
-
- a = new QAction( tr( "EDIT_PASTE_CMD" ), this );
- a->setStatusTip( tr( "EDIT_PASTE_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) );
- myActions.insert( PasteId, a );
-
- a = new QAction( tr( "EDIT_CLEAR_CMD" ), this );
- a->setStatusTip( tr( "EDIT_CLEAR_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( clear() ) );
- myActions.insert( ClearId, a );
-
- a = new QAction( tr( "EDIT_SELECTALL_CMD" ), this );
- a->setStatusTip( tr( "EDIT_SELECTALL_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) );
- myActions.insert( SelectAllId, a );
-
- a = new QAction( tr( "EDIT_DUMPCOMMANDS_CMD" ), this );
- a->setStatusTip( tr( "EDIT_DUMPCOMMANDS_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( dump() ) );
- myActions.insert( DumpCommandsId, a );
-
- a = new QAction( tr( "EDIT_STARTLOG_CMD" ), this );
- a->setStatusTip( tr( "EDIT_STARTLOG_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( startLog() ) );
- myActions.insert( StartLogId, a );
-
- a = new QAction( tr( "EDIT_STOPLOG_CMD" ), this );
- a->setStatusTip( tr( "EDIT_STOPLOG_CMD" ) );
- connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( stopLog() ) );
- myActions.insert( StopLogId, a );
-}
-
-/*!
- \brief Update menu actions.
-
- Update context popup menu action state.
-*/
-void PyConsole_Console::updateActions()
-{
- myActions[CopyId]->setEnabled( myEditor->textCursor().hasSelection() );
- myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
- myActions[SelectAllId]->setEnabled( !myEditor->document()->isEmpty() );
-}
-
-/*!
- \brief Start python trace logging
- \param fileName the path to the log file
-*/
-void PyConsole_Console::startLog( const QString& fileName )
-{
- myEditor->startLog( fileName );
-}
-
-/*!
- \brief Stop python trace logging
-*/
-void PyConsole_Console::stopLog()
-{
- myEditor->stopLog();
-}
-
-/**
- * Similar to constructor of the base class but using enhanced objects.
- * TODO: this should really be done in a factory to avoid code duplication.
- * @param parent
- * @param interp
- */
-PyConsole_EnhConsole::PyConsole_EnhConsole( QWidget* parent, PyConsole_Interp* interp )
- : PyConsole_Console( parent, interp, 0 )
-{
- PyConsole_Interp* anInterp = interp ? interp : new PyConsole_EnhInterp();
-
- // initialize Python interpretator
- anInterp->initialize();
-
- // create editor console
- QVBoxLayout* lay = new QVBoxLayout( this );
- lay->setMargin( 0 );
- myEditor = new PyConsole_EnhEditor( anInterp, this );
- char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
- if (synchronous && atoi(synchronous))
- {
- myEditor->setIsSync(true);
- }
- myEditor->viewport()->installEventFilter( this );
- lay->addWidget( myEditor );
-
- createActions();
-}
+++ /dev/null
-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-// File : PyConsole_Console.h
-// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
-//
-#ifndef PYCONSOLE_CONSOLE_H
-#define PYCONSOLE_CONSOLE_H
-
-#include "PyConsole.h"
-
-#include <SUIT_PopupClient.h>
-#include <QWidget>
-#include <QMap>
-
-class PyConsole_Interp;
-class PyConsole_Editor;
-
-class PYCONSOLE_EXPORT PyConsole_Console : public QWidget, public SUIT_PopupClient
-{
- 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_Interp* interp = 0 );
- virtual ~PyConsole_Console();
-
- //! \brief Get python interperter
- PyConsole_Interp* getInterp() const;
- QFont font() const;
- virtual void setFont( const QFont& );
-
- bool isSync() const;
- void setIsSync( const bool );
-
- bool isSuppressOutput() const;
- void setIsSuppressOutput( const bool );
-
- bool isShowBanner() const;
- void setIsShowBanner( const bool );
-
- void exec( const QString& );
- void execAndWait( const QString& );
-
- virtual bool eventFilter( QObject*, QEvent* );
-
- //! \brief Get popup client symbolic name
- virtual QString popupClientType() const { return QString( "PyConsole" ); }
- virtual void contextMenuPopup( QMenu* );
-
- void setMenuActions( const int );
- int menuActions() const;
-
- void startLog( const QString& );
- void stopLog();
-
-protected:
- void createActions();
- void updateActions();
-
- PyConsole_Console( QWidget* parent, PyConsole_Interp*, PyConsole_Editor*);
-
- PyConsole_Editor* myEditor; //!< python console editor widget
- QMap<int, QAction*> myActions; //!< menu actions list
-};
-
-/**
- * Enhance console object providing auto-completion.
- * Similar to PyConsole_Console except that an enhanced interpreter and enhanced editor
- * are encapsulated.
- */
-class PYCONSOLE_EXPORT PyConsole_EnhConsole: public PyConsole_Console
-{
- Q_OBJECT
-
-public:
- PyConsole_EnhConsole( QWidget* parent, PyConsole_Interp* interp = 0 );
- virtual ~PyConsole_EnhConsole() {}
-};
-
-#endif // PYCONSOLE_CONSOLE_H
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File : PyConsole_ConsoleBase.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+/*!
+ \class PyConsole_Console
+ \brief Python console widget.
+*/
+
+#include "PyConsole_Interp.h" /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
+#include "PyConsole_ConsoleBase.h"
+#include "PyConsole_EnhEditorBase.h"
+#include "PyConsole_EnhInterp.h"
+
+#include "Qtx.h"
+
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
+#include <QEvent>
+#include <QMenu>
+#include <QContextMenuEvent>
+#include <QVBoxLayout>
+
+PyConsole_EditorBase *PyConsole_ConsoleBase::PyConsole_Interp_CreatorBase::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new PyConsole_EditorBase(interp,console); }
+
+PyConsole_Interp *PyConsole_ConsoleBase::PyConsole_Interp_CreatorBase::createInterp( ) const
+{ return new PyConsole_Interp; }
+
+/*!
+ \brief Constructor.
+
+ Creates new python console widget.
+ \param parent parent widget
+ \param interp python interpreter
+*/
+PyConsole_ConsoleBase::PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp* interp )
+: QWidget( parent )
+{
+ PyConsole_ConsoleBase::PyConsole_Interp_CreatorBase crea;
+ defaultConstructor(interp,crea);
+}
+
+/*!
+ * MUST BE NON VIRTUAL ! (called from constructor !!!!)
+ */
+void PyConsole_ConsoleBase::defaultConstructor( PyConsole_Interp* interp, const PyConsole_Interp_CreatorBase& crea )
+{
+ PyConsole_Interp *anInterp = interp ? interp : crea.createInterp();
+
+ // initialize Python interpretator
+ anInterp->initialize();
+
+ // create editor console
+ QVBoxLayout* lay = new QVBoxLayout( this );
+ lay->setMargin( 0 );
+ myEditor = crea.createEditor( anInterp, this );
+ char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
+ if (synchronous && atoi(synchronous))
+ {
+ myEditor->setIsSync(true);
+ }
+ myEditor->viewport()->installEventFilter( this );
+ lay->addWidget( myEditor );
+
+ createActions();
+}
+
+/**
+ * Protected constructor.
+ */
+PyConsole_ConsoleBase::PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp* /*i*/, PyConsole_EditorBase* e )
+ : QWidget (parent), myEditor(e)
+{}
+
+/*!
+ \brief Destructor.
+
+ Does nothing for the moment.
+*/
+PyConsole_ConsoleBase::~PyConsole_ConsoleBase()
+{
+}
+
+PyConsole_Interp* PyConsole_ConsoleBase::getInterp() const
+{
+ return myEditor ? myEditor->getInterp() : 0;
+}
+
+/*!
+ \brief Execute python command in the interpreter.
+ \param command string with command and arguments
+*/
+void PyConsole_ConsoleBase::exec( const QString& command )
+{
+ if ( myEditor )
+ myEditor->exec( command );
+}
+
+/*!
+ \brief Execute python command in the interpreter
+ and wait until it is finished.
+
+ Block execution of main application until the python command is executed.
+ \param command string with command and arguments
+*/
+void PyConsole_ConsoleBase::execAndWait( const QString& command )
+{
+ if ( myEditor )
+ myEditor->execAndWait( command );
+}
+
+/*!
+ \brief Get synchronous mode flag value.
+
+ \sa setIsSync()
+ \return True if python console works in synchronous mode
+*/
+bool PyConsole_ConsoleBase::isSync() const
+{
+ return myEditor->isSync();
+}
+
+/*!
+ \brief Set synchronous mode flag value.
+
+ In synhronous mode the Python commands are executed in the GUI thread
+ and the GUI is blocked until the command is finished. In the asynchronous
+ mode each Python command is executed in the separate thread that does not
+ block the main GUI loop.
+
+ \param on synhronous mode flag
+*/
+void PyConsole_ConsoleBase::setIsSync( const bool on )
+{
+ myEditor->setIsSync( on );
+}
+
+/*!
+ \brief Get suppress output flag value.
+
+ \sa setIsSuppressOutput()
+ \return True if python console output is suppressed.
+*/
+bool PyConsole_ConsoleBase::isSuppressOutput() const
+{
+ return myEditor->isSuppressOutput();
+}
+
+/*!
+ \brief Set suppress output flag value.
+
+ In case if suppress output flag is true, the python
+ console output suppressed.
+
+ \param on suppress output flag
+*/
+void PyConsole_ConsoleBase::setIsSuppressOutput( const bool on )
+{
+ myEditor->setIsSuppressOutput(on);
+}
+
+/*!
+ \brief Get 'show banner' flag value.
+
+ \sa setIsShowBanner()
+ \return \c true if python console shows banner
+*/
+bool PyConsole_ConsoleBase::isShowBanner() const
+{
+ return myEditor->isShowBanner();
+}
+
+/*!
+ \brief Set 'show banner' flag value.
+
+ The banner is shown in the top of the python console window.
+
+ \sa isShowBanner()
+ \param on 'show banner' flag
+*/
+void PyConsole_ConsoleBase::setIsShowBanner( const bool on )
+{
+ myEditor->setIsShowBanner( on );
+}
+
+/*!
+ \brief Change the python console's font.
+ \param f new font
+*/
+void PyConsole_ConsoleBase::setFont( const QFont& f )
+{
+ if( myEditor )
+ myEditor->setFont( f );
+}
+
+/*!
+ \brief Get python console font.
+ \return current python console's font
+*/
+QFont PyConsole_ConsoleBase::font() const
+{
+ QFont res;
+ if( myEditor )
+ res = myEditor->font();
+ return res;
+}
+
+/*!
+ \brief Set actions to be visible in the context popup menu.
+
+ Actions, which IDs are set in \a flags parameter, will be shown in the
+ context popup menu. Other actions will not be shown.
+
+ \param flags ORed together actions flags
+*/
+void PyConsole_ConsoleBase::setMenuActions( const int flags )
+{
+ myActions[CopyId]->setVisible( flags & CopyId );
+ myActions[PasteId]->setVisible( flags & PasteId );
+ myActions[ClearId]->setVisible( flags & ClearId );
+ myActions[SelectAllId]->setVisible( flags & SelectAllId );
+ myActions[DumpCommandsId]->setVisible( flags & DumpCommandsId );
+ myActions[StartLogId]->setVisible( flags & StartLogId );
+ myActions[StopLogId]->setVisible( flags & StopLogId );
+}
+
+/*!
+ \brief Get menu actions which are currently visible in the context popup menu.
+ \return ORed together actions flags
+ \sa setMenuActions()
+*/
+int PyConsole_ConsoleBase::menuActions() const
+{
+ int ret = 0;
+ ret = ret | ( myActions[CopyId]->isVisible() ? CopyId : 0 );
+ ret = ret | ( myActions[PasteId]->isVisible() ? PasteId : 0 );
+ ret = ret | ( myActions[ClearId]->isVisible() ? ClearId : 0 );
+ ret = ret | ( myActions[SelectAllId]->isVisible() ? SelectAllId : 0 );
+ ret = ret | ( myActions[DumpCommandsId]->isVisible() ? DumpCommandsId : 0 );
+ ret = ret | ( myActions[StartLogId]->isVisible() ? StartLogId : 0 );
+ ret = ret | ( myActions[StopLogId]->isVisible() ? StopLogId : 0 );
+ return ret;
+}
+
+/*!
+ \brief Create menu actions.
+
+ Create context popup menu actions.
+*/
+void PyConsole_ConsoleBase::createActions()
+{
+ QAction* a = new QAction( tr( "EDIT_COPY_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_COPY_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) );
+ myActions.insert( CopyId, a );
+
+ a = new QAction( tr( "EDIT_PASTE_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_PASTE_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) );
+ myActions.insert( PasteId, a );
+
+ a = new QAction( tr( "EDIT_CLEAR_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_CLEAR_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( clear() ) );
+ myActions.insert( ClearId, a );
+
+ a = new QAction( tr( "EDIT_SELECTALL_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_SELECTALL_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) );
+ myActions.insert( SelectAllId, a );
+
+ a = new QAction( tr( "EDIT_DUMPCOMMANDS_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_DUMPCOMMANDS_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( dump() ) );
+ myActions.insert( DumpCommandsId, a );
+
+ a = new QAction( tr( "EDIT_STARTLOG_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_STARTLOG_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( startLog() ) );
+ myActions.insert( StartLogId, a );
+
+ a = new QAction( tr( "EDIT_STOPLOG_CMD" ), this );
+ a->setStatusTip( tr( "EDIT_STOPLOG_CMD" ) );
+ connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( stopLog() ) );
+ myActions.insert( StopLogId, a );
+}
+
+/*!
+ \brief Update menu actions.
+
+ Update context popup menu action state.
+*/
+void PyConsole_ConsoleBase::updateActions()
+{
+ myActions[CopyId]->setEnabled( myEditor->textCursor().hasSelection() );
+ myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
+ myActions[SelectAllId]->setEnabled( !myEditor->document()->isEmpty() );
+}
+
+/*!
+ \brief Start python trace logging
+ \param fileName the path to the log file
+*/
+void PyConsole_ConsoleBase::startLog( const QString& fileName )
+{
+ myEditor->startLog( fileName );
+}
+
+/*!
+ \brief Stop python trace logging
+*/
+void PyConsole_ConsoleBase::stopLog()
+{
+ myEditor->stopLog();
+}
+
+/*!
+ \brief Create the context popup menu.
+
+ Fill in the popup menu with the commands.
+
+ \param menu context popup menu
+*/
+void PyConsole_ConsoleBase::contextMenuPopup( QMenu *menu )
+{
+ if ( myEditor->isReadOnly() )
+ return;
+
+ menu->addAction( myActions[CopyId] );
+ menu->addAction( myActions[PasteId] );
+ menu->addAction( myActions[ClearId] );
+ menu->addSeparator();
+ menu->addAction( myActions[SelectAllId] );
+ menu->addSeparator();
+ menu->addAction( myActions[DumpCommandsId] );
+ if ( !myEditor->isLogging() )
+ menu->addAction( myActions[StartLogId] );
+ else
+ menu->addAction( myActions[StopLogId] );
+
+ Qtx::simplifySeparators( menu );
+
+ updateActions();
+}
+
+PyConsole_EditorBase *PyConsole_EnhConsoleBase::PyConsole_Interp_EnhCreatorBase::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new PyConsole_EnhEditorBase(interp,console); }
+
+PyConsole_Interp *PyConsole_EnhConsoleBase::PyConsole_Interp_EnhCreatorBase::createInterp( ) const
+{ return new PyConsole_EnhInterp; }
+
+/**
+ * Similar to constructor of the base class but using enhanced objects.
+ * TODO: this should really be done in a factory to avoid code duplication.
+ * @param parent
+ * @param interp
+ */
+PyConsole_EnhConsoleBase::PyConsole_EnhConsoleBase( QWidget* parent, PyConsole_Interp* interp )
+ : PyConsole_ConsoleBase( parent, interp, 0 )
+{
+ PyConsole_Interp_EnhCreatorBase crea;
+ defaultConstructor(interp,crea);
+}
+
+/*!
+ \brief Event handler.
+
+ Handles context menu request event.
+
+ \param o object
+ \param e event
+ \return True if the event is processed and further processing should be stopped
+*/
+bool PyConsole_EnhConsoleBase::eventFilter( QObject* o, QEvent* e )
+{
+ if ( o == myEditor->viewport() && e->type() == QEvent::ContextMenu )
+ {
+ contextMenuRequest( (QContextMenuEvent*)e );
+ return true;
+ }
+ return QWidget::eventFilter( o, e );
+}
+
+void PyConsole_EnhConsoleBase::contextMenuRequest( QContextMenuEvent * e )
+{
+ QMenu *menu(new QMenu(this));
+ contextMenuPopup(menu);
+ menu->move(e->globalPos());
+ menu->show();
+}
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File : PyConsole_Console.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#ifndef PYCONSOLE_CONSOLEBASE_H
+#define PYCONSOLE_CONSOLEBASE_H
+
+#include "PyConsole.h"
+
+#include <QWidget>
+#include <QMenu>
+#include <QMap>
+
+class PyConsole_Interp;
+class PyConsole_EditorBase;
+
+class PYCONSOLE_EXPORT PyConsole_ConsoleBase : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ struct PyConsole_Interp_CreatorBase
+ {
+ virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+ virtual PyConsole_Interp *createInterp( ) const;
+ };
+
+public:
+ //! Context popup menu actions flags
+ enum
+ {
+ CopyId = 0x01, //!< "Copy" menu action
+ PasteId = 0x02, //!< "Paste" menu action
+ ClearId = 0x04, //!< "Clear" menu action
+ SelectAllId = 0x08, //!< "Select All" menu action
+ DumpCommandsId = 0x10, //!< "DumpCommands" menu action
+ StartLogId = 0x20, //!< "Start log" menu action
+ StopLogId = 0x40, //!< "Stop log" menu action
+ All = 0xFF, //!< all menu actions
+ };
+
+public:
+ PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp* interp = 0 );
+ virtual ~PyConsole_ConsoleBase();
+
+ //! \brief Get python interperter
+ PyConsole_Interp* getInterp() const;
+ QFont font() const;
+ virtual void setFont( const QFont& );
+
+ bool isSync() const;
+ void setIsSync( const bool );
+
+ bool isSuppressOutput() const;
+ void setIsSuppressOutput( const bool );
+
+ bool isShowBanner() const;
+ void setIsShowBanner( const bool );
+
+ void exec( const QString& );
+ void execAndWait( const QString& );
+
+ void setMenuActions( const int );
+ int menuActions() const;
+
+ void startLog( const QString& );
+ void stopLog();
+
+ virtual void contextMenuPopup( QMenu* );
+
+protected:
+ void createActions();
+ void updateActions();
+ //! MUST BE NON VIRTUAL ! (called from constructor !!!!)
+ void defaultConstructor( PyConsole_Interp* interp, const PyConsole_Interp_CreatorBase& crea );
+ PyConsole_ConsoleBase( QWidget* parent, PyConsole_Interp*, PyConsole_EditorBase*);
+
+ PyConsole_EditorBase* myEditor; //!< python console editor widget
+ QMap<int, QAction*> myActions; //!< menu actions list
+};
+
+/**
+ * Enhance console object providing auto-completion.
+ * Similar to PyConsole_Console except that an enhanced interpreter and enhanced editor
+ * are encapsulated.
+ */
+class PYCONSOLE_EXPORT PyConsole_EnhConsoleBase : public PyConsole_ConsoleBase
+{
+ Q_OBJECT
+public:
+
+ struct PyConsole_Interp_EnhCreatorBase : public PyConsole_Interp_CreatorBase
+ {
+ virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+ virtual PyConsole_Interp *createInterp( ) const;
+ };
+
+public:
+ PyConsole_EnhConsoleBase( QWidget* parent, PyConsole_Interp* interp = 0 );
+ virtual ~PyConsole_EnhConsoleBase() {}
+ virtual bool eventFilter( QObject * o, QEvent * e );
+ virtual void contextMenuRequest( QContextMenuEvent * e ) ;
+};
+
+#endif // PYCONSOLE_CONSOLEBASE_H
+++ /dev/null
-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-// SALOME SALOMEGUI : implementation of desktop and GUI kernel
-// File : PyConsole_Editor.cxx
-// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
-//
-/*!
- \class PyConsole_Editor
- \brief Python command line interpreter front-end GUI widget.
-
- This class provides simple GUI interface to the Python interpreter, including basic
- navigation operations, executing commands (both interactively and programmatically),
- copy-paste operations, history of the commands and so on.
-
- Here below is the shortcut keyboard boundings used for navigation and other operations:
- - <Enter> : execute current command
- - <Ctrl><Break> : clear current command
- - <Escape> : clear current command
- - <Up> : previous command in the history
- - <Shift><Up> : move cursor one row up with selection
- - <Ctrl><Up> : move cursor one row up without selection
- - <Ctrl><Shift><Up> : move cursor one row up with selection
- - <Down> : next command in the history
- - <Shift><Down> : move cursor one row down with selection
- - <Ctrl><Down> : move cursor one row down without selection
- - <Ctrl><Shift><Down> : move cursor one row down with selection
- - <Left> : move one symbol left without selection
- - <Shift><Left> : move one symbol left with selection
- - <Ctrl><Left> : move one word left without selection
- - <Ctrl><Shift><Left> : move one word left with selection
- - <Right> : move one symbol right without selection
- - <Shift><Right> : move one symbol right with selection
- - <Ctrl><Right> : move one word right without selection
- - <Ctrl><Shift><Right> : move one word right with selection
- - <PgUp> : first command in the history
- - <Shift><PgUp> : move one page up with selection
- - <Ctrl><PgUp> : move one page up without selection
- - <Ctrl><Shift><PgUp> : scroll one page up
- - <PgDn> : last command in the history
- - <Shift><PgDn> : move one page down with selection
- - <Ctrl><PgDn> : move one page down without selection
- - <Ctrl><Shift><PgDn> : scroll one page down
- - <Home> : move to the beginning of the line without selection
- - <Shift><Home> : move to the beginning of the line with selection
- - <Ctrl><Home> : move to the very first symbol without selection
- - <Ctrl><Shift><Home> : move to the very first symbol with selection
- - <End> : move to the end of the line without selection
- - <Shift><End> : move to the end of the line with selection
- - <Ctrl><End> : move to the very last symbol without selection
- - <Ctrl><Shift><End> : move to the very last symbol with selection
- - <Backspace> : delete symbol before the cursor
- / remove selected text and put it to the clipboard (cut)
- - <Shift><Backspace> : delete previous word
- / remove selected text and put it to the clipboard (cut)
- - <Ctrl><Backspace> : delete text from the cursor to the beginning of the line
- / remove selected text and put it to the clipboard (cut)
- - <Delete> : delete symbol after the cursor
- / remove selected text and put it to the clipboard (cut)
- - <Shift><Delete> : delete next word
- / remove selected text and put it to the clipboard (cut)
- - <Ctrl><Delete> : delete text from the cursor to the end of the line
- / remove selected text and put it to the clipboard (cut)
- - <Ctrl><Insert> : copy
- - <Shift><Insert> : paste
- - <Ctrl><V> : paste
- - <Ctrl><C> : copy
- - <Ctrl><X> : cut
- - <Ctrl><V> : paste
-*/
-
-#include "PyConsole_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
-#include "PyConsole_Editor.h"
-#include "PyConsole_Event.h"
-#include "PyInterp_Event.h"
-#include "PyInterp_Dispatcher.h"
-#include "PyConsole_Request.h"
-
-#include <SUIT_Tools.h>
-#include <SUIT_FileDlg.h>
-#include <SUIT_MessageBox.h>
-#include <SUIT_FileValidator.h>
-
-#include <QApplication>
-#include <QClipboard>
-#include <QDropEvent>
-#include <QEvent>
-#include <QKeyEvent>
-#include <QMouseEvent>
-#include <QScrollBar>
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QTextDocument>
-#include <QTextStream>
-#include <QChar>
-
-//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 = "... ";
-
-class DumpCommandsFileValidator : public SUIT_FileValidator
-{
- public:
- DumpCommandsFileValidator( QWidget* parent = 0 ) : SUIT_FileValidator ( parent ) {};
- virtual ~DumpCommandsFileValidator() {};
- virtual bool canSave( const QString& file, bool permissions );
-};
-
-bool DumpCommandsFileValidator::canSave(const QString& file, bool permissions)
-{
- QFileInfo fi( file );
- if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
- SUIT_MessageBox::critical( parent(),
- QObject::tr("WRN_WARNING"),
- QObject::tr("WRN_FILE_NAME_BAD") );
- return false;
- }
- return SUIT_FileValidator::canSave( file, permissions);
-}
-
-void staticCallbackStdout( void* data, char* c )
-{
- if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
- PyConsole_Editor* e = (PyConsole_Editor*)data;
- e->putLog( fromUtf8(c) );
- QApplication::postEvent( e, new PrintEvent( fromUtf8(c), false ) );
- }
-}
-
-void staticCallbackStderr( void* data, char* c )
-{
- if(!((PyConsole_Editor*)data)->isSuppressOutput()) {
- PyConsole_Editor* e = (PyConsole_Editor*)data;
- e->putLog( fromUtf8(c) );
- QApplication::postEvent( e, new PrintEvent( fromUtf8(c), true ) );
- }
-}
-
-
-/*!
- \brief Constructor.
-
- Creates python editor window.
- \param theInterp python interper
- \param theParent parent widget
-*/
-PyConsole_Editor::PyConsole_Editor( PyConsole_Interp* theInterp,
- QWidget* theParent )
-: QTextEdit( theParent ),
- myInterp( 0 ),
- myCmdInHistory( -1 ),
- myEventLoop( 0 ),
- myShowBanner( true ),
- myIsSync( true ),
- myIsSuppressOutput( false )
-{
- QString fntSet( "" );
- QFont aFont = SUIT_Tools::stringToFont( fntSet );
- setFont( aFont );
- setUndoRedoEnabled( false );
-
- myPrompt = READY_PROMPT;
- setLineWrapMode( QTextEdit::WidgetWidth );
- setWordWrapMode( QTextOption::WrapAnywhere );
- setAcceptRichText( false );
-
- theInterp->setvoutcb( staticCallbackStdout, this );
- theInterp->setverrcb( staticCallbackStderr, this );
-
- // san - This is necessary for troubleless initialization
- onPyInterpChanged( theInterp );
-}
-
-/*!
- \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 True if python console works in synchronous mode
-*/
-bool PyConsole_Editor::isSync() const
-{
- return myIsSync;
-}
-
-/*!
- \brief Set synchronous mode flag value.
-
- In synhronous mode the Python commands are executed in the GUI thread
- and the GUI is blocked until the command is finished. In the asynchronous
- mode each Python command is executed in the separate thread that does not
- block the main GUI loop.
-
- \param on synhronous mode flag
-*/
-void PyConsole_Editor::setIsSync( const bool on )
-{
- myIsSync = on;
-}
-
-/*!
- \brief Get suppress output flag value.
-
- \sa setIsSuppressOutput()
- \return \c true if python console output is suppressed.
-*/
-bool PyConsole_Editor::isSuppressOutput() const
-{
- return myIsSuppressOutput;
-}
-
-/*!
- \brief Set suppress output flag value.
-
- In case if suppress output flag is true, the python
- console output suppressed.
-
- \param on suppress output flag
-*/
-void PyConsole_Editor::setIsSuppressOutput( const bool on )
-{
- myIsSuppressOutput = on;
-}
-
-/*!
- \brief Get 'show banner' flag value.
-
- \sa setIsShowBanner()
- \return \c true if python console shows banner
-*/
-bool PyConsole_Editor::isShowBanner() const
-{
- return myShowBanner;
-}
-
-/*!
- \brief Set 'show banner' flag value.
-
- The banner is shown in the top of the python console window.
-
- \sa isShowBanner()
- \param on 'show banner' flag
-*/
-void PyConsole_Editor::setIsShowBanner( const bool on )
-{
- if ( myShowBanner != on ) {
- myShowBanner = on;
- clear();
- }
-}
-
-/*!
- \brief Check if trace logging is switched on.
-
- \sa startLog(), stopLog()
- \return \c true if trace logging is switched on
-*/
-bool PyConsole_Editor::isLogging() const
-{
- return !myLogFile.isEmpty();
-}
-
-/*!
- \brief Get size hint for the Python console window
- \return size hint value
-*/
-QSize PyConsole_Editor::sizeHint() const
-{
- QFontMetrics fm( font() );
- int nbLines = ( isShowBanner() ? myBanner.split("\n").count() : 0 ) + 1;
- QSize s(100, fm.lineSpacing()*nbLines);
- return s;
-}
-
-/*!
- \brief Put the string \a str to the python editor.
- \param str string to be put in the command line of the editor
- \param newBlock if True, then the string is printed on a new line
- \param isError if true, the text is printed in dark red
-*/
-void PyConsole_Editor::addText( const QString& str,
- const bool newBlock,
- const bool isError)
-{
- QTextCursor theCursor(textCursor());
- QTextCharFormat cf;
-
- moveCursor( QTextCursor::End );
- if ( newBlock )
- theCursor.insertBlock();
- if (isError)
- cf.setForeground(QBrush(Qt::red));
- else
- cf.setForeground(QBrush(Qt::black));
- theCursor.insertText( str, cf);
- moveCursor( QTextCursor::End );
- ensureCursorVisible();
-}
-
-/*!
- \brief Convenient method for executing a Python command,
- as if the user typed it manually.
- \param command python command to be executed
-
- !!! WARNING: doesn't work properly with multi-line commands. !!!
-*/
-void PyConsole_Editor::exec( const QString& command )
-{
- if ( isReadOnly() ) {
- // some interactive command is being executed in this editor...
- // shedule the command to the queue
- myQueue.push_back( command );
- return;
- }
- // remove last line
- moveCursor( QTextCursor::End );
- moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- // set "ready" prompt
- myPrompt = READY_PROMPT;
- // clear command buffer
- myCommandBuffer.truncate( 0 );
- // unset history browsing mode
- myCmdInHistory = -1;
- // print command line by line
- QString cmd = command;
- if ( !cmd.endsWith( "\n" ) ) cmd += "\n";
- QStringList lines = command.split( "\n" );
- for ( int i = 0; i < lines.size(); i++ ) {
- if ( !lines[i].trimmed().isEmpty() )
- myHistory.push_back( lines[i] );
- addText( ( i == 0 ? READY_PROMPT : DOTS_PROMPT ) + lines[i], i != 0 );
- putLog( QString( "%1%2\n" ).arg( i == 0 ? READY_PROMPT : DOTS_PROMPT ).arg( lines[i] ) );
- }
- // IPAL20182
- addText( "", true );
- // set read-only mode
- setReadOnly( true );
- // set busy cursor
- setCursor( Qt::BusyCursor );
-
- // post a request to execute Python command;
- // editor will be informed via a custom event that execution has been completed
- PyInterp_Dispatcher::Get()->Exec( createRequest( cmd ) );
-}
-
-/*!
- \brief Create request to the python dispatcher for the command execution.
-
- \param command python command to be executed
- */
-PyInterp_Request* PyConsole_Editor::createRequest( const QString& command )
-{
- return new ExecCommand( myInterp, command, this, isSync() );
-}
-
-/*!
- \brief Execute command in the python interpreter
- and wait until it is finished.
-
- \param command python command to be executed
- */
-void PyConsole_Editor::execAndWait( const QString& command )
-{
- // already running ?
- if( myEventLoop )
- return;
-
- // create new event loop
- bool sync = isSync();
- if ( !sync ) {
- myEventLoop = new QEventLoop( this );
- }
-
- // execute command
- exec( command );
-
- if ( !sync ) {
- // run event loop
- myEventLoop->exec();
- // delete event loop after command is processed
- delete myEventLoop;
- myEventLoop = 0;
- }
-}
-
-/*!
- \brief Process "Enter" key press event.
-
- Execute the command entered by the user.
-*/
-void PyConsole_Editor::handleReturn()
-{
- // Position cursor at the end
- QTextCursor curs(textCursor());
- curs.movePosition(QTextCursor::End);
- setTextCursor(curs);
-
- // get last line
- QTextBlock par = document()->end().previous();
- if ( !par.isValid() ) return;
-
- // get command
- QString cmd = par.text().remove( 0, promptSize() );
- // extend the command buffer with the current command
- myCommandBuffer.append( cmd );
- // add command to the history
- if ( !cmd.trimmed().isEmpty() )
- myHistory.push_back( cmd );
- putLog( QString( "%1%2\n" ).arg( myPrompt ).arg( cmd ) );
-
- // IPAL19397
- addText( "", true );
-
- // set read-only mode
- setReadOnly( true );
- // set busy cursor
- setCursor( Qt::BusyCursor );
-
- // post a request to execute Python command;
- // editor will be informed via a custom event that execution has been completed
- PyInterp_Dispatcher::Get()->Exec( createRequest( myCommandBuffer ) );
-}
-
-/*!
- \brief Process drop event.
-
- Paste dragged text.
- \param event drop event
-*/
-void PyConsole_Editor::dropEvent( QDropEvent* event )
-{
- // get the initial drop position
- QPoint pos = event->pos();
- QTextCursor cur = cursorForPosition( event->pos() );
- // if the position is not in the last line move it to the end of the command line
- if ( cur.position() < document()->end().previous().position() + promptSize() ) {
- moveCursor( QTextCursor::End );
- pos = cursorRect().center();
- }
- // create new drop event and use it instead of the original
- QDropEvent de( pos,
- event->possibleActions(),
- event->mimeData(),
- event->mouseButtons(),
- event->keyboardModifiers(),
- event->type() );
- QTextEdit::dropEvent( &de );
- // accept the original event
- event->acceptProposedAction();
-}
-
-/*!
- \brief Process mouse button release event.
-
- Left mouse button: copy selection to the clipboard.
- Middle mouse button: paste clipboard's contents.
- \param event mouse event
-*/
-void PyConsole_Editor::mouseReleaseEvent( QMouseEvent* event )
-{
- if ( event->button() == Qt::LeftButton ) {
- QTextEdit::mouseReleaseEvent( event );
- //copy();
- }
- else if ( event->button() == Qt::MidButton ) {
- QTextCursor cur = cursorForPosition( event->pos() );
- // if the position is not in the last line move it to the end of the command line
- if ( cur.position() < document()->end().previous().position() + promptSize() ) {
- moveCursor( QTextCursor::End );
- }
- else {
- setTextCursor( cur );
- }
- const QMimeData* md = QApplication::clipboard()->mimeData( QApplication::clipboard()->supportsSelection() ?
- QClipboard::Selection : QClipboard::Clipboard );
- if ( md )
- insertFromMimeData( md );
- }
- else {
- QTextEdit::mouseReleaseEvent( event );
- }
-}
-
-/*!
- \brief Check if the string is command.
-
- Return True if the string \a str is likely to be the command
- (i.e. it is started from the '>>>' or '...').
- \param str string to be checked
-*/
-bool PyConsole_Editor::isCommand( const QString& str ) const
-{
- return str.startsWith( READY_PROMPT ) || str.startsWith( DOTS_PROMPT );
-}
-
-/*!
- \brief Handle keyboard event.
-
- Implement navigation, history browsing, copy/paste and other common
- operations.
- \param event keyboard event
-*/
-void PyConsole_Editor::keyPressEvent( QKeyEvent* event )
-{
- // get cursor position
- QTextCursor cur = textCursor();
- int curLine = cur.blockNumber();
- int curCol = cur.columnNumber();
-
- // get last edited line
- int endLine = document()->blockCount()-1;
-
- // get pressed key code
- int aKey = event->key();
-
- // check if <Ctrl> is pressed
- bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
- // check if <Shift> is pressed
- bool shftPressed = event->modifiers() & Qt::ShiftModifier;
-
- if ( aKey == Qt::Key_Escape || ( ctrlPressed && aKey == -1 ) ) {
- // process <Ctrl>+<Break> key-binding and <Escape> key: clear current command
- myCommandBuffer.truncate( 0 );
- myPrompt = READY_PROMPT;
- addText( myPrompt, true );
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- return;
- }
- else if ( ctrlPressed && aKey == Qt::Key_C ) {
- // process <Ctrl>+<C> key-binding : copy
- copy();
- return;
- }
- else if ( ctrlPressed && aKey == Qt::Key_X ) {
- // process <Ctrl>+<X> key-binding : cut
- cut();
- return;
- }
- else if ( ctrlPressed && aKey == Qt::Key_V ) {
- // process <Ctrl>+<V> key-binding : paste
- paste();
- return;
- }
-
- // check for printed key
- // #### aKey = ( aKey < Qt::Key_Space || aKey > Qt::Key_ydiaeresis ) ? aKey : 0;
- // Better:
- aKey = !(QChar(aKey).isPrint()) ? aKey : 0;
-
- switch ( aKey ) {
- case 0 :
- // any printed key: just print it
- {
- if ( curLine < endLine || curCol < promptSize() ) {
- moveCursor( QTextCursor::End );
- }
- QTextEdit::keyPressEvent( event );
- break;
- }
- case Qt::Key_Return:
- case Qt::Key_Enter:
- // <Enter> key: process the current command
- {
- handleReturn();
- break;
- }
- case Qt::Key_Up:
- // <Up> arrow key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: previous command in history
- // - with <Ctrl> modifier key pressed: move cursor one row up without selection
- // - with <Shift> modifier key pressed: move cursor one row up with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row up
- {
- if ( ctrlPressed && shftPressed ) {
- int value = verticalScrollBar()->value();
- int spacing = fontMetrics().lineSpacing();
- verticalScrollBar()->setValue( value > spacing ? value-spacing : 0 );
- }
- else if ( shftPressed || ctrlPressed ) {
- if ( curLine > 0 )
- moveCursor( QTextCursor::Up,
- shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
- }
- else {
- if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
- // set history browsing mode
- myCmdInHistory = myHistory.count();
- // remember current command
- QTextBlock par = document()->end().previous();
- myCurrentCommand = par.text().remove( 0, promptSize() );
- }
- if ( myCmdInHistory > 0 ) {
- myCmdInHistory--;
- // get previous command in the history
- QString previousCommand = myHistory.at( myCmdInHistory );
- // print previous command
- moveCursor( QTextCursor::End );
- moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- addText( myPrompt + previousCommand );
- // move cursor to the end
- moveCursor( QTextCursor::End );
- }
- }
- break;
- }
- case Qt::Key_Down:
- // <Down> arrow key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: next command in history
- // - with <Ctrl> modifier key pressed: move cursor one row down without selection
- // - with <Shift> modifier key pressed: move cursor one row down with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row down
- {
- if ( ctrlPressed && shftPressed ) {
- int value = verticalScrollBar()->value();
- int maxval = verticalScrollBar()->maximum();
- int spacing = fontMetrics().lineSpacing();
- verticalScrollBar()->setValue( value+spacing < maxval ? value+spacing : maxval );
- }
- else if ( shftPressed || ctrlPressed) {
- if ( curLine < endLine )
- moveCursor( QTextCursor::Down,
- shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
- }
- else {
- if ( myCmdInHistory >= 0 ) {
- // get next command in the history
- myCmdInHistory++;
- QString nextCommand;
- if ( myCmdInHistory < myHistory.count() ) {
- // next command in history
- nextCommand = myHistory.at( myCmdInHistory );
- }
- else {
- // end of history is reached
- // last printed command
- nextCommand = myCurrentCommand;
- // unset history browsing mode
- myCmdInHistory = -1;
- }
- // print next or current command
- moveCursor( QTextCursor::End );
- moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- addText( myPrompt + nextCommand );
- // move cursor to the end
- moveCursor( QTextCursor::End );
- }
- }
- break;
- }
- case Qt::Key_Left:
- // <Left> arrow key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: move one symbol left (taking into account prompt)
- // - with <Ctrl> modifier key pressed: move one word left (taking into account prompt)
- // - with <Shift> modifier key pressed: move one symbol left with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: move one word left with selection
- {
- QString txt = textCursor().block().text();
- if ( !shftPressed && isCommand( txt ) && curCol <= promptSize() ) {
- moveCursor( QTextCursor::Up );
- moveCursor( QTextCursor::EndOfBlock );
- }
- else {
- QTextEdit::keyPressEvent( event );
- }
- break;
- }
- case Qt::Key_Right:
- // <Right> arrow key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: move one symbol right (taking into account prompt)
- // - with <Ctrl> modifier key pressed: move one word right (taking into account prompt)
- // - with <Shift> modifier key pressed: move one symbol right with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: move one word right with selection
- {
- QString txt = textCursor().block().text();
- if ( !shftPressed ) {
- if ( curCol < txt.length() ) {
- if ( isCommand( txt ) && curCol < promptSize() ) {
- cur.setPosition( cur.block().position() + promptSize() );
- setTextCursor( cur );
- break;
- }
- }
- else {
- if ( curLine < endLine && isCommand( textCursor().block().next().text() ) ) {
- cur.setPosition( cur.position() + promptSize()+1 );
- setTextCursor( cur );
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- break;
- }
- }
- }
- QTextEdit::keyPressEvent( event );
- break;
- }
- case Qt::Key_PageUp:
- // <PageUp> key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: first command in history
- // - with <Ctrl> modifier key pressed: move cursor one page up without selection
- // - with <Shift> modifier key pressed: move cursor one page up with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page up
- {
- if ( ctrlPressed && shftPressed ) {
- verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub);
- }
- else if ( shftPressed || ctrlPressed ) {
- bool moved = false;
- qreal lastY = cursorRect( cur ).top();
- qreal distance = 0;
- // move using movePosition to keep the cursor's x
- do {
- qreal y = cursorRect( cur ).top();
- distance += qAbs( y - lastY );
- lastY = y;
- moved = cur.movePosition( QTextCursor::Up,
- shftPressed ? QTextCursor::KeepAnchor :
- QTextCursor::MoveAnchor );
- } while ( moved && distance < viewport()->height() );
- if ( moved ) {
- cur.movePosition( QTextCursor::Down,
- shftPressed ? QTextCursor::KeepAnchor :
- QTextCursor::MoveAnchor );
- verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
- }
- setTextCursor( cur );
- }
- else {
- if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
- // set history browsing mode
- myCmdInHistory = myHistory.count();
- // remember current command
- QTextBlock par = document()->end().previous();
- myCurrentCommand = par.text().remove( 0, promptSize() );
- }
- if ( myCmdInHistory > 0 ) {
- myCmdInHistory = 0;
- // get very first command in the history
- QString firstCommand = myHistory.at( myCmdInHistory );
- // print first command
- moveCursor( QTextCursor::End );
- moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- addText( myPrompt + firstCommand );
- // move cursor to the end
- moveCursor( QTextCursor::End );
- }
- }
- break;
- }
- case Qt::Key_PageDown:
- // <PageDown> key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: last command in history
- // - with <Ctrl> modifier key pressed: move cursor one page down without selection
- // - with <Shift> modifier key pressed: move cursor one page down with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page down
- {
- if ( ctrlPressed && shftPressed ) {
- verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd);
- }
- else if ( shftPressed || ctrlPressed ) {
- bool moved = false;
- qreal lastY = cursorRect( cur ).top();
- qreal distance = 0;
- // move using movePosition to keep the cursor's x
- do {
- qreal y = cursorRect( cur ).top();
- distance += qAbs( y - lastY );
- lastY = y;
- moved = cur.movePosition( QTextCursor::Down,
- shftPressed ? QTextCursor::KeepAnchor :
- QTextCursor::MoveAnchor );
- } while ( moved && distance < viewport()->height() );
- if ( moved ) {
- cur.movePosition( QTextCursor::Up,
- shftPressed ? QTextCursor::KeepAnchor :
- QTextCursor::MoveAnchor );
- verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
- }
- setTextCursor( cur );
- }
- else {
- if ( myCmdInHistory >= 0 ) {
- // unset history browsing mode
- myCmdInHistory = -1;
- // print current command
- moveCursor( QTextCursor::End );
- moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- addText( myPrompt + myCurrentCommand );
- // move cursor to the end
- moveCursor( QTextCursor::End );
- }
- }
- break;
- }
- case Qt::Key_Home:
- // <Home> key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: move cursor to the beginning of the current line without selection
- // - with <Ctrl> modifier key pressed: move cursor to the very first symbol without selection
- // - with <Shift> modifier key pressed: move cursor to the beginning of the current line with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very first symbol with selection
- {
- if ( ctrlPressed ) {
- moveCursor( QTextCursor::Start,
- shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
- }
- else {
- QString txt = textCursor().block().text();
- if ( isCommand( txt ) ) {
- if ( shftPressed ) {
- if ( curCol > promptSize() ) {
- cur.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
- cur.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
- }
- }
- else {
- cur.movePosition( QTextCursor::StartOfLine );
- cur.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
- }
- setTextCursor( cur );
- }
- else {
- moveCursor( QTextCursor::StartOfBlock,
- shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
- }
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- }
- break;
- }
- case Qt::Key_End:
- // <End> key: process as follows:
- // - without <Ctrl>, <Shift> modifiers: move cursor to the end of the current line without selection
- // - with <Ctrl> modifier key pressed: move cursor to the very last symbol without selection
- // - with <Shift> modifier key pressed: move cursor to the end of the current line with selection
- // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very last symbol with selection
- {
- moveCursor( ctrlPressed ? QTextCursor::End : QTextCursor::EndOfBlock,
- shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
- break;
- }
- case Qt::Key_Backspace :
- // <Backspace> key: process as follows
- // - without any modifiers : delete symbol before the cursor / selection (taking into account prompt)
- // - with <Shift> modifier key pressed: delete previous word
- // - with <Ctrl> modifier key pressed: delete text from the cursor to the line beginning
- // works only for last (command) line
- {
- if ( cur.hasSelection() ) {
- cut();
- }
- else if ( cur.position() > document()->end().previous().position() + promptSize() ) {
- if ( shftPressed ) {
- moveCursor( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- }
- else if ( ctrlPressed ) {
- cur.setPosition( document()->end().previous().position() + promptSize(),
- QTextCursor::KeepAnchor );
- setTextCursor( cur );
- textCursor().removeSelectedText();
- }
- else {
- QTextEdit::keyPressEvent( event );
- }
- }
- else {
- cur.setPosition( document()->end().previous().position() + promptSize() );
- setTextCursor( cur );
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- }
- break;
- }
- case Qt::Key_Delete :
- // <Delete> key: process as follows
- // - without any modifiers : delete symbol after the cursor / selection (taking into account prompt)
- // - with <Shift> modifier key pressed: delete next word
- // - with <Ctrl> modifier key pressed: delete text from the cursor to the end of line
- // works only for last (command) line
- {
- if ( cur.hasSelection() ) {
- cut();
- }
- else if ( cur.position() > document()->end().previous().position() + promptSize()-1 ) {
- if ( shftPressed ) {
- moveCursor( QTextCursor::NextWord, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- }
- else if ( ctrlPressed ) {
- moveCursor( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
- textCursor().removeSelectedText();
- }
- else {
- QTextEdit::keyPressEvent( event );
- }
- }
- else {
- cur.setPosition( document()->end().previous().position() + promptSize() );
- setTextCursor( cur );
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- }
- break;
- }
- case Qt::Key_Insert :
- // <Insert> key: process as follows
- // - with <Ctrl> modifier key pressed: copy()
- // - with <Shift> modifier key pressed: paste() to the command line
- {
- if ( ctrlPressed ) {
- copy();
- }
- else if ( shftPressed ) {
- paste();
- }
- else
- QTextEdit::keyPressEvent( event );
- break;
- }
- }
-}
-
-/*!
- \brief Handle notification event coming from Python dispatcher.
- \param event notification event
-*/
-void PyConsole_Editor::customEvent( QEvent* event )
-{
- switch( event->type() )
- {
- case PrintEvent::EVENT_ID:
- {
- PrintEvent* pe=(PrintEvent*)event;
- addText( pe->text(), false, pe->isError());
- return;
- }
- case PyInterp_Event::ES_OK:
- case PyInterp_Event::ES_ERROR:
- {
- // clear command buffer
- myCommandBuffer.truncate( 0 );
- // add caret return line if necessary
- QTextBlock par = document()->end().previous();
- QString txt = par.text();
- txt.truncate( txt.length() - 1 );
- // IPAL19397 : addText moved to handleReturn() method
- //if ( !txt.isEmpty() )
- // addText( "", true );
- // set "ready" prompt
- myPrompt = READY_PROMPT;
- addText( myPrompt );
- // unset busy cursor
- unsetCursor();
- // stop event loop (if running)
- if ( myEventLoop )
- myEventLoop->exit();
- break;
- }
- case PyInterp_Event::ES_INCOMPLETE:
- {
- // extend command buffer (multi-line command)
- myCommandBuffer.append( "\n" );
- // add caret return line if necessary
- QTextBlock par = document()->end().previous();
- QString txt = par.text();
- txt.truncate( txt.length() - 1 );
- // IPAL19397 : addText moved to handleReturn() method
- //if ( !txt.isEmpty() )
- // addText( "", true );
- // set "dot" prompt
- myPrompt = DOTS_PROMPT;
- addText( myPrompt/*, true*/ ); // IPAL19397
- // unset busy cursor
- unsetCursor();
- // stop event loop (if running)
- if ( myEventLoop )
- myEventLoop->exit();
- break;
- }
- default:
- QTextEdit::customEvent( event );
- }
-
- // unset read-only state
- setReadOnly( false );
- // unset history browsing mode
- myCmdInHistory = -1;
-
- if ( (int)event->type() == (int)PyInterp_Event::ES_OK && myQueue.count() > 0 )
- {
- // process the next sheduled command from the queue (if there is any)
- QString nextcmd = myQueue[0];
- myQueue.pop_front();
- exec( nextcmd );
- }
-}
-
-/*!
- \brief Handle Python interpreter change.
-
- Perform initialization actions if the interpreter is changed.
- \param interp python interpreter is being set
-*/
-void PyConsole_Editor::onPyInterpChanged( PyConsole_Interp* interp )
-{
- if ( myInterp != interp
- // Force read-only state and wait cursor when myInterp is NULL
- || !myInterp ) {
- myInterp = interp;
- if ( myInterp ) {
- // print banner
- myBanner = myInterp->getbanner().c_str();
- if ( isShowBanner() )
- addText( myBanner );
- // clear command buffer
- myCommandBuffer.truncate(0);
- // unset read-only state
- setReadOnly( false );
- // unset history browsing mode
- myCmdInHistory = -1;
- // add prompt
- addText( myPrompt );
- // unset busy cursor
- viewport()->unsetCursor();
- // stop event loop (if running)
- if( myEventLoop)
- myEventLoop->exit();
- }
- else {
- // clear contents
- clear();
- // set read-only state
- setReadOnly( true );
- // set busy cursor
- setCursor( Qt::WaitCursor );
- }
- }
-}
-
-/*!
- \brief "Copy" operation.
-
- Reimplemented from Qt.
- Warning! In Qt4 this method is not virtual.
- */
-void PyConsole_Editor::cut()
-{
- QTextCursor cur = textCursor();
- if ( cur.hasSelection() ) {
- QApplication::clipboard()->setText( cur.selectedText() );
- int startSelection = cur.selectionStart();
- if ( startSelection < document()->end().previous().position() + promptSize() )
- startSelection = document()->end().previous().position() + promptSize();
- int endSelection = cur.selectionEnd();
- if ( endSelection < document()->end().previous().position() + promptSize() )
- endSelection = document()->end().previous().position() + promptSize();
- cur.setPosition( startSelection );
- cur.setPosition( endSelection, QTextCursor::KeepAnchor );
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- setTextCursor( cur );
- textCursor().removeSelectedText();
- }
-}
-
-/*!
- \brief "Paste" operation.
-
- Reimplemented from Qt.
- Warning! In Qt4 this method is not virtual.
- */
-void PyConsole_Editor::paste()
-{
- QTextCursor cur = textCursor();
- if ( cur.hasSelection() ) {
- int startSelection = cur.selectionStart();
- if ( startSelection < document()->end().previous().position() + promptSize() )
- startSelection = document()->end().previous().position() + promptSize();
- int endSelection = cur.selectionEnd();
- if ( endSelection < document()->end().previous().position() + promptSize() )
- endSelection = document()->end().previous().position() + promptSize();
- cur.setPosition( startSelection );
- cur.setPosition( endSelection, QTextCursor::KeepAnchor );
- horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
- setTextCursor( cur );
- textCursor().removeSelectedText();
- }
- if ( textCursor().position() < document()->end().previous().position() + promptSize() )
- moveCursor( QTextCursor::End );
- QTextEdit::paste();
-}
-
-/*!
- \brief "Clear" operation.
-
- Reimplemented from Qt.
- Warning! In Qt4 this method is not virtual.
- */
-void PyConsole_Editor::clear()
-{
- QTextEdit::clear();
- if ( isShowBanner() )
- addText( myBanner );
- myPrompt = READY_PROMPT;
- addText( myPrompt );
-}
-
-/*!
- \brief "Dump commands" operation.
- */
-void PyConsole_Editor::dump()
-{
- QStringList aFilters;
- aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
-
- QString fileName = SUIT_FileDlg::getFileName( this, QString(),
- aFilters, tr( "TOT_DUMP_PYCOMMANDS" ),
- false, true, new DumpCommandsFileValidator( this ) );
- if ( !fileName.isEmpty() ) {
- QFile file( fileName );
- if ( !file.open( QFile::WriteOnly ) )
- return;
-
- QTextStream out (&file);
-
- for ( int i=0; i<myHistory.count(); i++ ) {
- out << myHistory[i] << endl;
- }
- file.close();
- }
-}
-/*!
- \brief "Start log" operation.
- */
-void PyConsole_Editor::startLog()
-{
- QStringList aFilters;
- aFilters.append( tr( "LOG_FILES_FILTER" ) );
-
- while (1) {
- QString fileName = SUIT_FileDlg::getFileName( this, QString(),
- aFilters, tr( "TOT_SAVE_PYLOG" ),
- false, true );
- if ( !fileName.isEmpty() ) {
- if ( startLog( fileName ) ) {
- break;
- }
- else {
- SUIT_MessageBox::critical( this,
- QObject::tr("ERR_ERROR"),
- QObject::tr("ERR_FILE_NOT_WRITABLE") );
- }
- }
- else {
- break;
- }
- }
-}
-
-/*!
- \brief Start python trace logging
- \param fileName the path to the log file
- \sa stopLog()
- */
-bool PyConsole_Editor::startLog( const QString& fileName )
-{
- bool ok = false;
- if ( !fileName.isEmpty() ) {
- QFile file( fileName );
- if ( file.open( QFile::WriteOnly ) ) {
- file.close();
- myLogFile = fileName;
- ok = true;
- }
- }
- return ok;
-}
-
-/*!
- \brief "Stop log" operation.
- \sa startLog()
- */
-void PyConsole_Editor::stopLog()
-{
- myLogFile = QString();
-}
-
-/*!
- \brief Put string to the log file
- */
-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();
- }
-}
+++ /dev/null
-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-// SALOME SALOMEGUI : implementation of desktop and GUI kernel
-// File : PyConsole_Editor.h
-// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
-//
-#ifndef PYCONSOLE_EDITOR_H
-#define PYCONSOLE_EDITOR_H
-
-#include "PyConsole.h"
-
-#include <QTextEdit>
-
-class PyConsole_Interp;
-class PyInterp_Request;
-class QEventLoop;
-
-class PYCONSOLE_EXPORT PyConsole_Editor : public QTextEdit
-{
- Q_OBJECT;
-
-public:
- PyConsole_Editor( PyConsole_Interp* theInterp, QWidget *theParent = 0 );
- ~PyConsole_Editor();
-
- PyConsole_Interp* getInterp() const;
-
- virtual void addText( const QString& str, const bool newBlock = false, const bool isError = false );
- bool isCommand( const QString& str ) const;
-
- virtual void exec( const QString& command );
- void execAndWait( const QString& command );
-
- bool isSync() const;
- void setIsSync( const bool );
-
- bool isSuppressOutput() const;
- void setIsSuppressOutput(const bool);
-
- bool isShowBanner() const;
- void setIsShowBanner( const bool );
-
- bool isLogging() const;
-
- virtual QSize sizeHint() const;
-
-public slots:
- void cut();
- void paste();
- void clear();
- void handleReturn();
- void onPyInterpChanged( PyConsole_Interp* );
- void dump();
- bool startLog( const QString& );
- void startLog();
- void stopLog();
- void putLog( const QString& );
-
-protected:
- virtual void dropEvent( QDropEvent* event );
- virtual void mouseReleaseEvent( QMouseEvent* event );
- virtual void keyPressEvent ( QKeyEvent* event);
- virtual void customEvent( QEvent* event);
-
- virtual PyInterp_Request* createRequest( const QString& );
-
- /** Convenience function */
- inline int promptSize() const { return myPrompt.size(); }
-
- PyConsole_Interp* myInterp; //!< python interpreter
-
- QString myCommandBuffer; //!< python command buffer
- QString myCurrentCommand; //!< currently being printed command
- QString myPrompt; //!< current command line prompt
- int myCmdInHistory; //!< current history command index
- QString myLogFile; //!< current output log
- QStringList myHistory; //!< commands history buffer
- QEventLoop* myEventLoop; //!< internal event loop
- QString myBanner; //!< current banner
- bool myShowBanner; //!< 'show banner' flag
- QStringList myQueue; //!< python commands queue
- bool myIsSync; //!< synchronous mode flag
- bool myIsSuppressOutput; //!< suppress output flag
-};
-
-#endif // PYCONSOLE_EDITOR_H
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SALOME SALOMEGUI : implementation of desktop and GUI kernel
+// File : PyConsole_Editor.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+/*!
+ \class PyConsole_Editor
+ \brief Python command line interpreter front-end GUI widget.
+
+ This class provides simple GUI interface to the Python interpreter, including basic
+ navigation operations, executing commands (both interactively and programmatically),
+ copy-paste operations, history of the commands and so on.
+
+ Here below is the shortcut keyboard boundings used for navigation and other operations:
+ - <Enter> : execute current command
+ - <Ctrl><Break> : clear current command
+ - <Escape> : clear current command
+ - <Up> : previous command in the history
+ - <Shift><Up> : move cursor one row up with selection
+ - <Ctrl><Up> : move cursor one row up without selection
+ - <Ctrl><Shift><Up> : move cursor one row up with selection
+ - <Down> : next command in the history
+ - <Shift><Down> : move cursor one row down with selection
+ - <Ctrl><Down> : move cursor one row down without selection
+ - <Ctrl><Shift><Down> : move cursor one row down with selection
+ - <Left> : move one symbol left without selection
+ - <Shift><Left> : move one symbol left with selection
+ - <Ctrl><Left> : move one word left without selection
+ - <Ctrl><Shift><Left> : move one word left with selection
+ - <Right> : move one symbol right without selection
+ - <Shift><Right> : move one symbol right with selection
+ - <Ctrl><Right> : move one word right without selection
+ - <Ctrl><Shift><Right> : move one word right with selection
+ - <PgUp> : first command in the history
+ - <Shift><PgUp> : move one page up with selection
+ - <Ctrl><PgUp> : move one page up without selection
+ - <Ctrl><Shift><PgUp> : scroll one page up
+ - <PgDn> : last command in the history
+ - <Shift><PgDn> : move one page down with selection
+ - <Ctrl><PgDn> : move one page down without selection
+ - <Ctrl><Shift><PgDn> : scroll one page down
+ - <Home> : move to the beginning of the line without selection
+ - <Shift><Home> : move to the beginning of the line with selection
+ - <Ctrl><Home> : move to the very first symbol without selection
+ - <Ctrl><Shift><Home> : move to the very first symbol with selection
+ - <End> : move to the end of the line without selection
+ - <Shift><End> : move to the end of the line with selection
+ - <Ctrl><End> : move to the very last symbol without selection
+ - <Ctrl><Shift><End> : move to the very last symbol with selection
+ - <Backspace> : delete symbol before the cursor
+ / remove selected text and put it to the clipboard (cut)
+ - <Shift><Backspace> : delete previous word
+ / remove selected text and put it to the clipboard (cut)
+ - <Ctrl><Backspace> : delete text from the cursor to the beginning of the line
+ / remove selected text and put it to the clipboard (cut)
+ - <Delete> : delete symbol after the cursor
+ / remove selected text and put it to the clipboard (cut)
+ - <Shift><Delete> : delete next word
+ / remove selected text and put it to the clipboard (cut)
+ - <Ctrl><Delete> : delete text from the cursor to the end of the line
+ / remove selected text and put it to the clipboard (cut)
+ - <Ctrl><Insert> : copy
+ - <Shift><Insert> : paste
+ - <Ctrl><V> : paste
+ - <Ctrl><C> : copy
+ - <Ctrl><X> : cut
+ - <Ctrl><V> : paste
+*/
+
+#include "PyConsole_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "PyConsole_EditorBase.h"
+#include "PyConsole_Event.h"
+#include "PyInterp_Event.h"
+#include "PyInterp_Dispatcher.h"
+#include "PyConsole_Request.h"
+
+#include <Qtx.h>
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDropEvent>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMouseEvent>
+#include <QScrollBar>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextDocument>
+#include <QTextStream>
+#include <QChar>
+#include <QFileInfo>
+#include <QFileDialog>
+#include <QMessageBox>
+
+//VSR: uncomment below macro to support unicode text properly in SALOME
+// current commented out due to regressions
+//#define PAL22528_UNICODE
+
+namespace
+{
+ QString fromUtf8( const char* txt )
+ {
+#ifdef PAL22528_UNICODE
+ return QString::fromUtf8( txt );
+#else
+ return QString( txt );
+#endif
+ }
+}
+
+static QString READY_PROMPT = ">>> ";
+static QString DOTS_PROMPT = "... ";
+
+void staticCallbackStdout( void* data, char* c )
+{
+ if(!((PyConsole_EditorBase*)data)->isSuppressOutput()) {
+ PyConsole_EditorBase* e = (PyConsole_EditorBase*)data;
+ e->putLog( fromUtf8(c) );
+ QApplication::postEvent( e, new PrintEvent( fromUtf8(c), false ) );
+ }
+}
+
+void staticCallbackStderr( void* data, char* c )
+{
+ if(!((PyConsole_EditorBase*)data)->isSuppressOutput()) {
+ PyConsole_EditorBase* e = (PyConsole_EditorBase*)data;
+ e->putLog( fromUtf8(c) );
+ QApplication::postEvent( e, new PrintEvent( fromUtf8(c), true ) );
+ }
+}
+
+
+/*!
+ \brief Constructor.
+
+ Creates python editor window.
+ \param theInterp python interper
+ \param theParent parent widget
+*/
+PyConsole_EditorBase::PyConsole_EditorBase( PyConsole_Interp* theInterp,
+ QWidget* theParent )
+: QTextEdit( theParent ),
+ myInterp( 0 ),
+ myCmdInHistory( -1 ),
+ myEventLoop( 0 ),
+ myShowBanner( true ),
+ myIsSync( true ),
+ myIsSuppressOutput( false )
+{
+ QString fntSet( "" );
+ QFont aFont ( Qtx::stringToFont(fntSet) );
+ setFont( aFont );
+ setUndoRedoEnabled( false );
+
+ myPrompt = READY_PROMPT;
+ setLineWrapMode( QTextEdit::WidgetWidth );
+ setWordWrapMode( QTextOption::WrapAnywhere );
+ setAcceptRichText( false );
+
+ theInterp->setvoutcb( staticCallbackStdout, this );
+ theInterp->setverrcb( staticCallbackStderr, this );
+
+ // san - This is necessary for troubleless initialization
+ onPyInterpChanged( theInterp );
+}
+
+/*!
+ \brief Destructor.
+*/
+PyConsole_EditorBase::~PyConsole_EditorBase()
+{
+ myInterp = 0;
+}
+
+/*!
+ \brief Get Python interpreter
+*/
+PyConsole_Interp* PyConsole_EditorBase::getInterp() const
+{
+ return myInterp;
+}
+
+/*!
+ \brief Get synchronous mode flag value.
+
+ \sa setIsSync()
+ \return True if python console works in synchronous mode
+*/
+bool PyConsole_EditorBase::isSync() const
+{
+ return myIsSync;
+}
+
+/*!
+ \brief Set synchronous mode flag value.
+
+ In synhronous mode the Python commands are executed in the GUI thread
+ and the GUI is blocked until the command is finished. In the asynchronous
+ mode each Python command is executed in the separate thread that does not
+ block the main GUI loop.
+
+ \param on synhronous mode flag
+*/
+void PyConsole_EditorBase::setIsSync( const bool on )
+{
+ myIsSync = on;
+}
+
+/*!
+ \brief Get suppress output flag value.
+
+ \sa setIsSuppressOutput()
+ \return \c true if python console output is suppressed.
+*/
+bool PyConsole_EditorBase::isSuppressOutput() const
+{
+ return myIsSuppressOutput;
+}
+
+/*!
+ \brief Set suppress output flag value.
+
+ In case if suppress output flag is true, the python
+ console output suppressed.
+
+ \param on suppress output flag
+*/
+void PyConsole_EditorBase::setIsSuppressOutput( const bool on )
+{
+ myIsSuppressOutput = on;
+}
+
+/*!
+ \brief Get 'show banner' flag value.
+
+ \sa setIsShowBanner()
+ \return \c true if python console shows banner
+*/
+bool PyConsole_EditorBase::isShowBanner() const
+{
+ return myShowBanner;
+}
+
+/*!
+ \brief Set 'show banner' flag value.
+
+ The banner is shown in the top of the python console window.
+
+ \sa isShowBanner()
+ \param on 'show banner' flag
+*/
+void PyConsole_EditorBase::setIsShowBanner( const bool on )
+{
+ if ( myShowBanner != on ) {
+ myShowBanner = on;
+ clear();
+ }
+}
+
+/*!
+ \brief Check if trace logging is switched on.
+
+ \sa startLog(), stopLog()
+ \return \c true if trace logging is switched on
+*/
+bool PyConsole_EditorBase::isLogging() const
+{
+ return !myLogFile.isEmpty();
+}
+
+/*!
+ \brief Get size hint for the Python console window
+ \return size hint value
+*/
+QSize PyConsole_EditorBase::sizeHint() const
+{
+ QFontMetrics fm( font() );
+ int nbLines = ( isShowBanner() ? myBanner.split("\n").count() : 0 ) + 1;
+ QSize s(100, fm.lineSpacing()*nbLines);
+ return s;
+}
+
+/*!
+ \brief Put the string \a str to the python editor.
+ \param str string to be put in the command line of the editor
+ \param newBlock if True, then the string is printed on a new line
+ \param isError if true, the text is printed in dark red
+*/
+void PyConsole_EditorBase::addText( const QString& str,
+ const bool newBlock,
+ const bool isError)
+{
+ QTextCursor theCursor(textCursor());
+ QTextCharFormat cf;
+
+ moveCursor( QTextCursor::End );
+ if ( newBlock )
+ theCursor.insertBlock();
+ if (isError)
+ cf.setForeground(QBrush(Qt::red));
+ else
+ cf.setForeground(QBrush(Qt::black));
+ theCursor.insertText( str, cf);
+ moveCursor( QTextCursor::End );
+ ensureCursorVisible();
+}
+
+/*!
+ \brief Convenient method for executing a Python command,
+ as if the user typed it manually.
+ \param command python command to be executed
+
+ !!! WARNING: doesn't work properly with multi-line commands. !!!
+*/
+void PyConsole_EditorBase::exec( const QString& command )
+{
+ if ( isReadOnly() ) {
+ // some interactive command is being executed in this editor...
+ // shedule the command to the queue
+ myQueue.push_back( command );
+ return;
+ }
+ // remove last line
+ moveCursor( QTextCursor::End );
+ moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ // set "ready" prompt
+ myPrompt = READY_PROMPT;
+ // clear command buffer
+ myCommandBuffer.truncate( 0 );
+ // unset history browsing mode
+ myCmdInHistory = -1;
+ // print command line by line
+ QString cmd = command;
+ if ( !cmd.endsWith( "\n" ) ) cmd += "\n";
+ QStringList lines = command.split( "\n" );
+ for ( int i = 0; i < lines.size(); i++ ) {
+ if ( !lines[i].trimmed().isEmpty() )
+ myHistory.push_back( lines[i] );
+ addText( ( i == 0 ? READY_PROMPT : DOTS_PROMPT ) + lines[i], i != 0 );
+ putLog( QString( "%1%2\n" ).arg( i == 0 ? READY_PROMPT : DOTS_PROMPT ).arg( lines[i] ) );
+ }
+ // IPAL20182
+ addText( "", true );
+ // set read-only mode
+ setReadOnly( true );
+ // set busy cursor
+ setCursor( Qt::BusyCursor );
+
+ // post a request to execute Python command;
+ // editor will be informed via a custom event that execution has been completed
+ PyInterp_Dispatcher::Get()->Exec( createRequest( cmd ) );
+}
+
+/*!
+ \brief Create request to the python dispatcher for the command execution.
+
+ \param command python command to be executed
+ */
+PyInterp_Request* PyConsole_EditorBase::createRequest( const QString& command )
+{
+ return new ExecCommand( myInterp, command, this, isSync() );
+}
+
+/*!
+ \brief Execute command in the python interpreter
+ and wait until it is finished.
+
+ \param command python command to be executed
+ */
+void PyConsole_EditorBase::execAndWait( const QString& command )
+{
+ // already running ?
+ if( myEventLoop )
+ return;
+
+ // create new event loop
+ bool sync = isSync();
+ if ( !sync ) {
+ myEventLoop = new QEventLoop( this );
+ }
+
+ // execute command
+ exec( command );
+
+ if ( !sync ) {
+ // run event loop
+ myEventLoop->exec();
+ // delete event loop after command is processed
+ delete myEventLoop;
+ myEventLoop = 0;
+ }
+}
+
+/*!
+ \brief Process "Enter" key press event.
+
+ Execute the command entered by the user.
+*/
+void PyConsole_EditorBase::handleReturn()
+{
+ // Position cursor at the end
+ QTextCursor curs(textCursor());
+ curs.movePosition(QTextCursor::End);
+ setTextCursor(curs);
+
+ // get last line
+ QTextBlock par = document()->end().previous();
+ if ( !par.isValid() ) return;
+
+ // get command
+ QString cmd = par.text().remove( 0, promptSize() );
+ // extend the command buffer with the current command
+ myCommandBuffer.append( cmd );
+ // add command to the history
+ if ( !cmd.trimmed().isEmpty() )
+ myHistory.push_back( cmd );
+ putLog( QString( "%1%2\n" ).arg( myPrompt ).arg( cmd ) );
+
+ // IPAL19397
+ addText( "", true );
+
+ // set read-only mode
+ setReadOnly( true );
+ // set busy cursor
+ setCursor( Qt::BusyCursor );
+
+ // post a request to execute Python command;
+ // editor will be informed via a custom event that execution has been completed
+ PyInterp_Dispatcher::Get()->Exec( createRequest( myCommandBuffer ) );
+}
+
+/*!
+ \brief Process drop event.
+
+ Paste dragged text.
+ \param event drop event
+*/
+void PyConsole_EditorBase::dropEvent( QDropEvent* event )
+{
+ // get the initial drop position
+ QPoint pos = event->pos();
+ QTextCursor cur = cursorForPosition( event->pos() );
+ // if the position is not in the last line move it to the end of the command line
+ if ( cur.position() < document()->end().previous().position() + promptSize() ) {
+ moveCursor( QTextCursor::End );
+ pos = cursorRect().center();
+ }
+ // create new drop event and use it instead of the original
+ QDropEvent de( pos,
+ event->possibleActions(),
+ event->mimeData(),
+ event->mouseButtons(),
+ event->keyboardModifiers(),
+ event->type() );
+ QTextEdit::dropEvent( &de );
+ // accept the original event
+ event->acceptProposedAction();
+}
+
+/*!
+ \brief Process mouse button release event.
+
+ Left mouse button: copy selection to the clipboard.
+ Middle mouse button: paste clipboard's contents.
+ \param event mouse event
+*/
+void PyConsole_EditorBase::mouseReleaseEvent( QMouseEvent* event )
+{
+ if ( event->button() == Qt::LeftButton ) {
+ QTextEdit::mouseReleaseEvent( event );
+ //copy();
+ }
+ else if ( event->button() == Qt::MidButton ) {
+ QTextCursor cur = cursorForPosition( event->pos() );
+ // if the position is not in the last line move it to the end of the command line
+ if ( cur.position() < document()->end().previous().position() + promptSize() ) {
+ moveCursor( QTextCursor::End );
+ }
+ else {
+ setTextCursor( cur );
+ }
+ const QMimeData* md = QApplication::clipboard()->mimeData( QApplication::clipboard()->supportsSelection() ?
+ QClipboard::Selection : QClipboard::Clipboard );
+ if ( md )
+ insertFromMimeData( md );
+ }
+ else {
+ QTextEdit::mouseReleaseEvent( event );
+ }
+}
+
+/*!
+ \brief Check if the string is command.
+
+ Return True if the string \a str is likely to be the command
+ (i.e. it is started from the '>>>' or '...').
+ \param str string to be checked
+*/
+bool PyConsole_EditorBase::isCommand( const QString& str ) const
+{
+ return str.startsWith( READY_PROMPT ) || str.startsWith( DOTS_PROMPT );
+}
+
+/*!
+ \brief Handle keyboard event.
+
+ Implement navigation, history browsing, copy/paste and other common
+ operations.
+ \param event keyboard event
+*/
+void PyConsole_EditorBase::keyPressEvent( QKeyEvent* event )
+{
+ // get cursor position
+ QTextCursor cur = textCursor();
+ int curLine = cur.blockNumber();
+ int curCol = cur.columnNumber();
+
+ // get last edited line
+ int endLine = document()->blockCount()-1;
+
+ // get pressed key code
+ int aKey = event->key();
+
+ // check if <Ctrl> is pressed
+ bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
+ // check if <Shift> is pressed
+ bool shftPressed = event->modifiers() & Qt::ShiftModifier;
+
+ if ( aKey == Qt::Key_Escape || ( ctrlPressed && aKey == -1 ) ) {
+ // process <Ctrl>+<Break> key-binding and <Escape> key: clear current command
+ myCommandBuffer.truncate( 0 );
+ myPrompt = READY_PROMPT;
+ addText( myPrompt, true );
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ return;
+ }
+ else if ( ctrlPressed && aKey == Qt::Key_C ) {
+ // process <Ctrl>+<C> key-binding : copy
+ copy();
+ return;
+ }
+ else if ( ctrlPressed && aKey == Qt::Key_X ) {
+ // process <Ctrl>+<X> key-binding : cut
+ cut();
+ return;
+ }
+ else if ( ctrlPressed && aKey == Qt::Key_V ) {
+ // process <Ctrl>+<V> key-binding : paste
+ paste();
+ return;
+ }
+
+ // check for printed key
+ // #### aKey = ( aKey < Qt::Key_Space || aKey > Qt::Key_ydiaeresis ) ? aKey : 0;
+ // Better:
+ aKey = !(QChar(aKey).isPrint()) ? aKey : 0;
+
+ switch ( aKey ) {
+ case 0 :
+ // any printed key: just print it
+ {
+ if ( curLine < endLine || curCol < promptSize() ) {
+ moveCursor( QTextCursor::End );
+ }
+ QTextEdit::keyPressEvent( event );
+ break;
+ }
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ // <Enter> key: process the current command
+ {
+ handleReturn();
+ break;
+ }
+ case Qt::Key_Up:
+ // <Up> arrow key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: previous command in history
+ // - with <Ctrl> modifier key pressed: move cursor one row up without selection
+ // - with <Shift> modifier key pressed: move cursor one row up with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row up
+ {
+ if ( ctrlPressed && shftPressed ) {
+ int value = verticalScrollBar()->value();
+ int spacing = fontMetrics().lineSpacing();
+ verticalScrollBar()->setValue( value > spacing ? value-spacing : 0 );
+ }
+ else if ( shftPressed || ctrlPressed ) {
+ if ( curLine > 0 )
+ moveCursor( QTextCursor::Up,
+ shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+ }
+ else {
+ if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
+ // set history browsing mode
+ myCmdInHistory = myHistory.count();
+ // remember current command
+ QTextBlock par = document()->end().previous();
+ myCurrentCommand = par.text().remove( 0, promptSize() );
+ }
+ if ( myCmdInHistory > 0 ) {
+ myCmdInHistory--;
+ // get previous command in the history
+ QString previousCommand = myHistory.at( myCmdInHistory );
+ // print previous command
+ moveCursor( QTextCursor::End );
+ moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ addText( myPrompt + previousCommand );
+ // move cursor to the end
+ moveCursor( QTextCursor::End );
+ }
+ }
+ break;
+ }
+ case Qt::Key_Down:
+ // <Down> arrow key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: next command in history
+ // - with <Ctrl> modifier key pressed: move cursor one row down without selection
+ // - with <Shift> modifier key pressed: move cursor one row down with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row down
+ {
+ if ( ctrlPressed && shftPressed ) {
+ int value = verticalScrollBar()->value();
+ int maxval = verticalScrollBar()->maximum();
+ int spacing = fontMetrics().lineSpacing();
+ verticalScrollBar()->setValue( value+spacing < maxval ? value+spacing : maxval );
+ }
+ else if ( shftPressed || ctrlPressed) {
+ if ( curLine < endLine )
+ moveCursor( QTextCursor::Down,
+ shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+ }
+ else {
+ if ( myCmdInHistory >= 0 ) {
+ // get next command in the history
+ myCmdInHistory++;
+ QString nextCommand;
+ if ( myCmdInHistory < myHistory.count() ) {
+ // next command in history
+ nextCommand = myHistory.at( myCmdInHistory );
+ }
+ else {
+ // end of history is reached
+ // last printed command
+ nextCommand = myCurrentCommand;
+ // unset history browsing mode
+ myCmdInHistory = -1;
+ }
+ // print next or current command
+ moveCursor( QTextCursor::End );
+ moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ addText( myPrompt + nextCommand );
+ // move cursor to the end
+ moveCursor( QTextCursor::End );
+ }
+ }
+ break;
+ }
+ case Qt::Key_Left:
+ // <Left> arrow key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: move one symbol left (taking into account prompt)
+ // - with <Ctrl> modifier key pressed: move one word left (taking into account prompt)
+ // - with <Shift> modifier key pressed: move one symbol left with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: move one word left with selection
+ {
+ QString txt = textCursor().block().text();
+ if ( !shftPressed && isCommand( txt ) && curCol <= promptSize() ) {
+ moveCursor( QTextCursor::Up );
+ moveCursor( QTextCursor::EndOfBlock );
+ }
+ else {
+ QTextEdit::keyPressEvent( event );
+ }
+ break;
+ }
+ case Qt::Key_Right:
+ // <Right> arrow key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: move one symbol right (taking into account prompt)
+ // - with <Ctrl> modifier key pressed: move one word right (taking into account prompt)
+ // - with <Shift> modifier key pressed: move one symbol right with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: move one word right with selection
+ {
+ QString txt = textCursor().block().text();
+ if ( !shftPressed ) {
+ if ( curCol < txt.length() ) {
+ if ( isCommand( txt ) && curCol < promptSize() ) {
+ cur.setPosition( cur.block().position() + promptSize() );
+ setTextCursor( cur );
+ break;
+ }
+ }
+ else {
+ if ( curLine < endLine && isCommand( textCursor().block().next().text() ) ) {
+ cur.setPosition( cur.position() + promptSize()+1 );
+ setTextCursor( cur );
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ break;
+ }
+ }
+ }
+ QTextEdit::keyPressEvent( event );
+ break;
+ }
+ case Qt::Key_PageUp:
+ // <PageUp> key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: first command in history
+ // - with <Ctrl> modifier key pressed: move cursor one page up without selection
+ // - with <Shift> modifier key pressed: move cursor one page up with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page up
+ {
+ if ( ctrlPressed && shftPressed ) {
+ verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub);
+ }
+ else if ( shftPressed || ctrlPressed ) {
+ bool moved = false;
+ qreal lastY = cursorRect( cur ).top();
+ qreal distance = 0;
+ // move using movePosition to keep the cursor's x
+ do {
+ qreal y = cursorRect( cur ).top();
+ distance += qAbs( y - lastY );
+ lastY = y;
+ moved = cur.movePosition( QTextCursor::Up,
+ shftPressed ? QTextCursor::KeepAnchor :
+ QTextCursor::MoveAnchor );
+ } while ( moved && distance < viewport()->height() );
+ if ( moved ) {
+ cur.movePosition( QTextCursor::Down,
+ shftPressed ? QTextCursor::KeepAnchor :
+ QTextCursor::MoveAnchor );
+ verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
+ }
+ setTextCursor( cur );
+ }
+ else {
+ if ( myCmdInHistory < 0 && myHistory.count() > 0 ) {
+ // set history browsing mode
+ myCmdInHistory = myHistory.count();
+ // remember current command
+ QTextBlock par = document()->end().previous();
+ myCurrentCommand = par.text().remove( 0, promptSize() );
+ }
+ if ( myCmdInHistory > 0 ) {
+ myCmdInHistory = 0;
+ // get very first command in the history
+ QString firstCommand = myHistory.at( myCmdInHistory );
+ // print first command
+ moveCursor( QTextCursor::End );
+ moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ addText( myPrompt + firstCommand );
+ // move cursor to the end
+ moveCursor( QTextCursor::End );
+ }
+ }
+ break;
+ }
+ case Qt::Key_PageDown:
+ // <PageDown> key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: last command in history
+ // - with <Ctrl> modifier key pressed: move cursor one page down without selection
+ // - with <Shift> modifier key pressed: move cursor one page down with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page down
+ {
+ if ( ctrlPressed && shftPressed ) {
+ verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd);
+ }
+ else if ( shftPressed || ctrlPressed ) {
+ bool moved = false;
+ qreal lastY = cursorRect( cur ).top();
+ qreal distance = 0;
+ // move using movePosition to keep the cursor's x
+ do {
+ qreal y = cursorRect( cur ).top();
+ distance += qAbs( y - lastY );
+ lastY = y;
+ moved = cur.movePosition( QTextCursor::Down,
+ shftPressed ? QTextCursor::KeepAnchor :
+ QTextCursor::MoveAnchor );
+ } while ( moved && distance < viewport()->height() );
+ if ( moved ) {
+ cur.movePosition( QTextCursor::Up,
+ shftPressed ? QTextCursor::KeepAnchor :
+ QTextCursor::MoveAnchor );
+ verticalScrollBar()->triggerAction( QAbstractSlider::SliderPageStepSub );
+ }
+ setTextCursor( cur );
+ }
+ else {
+ if ( myCmdInHistory >= 0 ) {
+ // unset history browsing mode
+ myCmdInHistory = -1;
+ // print current command
+ moveCursor( QTextCursor::End );
+ moveCursor( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ addText( myPrompt + myCurrentCommand );
+ // move cursor to the end
+ moveCursor( QTextCursor::End );
+ }
+ }
+ break;
+ }
+ case Qt::Key_Home:
+ // <Home> key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: move cursor to the beginning of the current line without selection
+ // - with <Ctrl> modifier key pressed: move cursor to the very first symbol without selection
+ // - with <Shift> modifier key pressed: move cursor to the beginning of the current line with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very first symbol with selection
+ {
+ if ( ctrlPressed ) {
+ moveCursor( QTextCursor::Start,
+ shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+ }
+ else {
+ QString txt = textCursor().block().text();
+ if ( isCommand( txt ) ) {
+ if ( shftPressed ) {
+ if ( curCol > promptSize() ) {
+ cur.movePosition( QTextCursor::StartOfLine, QTextCursor::KeepAnchor );
+ cur.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, promptSize() );
+ }
+ }
+ else {
+ cur.movePosition( QTextCursor::StartOfLine );
+ cur.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptSize() );
+ }
+ setTextCursor( cur );
+ }
+ else {
+ moveCursor( QTextCursor::StartOfBlock,
+ shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+ }
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ }
+ break;
+ }
+ case Qt::Key_End:
+ // <End> key: process as follows:
+ // - without <Ctrl>, <Shift> modifiers: move cursor to the end of the current line without selection
+ // - with <Ctrl> modifier key pressed: move cursor to the very last symbol without selection
+ // - with <Shift> modifier key pressed: move cursor to the end of the current line with selection
+ // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very last symbol with selection
+ {
+ moveCursor( ctrlPressed ? QTextCursor::End : QTextCursor::EndOfBlock,
+ shftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor );
+ break;
+ }
+ case Qt::Key_Backspace :
+ // <Backspace> key: process as follows
+ // - without any modifiers : delete symbol before the cursor / selection (taking into account prompt)
+ // - with <Shift> modifier key pressed: delete previous word
+ // - with <Ctrl> modifier key pressed: delete text from the cursor to the line beginning
+ // works only for last (command) line
+ {
+ if ( cur.hasSelection() ) {
+ cut();
+ }
+ else if ( cur.position() > document()->end().previous().position() + promptSize() ) {
+ if ( shftPressed ) {
+ moveCursor( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ }
+ else if ( ctrlPressed ) {
+ cur.setPosition( document()->end().previous().position() + promptSize(),
+ QTextCursor::KeepAnchor );
+ setTextCursor( cur );
+ textCursor().removeSelectedText();
+ }
+ else {
+ QTextEdit::keyPressEvent( event );
+ }
+ }
+ else {
+ cur.setPosition( document()->end().previous().position() + promptSize() );
+ setTextCursor( cur );
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ }
+ break;
+ }
+ case Qt::Key_Delete :
+ // <Delete> key: process as follows
+ // - without any modifiers : delete symbol after the cursor / selection (taking into account prompt)
+ // - with <Shift> modifier key pressed: delete next word
+ // - with <Ctrl> modifier key pressed: delete text from the cursor to the end of line
+ // works only for last (command) line
+ {
+ if ( cur.hasSelection() ) {
+ cut();
+ }
+ else if ( cur.position() > document()->end().previous().position() + promptSize()-1 ) {
+ if ( shftPressed ) {
+ moveCursor( QTextCursor::NextWord, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ }
+ else if ( ctrlPressed ) {
+ moveCursor( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
+ textCursor().removeSelectedText();
+ }
+ else {
+ QTextEdit::keyPressEvent( event );
+ }
+ }
+ else {
+ cur.setPosition( document()->end().previous().position() + promptSize() );
+ setTextCursor( cur );
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ }
+ break;
+ }
+ case Qt::Key_Insert :
+ // <Insert> key: process as follows
+ // - with <Ctrl> modifier key pressed: copy()
+ // - with <Shift> modifier key pressed: paste() to the command line
+ {
+ if ( ctrlPressed ) {
+ copy();
+ }
+ else if ( shftPressed ) {
+ paste();
+ }
+ else
+ QTextEdit::keyPressEvent( event );
+ break;
+ }
+ }
+}
+
+/*!
+ \brief Handle notification event coming from Python dispatcher.
+ \param event notification event
+*/
+void PyConsole_EditorBase::customEvent( QEvent* event )
+{
+ switch( event->type() )
+ {
+ case PrintEvent::EVENT_ID:
+ {
+ PrintEvent* pe=(PrintEvent*)event;
+ addText( pe->text(), false, pe->isError());
+ return;
+ }
+ case PyInterp_Event::ES_OK:
+ case PyInterp_Event::ES_ERROR:
+ {
+ // clear command buffer
+ myCommandBuffer.truncate( 0 );
+ // add caret return line if necessary
+ QTextBlock par = document()->end().previous();
+ QString txt = par.text();
+ txt.truncate( txt.length() - 1 );
+ // IPAL19397 : addText moved to handleReturn() method
+ //if ( !txt.isEmpty() )
+ // addText( "", true );
+ // set "ready" prompt
+ myPrompt = READY_PROMPT;
+ addText( myPrompt );
+ // unset busy cursor
+ unsetCursor();
+ // stop event loop (if running)
+ if ( myEventLoop )
+ myEventLoop->exit();
+ break;
+ }
+ case PyInterp_Event::ES_INCOMPLETE:
+ {
+ // extend command buffer (multi-line command)
+ myCommandBuffer.append( "\n" );
+ // add caret return line if necessary
+ QTextBlock par = document()->end().previous();
+ QString txt = par.text();
+ txt.truncate( txt.length() - 1 );
+ // IPAL19397 : addText moved to handleReturn() method
+ //if ( !txt.isEmpty() )
+ // addText( "", true );
+ // set "dot" prompt
+ myPrompt = DOTS_PROMPT;
+ addText( myPrompt/*, true*/ ); // IPAL19397
+ // unset busy cursor
+ unsetCursor();
+ // stop event loop (if running)
+ if ( myEventLoop )
+ myEventLoop->exit();
+ break;
+ }
+ default:
+ QTextEdit::customEvent( event );
+ }
+
+ // unset read-only state
+ setReadOnly( false );
+ // unset history browsing mode
+ myCmdInHistory = -1;
+
+ if ( (int)event->type() == (int)PyInterp_Event::ES_OK && myQueue.count() > 0 )
+ {
+ // process the next sheduled command from the queue (if there is any)
+ QString nextcmd = myQueue[0];
+ myQueue.pop_front();
+ exec( nextcmd );
+ }
+}
+
+/*!
+ \brief Handle Python interpreter change.
+
+ Perform initialization actions if the interpreter is changed.
+ \param interp python interpreter is being set
+*/
+void PyConsole_EditorBase::onPyInterpChanged( PyConsole_Interp* interp )
+{
+ if ( myInterp != interp
+ // Force read-only state and wait cursor when myInterp is NULL
+ || !myInterp ) {
+ myInterp = interp;
+ if ( myInterp ) {
+ // print banner
+ myBanner = myInterp->getbanner().c_str();
+ if ( isShowBanner() )
+ addText( myBanner );
+ // clear command buffer
+ myCommandBuffer.truncate(0);
+ // unset read-only state
+ setReadOnly( false );
+ // unset history browsing mode
+ myCmdInHistory = -1;
+ // add prompt
+ addText( myPrompt );
+ // unset busy cursor
+ viewport()->unsetCursor();
+ // stop event loop (if running)
+ if( myEventLoop)
+ myEventLoop->exit();
+ }
+ else {
+ // clear contents
+ clear();
+ // set read-only state
+ setReadOnly( true );
+ // set busy cursor
+ setCursor( Qt::WaitCursor );
+ }
+ }
+}
+
+/*!
+ \brief "Copy" operation.
+
+ Reimplemented from Qt.
+ Warning! In Qt4 this method is not virtual.
+ */
+void PyConsole_EditorBase::cut()
+{
+ QTextCursor cur = textCursor();
+ if ( cur.hasSelection() ) {
+ QApplication::clipboard()->setText( cur.selectedText() );
+ int startSelection = cur.selectionStart();
+ if ( startSelection < document()->end().previous().position() + promptSize() )
+ startSelection = document()->end().previous().position() + promptSize();
+ int endSelection = cur.selectionEnd();
+ if ( endSelection < document()->end().previous().position() + promptSize() )
+ endSelection = document()->end().previous().position() + promptSize();
+ cur.setPosition( startSelection );
+ cur.setPosition( endSelection, QTextCursor::KeepAnchor );
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ setTextCursor( cur );
+ textCursor().removeSelectedText();
+ }
+}
+
+/*!
+ \brief "Paste" operation.
+
+ Reimplemented from Qt.
+ Warning! In Qt4 this method is not virtual.
+ */
+void PyConsole_EditorBase::paste()
+{
+ QTextCursor cur = textCursor();
+ if ( cur.hasSelection() ) {
+ int startSelection = cur.selectionStart();
+ if ( startSelection < document()->end().previous().position() + promptSize() )
+ startSelection = document()->end().previous().position() + promptSize();
+ int endSelection = cur.selectionEnd();
+ if ( endSelection < document()->end().previous().position() + promptSize() )
+ endSelection = document()->end().previous().position() + promptSize();
+ cur.setPosition( startSelection );
+ cur.setPosition( endSelection, QTextCursor::KeepAnchor );
+ horizontalScrollBar()->setValue( horizontalScrollBar()->minimum() );
+ setTextCursor( cur );
+ textCursor().removeSelectedText();
+ }
+ if ( textCursor().position() < document()->end().previous().position() + promptSize() )
+ moveCursor( QTextCursor::End );
+ QTextEdit::paste();
+}
+
+/*!
+ \brief "Clear" operation.
+
+ Reimplemented from Qt.
+ Warning! In Qt4 this method is not virtual.
+ */
+void PyConsole_EditorBase::clear()
+{
+ QTextEdit::clear();
+ if ( isShowBanner() )
+ addText( myBanner );
+ myPrompt = READY_PROMPT;
+ addText( myPrompt );
+}
+
+/*!
+ \brief "Dump commands" operation.
+ */
+void PyConsole_EditorBase::dumpImpl(const QString& fileName)
+{
+ if ( !fileName.isEmpty() ) {
+ QFile file( fileName );
+ if ( !file.open( QFile::WriteOnly ) )
+ return;
+
+ QTextStream out (&file);
+
+ for ( int i=0; i<myHistory.count(); i++ ) {
+ out << myHistory[i] << endl;
+ }
+ file.close();
+ }
+}
+
+/*!
+ \brief "Dump commands" operation.
+ */
+void PyConsole_EditorBase::dump(const QString& fileName)
+{
+ dumpImpl(fileName);
+}
+
+/*!
+ \brief "Dump commands" operation.
+ */
+void PyConsole_EditorBase::dump()
+{
+ dumpSlot();
+}
+
+void PyConsole_EditorBase::dumpSlot()
+{
+ QString fileName(QFileDialog::getSaveFileName(this,tr("Choose python file where to store"),QString(),tr("Python scripts ext (*.py)")));
+ if ( !fileName.isEmpty() )
+ this->dump( fileName );
+ else
+ QMessageBox::warning(this,tr("WARNING"),tr("Python file has not been written"));
+}
+
+/*!
+ \brief Start python trace logging
+ \param fileName the path to the log file
+ \sa stopLog()
+ */
+bool PyConsole_EditorBase::startLogImpl( const QString& fileName )
+{
+ bool ok = false;
+ if ( !fileName.isEmpty() ) {
+ QFile file( fileName );
+ if ( file.open( QFile::WriteOnly ) ) {
+ file.close();
+ myLogFile = fileName;
+ ok = true;
+ }
+ }
+ return ok;
+}
+
+
+/*!
+ \brief Start python trace logging
+ \param fileName the path to the log file
+ \sa stopLog()
+ */
+bool PyConsole_EditorBase::startLog( const QString& fileName )
+{
+ return startLogImpl(fileName);
+}
+
+/*!
+ \brief Start python trace logging
+ \sa stopLog()
+ */
+void PyConsole_EditorBase::startLog()
+{
+ startLogSlot();
+}
+
+void PyConsole_EditorBase::startLogSlot()
+{
+ while (1)
+ {
+ QString fileName(QFileDialog::getSaveFileName(this,tr("Choose python file where to store log"),QString(),tr("Log files ext (*.log *.txt)")));
+ if ( !fileName.isEmpty() )
+ {
+ if ( startLogImpl( fileName ) )
+ break;
+ else
+ QMessageBox::warning(this,tr("WARNING"),tr("Log file is not writable"));
+ }
+ else
+ break;
+ }
+}
+
+/*!
+ \brief "Stop log" operation.
+ \sa startLog()
+ */
+void PyConsole_EditorBase::stopLog()
+{
+ myLogFile = QString();
+}
+
+/*!
+ \brief Put string to the log file
+ */
+void PyConsole_EditorBase::putLog( const QString& s )
+{
+ if ( !myLogFile.isEmpty() ) {
+ QFile file( myLogFile );
+ if ( !file.open( QFile::Append ) )
+ return;
+
+ QTextStream out (&file);
+ out << s;
+
+ file.close();
+ }
+}
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SALOME SALOMEGUI : implementation of desktop and GUI kernel
+// File : PyConsole_Editor.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#ifndef PYCONSOLE_EDITORBASE_H
+#define PYCONSOLE_EDITORBASE_H
+
+#include "PyConsole.h"
+
+#include <QTextEdit>
+
+class PyConsole_Interp;
+class PyInterp_Request;
+class QEventLoop;
+
+class PYCONSOLE_EXPORT PyConsole_EditorBase : public QTextEdit
+{
+ Q_OBJECT;
+
+public:
+ PyConsole_EditorBase( PyConsole_Interp* theInterp, QWidget *theParent = 0 );
+ ~PyConsole_EditorBase();
+
+ PyConsole_Interp* getInterp() const;
+
+ virtual void addText( const QString& str, const bool newBlock = false, const bool isError = false );
+ bool isCommand( const QString& str ) const;
+
+ virtual void exec( const QString& command );
+ void execAndWait( const QString& command );
+
+ bool isSync() const;
+ void setIsSync( const bool );
+
+ bool isSuppressOutput() const;
+ void setIsSuppressOutput(const bool);
+
+ bool isShowBanner() const;
+ void setIsShowBanner( const bool );
+
+ bool isLogging() const;
+
+ virtual QSize sizeHint() const;
+ void dumpImpl(const QString& fileName);
+ bool startLogImpl( const QString& );
+public slots:
+ void cut();
+ void paste();
+ void clear();
+ void handleReturn();
+ void onPyInterpChanged( PyConsole_Interp* );
+ void dump(const QString& fileName);
+ void dump();
+ void startLog();
+ bool startLog( const QString& );
+ void stopLog();
+ void putLog( const QString& );
+
+protected:
+ virtual void dropEvent( QDropEvent* event );
+ virtual void mouseReleaseEvent( QMouseEvent* event );
+ virtual void keyPressEvent ( QKeyEvent* event);
+ virtual void customEvent( QEvent* event);
+ virtual void dumpSlot();
+ virtual void startLogSlot();
+
+ virtual PyInterp_Request* createRequest( const QString& );
+
+ /** Convenience function */
+ inline int promptSize() const { return myPrompt.size(); }
+
+ PyConsole_Interp* myInterp; //!< python interpreter
+
+ QString myCommandBuffer; //!< python command buffer
+ QString myCurrentCommand; //!< currently being printed command
+ QString myPrompt; //!< current command line prompt
+ int myCmdInHistory; //!< current history command index
+ QString myLogFile; //!< current output log
+ QStringList myHistory; //!< commands history buffer
+ QEventLoop* myEventLoop; //!< internal event loop
+ QString myBanner; //!< current banner
+ bool myShowBanner; //!< 'show banner' flag
+ QStringList myQueue; //!< python commands queue
+ bool myIsSync; //!< synchronous mode flag
+ bool myIsSuppressOutput; //!< suppress output flag
+};
+
+#endif // PYCONSOLE_EDITORBASE_H
+++ /dev/null
-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-// Author : Adrien Bruneton (CEA/DEN)
-// Created on: 4 avr. 2013
-
-#include "PyConsole.h"
-#include <Python.h>
-
-#include <QKeyEvent>
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QTextCharFormat>
-#include <QRegExp>
-#include <QMimeData>
-
-#include "PyConsole_EnhEditor.h"
-#include "PyConsole_EnhInterp.h"
-#include "PyConsole_Request.h"
-#include "PyInterp_Dispatcher.h"
-
-// Initialize list of valid separators
-static const char * tmp_a[] = {" ", "(", "[","+", "-", "*", "/", ";", "^", "="};
-const std::vector<QString> PyConsole_EnhEditor::SEPARATORS = \
- std::vector<QString>(tmp_a, tmp_a + sizeof(tmp_a)/sizeof(tmp_a[0]));
-
-/**
- * Constructor.
- * @param interp the interpreter linked to the editor
- * @param parent parent widget
- */
-PyConsole_EnhEditor::PyConsole_EnhEditor(PyConsole_Interp* interp, QWidget* parent) :
- PyConsole_Editor(interp, parent),
- _tab_mode(false),
- _cursor_pos(-1),
- _multi_line_paste(false),
- _multi_line_content()
-{
- document()->setUndoRedoEnabled(true);
-}
-
-/**
- * Overrides. Catches the TAB and Ctrl+TAB combinations.
- * @param event
- */
-void PyConsole_EnhEditor::keyPressEvent ( QKeyEvent* event)
-{
- // check if <Ctrl> is pressed
- bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
- // check if <Shift> is pressed
- bool shftPressed = event->modifiers() & Qt::ShiftModifier;
-
- if (event->key() == Qt::Key_Tab && !shftPressed)
- {
- if (!ctrlPressed)
- handleTab();
- else
- {
- clearCompletion();
- handleBackTab();
- }
- PyConsole_Editor::keyPressEvent(event);
- }
- else
- {
- // If ctrl is not pressed (and sth else is pressed with it),
- // or if ctrl is not pressed alone
- if (!ctrlPressed || (ctrlPressed && event->key() != Qt::Key_Control))
- {
- clearCompletion();
- _cursor_pos = -1;
- }
- // Discard ctrl pressed alone:
- if (event->key() != Qt::Key_Control)
- PyConsole_Editor::keyPressEvent(event);
- }
-}
-
-/**
- * Whenever the mouse is clicked, clear the completion.
- * @param e
- */
-void PyConsole_EnhEditor::mousePressEvent(QMouseEvent* e)
-{
- clearCompletion();
- _cursor_pos = -1;
- PyConsole_Editor::mousePressEvent(e);
-}
-
-/**
- * Clear in the editor the block of text displayed after having hit <TAB>.
- */
-void PyConsole_EnhEditor::clearCompletion()
-{
- // Delete completion text if present
- if (_tab_mode)
- {
- // Remove completion display
- document()->undo();
- // Remove trailing line return:
- QTextCursor tc(textCursor());
- tc.setPosition(document()->characterCount()-1);
- setTextCursor(tc);
- textCursor().deletePreviousChar();
- // TODO: before wait for any TAB event to be completed
- if ( myInterp )
- myInterp->clearCompletion();
- }
- _tab_mode = false;
-}
-
-/**
- * Handle the sequence of events after having hit <TAB>
- */
-void PyConsole_EnhEditor::handleTab()
-{
- if (_tab_mode)
- {
- // Already tab mode - nothing to do !
- return;
- }
-
- QTextCursor cursor(textCursor());
-
- // Cursor at end of input
- cursor.movePosition(QTextCursor::End);
- setTextCursor(cursor);
-
- // Save cursor position if needed
- if (_cursor_pos == -1)
- _cursor_pos = textCursor().position();
-
- // get last line
- QTextBlock par = document()->end().previous();
- if ( !par.isValid() ) return;
-
- // Switch to completion mode
- _tab_mode = true;
-
- QString cmd = par.text().mid(promptSize());
-
- // Post completion request
- // Editor will be informed via a custom event that completion has been run
- PyInterp_Request* req = createTabRequest(cmd);
- PyInterp_Dispatcher::Get()->Exec(req);
-}
-
-/**
- * Handles what happens after hitting Ctrl-TAB
- */
-void PyConsole_EnhEditor::handleBackTab()
-{
- QTextCursor cursor(textCursor());
-
- if (_cursor_pos == -1)
- {
- // Invalid cursor position - we can't do anything:
- return;
- }
- // Ensure cursor is at the end of command line
- cursor.setPosition(_cursor_pos);
- cursor.movePosition(QTextCursor::EndOfLine);
- //setCursor(cursor);
-
- // Delete last completed text
- int i = cursor.position() - _cursor_pos;
- cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, i);
- cursor.removeSelectedText();
- _cursor_pos = -1;
-}
-
-/**
- * Create the Python requested that will be posted to the interpreter to
- * get the completions.
- * @param input line typed by the user at the time TAB was hit
- * @return a CompletionCommand
- * @sa CompletionCommand
- */
-PyInterp_Request* PyConsole_EnhEditor::createTabRequest( const QString& input )
-{
- // Parse input to extract on what part the dir() has to be executed
- QString input2(input);
-
- // Split up to the last syntaxical separator
- int lastSp = -1;
- for (std::vector<QString>::const_iterator i = SEPARATORS.begin(); i != SEPARATORS.end(); i++)
- {
- int j = input2.lastIndexOf(*i);
- if (j > lastSp)
- lastSp = j;
- }
- if (lastSp >= 0)
- input2 = input.mid(lastSp+1);
-
- // Detect a qualified name (with a point)
- int lastPt = input2.lastIndexOf(QString("."));
-
- // Split the 2 surrounding parts of the qualified name
- if (lastPt != -1)
- {
- _compl_before_point = input2.left(lastPt);
- _compl_after_point = input2.mid(lastPt+1);
- }
- else
- {
- // No point found - do a global matching -
- // (the following will call dir() with an empty string)
- _compl_after_point = input2;
- _compl_before_point = QString("");
- }
-
- return new CompletionCommand( myInterp, _compl_before_point,
- _compl_after_point, this, isSync() );
-}
-
-/**
- * Format completion results - this is where we should create 3 columns etc ...
- * @param matches list of possible completions
- * @param result return value
- */
-void PyConsole_EnhEditor::formatCompletion(const QStringList& matches, QString& result) const
-{
- int sz = matches.size();
-
- if (sz > MAX_COMPLETIONS)
- {
- sz = MAX_COMPLETIONS;
- result.append("[Too many matches! Displaying first ones only ...]\n");
- }
-
- for (int i = 0; i < sz; ++i)
- {
- result.append(matches[i]);
- result.append("\n");
- }
-}
-
-/**
- * Override. Catches the events generated by the enhanced interpreter after the execution
- * of a completion request.
- * @param event
- */
-void PyConsole_EnhEditor::customEvent( QEvent* event )
-{
- QStringList matches;
- QString first_match, comple_text, doc, base;
- QTextCursor cursor(textCursor());
- QTextBlockFormat bf;
- QTextCharFormat cf;
- int cursorPos;
-
- switch( event->type() )
- {
- case PyInterp_Event::ES_TAB_COMPLETE_OK:
- {
- // Extract corresponding matches from the interpreter
- matches = getInterp()->getLastMatches();
- doc = getInterp()->getDocStr();
-
- if (matches.size() == 0)
- {
- // Completion successful but nothing returned.
- _tab_mode = false;
- _cursor_pos = -1;
- return;
- }
-
- // Only one match - complete directly and update doc string window
- if (matches.size() == 1)
- {
- first_match = matches[0].mid(_compl_after_point.size());
- cursor.insertText(first_match);
- _tab_mode = false;
- if (doc.isEmpty())
- emit updateDoc(formatDocHTML("(no documentation available)\n"));
- else
- emit updateDoc(formatDocHTML(doc));
- }
- else
- {
- // Detect if there is a common base to all available completion
- // In this case append this base to the text already
- extractCommon(matches, base);
- first_match = base.mid(_compl_after_point.size());
- cursor.insertText(first_match);
-
- // If this happens to match exaclty the first completion
- // also provide doc
- if (base == matches[0])
- {
- doc = formatDocHTML(doc);
- emit updateDoc(doc);
- }
-
- // Print all matching completion in a "undo-able" block
- cursorPos = cursor.position();
- cursor.insertBlock();
- cursor.beginEditBlock();
-
- // Insert all matches
- QTextCharFormat cf;
- cf.setForeground(QBrush(Qt::darkGreen));
- cursor.setCharFormat(cf);
- formatCompletion(matches, comple_text);
- cursor.insertText(comple_text);
- cursor.endEditBlock();
-
- // Position cursor where it was before inserting the completion list:
- cursor.setPosition(cursorPos);
- setTextCursor(cursor);
- }
- break;
- }
- case PyInterp_Event::ES_TAB_COMPLETE_ERR:
- {
- // Tab completion was unsuccessful, switch off mode:
- _tab_mode = false;
- _cursor_pos = -1;
- break;
- }
- case PyInterp_Event::ES_OK:
- case PyInterp_Event::ES_ERROR:
- case PyInterp_Event::ES_INCOMPLETE:
- {
- // Before everything else, call super()
- PyConsole_Editor::customEvent(event);
- // If we are in multi_paste_mode, process the next item:
- multiLineProcessNextLine();
- break;
- }
- default:
- {
- PyConsole_Editor::customEvent( event );
- break;
- }
- }
-}
-
-/**
- * Extract the common leading part of all strings in matches.
- * @param matches
- * @param result
- */
-void PyConsole_EnhEditor::extractCommon(const QStringList& matches, QString& result) const
-{
- result = "";
- int charIdx = 0;
-
- if (matches.size() < 2)
- return;
-
- while (true)
- {
- if (charIdx >= matches[0].size())
- return;
- QChar ch = matches[0][charIdx];
- for (int j = 1; j < matches.size(); j++)
- if (charIdx >= matches[j].size() || matches[j][charIdx] != ch)
- return;
- result += ch;
- charIdx++;
- }
-}
-
-/**
- * Format the doc string in HTML format with the first line in bold blue
- * @param doc initial doc string
- * @return HTML string
- */
-QString PyConsole_EnhEditor::formatDocHTML(const QString & doc) const
-{
- QString templ = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" ") +
- QString(" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n ") +
- QString("<html><head><meta name=\"qrichtext\" content=\"1\" /> ") +
- QString("<style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style> ") +
- QString("</head><body style=\" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;\">\n") +
- QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">") +
- QString("<span style=\" font-weight:600; color:#0000ff;\">%1</span></p>") +
- QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%2</p>") +
- QString("</body></html>");
-
- QString fst, rest("");
-
- // Extract first line of doc
- int idx = doc.indexOf("\n");
- if (idx > 0)
- {
- fst = doc.left(idx);
- rest = doc.mid(idx+1);
- }
- else
- {
- fst = doc;
- }
-
- fst = fst.replace("\n", " ");
- rest = rest.replace("\n", " ");
- return templ.arg(fst).arg(rest);
-}
-
-/**
- * Handle properly multi-line pasting. Qt4 doc recommends overriding this function.
- * If the pasted text doesn't contain a line return, no special treatment is done.
- * @param source
- */
-void PyConsole_EnhEditor::insertFromMimeData(const QMimeData* source)
-{
- if (_multi_line_paste)
- return;
-
- if (source->hasText())
- {
- QString s = source->text();
- if (s.contains("\n"))
- multilinePaste(s);
- else
- PyConsole_Editor::insertFromMimeData(source);
- }
- else
- {
- PyConsole_Editor::insertFromMimeData(source);
- }
-}
-
-
-void PyConsole_EnhEditor::multilinePaste(const QString & s)
-{
- // Turn on multi line pasting mode
- _multi_line_paste = true;
-
- // Split the string:
- QString s2 = s;
- s2.replace("\r", ""); // Windows string format converted to Unix style
-
- QStringList lst = s2.split(QChar('\n'), QString::KeepEmptyParts);
-
- // Perform the proper paste operation for the first line to handle the case where
- // sth was already there:
- QMimeData source;
- source.setText(lst[0]);
- PyConsole_Editor::insertFromMimeData(&source);
-
- // Prepare what will have to be executed after the first line:
- _multi_line_content = std::queue<QString>();
- for (int i = 1; i < lst.size(); ++i)
- _multi_line_content.push(lst[i]);
-
- // Trigger the execution of the first (mixed) line
- handleReturn();
-
- // See customEvent() and multiLineProcessNext() for the rest of the handling.
-}
-
-/**
- * Process the next line in the queue of a multiple copy/paste:
- */
-void PyConsole_EnhEditor::multiLineProcessNextLine()
-{
- if (!_multi_line_paste)
- return;
-
- QString line(_multi_line_content.front());
- _multi_line_content.pop();
- if (!_multi_line_content.size())
- {
- // last line in the queue, just paste it
- addText(line, false, false);
- _multi_line_paste = false;
- }
- else
- {
- // paste the line and simulate a <RETURN> key stroke
- addText(line, false, false);
- handleReturn();
- }
-}
+++ /dev/null
-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-// Author : Adrien Bruneton (CEA/DEN)
-// Created on: 4 avr. 2013
-
-#ifndef PYCONSOLE_ENHEDITOR_H_
-#define PYCONSOLE_ENHEDITOR_H_
-
-#include "PyConsole.h"
-#include "PyConsole_Editor.h"
-
-#include <QObject>
-#include <queue>
-
-/**
- * Enhanced Python editor handling tab completion.
- */
-class PYCONSOLE_EXPORT PyConsole_EnhEditor: public PyConsole_Editor
-{
- Q_OBJECT;
-
-public:
- PyConsole_EnhEditor(PyConsole_Interp* interp, QWidget* parent = 0);
- virtual ~PyConsole_EnhEditor() {}
-
-signals:
- /**
- * Signal emitted by the editor widget when the doc string should be updated.
- * @param doc a HTML block with the formatted doc string.
- * TODO: for now this signal is left uncaught.
- */
- void updateDoc(QString doc);
-
-protected:
- /** List of separators identifying the last parsable token for completion */
- static const std::vector<QString> SEPARATORS;
-
- /** Maximum number of completions shown at once */
- static const int MAX_COMPLETIONS = 70;
-
- /** Are we in completion mode */
- bool _tab_mode;
-
- /** String on which the dir() comamnd is executed */
- QString _compl_before_point;
- /** String on which the results of the dir() are matched */
- QString _compl_after_point;
-
- /** Cursor position when <TAB> is hit */
- int _cursor_pos;
-
- /** Are we currently pasting several lines */
- bool _multi_line_paste;
-
- /** Queue of lines being pasted */
- std::queue<QString> _multi_line_content;
-
- // Overrides:
- virtual void keyPressEvent ( QKeyEvent* event);
- virtual void customEvent( QEvent* event);
- virtual void mousePressEvent( QMouseEvent* event );
- virtual void insertFromMimeData(const QMimeData* source);
-
- virtual PyInterp_Request* createTabRequest( const QString& input );
- virtual void handleTab();
- virtual void handleBackTab();
- virtual void clearCompletion();
- virtual void formatCompletion(const QStringList& matches, QString& result) const;
- virtual QString formatDocHTML(const QString & doc) const;
-
- virtual void multilinePaste(const QString & s);
- virtual void multiLineProcessNextLine();
-
-private:
- void extractCommon(const QStringList& matches, QString& result) const;
-
-};
-
-#endif /* PYCONSOLE_ENHEDITOR_H_ */
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+#include "PyConsole.h"
+#include <Python.h>
+
+#include <QKeyEvent>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextCharFormat>
+#include <QRegExp>
+#include <QMimeData>
+
+#include "PyConsole_EnhEditorBase.h"
+#include "PyConsole_EnhInterp.h"
+#include "PyConsole_Request.h"
+#include "PyInterp_Dispatcher.h"
+
+// Initialize list of valid separators
+static const char * tmp_a[] = {" ", "(", "[","+", "-", "*", "/", ";", "^", "="};
+const std::vector<QString> PyConsole_EnhEditorBase::SEPARATORS = \
+ std::vector<QString>(tmp_a, tmp_a + sizeof(tmp_a)/sizeof(tmp_a[0]));
+
+/**
+ * Constructor.
+ * @param interp the interpreter linked to the editor
+ * @param parent parent widget
+ */
+PyConsole_EnhEditorBase::PyConsole_EnhEditorBase(PyConsole_Interp* interp, QWidget* parent) :
+ PyConsole_EditorBase(interp, parent),
+ _tab_mode(false),
+ _cursor_pos(-1),
+ _multi_line_paste(false),
+ _multi_line_content()
+{
+ document()->setUndoRedoEnabled(true);
+}
+
+/**
+ * Overrides. Catches the TAB and Ctrl+TAB combinations.
+ * @param event
+ */
+void PyConsole_EnhEditorBase::keyPressEvent ( QKeyEvent* event)
+{
+ // check if <Ctrl> is pressed
+ bool ctrlPressed = event->modifiers() & Qt::ControlModifier;
+ // check if <Shift> is pressed
+ bool shftPressed = event->modifiers() & Qt::ShiftModifier;
+
+ if (event->key() == Qt::Key_Tab && !shftPressed)
+ {
+ if (!ctrlPressed)
+ handleTab();
+ else
+ {
+ clearCompletion();
+ handleBackTab();
+ }
+ PyConsole_EditorBase::keyPressEvent(event);
+ }
+ else
+ {
+ // If ctrl is not pressed (and sth else is pressed with it),
+ // or if ctrl is not pressed alone
+ if (!ctrlPressed || (ctrlPressed && event->key() != Qt::Key_Control))
+ {
+ clearCompletion();
+ _cursor_pos = -1;
+ }
+ // Discard ctrl pressed alone:
+ if (event->key() != Qt::Key_Control)
+ PyConsole_EditorBase::keyPressEvent(event);
+ }
+}
+
+/**
+ * Whenever the mouse is clicked, clear the completion.
+ * @param e
+ */
+void PyConsole_EnhEditorBase::mousePressEvent(QMouseEvent* e)
+{
+ clearCompletion();
+ _cursor_pos = -1;
+ PyConsole_EditorBase::mousePressEvent(e);
+}
+
+/**
+ * Clear in the editor the block of text displayed after having hit <TAB>.
+ */
+void PyConsole_EnhEditorBase::clearCompletion()
+{
+ // Delete completion text if present
+ if (_tab_mode)
+ {
+ // Remove completion display
+ document()->undo();
+ // Remove trailing line return:
+ QTextCursor tc(textCursor());
+ tc.setPosition(document()->characterCount()-1);
+ setTextCursor(tc);
+ textCursor().deletePreviousChar();
+ // TODO: before wait for any TAB event to be completed
+ if ( myInterp )
+ myInterp->clearCompletion();
+ }
+ _tab_mode = false;
+}
+
+/**
+ * Handle the sequence of events after having hit <TAB>
+ */
+void PyConsole_EnhEditorBase::handleTab()
+{
+ if (_tab_mode)
+ {
+ // Already tab mode - nothing to do !
+ return;
+ }
+
+ QTextCursor cursor(textCursor());
+
+ // Cursor at end of input
+ cursor.movePosition(QTextCursor::End);
+ setTextCursor(cursor);
+
+ // Save cursor position if needed
+ if (_cursor_pos == -1)
+ _cursor_pos = textCursor().position();
+
+ // get last line
+ QTextBlock par = document()->end().previous();
+ if ( !par.isValid() ) return;
+
+ // Switch to completion mode
+ _tab_mode = true;
+
+ QString cmd = par.text().mid(promptSize());
+
+ // Post completion request
+ // Editor will be informed via a custom event that completion has been run
+ PyInterp_Request* req = createTabRequest(cmd);
+ PyInterp_Dispatcher::Get()->Exec(req);
+}
+
+/**
+ * Handles what happens after hitting Ctrl-TAB
+ */
+void PyConsole_EnhEditorBase::handleBackTab()
+{
+ QTextCursor cursor(textCursor());
+
+ if (_cursor_pos == -1)
+ {
+ // Invalid cursor position - we can't do anything:
+ return;
+ }
+ // Ensure cursor is at the end of command line
+ cursor.setPosition(_cursor_pos);
+ cursor.movePosition(QTextCursor::EndOfLine);
+ //setCursor(cursor);
+
+ // Delete last completed text
+ int i = cursor.position() - _cursor_pos;
+ cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, i);
+ cursor.removeSelectedText();
+ _cursor_pos = -1;
+}
+
+/**
+ * Create the Python requested that will be posted to the interpreter to
+ * get the completions.
+ * @param input line typed by the user at the time TAB was hit
+ * @return a CompletionCommand
+ * @sa CompletionCommand
+ */
+PyInterp_Request* PyConsole_EnhEditorBase::createTabRequest( const QString& input )
+{
+ // Parse input to extract on what part the dir() has to be executed
+ QString input2(input);
+
+ // Split up to the last syntaxical separator
+ int lastSp = -1;
+ for (std::vector<QString>::const_iterator i = SEPARATORS.begin(); i != SEPARATORS.end(); i++)
+ {
+ int j = input2.lastIndexOf(*i);
+ if (j > lastSp)
+ lastSp = j;
+ }
+ if (lastSp >= 0)
+ input2 = input.mid(lastSp+1);
+
+ // Detect a qualified name (with a point)
+ int lastPt = input2.lastIndexOf(QString("."));
+
+ // Split the 2 surrounding parts of the qualified name
+ if (lastPt != -1)
+ {
+ _compl_before_point = input2.left(lastPt);
+ _compl_after_point = input2.mid(lastPt+1);
+ }
+ else
+ {
+ // No point found - do a global matching -
+ // (the following will call dir() with an empty string)
+ _compl_after_point = input2;
+ _compl_before_point = QString("");
+ }
+
+ return new CompletionCommand( myInterp, _compl_before_point,
+ _compl_after_point, this, isSync() );
+}
+
+/**
+ * Format completion results - this is where we should create 3 columns etc ...
+ * @param matches list of possible completions
+ * @param result return value
+ */
+void PyConsole_EnhEditorBase::formatCompletion(const QStringList& matches, QString& result) const
+{
+ int sz = matches.size();
+
+ if (sz > MAX_COMPLETIONS)
+ {
+ sz = MAX_COMPLETIONS;
+ result.append("[Too many matches! Displaying first ones only ...]\n");
+ }
+
+ for (int i = 0; i < sz; ++i)
+ {
+ result.append(matches[i]);
+ result.append("\n");
+ }
+}
+
+/**
+ * Override. Catches the events generated by the enhanced interpreter after the execution
+ * of a completion request.
+ * @param event
+ */
+void PyConsole_EnhEditorBase::customEvent( QEvent* event )
+{
+ QStringList matches;
+ QString first_match, comple_text, doc, base;
+ QTextCursor cursor(textCursor());
+ QTextBlockFormat bf;
+ QTextCharFormat cf;
+ int cursorPos;
+
+ switch( event->type() )
+ {
+ case PyInterp_Event::ES_TAB_COMPLETE_OK:
+ {
+ // Extract corresponding matches from the interpreter
+ matches = getInterp()->getLastMatches();
+ doc = getInterp()->getDocStr();
+
+ if (matches.size() == 0)
+ {
+ // Completion successful but nothing returned.
+ _tab_mode = false;
+ _cursor_pos = -1;
+ return;
+ }
+
+ // Only one match - complete directly and update doc string window
+ if (matches.size() == 1)
+ {
+ first_match = matches[0].mid(_compl_after_point.size());
+ cursor.insertText(first_match);
+ _tab_mode = false;
+ if (doc.isEmpty())
+ emit updateDoc(formatDocHTML("(no documentation available)\n"));
+ else
+ emit updateDoc(formatDocHTML(doc));
+ }
+ else
+ {
+ // Detect if there is a common base to all available completion
+ // In this case append this base to the text already
+ extractCommon(matches, base);
+ first_match = base.mid(_compl_after_point.size());
+ cursor.insertText(first_match);
+
+ // If this happens to match exaclty the first completion
+ // also provide doc
+ if (base == matches[0])
+ {
+ doc = formatDocHTML(doc);
+ emit updateDoc(doc);
+ }
+
+ // Print all matching completion in a "undo-able" block
+ cursorPos = cursor.position();
+ cursor.insertBlock();
+ cursor.beginEditBlock();
+
+ // Insert all matches
+ QTextCharFormat cf;
+ cf.setForeground(QBrush(Qt::darkGreen));
+ cursor.setCharFormat(cf);
+ formatCompletion(matches, comple_text);
+ cursor.insertText(comple_text);
+ cursor.endEditBlock();
+
+ // Position cursor where it was before inserting the completion list:
+ cursor.setPosition(cursorPos);
+ setTextCursor(cursor);
+ }
+ break;
+ }
+ case PyInterp_Event::ES_TAB_COMPLETE_ERR:
+ {
+ // Tab completion was unsuccessful, switch off mode:
+ _tab_mode = false;
+ _cursor_pos = -1;
+ break;
+ }
+ case PyInterp_Event::ES_OK:
+ case PyInterp_Event::ES_ERROR:
+ case PyInterp_Event::ES_INCOMPLETE:
+ {
+ // Before everything else, call super()
+ PyConsole_EditorBase::customEvent(event);
+ // If we are in multi_paste_mode, process the next item:
+ multiLineProcessNextLine();
+ break;
+ }
+ default:
+ {
+ PyConsole_EditorBase::customEvent( event );
+ break;
+ }
+ }
+}
+
+/**
+ * Extract the common leading part of all strings in matches.
+ * @param matches
+ * @param result
+ */
+void PyConsole_EnhEditorBase::extractCommon(const QStringList& matches, QString& result) const
+{
+ result = "";
+ int charIdx = 0;
+
+ if (matches.size() < 2)
+ return;
+
+ while (true)
+ {
+ if (charIdx >= matches[0].size())
+ return;
+ QChar ch = matches[0][charIdx];
+ for (int j = 1; j < matches.size(); j++)
+ if (charIdx >= matches[j].size() || matches[j][charIdx] != ch)
+ return;
+ result += ch;
+ charIdx++;
+ }
+}
+
+/**
+ * Format the doc string in HTML format with the first line in bold blue
+ * @param doc initial doc string
+ * @return HTML string
+ */
+QString PyConsole_EnhEditorBase::formatDocHTML(const QString & doc) const
+{
+ QString templ = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" ") +
+ QString(" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n ") +
+ QString("<html><head><meta name=\"qrichtext\" content=\"1\" /> ") +
+ QString("<style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style> ") +
+ QString("</head><body style=\" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;\">\n") +
+ QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">") +
+ QString("<span style=\" font-weight:600; color:#0000ff;\">%1</span></p>") +
+ QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%2</p>") +
+ QString("</body></html>");
+
+ QString fst, rest("");
+
+ // Extract first line of doc
+ int idx = doc.indexOf("\n");
+ if (idx > 0)
+ {
+ fst = doc.left(idx);
+ rest = doc.mid(idx+1);
+ }
+ else
+ {
+ fst = doc;
+ }
+
+ fst = fst.replace("\n", " ");
+ rest = rest.replace("\n", " ");
+ return templ.arg(fst).arg(rest);
+}
+
+/**
+ * Handle properly multi-line pasting. Qt4 doc recommends overriding this function.
+ * If the pasted text doesn't contain a line return, no special treatment is done.
+ * @param source
+ */
+void PyConsole_EnhEditorBase::insertFromMimeData(const QMimeData* source)
+{
+ if (_multi_line_paste)
+ return;
+
+ if (source->hasText())
+ {
+ QString s = source->text();
+ if (s.contains("\n"))
+ multilinePaste(s);
+ else
+ PyConsole_EditorBase::insertFromMimeData(source);
+ }
+ else
+ {
+ PyConsole_EditorBase::insertFromMimeData(source);
+ }
+}
+
+
+void PyConsole_EnhEditorBase::multilinePaste(const QString & s)
+{
+ // Turn on multi line pasting mode
+ _multi_line_paste = true;
+
+ // Split the string:
+ QString s2 = s;
+ s2.replace("\r", ""); // Windows string format converted to Unix style
+
+ QStringList lst = s2.split(QChar('\n'), QString::KeepEmptyParts);
+
+ // Perform the proper paste operation for the first line to handle the case where
+ // sth was already there:
+ QMimeData source;
+ source.setText(lst[0]);
+ PyConsole_EditorBase::insertFromMimeData(&source);
+
+ // Prepare what will have to be executed after the first line:
+ _multi_line_content = std::queue<QString>();
+ for (int i = 1; i < lst.size(); ++i)
+ _multi_line_content.push(lst[i]);
+
+ // Trigger the execution of the first (mixed) line
+ handleReturn();
+
+ // See customEvent() and multiLineProcessNext() for the rest of the handling.
+}
+
+/**
+ * Process the next line in the queue of a multiple copy/paste:
+ */
+void PyConsole_EnhEditorBase::multiLineProcessNextLine()
+{
+ if (!_multi_line_paste)
+ return;
+
+ QString line(_multi_line_content.front());
+ _multi_line_content.pop();
+ if (!_multi_line_content.size())
+ {
+ // last line in the queue, just paste it
+ addText(line, false, false);
+ _multi_line_paste = false;
+ }
+ else
+ {
+ // paste the line and simulate a <RETURN> key stroke
+ addText(line, false, false);
+ handleReturn();
+ }
+}
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+#ifndef PYCONSOLE_ENHEDITORBASE_H_
+#define PYCONSOLE_ENHEDITORBASE_H_
+
+#include "PyConsole.h"
+#include "PyConsole_EditorBase.h"
+
+#include <QObject>
+#include <queue>
+
+/**
+ * Enhanced Python editor handling tab completion.
+ */
+class PYCONSOLE_EXPORT PyConsole_EnhEditorBase : public PyConsole_EditorBase
+{
+ Q_OBJECT;
+
+public:
+ PyConsole_EnhEditorBase(PyConsole_Interp* interp, QWidget* parent = 0);
+ virtual ~PyConsole_EnhEditorBase() {}
+
+signals:
+ /**
+ * Signal emitted by the editor widget when the doc string should be updated.
+ * @param doc a HTML block with the formatted doc string.
+ * TODO: for now this signal is left uncaught.
+ */
+ void updateDoc(QString doc);
+
+protected:
+ /** List of separators identifying the last parsable token for completion */
+ static const std::vector<QString> SEPARATORS;
+
+ /** Maximum number of completions shown at once */
+ static const int MAX_COMPLETIONS = 70;
+
+ /** Are we in completion mode */
+ bool _tab_mode;
+
+ /** String on which the dir() comamnd is executed */
+ QString _compl_before_point;
+ /** String on which the results of the dir() are matched */
+ QString _compl_after_point;
+
+ /** Cursor position when <TAB> is hit */
+ int _cursor_pos;
+
+ /** Are we currently pasting several lines */
+ bool _multi_line_paste;
+
+ /** Queue of lines being pasted */
+ std::queue<QString> _multi_line_content;
+
+ // Overrides:
+ virtual void keyPressEvent ( QKeyEvent* event);
+ virtual void customEvent( QEvent* event);
+ virtual void mousePressEvent( QMouseEvent* event );
+ virtual void insertFromMimeData(const QMimeData* source);
+
+ virtual PyInterp_Request* createTabRequest( const QString& input );
+ virtual void handleTab();
+ virtual void handleBackTab();
+ virtual void clearCompletion();
+ virtual void formatCompletion(const QStringList& matches, QString& result) const;
+ virtual QString formatDocHTML(const QString & doc) const;
+
+ virtual void multilinePaste(const QString & s);
+ virtual void multiLineProcessNextLine();
+
+private:
+ void extractCommon(const QStringList& matches, QString& result) const;
+
+};
+
+#endif /* PYCONSOLE_ENHEDITORBASE_H_ */
<!DOCTYPE TS>
<TS version="2.0" language="en_US">
<context>
- <name>PyConsole_Console</name>
+ <name>PyConsole_ConsoleBase</name>
<message>
- <location filename="../PyConsole_Console.cxx" line="216"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="216"/>
<source>EDIT_COPY_CMD</source>
<translation>&Copy</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="221"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
<source>EDIT_PASTE_CMD</source>
<translation>&Paste</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="226"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
<source>EDIT_CLEAR_CMD</source>
<translation>Clea&r</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="231"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="231"/>
<source>EDIT_SELECTALL_CMD</source>
<translation>Select &All</translation>
</message>
</message>
</context>
<context>
- <name>PyConsole_Editor</name>
+ <name>PyConsole_EditorBase</name>
<message>
- <source>TOT_DUMP_PYCOMMANDS</source>
- <translation>Dump commands</translation>
+ <source>Choose python file where to store</source>
+ <translation>Choose python file where to store dump</translation>
</message>
<message>
- <source>TOT_SAVE_PYLOG</source>
- <translation>Save log</translation>
+ <source>Python scripts ext (*.py)</source>
+ <translation>Python scripts (*.py)</translation>
</message>
<message>
- <source>PYTHON_FILES_FILTER</source>
- <translation>PYTHON Files (*.py)</translation>
+ <source>WARNING</source>
+ <translation>WARNING !</translation>
</message>
<message>
- <source>LOG_FILES_FILTER</source>
- <translation>Log files (*.log *.txt)</translation>
+ <source>Python file has not been written</source>
+ <translation>Python file has not been written !</translation>
</message>
<message>
- <source>ERR_FILE_NOT_WRITABLE</source>
- <translation>File is not writable!</translation>
+ <source>Choose python file where to store log</source>
+ <translation>Choose python file where to store log</translation>
+ </message>
+ <message>
+ <source>Log files ext (*.log *.txt)</source>
+ <translation>Log files extension (*.log *.txt)</translation>
+ </message>
+ <message>
+ <source>Log file is not writable</source>
+ <translation>Log file is not writable !</translation>
</message>
</context>
</TS>
<!DOCTYPE TS>
<TS version="2.0" language="fr_FR">
<context>
- <name>PyConsole_Console</name>
+ <name>PyConsole_ConsoleBase</name>
<message>
- <location filename="../PyConsole_Console.cxx" line="216"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="216"/>
<source>EDIT_COPY_CMD</source>
<translation>&Copier</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="221"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
<source>EDIT_PASTE_CMD</source>
<translation>C&oller</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="226"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
<source>EDIT_CLEAR_CMD</source>
<translation>&Effacer</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="231"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="231"/>
<source>EDIT_SELECTALL_CMD</source>
<translation>&Tout sélectionner</translation>
</message>
</message>
</context>
<context>
- <name>PyConsole_Editor</name>
+ <name>PyConsole_EditorBase</name>
<message>
- <source>TOT_DUMP_PYCOMMANDS</source>
- <translation>&Générer le script des commandes</translation>
+ <source>Choose python file where to store</source>
+ <translation>Choisissez un fichier python où sauver le dump</translation>
+ </message>
+ <message>
+ <source>Python scripts ext (*.py)</source>
+ <translation>Scripts Python (*.py)</translation>
+ </message>
+ <message>
+ <source>WARNING</source>
+ <translation>Attention !</translation>
</message>
<message>
- <source>TOT_SAVE_PYLOG</source>
- <translation>Sauver la trace</translation>
+ <source>Python file has not been written</source>
+ <translation>Le fichier Python n'a pas été écrit !</translation>
</message>
<message>
- <source>PYTHON_FILES_FILTER</source>
- <translation>Fichiers PYTHON (*.py)</translation>
+ <source>Choose python file where to store log</source>
+ <translation>Choisissez un fichier python où sauver le log</translation>
</message>
<message>
- <source>LOG_FILES_FILTER</source>
- <translation>Fichiers de trace (*.log *.txt)</translation>
+ <source>Log files ext (*.log *.txt)</source>
+ <translation>Extensions possible des fichiers log (*.log *.txt)</translation>
</message>
<message>
- <source>ERR_FILE_NOT_WRITABLE</source>
- <translation>Le fichier n'est pas accessible en écriture!</translation>
+ <source>Log file is not writable</source>
+ <translation>Le fichier log sélectionné n'est pas writable !</translation>
</message>
</context>
</TS>
<!DOCTYPE TS>
<TS version="2.0" language="ja" sourcelanguage="en">
<context>
- <name>PyConsole_Console</name>
+ <name>PyConsole_ConsoleBase</name>
<message>
- <location filename="../PyConsole_Console.cxx" line="216"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="216"/>
<source>EDIT_COPY_CMD</source>
<translation>コピー(&C)</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="221"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="221"/>
<source>EDIT_PASTE_CMD</source>
<translation>貼り付け(&P)</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="226"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="226"/>
<source>EDIT_CLEAR_CMD</source>
<translation>削除(&r)</translation>
</message>
<message>
- <location filename="../PyConsole_Console.cxx" line="231"/>
+ <location filename="../PyConsole_ConsoleBase.cxx" line="231"/>
<source>EDIT_SELECTALL_CMD</source>
<translation>すべて選択します。(&A)</translation>
</message>
</message>
</context>
<context>
- <name>PyConsole_Editor</name>
+ <name>PyConsole_EditorBase</name>
<message>
- <source>TOT_DUMP_PYCOMMANDS</source>
- <translation>スクリプト コマンドを生成します。</translation>
+ <source>Choose python file where to store</source>
+ <translation>Choose python file where to store dump</translation>
</message>
<message>
- <source>TOT_SAVE_PYLOG</source>
- <translation>ログの保存</translation>
+ <source>Python scripts ext (*.py)</source>
+ <translation>Python scripts (*.py)</translation>
</message>
<message>
- <source>PYTHON_FILES_FILTER</source>
- <translation>ファイル (*.py) PYTHON</translation>
+ <source>WARNING</source>
+ <translation>WARNING !</translation>
</message>
<message>
- <source>LOG_FILES_FILTER</source>
- <translation>ログファイル (*.log *.txt)</translation>
+ <source>Python file has not been written</source>
+ <translation>Python file has not been written !</translation>
</message>
<message>
- <source>ERR_FILE_NOT_WRITABLE</source>
- <translation>ファイルが書き込み禁止です!</translation>
+ <source>Choose python file where to store log</source>
+ <translation>Choose python file where to store log</translation>
</message>
- </context>
+ <message>
+ <source>Log files ext (*.log *.txt)</source>
+ <translation>Log files extension (*.log *.txt)</translation>
+ </message>
+ <message>
+ <source>Log file is not writable</source>
+ <translation>Log file is not writable !</translation>
+ </message>
+</context>
</TS>
return qtPath;
}
+/*!
+ Creates font from string description
+*/
+QFont Qtx::stringToFont( const QString& fontDescription )
+{
+ QFont font;
+ if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
+ font = QFont( "Courier", 11 );
+ return font;
+}
+
#ifndef WIN32
#include <X11/Xlib.h>
#include <QString>
#include <QList>
+#include <QFont>
#include <QColor>
#include <QImage>
#include <QPixmap>
static QString qtDir( const QString& = QString());
+ static QFont stringToFont( const QString& fontDescription );
+
#ifndef WIN32
static void* getDisplay();
static Qt::HANDLE getVisual();
${PROJECT_SOURCE_DIR}/src/ObjBrowser
${PROJECT_SOURCE_DIR}/src/PyInterp
${PROJECT_SOURCE_DIR}/src/PyConsole
+ ${PROJECT_SOURCE_DIR}/src/SalomePyConsole
${PROJECT_SOURCE_DIR}/src/Qtx
${PROJECT_SOURCE_DIR}/src/SALOME_PYQT/SALOME_PYQT_GUILight
${PROJECT_SOURCE_DIR}/src/STD
#include "SUIT_Tools.h"
#include "SUIT_ViewManager.h"
#include "SUIT_ViewWindow.h"
-#include "PyConsole_Console.h"
+#include "SalomePyConsole_Console.h"
#include <QAction>
#include <QApplication>
virtual void Execute()
{
if ( getApplication() ) {
- PyConsole_Console* pyConsole = getApplication()->pythonConsole( false );
+ SalomePyConsole_Console* pyConsole = getApplication()->pythonConsole( false );
if ( pyConsole ) pyConsole->startLog( myFileName );
}
}
virtual void Execute()
{
if ( getApplication() ) {
- PyConsole_Console* pyConsole = getApplication()->pythonConsole( false );
+ SalomePyConsole_Console* pyConsole = getApplication()->pythonConsole( false );
if ( pyConsole ) pyConsole->stopLog();
}
}
return QRect( qMin( x1, x2 ), qMin( y1, y2 ), qAbs( x2 - x1 ), qAbs( y2 - y1 ) );
}
-/*!
- Creates font from string description
-*/
-QFont SUIT_Tools::stringToFont( const QString& fontDescription )
-{
- QFont font;
- if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
- font = QFont( "Courier", 11 );
- return font;
-}
-
/*!
Creates font's string description
*/
static QRect makeRect( const int x1, const int y1, const int x2, const int y2 );
static QString fontToString( const QFont& font );
- static QFont stringToFont( const QString& fontDescription );
static void centerWidget( QWidget* src, const QWidget* ref );
};
IF(SALOME_USE_PYCONSOLE)
INCLUDE_DIRECTORIES(
${PYTHON_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}/src/SalomePyConsole
${PROJECT_SOURCE_DIR}/src/PyConsole
${PROJECT_SOURCE_DIR}/src/PyInterp
)
ENDIF()
IF(SALOME_USE_PYCONSOLE)
- LIST(APPEND _link_LIBRARIES PyInterp PyConsole)
+ LIST(APPEND _link_LIBRARIES PyInterp SalomePyConsole)
ENDIF()
IF(SALOME_USE_GLVIEWER)
#ifndef DISABLE_PYCONSOLE
#include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
- #include <PyConsole_Console.h>
+ #include <SalomePyConsole_Console.h>
#include "SalomeApp_NoteBook.h"
#endif
#include "SalomeApp_Application.h"
// import/execute python scripts
if ( pyfiles.count() > 0 && activeStudy() ) {
SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
- PyConsole_Console* pyConsole = pythonConsole();
+ SalomePyConsole_Console* pyConsole = pythonConsole();
if ( appStudy && pyConsole ) {
_PTR(Study) aStudy = appStudy->studyDS();
if ( !aStudy->GetProperties()->IsLocked() ) {
QString command = QString("execfile(r\"%1\")").arg(aFile);
#ifndef DISABLE_PYCONSOLE
- PyConsole_Console* pyConsole = pythonConsole();
+ SalomePyConsole_Console* pyConsole = pythonConsole();
if ( pyConsole )
pyConsole->exec( command );
QString command = QString("execfile(r\"%1\")").arg(aFile);
#ifndef DISABLE_PYCONSOLE
- PyConsole_Console* pyConsole = pythonConsole();
+ SalomePyConsole_Console* pyConsole = pythonConsole();
if ( pyConsole )
pyConsole->exec( command );
#ifndef DISABLE_PYCONSOLE
else if ( flag == WT_PyConsole )
{
- PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
+ SalomePyConsole_Console* pyCons = new SalomePyConsole_EnhConsole( desktop(), getPyInterp() );
pyCons->setObjectName( "pythonConsole" );
pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
#ifndef DISABLE_PYCONSOLE
- PyConsole_Console* pyConsole = app->pythonConsole();
+ SalomePyConsole_Console* pyConsole = app->pythonConsole();
if ( pyConsole )
pyConsole->execAndWait( command );
#endif
// Module : GUI
//
#include "PyConsole_Interp.h" // this include must be first (see PyInterp_base.h)!
-#include "PyConsole_Console.h"
+#include "SalomePyConsole_Console.h"
#include "SalomeApp_NoteBook.h"
#include "SalomeApp_Application.h"
myParentTable->myRows[ aNumRows - 1 ]->GetValue().isEmpty();
SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
- PyConsole_Console* pyConsole = app->pythonConsole();
+ SalomePyConsole_Console* pyConsole = app->pythonConsole();
PyConsole_Interp* pyInterp = app->getPyInterp();
PyLockWrapper aLock; // Acquire GIL
std::string command = "import salome_notebook ; ";
return false;
SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
- PyConsole_Console* pyConsole = app->pythonConsole();
+ SalomePyConsole_Console* pyConsole = app->pythonConsole();
PyConsole_Interp* pyInterp = app->getPyInterp();
PyLockWrapper aLock; // Acquire GIL
std::string command = "import salome_notebook ; ";
#include "SalomeApp_Study.h"
#include "SalomeApp_Application.h"
-//#include <SUIT_ResourceMgr.h>
+#include <SUIT_Session.h>
+#include <SUIT_ResourceMgr.h>
#include <SUIT_ViewManager.h>
#include <SUIT_ViewWindow.h>
#include <QtxWorkstack.h>
myApp->modules( mlist );
QListIterator<CAM_Module*> itM( mlist );
CAM_Module* module = 0;
+ SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
+ bool loadLight = aResMgr->booleanValue( "Study", "autoload_light_modules", true );
+
while ( itM.hasNext() ) {
module = itM.next();
if ( !module ) continue;
- if ( SalomeApp_Module* sModule = dynamic_cast<SalomeApp_Module*>( module ) ) {
- ip->append( "AP_MODULES_LIST", sModule->moduleName().toStdString() );
- sModule->storeVisualParameters( savePoint );
+
+ if ( LightApp_Module* lModule = dynamic_cast<LightApp_Module*>( module ) ) {
+ if (loadLight)
+ ip->append( "AP_MODULES_LIST", lModule->moduleName().toStdString() );
+ if ( SalomeApp_Module* sModule = dynamic_cast<SalomeApp_Module*>( module ) )
+ sModule->storeVisualParameters( savePoint );
}
}
</section>
<section name="Study">
<!-- General study settings -->
+ <parameter name="autoload_light_modules" value="true" />
<parameter name="store_positions" value="true" />
<parameter name="store_tool_positions" value="true" />
<parameter name="store_visual_state" value="false" />
--- /dev/null
+# Copyright (C) 2012-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+INCLUDE(UseQtExt)
+
+# --- options ---
+
+# additional include directories
+INCLUDE_DIRECTORIES(
+ ${QT_INCLUDES}
+ ${PYTHON_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}/src/SalomePyConsole
+ ${PROJECT_SOURCE_DIR}/src/PyConsole
+ ${PROJECT_SOURCE_DIR}/src/Qtx
+ ${PROJECT_SOURCE_DIR}/src/SUIT
+ ${PROJECT_SOURCE_DIR}/src/Event
+ ${PROJECT_SOURCE_DIR}/src/PyInterp
+)
+
+# additional preprocessor / compiler flags
+ADD_DEFINITIONS(${QT_DEFINITIONS} ${PYTHON_DEFINITIONS})
+
+# libraries to link to
+SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} qtx suit PyConsole)
+
+# --- headers ---
+
+# header files / to be processed by moc
+SET(_moc_HEADERS
+ SalomePyConsole_Console.h
+ SalomePyConsole_Editor.h
+ SalomePyConsole_EnhEditor.h
+)
+
+# header files / no moc processing
+SET(_other_HEADERS
+ SalomePyConsole.h
+)
+
+# header files / to install
+SET(SalomePyConsole_HEADERS ${_moc_HEADERS} ${_other_HEADERS})
+
+# --- resources ---
+
+# --- sources ---
+# resource files / to be processed by lrelease
+
+SET(_ts_RESOURCES
+ resources/SalomePyConsole_msg_en.ts
+ resources/SalomePyConsole_msg_fr.ts
+ resources/SalomePyConsole_msg_ja.ts
+)
+
+# sources / moc wrappings
+QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS})
+
+# sources / static
+SET(_other_SOURCES
+ SalomePyConsole_Console.cxx
+ SalomePyConsole_EnhEditor.cxx
+ SalomePyConsole_Editor.cxx
+)
+
+# sources / to compile
+SET(PyConsole_SOURCES ${_other_SOURCES} ${_moc_SOURCES})
+
+# --- rules ---
+
+ADD_LIBRARY(SalomePyConsole ${PyConsole_SOURCES})
+TARGET_LINK_LIBRARIES(SalomePyConsole ${_link_LIBRARIES})
+INSTALL(TARGETS SalomePyConsole EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
+
+INSTALL(FILES ${SalomePyConsole_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
+QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}")
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File : PyConsole.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#if !defined ( SALOMEPYCONSOLE_H )
+#define SALOMEPYCONSOLE_H
+
+// ========================================================
+// set dllexport type for Win platform
+#ifdef WIN32
+# if defined SALOMEPYCONSOLE_EXPORTS || defined SalomePyConsole_EXPORTS
+# define SALOMEPYCONSOLE_EXPORT __declspec(dllexport)
+# else
+# define SALOMEPYCONSOLE_EXPORT __declspec(dllimport)
+# endif
+#else // WIN32
+# define SALOMEPYCONSOLE_EXPORT
+#endif // WIN32
+
+// ========================================================
+// avoid warning messages
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#pragma warning (disable : 4251)
+#endif
+
+#endif // SALOMEPYCONSOLE_H
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File : PyConsole_Console.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+/*!
+ \class PyConsole_Console
+ \brief Python console widget.
+*/
+
+#include "PyConsole_Interp.h" /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
+#include "SalomePyConsole_Console.h"
+#include "SalomePyConsole_Editor.h"
+#include "SalomePyConsole_EnhEditor.h"
+#include "PyConsole_EnhInterp.h"
+
+#include <Qtx.h>
+
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
+#include <QEvent>
+#include <QMenu>
+#include <QVBoxLayout>
+
+PyConsole_EditorBase *SalomePyConsole_Console::SalomePyConsole_Interp_Creator::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new SalomePyConsole_Editor(interp,console); }
+
+PyConsole_Interp *SalomePyConsole_Console::SalomePyConsole_Interp_Creator::createInterp( ) const
+{ return new PyConsole_Interp; }
+
+/*!
+ \brief Constructor.
+
+ Creates new python console widget.
+ \param parent parent widget
+ \param interp python interpreter
+*/
+SalomePyConsole_Console::SalomePyConsole_Console( QWidget* parent, PyConsole_Interp* interp )
+ : PyConsole_ConsoleBase( parent, interp, 0 )
+{
+ SalomePyConsole_Interp_Creator crea;
+ defaultConstructor(interp,crea);
+}
+
+/**
+ * Protected constructor.
+ */
+SalomePyConsole_Console::SalomePyConsole_Console( QWidget* parent, PyConsole_Interp* i, SalomePyConsole_Editor* e )
+ : PyConsole_ConsoleBase(parent,i,e)
+{
+}
+
+/*!
+ \brief Destructor.
+
+ Does nothing for the moment.
+*/
+SalomePyConsole_Console::~SalomePyConsole_Console()
+{
+}
+
+/*!
+ \brief Create the context popup menu.
+
+ Fill in the popup menu with the commands.
+
+ \param menu context popup menu
+*/
+void SalomePyConsole_Console::contextMenuPopup( QMenu *menu )
+{
+ PyConsole_ConsoleBase::contextMenuPopup(menu);
+}
+
+/*!
+ \brief Event handler.
+
+ Handles context menu request event.
+
+ \param o object
+ \param e event
+ \return True if the event is processed and further processing should be stopped
+*/
+bool SalomePyConsole_Console::eventFilter( QObject* o, QEvent* e )
+{
+ if ( o == myEditor->viewport() && e->type() == QEvent::ContextMenu )
+ {
+ contextMenuRequest( (QContextMenuEvent*)e );
+ return true;
+ }
+ return QWidget::eventFilter( o, e );
+}
+
+PyConsole_EditorBase *SalomePyConsole_EnhConsole::SalomePyConsole_Interp_EnhCreator::createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const
+{ return new SalomePyConsole_EnhEditor(interp,console); }
+
+PyConsole_Interp *SalomePyConsole_EnhConsole::SalomePyConsole_Interp_EnhCreator::createInterp( ) const
+{ return new PyConsole_EnhInterp; }
+
+/**
+ * Similar to constructor of the base class but using enhanced objects.
+ * TODO: this should really be done in a factory to avoid code duplication.
+ * @param parent
+ * @param interp
+ */
+SalomePyConsole_EnhConsole::SalomePyConsole_EnhConsole( QWidget* parent, PyConsole_Interp* interp )
+ : SalomePyConsole_Console( parent, interp, 0 )
+{
+ SalomePyConsole_Interp_EnhCreator crea;
+ defaultConstructor(interp,crea);
+}
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File : PyConsole_Console.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#ifndef SALOMEPYCONSOLE_CONSOLE_H
+#define SALOMEPYCONSOLE_CONSOLE_H
+
+#include "SalomePyConsole.h"
+#include <PyConsole_ConsoleBase.h>
+#include <SUIT_PopupClient.h>
+#include <QWidget>
+#include <QMap>
+
+class SalomePyConsole_Interp;
+class SalomePyConsole_Editor;
+
+class SALOMEPYCONSOLE_EXPORT SalomePyConsole_Console : public PyConsole_ConsoleBase, public SUIT_PopupClient
+{
+ Q_OBJECT
+public:
+
+ struct SalomePyConsole_Interp_Creator : public PyConsole_Interp_CreatorBase
+ {
+ virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+ virtual PyConsole_Interp *createInterp( ) const;
+ };
+
+public:
+ SalomePyConsole_Console( QWidget* parent, PyConsole_Interp* interp = 0 );
+ virtual ~SalomePyConsole_Console();
+ //! \brief Get popup client symbolic name
+ virtual QString popupClientType() const { return QString( "PyConsole" ); }
+ virtual void contextMenuPopup( QMenu* );
+ virtual bool eventFilter( QObject*, QEvent* );
+protected:
+ SalomePyConsole_Console( QWidget* parent, PyConsole_Interp*, SalomePyConsole_Editor*);
+};
+
+/**
+ * Enhance console object providing auto-completion.
+ * Similar to PyConsole_Console except that an enhanced interpreter and enhanced editor
+ * are encapsulated.
+ */
+class PYCONSOLE_EXPORT SalomePyConsole_EnhConsole : public SalomePyConsole_Console
+{
+ Q_OBJECT
+public:
+
+ struct SalomePyConsole_Interp_EnhCreator : public PyConsole_Interp_CreatorBase
+ {
+ virtual PyConsole_EditorBase *createEditor( PyConsole_Interp *interp, PyConsole_ConsoleBase *console ) const;
+ virtual PyConsole_Interp *createInterp( ) const;
+ };
+
+public:
+ SalomePyConsole_EnhConsole( QWidget* parent, PyConsole_Interp* interp = 0 );
+ virtual ~SalomePyConsole_EnhConsole() {}
+};
+
+#endif // SALOMEPYCONSOLE_CONSOLE_H
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SALOME SALOMEGUI : implementation of desktop and GUI kernel
+// File : PyConsole_Editor.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+/*!
+ \class PyConsole_Editor
+ \brief Python command line interpreter front-end GUI widget.
+
+ This class provides simple GUI interface to the Python interpreter, including basic
+ navigation operations, executing commands (both interactively and programmatically),
+ copy-paste operations, history of the commands and so on.
+
+ Here below is the shortcut keyboard boundings used for navigation and other operations:
+ - <Enter> : execute current command
+ - <Ctrl><Break> : clear current command
+ - <Escape> : clear current command
+ - <Up> : previous command in the history
+ - <Shift><Up> : move cursor one row up with selection
+ - <Ctrl><Up> : move cursor one row up without selection
+ - <Ctrl><Shift><Up> : move cursor one row up with selection
+ - <Down> : next command in the history
+ - <Shift><Down> : move cursor one row down with selection
+ - <Ctrl><Down> : move cursor one row down without selection
+ - <Ctrl><Shift><Down> : move cursor one row down with selection
+ - <Left> : move one symbol left without selection
+ - <Shift><Left> : move one symbol left with selection
+ - <Ctrl><Left> : move one word left without selection
+ - <Ctrl><Shift><Left> : move one word left with selection
+ - <Right> : move one symbol right without selection
+ - <Shift><Right> : move one symbol right with selection
+ - <Ctrl><Right> : move one word right without selection
+ - <Ctrl><Shift><Right> : move one word right with selection
+ - <PgUp> : first command in the history
+ - <Shift><PgUp> : move one page up with selection
+ - <Ctrl><PgUp> : move one page up without selection
+ - <Ctrl><Shift><PgUp> : scroll one page up
+ - <PgDn> : last command in the history
+ - <Shift><PgDn> : move one page down with selection
+ - <Ctrl><PgDn> : move one page down without selection
+ - <Ctrl><Shift><PgDn> : scroll one page down
+ - <Home> : move to the beginning of the line without selection
+ - <Shift><Home> : move to the beginning of the line with selection
+ - <Ctrl><Home> : move to the very first symbol without selection
+ - <Ctrl><Shift><Home> : move to the very first symbol with selection
+ - <End> : move to the end of the line without selection
+ - <Shift><End> : move to the end of the line with selection
+ - <Ctrl><End> : move to the very last symbol without selection
+ - <Ctrl><Shift><End> : move to the very last symbol with selection
+ - <Backspace> : delete symbol before the cursor
+ / remove selected text and put it to the clipboard (cut)
+ - <Shift><Backspace> : delete previous word
+ / remove selected text and put it to the clipboard (cut)
+ - <Ctrl><Backspace> : delete text from the cursor to the beginning of the line
+ / remove selected text and put it to the clipboard (cut)
+ - <Delete> : delete symbol after the cursor
+ / remove selected text and put it to the clipboard (cut)
+ - <Shift><Delete> : delete next word
+ / remove selected text and put it to the clipboard (cut)
+ - <Ctrl><Delete> : delete text from the cursor to the end of the line
+ / remove selected text and put it to the clipboard (cut)
+ - <Ctrl><Insert> : copy
+ - <Shift><Insert> : paste
+ - <Ctrl><V> : paste
+ - <Ctrl><C> : copy
+ - <Ctrl><X> : cut
+ - <Ctrl><V> : paste
+*/
+
+#include "PyConsole_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "SalomePyConsole_Editor.h"
+#include "PyConsole_Event.h"
+#include "PyInterp_Event.h"
+#include "PyInterp_Dispatcher.h"
+#include "PyConsole_Request.h"
+
+#include "SUIT_FileValidator.h"
+#include "SUIT_MessageBox.h"
+#include "SUIT_FileDlg.h"
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDropEvent>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMouseEvent>
+#include <QScrollBar>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextDocument>
+#include <QTextStream>
+#include <QChar>
+#include <QFileInfo>
+
+class DumpCommandsFileValidator : public SUIT_FileValidator
+{
+ public:
+ DumpCommandsFileValidator( QWidget* parent = 0 ) : SUIT_FileValidator ( parent ) {};
+ virtual ~DumpCommandsFileValidator() {};
+ virtual bool canSave( const QString& file, bool permissions );
+};
+
+bool DumpCommandsFileValidator::canSave(const QString& file, bool permissions)
+{
+ QFileInfo fi( file );
+ if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
+ SUIT_MessageBox::critical( parent(),
+ QObject::tr("WRN_WARNING"),
+ QObject::tr("WRN_FILE_NAME_BAD") );
+ return false;
+ }
+ return SUIT_FileValidator::canSave( file, permissions);
+}
+
+/*!
+ \brief Constructor.
+
+ Creates python editor window.
+ \param theInterp python interper
+ \param theParent parent widget
+*/
+SalomePyConsole_Editor::SalomePyConsole_Editor( PyConsole_Interp* theInterp,
+ QWidget* theParent )
+ : PyConsole_EditorBase(theInterp,theParent)
+{
+}
+
+/*!
+ \brief Destructor.
+*/
+SalomePyConsole_Editor::~SalomePyConsole_Editor()
+{
+}
+
+
+void SalomePyConsole_Editor::StaticDumpSlot(PyConsole_EditorBase *base)
+{
+ QStringList aFilters;
+ aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
+
+ QString fileName = SUIT_FileDlg::getFileName( base, QString(),
+ aFilters, tr( "TOT_DUMP_PYCOMMANDS" ),
+ false, true, new DumpCommandsFileValidator( base ) );
+ base->dumpImpl(fileName);
+}
+
+/*!
+ \brief "Dump commands" operation.
+ */
+void SalomePyConsole_Editor::dumpSlot()
+{
+ SalomePyConsole_Editor::StaticDumpSlot(this);
+}
+
+void SalomePyConsole_Editor::StaticStartLogSlot(PyConsole_EditorBase *base)
+{
+ QStringList aFilters;
+ aFilters.append( tr( "LOG_FILES_FILTER" ) );
+
+ while (1) {
+ QString fileName = SUIT_FileDlg::getFileName( base, QString(),
+ aFilters, tr( "TOT_SAVE_PYLOG" ),
+ false, true );
+ if ( !fileName.isEmpty() ) {
+ if ( base->startLogImpl( fileName ) ) {
+ break;
+ }
+ else {
+ SUIT_MessageBox::critical( base,
+ QObject::tr("ERR_ERROR"),
+ QObject::tr("ERR_FILE_NOT_WRITABLE") );
+ }
+ }
+ else {
+ break;
+ }
+ }
+}
+
+/*!
+ \brief "Start log" operation.
+ */
+void SalomePyConsole_Editor::startLogSlot()
+{
+ StaticStartLogSlot(this);
+}
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SALOME SALOMEGUI : implementation of desktop and GUI kernel
+// File : PyConsole_Editor.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+#ifndef SALOMEPYCONSOLE_EDITOR_H
+#define SALOMEPYCONSOLE_EDITOR_H
+
+#include "SalomePyConsole.h"
+#include "PyConsole_EditorBase.h"
+
+#include <QTextEdit>
+
+class PyConsole_Interp;
+class PyInterp_Request;
+class QEventLoop;
+
+class PYCONSOLE_EXPORT SalomePyConsole_Editor : public PyConsole_EditorBase
+{
+ Q_OBJECT;
+public:
+ SalomePyConsole_Editor( PyConsole_Interp* theInterp, QWidget *theParent = 0 );
+ ~SalomePyConsole_Editor();
+ static void StaticDumpSlot(PyConsole_EditorBase *base);
+ static void StaticStartLogSlot(PyConsole_EditorBase *base);
+protected:
+ virtual void dumpSlot();
+ virtual void startLogSlot();
+};
+
+#endif // SALOMEPYCONSOLE_EDITOR_H
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+#include "SalomePyConsole.h"
+#include <Python.h>
+
+#include <QKeyEvent>
+#include <QTextBlock>
+#include <QTextCursor>
+#include <QTextCharFormat>
+#include <QRegExp>
+#include <QMimeData>
+
+#include "SalomePyConsole_EnhEditor.h"
+#include "SalomePyConsole_Editor.h"
+
+/**
+ * Constructor.
+ * @param interp the interpreter linked to the editor
+ * @param parent parent widget
+ */
+SalomePyConsole_EnhEditor::SalomePyConsole_EnhEditor(PyConsole_Interp* interp, QWidget* parent) :
+ PyConsole_EnhEditorBase(interp, parent)
+{
+}
+
+void SalomePyConsole_EnhEditor::dumpSlot()
+{
+ SalomePyConsole_Editor::StaticDumpSlot(this);
+}
+
+void SalomePyConsole_EnhEditor::startLogSlot()
+{
+ SalomePyConsole_Editor::StaticStartLogSlot(this);
+}
--- /dev/null
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// Author : Adrien Bruneton (CEA/DEN)
+// Created on: 4 avr. 2013
+
+#ifndef SALOMEPYCONSOLE_ENHEDITOR_H_
+#define SALOMEPYCONSOLE_ENHEDITOR_H_
+
+#include "SalomePyConsole.h"
+#include "PyConsole_EnhEditorBase.h"
+
+#include <QObject>
+#include <queue>
+
+/**
+ * Enhanced Python editor handling tab completion.
+ */
+class PYCONSOLE_EXPORT SalomePyConsole_EnhEditor : public PyConsole_EnhEditorBase
+{
+ Q_OBJECT;
+public:
+ SalomePyConsole_EnhEditor(PyConsole_Interp* interp, QWidget* parent = 0);
+ virtual ~SalomePyConsole_EnhEditor() {}
+protected:
+ virtual void dumpSlot();
+ virtual void startLogSlot();
+};
+
+#endif /* PYCONSOLE_ENHEDITOR_H_ */
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="en_US">
+<context>
+ <name>SalomePyConsole_Editor</name>
+ <message>
+ <source>TOT_DUMP_PYCOMMANDS</source>
+ <translation>Dump commands</translation>
+ </message>
+ <message>
+ <source>TOT_SAVE_PYLOG</source>
+ <translation>Save log</translation>
+ </message>
+ <message>
+ <source>PYTHON_FILES_FILTER</source>
+ <translation>PYTHON Files (*.py)</translation>
+ </message>
+ <message>
+ <source>LOG_FILES_FILTER</source>
+ <translation>Log files (*.log *.txt)</translation>
+ </message>
+ <message>
+ <source>ERR_FILE_NOT_WRITABLE</source>
+ <translation>File is not writable!</translation>
+ </message>
+</context>
+</TS>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+<context>
+ <name>SalomePyConsole_Editor</name>
+ <message>
+ <source>TOT_DUMP_PYCOMMANDS</source>
+ <translation>&Générer le script des commandes</translation>
+ </message>
+ <message>
+ <source>TOT_SAVE_PYLOG</source>
+ <translation>Sauver la trace</translation>
+ </message>
+ <message>
+ <source>PYTHON_FILES_FILTER</source>
+ <translation>Fichiers PYTHON (*.py)</translation>
+ </message>
+ <message>
+ <source>LOG_FILES_FILTER</source>
+ <translation>Fichiers de trace (*.log *.txt)</translation>
+ </message>
+ <message>
+ <source>ERR_FILE_NOT_WRITABLE</source>
+ <translation>Le fichier n'est pas accessible en écriture!</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>SalomePyConsole_Editor</name>
+ <message>
+ <source>TOT_DUMP_PYCOMMANDS</source>
+ <translation>スクリプト コマンドを生成します。</translation>
+ </message>
+ <message>
+ <source>TOT_SAVE_PYLOG</source>
+ <translation>ログの保存</translation>
+ </message>
+ <message>
+ <source>PYTHON_FILES_FILTER</source>
+ <translation>ファイル (*.py) PYTHON</translation>
+ </message>
+ <message>
+ <source>LOG_FILES_FILTER</source>
+ <translation>ログファイル (*.log *.txt)</translation>
+ </message>
+ <message>
+ <source>ERR_FILE_NOT_WRITABLE</source>
+ <translation>ファイルが書き込み禁止です!</translation>
+ </message>
+ </context>
+</TS>