From: vsr Date: Thu, 28 Jul 2016 13:45:47 +0000 (+0300) Subject: PyEditor refactoring X-Git-Tag: V8_1_0b1~7 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=697be73cb19b395786e76773a7e4e304c8cfa476;p=modules%2Fgui.git PyEditor refactoring * Remove dependency on Qtx in PyEditor package * Redesign editor class; * Change the way preferences are managed; * Add main window class for PyEditor; * Add pyeditor standalone executable; * Redesign build procedure for PyEditor; * Move PyEditor to standalone project in tools directory; * Add Python wrappings (via sip) for PyEditor widget. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7161a9cc..f4b1b7fed 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -119,7 +119,6 @@ ENDIF() # Python Viewer ## IF(SALOME_USE_PYVIEWER) - ADD_SUBDIRECTORY(PyEditor) ADD_SUBDIRECTORY(PyViewer) ENDIF(SALOME_USE_PYVIEWER) diff --git a/src/LightApp/LightApp_Application.cxx b/src/LightApp/LightApp_Application.cxx index 70ddd87e9..9702d04f2 100644 --- a/src/LightApp/LightApp_Application.cxx +++ b/src/LightApp/LightApp_Application.cxx @@ -85,6 +85,7 @@ #include #include +#include #include #include #include @@ -2898,8 +2899,9 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref ) int pyeditTab = pref->addPreference( tr( "PREF_TAB_PYEDITOR" ), salomeCat ); // ... "Font settings" group <> int pyFontGroup = pref->addPreference( tr( "PREF_GROUP_PY_FONT" ), pyeditTab ); - pref->addPreference( tr( "PREF_PY_FONT" ), pyFontGroup, - LightApp_Preferences::Font, "PyEditor", "Font" ); + int pyFont = pref->addPreference( tr( "PREF_PY_FONT" ), pyFontGroup, + LightApp_Preferences::Font, "PyEditor", "Font" ); + pref->setItemProperty( "features", QtxFontEdit::Family | QtxFontEdit::Size | QtxFontEdit::UserSize, pyFont ); // ... "Font settings" group <> // ... "Display settings" group <> int pyDispGroup = pref->addPreference( tr( "PREF_GROUP_PY_DISPLAY" ), pyeditTab ); @@ -3686,39 +3688,6 @@ void LightApp_Application::preferencesChanged( const QString& sec, const QString } } #endif - -#ifndef DISABLE_PYVIEWER - if ( sec == QString( "PyViewer" ) && ( param == QString( "HighlightCurrentLine" ) || - param == QString( "LineNumberArea" ) || - param == QString( "TextWrapping" ) || - param == QString( "CenterCursorOnScroll" ) || - param == QString( "TabSpaceVisible" ) || - param == QString( "TabSize" ) || - param == QString( "VerticalEdge" ) || - param == QString( "NumberColumns" ) || - param == QString( "Font" ) ) ) - { - QList lst; - viewManagers( PyViewer_Viewer::Type(), lst ); - QListIterator itPy( lst ); - while ( itPy.hasNext() ) - { - SUIT_ViewManager* viewMgr = itPy.next(); - SUIT_ViewModel* vm = viewMgr->getViewModel(); - if ( !vm || !vm->inherits( "PyViewer_Viewer" ) ) - continue; - - PyViewer_Viewer* pyEditVM = dynamic_cast( vm ); - - viewMgr->setViewModel( vm ); - PyViewer_ViewWindow* pyView = dynamic_cast( viewMgr->getActiveView() ); - if( pyView ) - { - pyView->setPreferences(); - } - } - } -#endif } /*! diff --git a/src/PyEditor/CMakeLists.txt b/src/PyEditor/CMakeLists.txt deleted file mode 100644 index be15881f7..000000000 --- a/src/PyEditor/CMakeLists.txt +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) 2015-2016 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 : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -# - -INCLUDE(UseQtExt) - -# --- options --- - -# additional include directories -INCLUDE_DIRECTORIES( - ${QT_INCLUDES} - ${PROJECT_SOURCE_DIR}/src/Qtx -) - -# additional preprocessor / compiler flags -ADD_DEFINITIONS(${QT_DEFINITIONS}) - -# libraries to link to -SET(_link_LIBRARIES ${PLATFORM_LIBS} ${QT_LIBRARIES} qtx) - -# --- headers --- - -# header files / to be processed by moc -SET(_moc_HEADERS - PyEditor_Editor.h - PyEditor_LineNumberArea.h - PyEditor_PyHighlighter.h - PyEditor_SettingsDlg.h -) - -# header files / no moc processing -SET(_other_HEADERS - PyEditor.h - PyEditor_Settings.h -) - -# header files / to install -SET(PyEditor_HEADERS ${_moc_HEADERS} ${_other_HEADERS}) - -# --- resources --- - -# resource files / to be processed by lrelease -SET(RESOURCES_PATH resources) - -SET(_ts_RESOURCES - ${RESOURCES_PATH}/translations/PyEditor_msg_en.ts - ${RESOURCES_PATH}/translations/PyEditor_msg_fr.ts - ${RESOURCES_PATH}/translations/PyEditor_msg_ja.ts -) - -# sources / moc wrappings -QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS}) - -# sources / static -SET(_other_SOURCES - PyEditor_Editor.cxx - PyEditor_LineNumberArea.cxx - PyEditor_PyHighlighter.cxx - PyEditor_Settings.cxx - PyEditor_SettingsDlg.cxx -) - -# sources / to compile -SET(PyEditor_SOURCES ${_other_SOURCES} ${_moc_SOURCES}) - -# --- rules --- -ADD_LIBRARY(PyEditor ${PyEditor_SOURCES}) -TARGET_LINK_LIBRARIES(PyEditor ${_link_LIBRARIES}) -INSTALL(TARGETS PyEditor EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS}) - -INSTALL(FILES ${PyEditor_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS}) -QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}") diff --git a/src/PyEditor/PyEditor.h b/src/PyEditor/PyEditor.h deleted file mode 100644 index 165f53a77..000000000 --- a/src/PyEditor/PyEditor.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor.h -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#ifdef WIN32 - -#if defined PYEDITOR_EXPORTS || defined PyEditor_EXPORTS -#define PYEDITOR_EXPORT __declspec(dllexport) -#else -#define PYEDITOR_EXPORT __declspec(dllimport) -#endif - -#else -#define PYEDITOR_EXPORT -#endif // WIN32 diff --git a/src/PyEditor/PyEditor_Editor.cxx b/src/PyEditor/PyEditor_Editor.cxx deleted file mode 100644 index 141d7ee9d..000000000 --- a/src/PyEditor/PyEditor_Editor.cxx +++ /dev/null @@ -1,804 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_Editor.cxx -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -//Local includes -#include "PyEditor_Editor.h" -#include "PyEditor_LineNumberArea.h" -#include "PyEditor_PyHighlighter.h" -#include "PyEditor_Settings.h" - -//Qtx includes -#include - -//Qt includes -#include -#include - -/*! - \class PyEditor_Editor - \brief Viewer/Editor is used to edit and show advanced plain text. -*/ - -/*! - \brief Constructor. - \param isSingle flag determined single application or reccesed. - \param theParent parent widget -*/ -PyEditor_Editor::PyEditor_Editor( bool isSingle, QtxResourceMgr* theMgr, QWidget* theParent ) - : QPlainTextEdit( theParent ) -{ - my_Settings = new PyEditor_Settings( theMgr, isSingle ); - - // Create line number area - my_LineNumberArea = new PyEditor_LineNumberArea( this ); - my_LineNumberArea->setMouseTracking( true ); - - my_SyntaxHighlighter = new PyEditor_PyHighlighter( this->document() ); - - // Signals and slots - connect( this, SIGNAL( blockCountChanged( int ) ), this, SLOT( updateLineNumberAreaWidth( int ) ) ); - connect( this, SIGNAL( updateRequest( QRect, int ) ), this, SLOT( updateLineNumberArea( QRect, int ) ) ); - connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( updateHighlightCurrentLine() ) ); - connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( matchParentheses() ) ); - - updateStatement(); -} - -/*! - \brief Destructor. -*/ -PyEditor_Editor::~PyEditor_Editor() -{ -} - -/*! - Updates editor. - */ -void PyEditor_Editor::updateStatement() -{ - //Set font size - QFont aFont = font(); - aFont.setFamily( settings()->p_Font.family() ); - aFont.setPointSize( settings()->p_Font.pointSize() ); - setFont( aFont ); - - // Set line wrap mode - setLineWrapMode( settings()->p_TextWrapping ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap ); - - // Center the cursor on screen - setCenterOnScroll( settings()->p_CenterCursorOnScroll ); - - // Set size white spaces - setTabStopWidth( settings()->p_TabSize * 10 ); - - // Update current line highlight - updateHighlightCurrentLine(); - - // Update line numbers area - updateLineNumberAreaWidth( 0 ); - - my_SyntaxHighlighter->rehighlight(); - viewport()->update(); -} - -/*! - SLOT: Delete the current selection's contents - */ -void PyEditor_Editor::deleteSelected() -{ - QTextCursor aCursor = textCursor(); - if ( aCursor.hasSelection() ) - aCursor.removeSelectedText(); - setTextCursor( aCursor ); -} - -/*! - \brief Reimplemented calss is to receive key press events for the plain text widget. - \param theEvent event - */ -void PyEditor_Editor::keyPressEvent( QKeyEvent* theEvent ) -{ - if ( theEvent->type() == QEvent::KeyPress ) - { - int aKey = theEvent->key(); - Qt::KeyboardModifiers aCtrl = theEvent->modifiers() & Qt::ControlModifier; - Qt::KeyboardModifiers aShift = theEvent->modifiers() & Qt::ShiftModifier; - - if ( aKey == Qt::Key_Tab || ( aKey == Qt::Key_Backtab || ( aKey == Qt::Key_Tab && aShift ) ) ) - { - QTextCursor aCursor = textCursor(); - aCursor.beginEditBlock(); - tabIndentation( aKey == Qt::Key_Backtab ); - aCursor.endEditBlock(); - theEvent->accept(); - } - else if ( aKey == Qt::Key_Enter || aKey == Qt::Key_Return ) - { - QTextCursor aCursor = textCursor(); - aCursor.beginEditBlock(); - if ( lineIndent() == 0 ) - { - QPlainTextEdit::keyPressEvent( theEvent ); - } - aCursor.endEditBlock(); - theEvent->accept(); - } - else if ( theEvent == QKeySequence::MoveToStartOfLine || theEvent == QKeySequence::SelectStartOfLine ) - { - QTextCursor aCursor = this->textCursor(); - if ( QTextLayout* aLayout = aCursor.block().layout() ) - { - if ( aLayout->lineForTextPosition( aCursor.position() - aCursor.block().position() ).lineNumber() == 0 ) - { - handleHome( theEvent == QKeySequence::SelectStartOfLine ); - } - } - } - else if ( ( aKey == Qt::Key_Colon || ( aKey == Qt::Key_Space && !aCtrl && !aShift ) ) && - !textCursor().hasSelection() ) - { - QTextCursor aCursor = textCursor(); - aCursor.movePosition( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor ); - - QString aSelectedText = aCursor.selectedText(); - int numSpaces = findFirstNonSpace( aSelectedText ); - int amountChars = aSelectedText.size() - findFirstNonSpace( aSelectedText ); - QString aLeadingText = aSelectedText.right( amountChars ); - - QStringList aReservedWords; - aReservedWords.append( "except" ); - if ( aKey == Qt::Key_Colon ) - { - aReservedWords.append( "else" ); - aReservedWords.append( "finally" ); - } - else if ( aKey == Qt::Key_Space ) - { - aReservedWords.append( "elif" ); - } - - if ( aReservedWords.contains( aLeadingText ) ) - { - QString aPreviousText = aCursor.block().previous().text(); - int numSpacesPrevious = findFirstNonSpace( aPreviousText ); - if ( numSpaces == numSpacesPrevious ) - { - tabIndentation( true ); - aCursor.movePosition( QTextCursor::EndOfBlock ); - setTextCursor( aCursor ); - } - } - QPlainTextEdit::keyPressEvent( theEvent ); - } - else - { - QPlainTextEdit::keyPressEvent( theEvent ); - } - } -} - -/*! - \brief Reimplemented calss is to receive plain text widget resize events - which are passed in the event parameter. - \param theEvent event - */ -void PyEditor_Editor::resizeEvent( QResizeEvent* theEvent ) -{ - QPlainTextEdit::resizeEvent( theEvent ); - - // Change size geometry of line number area - QRect aContentsRect = contentsRect(); - my_LineNumberArea->setGeometry( - QRect( aContentsRect.left(), - aContentsRect.top(), - lineNumberAreaWidth(), - aContentsRect.height() ) ); -} - -/*! - \brief Reimplemented calss is to receive paint events passed in theEvent. - \param theEvent event - */ -void PyEditor_Editor::paintEvent( QPaintEvent* theEvent ) -{ - QPlainTextEdit::paintEvent( theEvent ); - - QTextBlock aBlock( firstVisibleBlock() ); - QPointF anOffset( contentOffset() ); - QPainter aPainter( this->viewport() ); - - int aTabSpaces = this->tabStopWidth() / 10; - - // Visualization tab spaces - if ( settings()->p_TabSpaceVisible ) - { - qreal aTop = blockBoundingGeometry( aBlock ).translated( anOffset ).top(); - while ( aBlock.isValid() && aTop <= theEvent->rect().bottom() ) - { - if ( aBlock.isVisible() && blockBoundingGeometry( aBlock ).translated( anOffset ).toRect().intersects( theEvent->rect() ) ) - { - QString aText = aBlock.text(); - if ( aText.contains( QRegExp( "\\w+" ) ) ) - aText.remove( QRegExp( "(?!\\w+)\\s+$" ) ); - - int aColumn = 0; - int anIndex = 0; - while ( anIndex != -1 ) - { - anIndex = aText.indexOf( QRegExp( QString( "^\\s{%1}" ).arg( aTabSpaces ) ), 0 ); - if ( anIndex != -1 ) - { - aColumn = aColumn + aTabSpaces; - aText = aText.mid( aTabSpaces ); - - if ( aText.startsWith( ' ' ) ) - { - QTextCursor aCursor( aBlock ); - aCursor.setPosition( aBlock.position() + aColumn ); - - QRect aRect = cursorRect( aCursor ); - aPainter.setPen( QPen( Qt::darkGray, 1, Qt::DotLine ) ); - aPainter.drawLine( aRect.x() + 1, aRect.top(), aRect.x() + 1, aRect.bottom() ); - } - } - } - } - aBlock = aBlock.next(); - } - } - - // Vertical edge line - if ( settings()->p_VerticalEdge ) - { - const QRect aRect = theEvent->rect(); - const QFont aFont = currentCharFormat().font(); - int aNumberColumn = QFontMetrics( aFont ).averageCharWidth() * settings()->p_NumberColumns + anOffset.x() + document()->documentMargin(); - aPainter.setPen( QPen( Qt::lightGray, 1, Qt::SolidLine ) ); - aPainter.drawLine( aNumberColumn, aRect.top(), aNumberColumn, aRect.bottom() ); - } -} - -/*! - \return manager of setting values. - */ -PyEditor_Settings* PyEditor_Editor::settings() -{ - return my_Settings; -} - -/*! - \brief Indenting and tabbing of the text - \param isShift flag defines reverse tab - */ -void PyEditor_Editor::tabIndentation( bool isShift ) -{ - QTextCursor aCursor = textCursor(); - int aTabSpaces = this->tabStopWidth()/10; - - if ( !aCursor.hasSelection() ) - { - if ( !isShift ) - { - int N = aCursor.columnNumber() % aTabSpaces; - aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) ); - } - else - { - QTextBlock aCurrentBlock = document()->findBlock( aCursor.position() ); - int anIndentPos = findFirstNonSpace( aCurrentBlock.text() ); - aCursor.setPosition( aCurrentBlock.position() + anIndentPos ); - setTextCursor( aCursor ); - - //if ( aCurrCursorColumnPos <= anIndentPos ) - //{ - int aColumnPos = aCursor.columnNumber(); - if ( aColumnPos != 0 ) - { - int N = aCursor.columnNumber() % aTabSpaces; - if ( N == 0 ) N = aTabSpaces; - aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, N ); - aCursor.removeSelectedText(); - } - setTextCursor( aCursor ); - //} - } - } - else - { - indentSelection( isShift ); - } -} - -/*! - \brief Indenting and tabbing of the selected text - \param isShift flag defines reverse tab - */ -void PyEditor_Editor::indentSelection( bool isShift ) -{ - QTextCursor aCursor = this->textCursor(); - - int aCursorStart = aCursor.selectionStart(); - int aCursorEnd = aCursor.selectionEnd(); - - QTextBlock aStartBlock = document()->findBlock( aCursorStart ); - QTextBlock anEndBlock = document()->findBlock( aCursorEnd - 1 ).next(); - - int aTabSpaces = this->tabStopWidth()/10; - - for ( QTextBlock aBlock = aStartBlock; aBlock.isValid() && aBlock != anEndBlock; aBlock = aBlock.next() ) - { - QString aText = aBlock.text(); - int anIndentPos = findFirstNonSpace( aText ); - int N = ( anIndentPos % aTabSpaces ); - - aCursor.setPosition( aBlock.position() + anIndentPos ); - if ( !isShift ) - { - aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) ); - setTextCursor( aCursor ); - } - else - { - int aColumnPos = aCursor.columnNumber(); - if ( aColumnPos != 0 ) - { - int blockN = aColumnPos % aTabSpaces; - if ( blockN == 0 ) blockN = aTabSpaces; - aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, blockN ); - aCursor.removeSelectedText(); - setTextCursor( aCursor ); - } - } - } - - // Reselect the selected lines - aCursor.setPosition( aStartBlock.position() ); - aCursor.setPosition( anEndBlock.previous().position(), QTextCursor::KeepAnchor ); - aCursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor ); - setTextCursor( aCursor ); -} - -/*! - \brief Finds the first non-white sapce in theText. - \param theText string - \return index of the first non-white space - */ -int PyEditor_Editor::findFirstNonSpace( const QString& theText ) -{ - int i = 0; - while ( i < theText.size() ) - { - if ( !theText.at(i).isSpace() ) - return i; - ++i; - } - return i; -} - -/*! - \brief Auto line indenting - \return error code - */ -int PyEditor_Editor::lineIndent() -{ - int aTabSpaces = this->tabStopWidth() / 10; - - QTextCursor aCursor = textCursor(); - aCursor.insertBlock(); - setTextCursor( aCursor ); - - QTextBlock aCurrentBlock = aCursor.block(); - if ( aCurrentBlock == document()->begin() ) - return 0; - - QTextBlock aPreviousBlock = aCurrentBlock.previous(); - - QString aPreviousText; - forever - { - if ( aPreviousBlock == document()->begin() ) - { - aPreviousText = aPreviousBlock.text(); - if ( aPreviousText.isEmpty() && aPreviousText.trimmed().isEmpty() ) - return -1; - break; - } - - // If the text of this block is not empty then break the loop. - aPreviousText = aPreviousBlock.text(); - if ( !aPreviousText.isEmpty() && !aPreviousText.trimmed().isEmpty() ) - break; - - aPreviousBlock = aPreviousBlock.previous(); - } - - int aTabIndentation = 0; - int anAmountIndentation = -1; - int i = 0; - while ( i < aPreviousText.size() ) - { - if ( !aPreviousText.at(i).isSpace() ) - { - anAmountIndentation = findFirstNonSpace( aPreviousText ); - break; - } - else - { - ++aTabIndentation; - } - ++i; - } - - if ( anAmountIndentation == -1 ) - { - if ( aTabIndentation > 0 ) - anAmountIndentation = aTabIndentation; - else - return 0; - } - - const QString aPreviousTrimmed = aPreviousText.trimmed(); - if ( aPreviousTrimmed.endsWith( ":" ) ) - { - anAmountIndentation += aTabSpaces; - } - else - { - if ( aPreviousTrimmed == "continue" - || aPreviousTrimmed == "break" - || aPreviousTrimmed == "pass" - || aPreviousTrimmed == "return" - || aPreviousTrimmed == "raise" - || aPreviousTrimmed.startsWith( "raise " ) - || aPreviousTrimmed.startsWith( "return " ) ) - anAmountIndentation -= aTabSpaces; - } - - aCursor.insertText( QString( anAmountIndentation, QLatin1Char(' ') ) ); - setTextCursor( aCursor ); - - return 1; -} - -/*! - \brief Set text cursor on home position. - */ -void PyEditor_Editor::handleHome( bool isExtendLine ) -{ - QTextCursor aCursor = textCursor(); - QTextCursor::MoveMode aMode = QTextCursor::MoveAnchor; - - if ( isExtendLine ) - aMode = QTextCursor::KeepAnchor; - - int anInitPos = aCursor.position(); - int aBlockPos = aCursor.block().position(); - - QChar aCharacter = document()->characterAt( aBlockPos ); - while ( aCharacter.category() == QChar::Separator_Space ) - { - ++aBlockPos; - if ( aBlockPos == anInitPos ) - break; - aCharacter = document()->characterAt( aBlockPos ); - } - - if ( aBlockPos == anInitPos ) - aBlockPos = aCursor.block().position(); - - aCursor.setPosition( aBlockPos, aMode ); - setTextCursor( aCursor ); -} - -/*! - SLOT: Updates the highlight current line. - */ -void PyEditor_Editor::updateHighlightCurrentLine() -{ - QList anExtraSelections; - if ( !isReadOnly() && settings()->p_HighlightCurrentLine ) - { - QTextEdit::ExtraSelection selection; - - QColor lineColor = QColor( Qt::gray ).lighter( 155 ); - - selection.format.setBackground( lineColor ); - selection.format.setProperty( QTextFormat::FullWidthSelection, QVariant( true ) ); - selection.cursor = textCursor(); - selection.cursor.clearSelection(); - anExtraSelections.append( selection ); - } - setExtraSelections( anExtraSelections ); -} - -/*! - \brief Creates line number area. - \param theEvent event for paint events. - */ -void PyEditor_Editor::lineNumberAreaPaintEvent( QPaintEvent* theEvent ) -{ - QPainter aPainter( my_LineNumberArea ); - aPainter.fillRect( theEvent->rect(), QColor( Qt::lightGray ).lighter( 125 ) ); - - QTextBlock aBlock = firstVisibleBlock(); - int aBlockNumber = aBlock.blockNumber(); - int aTop = (int)blockBoundingGeometry( aBlock ).translated( contentOffset() ).top(); - int aBottom = aTop + (int)blockBoundingRect( aBlock ).height(); - int aCurrentLine = document()->findBlock( textCursor().position() ).blockNumber(); - - QFont aFont = aPainter.font(); - aPainter.setPen( this->palette().color( QPalette::Text ) ); - - while ( aBlock.isValid() && aTop <= theEvent->rect().bottom() ) - { - if ( aBlock.isVisible() && aBottom >= theEvent->rect().top() ) - { - if ( aBlockNumber == aCurrentLine ) - { - aPainter.setPen( Qt::darkGray ); - aFont.setBold( true ); - aPainter.setFont( aFont ); - } - else - { - aPainter.setPen( Qt::gray ) ; - aFont.setBold( false ); - aPainter.setFont( aFont ); - } - QString aNumber = QString::number( aBlockNumber + 1 ); - aPainter.drawText( 0, aTop, my_LineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, aNumber ); - } - - aBlock = aBlock.next(); - aTop = aBottom; - aBottom = aTop + (int)blockBoundingRect( aBlock ).height(); - ++aBlockNumber; - } -} - -/*! - \return width of line number area - */ -int PyEditor_Editor::lineNumberAreaWidth() -{ - int aSpace = 0; - - int aDigits = 1; - int aMaximum = qMax( 1, blockCount() ); - while ( aMaximum >= 10 ) - { - aMaximum /= 10; - ++aDigits; - } - - if ( settings()->p_LineNumberArea ) - aSpace += 5 + fontMetrics().width( QLatin1Char( '9' ) ) * aDigits; - - return aSpace; -} - -/*! - SLOT: Updates the width of line number area. - */ -void PyEditor_Editor::updateLineNumberAreaWidth( int /*theNewBlockCount*/ ) -{ - setViewportMargins( lineNumberAreaWidth(), 0, 0, 0 ); -} - -/*! - SLOT: When the editor viewport has been scrolled. - */ -void PyEditor_Editor::updateLineNumberArea( const QRect& theRect, int theDY ) -{ - if ( theDY ) - my_LineNumberArea->scroll( 0, theDY ); - else - my_LineNumberArea->update( 0, theRect.y(), my_LineNumberArea->width(), theRect.height() ); - - if ( theRect.contains( viewport()->rect() ) ) - updateLineNumberAreaWidth( 0 ); -} - -/*! - \brief Parenthesis management. - SLOT: Walk through and check that we don't exceed 80 chars per line. - */ -void PyEditor_Editor::matchParentheses() -{ - PyEditor_PyHighlighter::TextBlockData* data = - static_cast( textCursor().block().userData() ); - - if ( data ) - { - QVector infoEntries = data->parentheses(); - - int aPos = textCursor().block().position(); - bool ignore = false; - for ( int i = 0; i < infoEntries.size(); ++i ) - { - PyEditor_PyHighlighter::ParenthesisInfo* info = infoEntries.at(i); - - int currentColumnPosition = textCursor().columnNumber(); - if ( info->position == currentColumnPosition - 1 && isLeftBrackets( info->character ) ) - { - if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) ) - createParenthesisSelection( aPos + info->position ); - } - else if ( info->position == currentColumnPosition && isLeftBrackets( info->character ) ) - { - if ( !ignore ) - { - if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) ) - createParenthesisSelection( aPos + info->position ); - } - } - else if ( info->position == currentColumnPosition - 1 && isRightBrackets( info->character ) ) - { - if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) ) - createParenthesisSelection( aPos + info->position ); - ignore = true; - } - else if ( info->position == currentColumnPosition && isRightBrackets( info->character ) ) - { - if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) ) - createParenthesisSelection( aPos + info->position ); - } - } - } -} - -/*! - \brief Matches the left brackets. - \param theCurrentBlock text block - \param theI index - \param theNumLeftParentheses number of left parentheses - \return \c true if the left match - */ -bool PyEditor_Editor::matchLeftParenthesis( - const QTextBlock& theCurrentBlock, int theI, int theNumLeftParentheses ) -{ - PyEditor_PyHighlighter::TextBlockData* data = - static_cast( theCurrentBlock.userData() ); - QVector infos = data->parentheses(); - - int docPos = theCurrentBlock.position(); - for ( ; theI < infos.size(); ++theI ) - { - PyEditor_PyHighlighter::ParenthesisInfo* info = infos.at(theI); - - if ( isLeftBrackets( info->character ) ) - { - ++theNumLeftParentheses; - continue; - } - - if ( isRightBrackets( info->character ) && theNumLeftParentheses == 0 ) - { - createParenthesisSelection( docPos + info->position ); - return true; - } - else - --theNumLeftParentheses; - } - - QTextBlock nextBlock = theCurrentBlock.next(); - if ( nextBlock.isValid() ) - return matchLeftParenthesis( nextBlock, 0, theNumLeftParentheses ); - - return false; -} - -/*! - \brief Matches the right brackets. - \param theCurrentBlock text block - \param theI index - \param theNumRightParentheses number of right parentheses - \return \c true if the right match - */ -bool PyEditor_Editor::matchRightParenthesis( const QTextBlock& theCurrentBlock, int theI, int theNumRightParentheses ) -{ - PyEditor_PyHighlighter::TextBlockData* data = static_cast( theCurrentBlock.userData() ); - QVector parentheses = data->parentheses(); - - int docPos = theCurrentBlock.position(); - for ( ; theI > -1 && parentheses.size() > 0; --theI ) - { - PyEditor_PyHighlighter::ParenthesisInfo* info = parentheses.at(theI); - if ( isRightBrackets( info->character ) ) - { - ++theNumRightParentheses; - continue; - } - if ( isLeftBrackets( info->character ) && theNumRightParentheses == 0 ) - { - createParenthesisSelection( docPos + info->position ); - return true; - } - else - --theNumRightParentheses; - } - - QTextBlock prevBlock = theCurrentBlock.previous(); - if ( prevBlock.isValid() ) - { - PyEditor_PyHighlighter::TextBlockData* data = static_cast( prevBlock.userData() ); - QVector parentheses = data->parentheses(); - return matchRightParenthesis( prevBlock, parentheses.size() - 1, theNumRightParentheses ); - } - - return false; -} - -/*! - \brief Creates brackets selection. - \param thePosition position - */ -// Create brackets -void PyEditor_Editor::createParenthesisSelection( int thePosition ) -{ - QList selections = extraSelections(); - - QTextEdit::ExtraSelection selection; - - QTextCharFormat format = selection.format; - format.setForeground( Qt::red ); - format.setBackground( Qt::white ); - selection.format = format; - - QTextCursor cursor = textCursor(); - cursor.setPosition( thePosition ); - cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor ); - selection.cursor = cursor; - - selections.append( selection ); - setExtraSelections( selections ); -} - -/*! - return true whether the left bracket - */ -bool PyEditor_Editor::isLeftBrackets( QChar theSymbol ) -{ - return theSymbol == '(' || theSymbol == '{' || theSymbol == '['; -} - -/*! - Appends a new paragraph with text to the end of the text edit. - */ -void PyEditor_Editor::append( const QString & text ) { - QPlainTextEdit::appendPlainText(text); -} - -/*! - Sets the text edit's text. -*/ -void PyEditor_Editor::setText( const QString & text ) { - QPlainTextEdit::appendPlainText(text); -} - -/*! - return true whether the right bracket - */ -bool PyEditor_Editor::isRightBrackets( QChar theSymbol ) -{ - return theSymbol == ')' || theSymbol == '}' || theSymbol == ']'; -} diff --git a/src/PyEditor/PyEditor_Editor.h b/src/PyEditor/PyEditor_Editor.h deleted file mode 100644 index 518e56838..000000000 --- a/src/PyEditor/PyEditor_Editor.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_Editor.h -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#ifndef PYEDITOR_EDITOR_H -#define PYEDITOR_EDITOR_H - -#include -#include "PyEditor.h" - -class PyEditor_PyHighlighter; -class PyEditor_Settings; -class QtxResourceMgr; - -class PYEDITOR_EXPORT PyEditor_Editor : public QPlainTextEdit -{ - Q_OBJECT - -public: - PyEditor_Editor( bool isSingle = false, QtxResourceMgr* = 0, QWidget* = 0 ); - virtual ~PyEditor_Editor(); - - void lineNumberAreaPaintEvent( QPaintEvent* ); - int lineNumberAreaWidth(); - - void updateStatement(); - PyEditor_Settings* settings(); - -public Q_SLOTS: - void deleteSelected(); - void append ( const QString & ); - void setText ( const QString & text ); -protected: - virtual void keyPressEvent( QKeyEvent* ); - virtual void resizeEvent( QResizeEvent* ); - virtual void paintEvent( QPaintEvent* ); - -private Q_SLOTS: - void updateHighlightCurrentLine(); - void matchParentheses(); - - void updateLineNumberAreaWidth( int ); - void updateLineNumberArea( const QRect&, int ); - -private: - bool matchLeftParenthesis( const QTextBlock&, int, int ); - bool matchRightParenthesis( const QTextBlock&, int, int ); - void createParenthesisSelection( int ); - bool isLeftBrackets( QChar ); - bool isRightBrackets( QChar ); - - void handleHome( bool ); - int lineIndent(); - void tabIndentation( bool ); - void indentSelection( bool ); - - int findFirstNonSpace( const QString& ); - - QWidget* my_LineNumberArea; - PyEditor_PyHighlighter* my_SyntaxHighlighter; - PyEditor_Settings* my_Settings; -}; - -#endif // PYEDITOR_EDITOR_H diff --git a/src/PyEditor/PyEditor_LineNumberArea.cxx b/src/PyEditor/PyEditor_LineNumberArea.cxx deleted file mode 100644 index 0a47c9f5f..000000000 --- a/src/PyEditor/PyEditor_LineNumberArea.cxx +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_LineNumberArea.cxx -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#include "PyEditor_LineNumberArea.h" - -#include "PyEditor_Editor.h" - -/*! - \class PyEditor_LineNumberArea - \brief Widget shows line number. -*/ - -/*! - \brief Constructor. - \param theCodeEditor parent widget -*/ -PyEditor_LineNumberArea::PyEditor_LineNumberArea( PyEditor_Editor* theCodeEditor ) : - QWidget( theCodeEditor ) -{ - my_CodeEditor = theCodeEditor; -} - -QSize PyEditor_LineNumberArea::sizeHint() const -{ - return QSize( my_CodeEditor->lineNumberAreaWidth(), 0 ); -} - -void PyEditor_LineNumberArea::paintEvent( QPaintEvent* theEvent ) -{ - my_CodeEditor->lineNumberAreaPaintEvent( theEvent ); - QWidget::paintEvent( theEvent ); -} diff --git a/src/PyEditor/PyEditor_LineNumberArea.h b/src/PyEditor/PyEditor_LineNumberArea.h deleted file mode 100644 index e1b9e3040..000000000 --- a/src/PyEditor/PyEditor_LineNumberArea.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_LineNumberArea.h -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#ifndef PYEDITOR_LINENUMBERAREA_H -#define PYEDITOR_LINENUMBERAREA_H - -#include - -class PyEditor_Editor; - -class PyEditor_LineNumberArea : public QWidget -{ - Q_OBJECT - -public: - explicit PyEditor_LineNumberArea( PyEditor_Editor* ); - - QSize sizeHint() const; - -protected: - void paintEvent( QPaintEvent* ); - -private: - PyEditor_Editor* my_CodeEditor; -}; - -#endif // PYEDITOR_LINENUMBERAREA_H diff --git a/src/PyEditor/PyEditor_PyHighlighter.cxx b/src/PyEditor/PyEditor_PyHighlighter.cxx deleted file mode 100644 index 73ea030ec..000000000 --- a/src/PyEditor/PyEditor_PyHighlighter.cxx +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_PyHighlighter.cxx -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#include "PyEditor_PyHighlighter.h" - -#define NORMAL 0 -#define TRIPLESINGLE 1 -#define TRIPLEDOUBLE 2 - -/*! - \class PyEditor_PyHighlighter - \brief Python highlighter class defines the syntax highlighting rules. -*/ - -PyEditor_PyHighlighter::TextBlockData::TextBlockData() -{ -} - -QVector PyEditor_PyHighlighter::TextBlockData::parentheses() -{ - return my_Parentheses; -} - -void PyEditor_PyHighlighter::TextBlockData::insert( PyEditor_PyHighlighter::ParenthesisInfo* theInfo ) -{ - int i = 0; - while ( i < my_Parentheses.size() && theInfo->position > my_Parentheses.at(i)->position ) - ++i; - - my_Parentheses.insert( i, theInfo ); -} - -/*! - \brief Constructor. - \param theDocument container for structured rich text documents. -*/ -PyEditor_PyHighlighter::PyEditor_PyHighlighter( QTextDocument* theDocument ) - : QSyntaxHighlighter( theDocument ) -{ - initialize(); -} - -/*! - \brief Initialization rules. - */ -void PyEditor_PyHighlighter::initialize() -{ - HighlightingRule aRule; - - // Keywords - keywordFormat.setForeground( Qt::blue ); - QStringList aKeywords = keywords(); - foreach ( const QString &keyword, aKeywords ) - { - aRule.pattern = QRegExp( QString( "\\b%1\\b" ).arg( keyword ) ); - aRule.format = keywordFormat; - aRule.capture = 0; - highlightingRules.append( aRule ); - } - - // Special keywords - specialFromat.setForeground( Qt::magenta ); - QStringList aSpecialKeywords = specialKeywords(); - foreach ( const QString &keyword, aSpecialKeywords ) - { - aRule.pattern = QRegExp( QString( "\\b%1\\b" ).arg( keyword ) ); - aRule.format = specialFromat; - aRule.capture = 0; - highlightingRules.append( aRule ); - } - - // Reference to the current instance of the class - referenceClassFormat.setForeground( QColor( 179, 143, 0 ) ); - referenceClassFormat.setFontItalic( true ); - aRule.pattern = QRegExp( "\\bself\\b" ); - aRule.format = referenceClassFormat; - aRule.capture = 0; - highlightingRules.append( aRule ); - - // Numbers - numberFormat.setForeground( Qt::darkMagenta ); - aRule.pattern = QRegExp( "\\b([-+])?(\\d+(\\.)?\\d*|\\d*(\\.)?\\d+)(([eE]([-+])?)?\\d+)?\\b" ); - aRule.format = numberFormat; - aRule.capture = 0; - highlightingRules.append( aRule ); - - // String qoutation - quotationFormat.setForeground( Qt::darkGreen ); - aRule.pattern = QRegExp( "(?:'[^']*'|\"[^\"]*\")" ); - aRule.pattern.setMinimal( true ); - aRule.format = quotationFormat; - aRule.capture = 0; - highlightingRules.append( aRule ); - - // Function names - functionFormat.setFontWeight( QFont::Bold ); - aRule.pattern = QRegExp( "(?:def\\s*)(\\b[A-Za-z0-9_]+)(?=[\\W])" ); - aRule.capture = 1; - aRule.format = functionFormat; - highlightingRules.append( aRule ); - - // Class names - classFormat.setForeground( Qt::darkBlue ); - classFormat.setFontWeight( QFont::Bold ); - aRule.pattern = QRegExp( "(?:class\\s*)(\\b[A-Za-z0-9_]+)(?=[\\W])" ); - aRule.capture = 1; - aRule.format = classFormat; - highlightingRules.append( aRule ); - - // Multi line comments - multiLineCommentFormat.setForeground( Qt::darkRed ); - tripleQuotesExpression = QRegExp( "(:?\"[\"]\".*\"[\"]\"|'''.*''')" ); - aRule.pattern = tripleQuotesExpression; - aRule.pattern.setMinimal( true ); - aRule.format = multiLineCommentFormat; - aRule.capture = 0; - highlightingRules.append( aRule ); - - tripleSingleExpression = QRegExp( "'''(?!\")" ); - tripleDoubleExpression = QRegExp( "\"\"\"(?!')" ); - - // Single comments - singleLineCommentFormat.setForeground( Qt::darkGray ); - aRule.pattern = QRegExp( "#[^\n]*" ); - aRule.format = singleLineCommentFormat; - aRule.capture = 0; - highlightingRules.append( aRule ); -} - -/*! - \return string list of Python keywords. - */ -QStringList PyEditor_PyHighlighter::keywords() -{ - QStringList aKeywords; - aKeywords << "and" - << "as" - << "assert" - << "break" - << "class" - << "continue" - << "def" - << "elif" - << "else" - << "except" - << "exec" - << "finally" - << "False" - << "for" - << "from" - << "global" - << "if" - << "import" - << "in" - << "is" - << "lambda" - << "None" - << "not" - << "or" - << "pass" - << "print" - << "raise" - << "return" - << "True" - << "try" - << "while" - << "with" - << "yield"; - return aKeywords; -} - -/*! - \return string list of special Python keywords. - */ -QStringList PyEditor_PyHighlighter::specialKeywords() -{ - QStringList aSpecialKeywords; - aSpecialKeywords << "ArithmeticError" - << "AssertionError" - << "AttributeError" - << "EnvironmentError" - << "EOFError" - << "Exception" - << "FloatingPointError" - << "ImportError" - << "IndentationError" - << "IndexError" - << "IOError" - << "KeyboardInterrupt" - << "KeyError" - << "LookupError" - << "MemoryError" - << "NameError" - << "NotImplementedError" - << "OSError" - << "OverflowError" - << "ReferenceError" - << "RuntimeError" - << "StandardError" - << "StopIteration" - << "SyntaxError" - << "SystemError" - << "SystemExit" - << "TabError" - << "TypeError" - << "UnboundLocalError" - << "UnicodeDecodeError" - << "UnicodeEncodeError" - << "UnicodeError" - << "UnicodeTranslateError" - << "ValueError" - << "WindowsError" - << "ZeroDivisionError" - << "Warning" - << "UserWarning" - << "DeprecationWarning" - << "PendingDeprecationWarning" - << "SyntaxWarning" - << "OverflowWarning" - << "RuntimeWarning" - << "FutureWarning"; - return aSpecialKeywords; -} - -void PyEditor_PyHighlighter::highlightBlock( const QString& theText ) -{ - TextBlockData* aData = new TextBlockData; - - insertBracketsData( RoundBrackets, aData, theText ); - insertBracketsData( CurlyBrackets, aData, theText ); - insertBracketsData( SquareBrackets, aData, theText ); - - setCurrentBlockUserData( aData ); - - foreach ( const HighlightingRule& rule, highlightingRules ) - { - QRegExp expression( rule.pattern ); - int anIndex = expression.indexIn( theText ); - while ( anIndex >= 0 ) - { - anIndex = expression.pos( rule.capture ); - int aLength = expression.cap( rule.capture ).length(); - setFormat( anIndex, aLength, rule.format ); - anIndex = expression.indexIn( theText, anIndex + aLength ); - } - } - - setCurrentBlockState( NORMAL ); - - if ( theText.indexOf( tripleQuotesExpression ) != -1 ) - return; - - QList aTripleSingle; - aTripleSingle << theText.indexOf( tripleSingleExpression ) << TRIPLESINGLE; - - QList aTripleDouble; - aTripleDouble << theText.indexOf( tripleDoubleExpression ) << TRIPLEDOUBLE; - - QList< QList > aTripleExpressions; - aTripleExpressions << aTripleSingle << aTripleDouble; - - for ( int i = 0; i < aTripleExpressions.length(); i++ ) - { - QList aBlock = aTripleExpressions[i]; - int anIndex = aBlock[0]; - int aState = aBlock[1]; - if ( previousBlockState() == aState ) - { - if ( anIndex == -1 ) - { - anIndex = theText.length(); - setCurrentBlockState( aState ); - } - setFormat( 0, anIndex + 3, multiLineCommentFormat ); - } - else if ( anIndex > -1 ) - { - setCurrentBlockState( aState ); - setFormat( anIndex, theText.length(), multiLineCommentFormat ); - } - } -} - -void PyEditor_PyHighlighter::insertBracketsData( char theLeftSymbol, - char theRightSymbol, - TextBlockData* theData, - const QString& theText ) -{ - int leftPosition = theText.indexOf( theLeftSymbol ); - while( leftPosition != -1 ) - { - ParenthesisInfo* info = new ParenthesisInfo(); - info->character = theLeftSymbol; - info->position = leftPosition; - - theData->insert( info ); - leftPosition = theText.indexOf( theLeftSymbol, leftPosition + 1 ); - } - - int rightPosition = theText.indexOf( theRightSymbol ); - while( rightPosition != -1 ) - { - ParenthesisInfo* info = new ParenthesisInfo(); - info->character = theRightSymbol; - info->position = rightPosition; - - theData->insert( info ); - rightPosition = theText.indexOf( theRightSymbol, rightPosition + 1 ); - } -} - -void PyEditor_PyHighlighter::insertBracketsData( Brackets theBrackets, - TextBlockData* theData, - const QString& theText ) -{ - char leftChar = '0'; - char rightChar = '0'; - - switch( theBrackets ) - { - case RoundBrackets: - leftChar = '('; - rightChar = ')'; - break; - case CurlyBrackets: - leftChar = '{'; - rightChar = '}'; - break; - case SquareBrackets: - leftChar = '['; - rightChar = ']'; - break; - } - - insertBracketsData( leftChar, rightChar, theData, theText ); -} diff --git a/src/PyEditor/PyEditor_PyHighlighter.h b/src/PyEditor/PyEditor_PyHighlighter.h deleted file mode 100644 index 1256813dd..000000000 --- a/src/PyEditor/PyEditor_PyHighlighter.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_PyHighlighter.h -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#ifndef PYEDITOR_PYHIGHLIGHTER_H -#define PYEDITOR_PYHIGHLIGHTER_H - -#include - -class QTextDocument; - -class PyEditor_PyHighlighter : public QSyntaxHighlighter -{ - Q_OBJECT - -public: - - struct ParenthesisInfo - { - char character; - int position; - }; - - class TextBlockData : public QTextBlockUserData - { - public: - TextBlockData(); - - QVector parentheses(); - void insert( ParenthesisInfo* ); - - private: - QVector my_Parentheses; - }; - -public: - PyEditor_PyHighlighter( QTextDocument* = 0 ); - - void initialize(); - QStringList keywords(); - QStringList specialKeywords(); - -protected: - struct HighlightingRule - { - QRegExp pattern; - QTextCharFormat format; - int capture; - }; - QVector highlightingRules; - - enum Brackets { RoundBrackets, CurlyBrackets, SquareBrackets }; - - QRegExp tripleQuotesExpression; - QRegExp tripleSingleExpression; - QRegExp tripleDoubleExpression; - - QTextCharFormat classFormat; - QTextCharFormat referenceClassFormat; - QTextCharFormat functionFormat; - QTextCharFormat keywordFormat; - QTextCharFormat specialFromat; - QTextCharFormat numberFormat; - QTextCharFormat singleLineCommentFormat; - QTextCharFormat multiLineCommentFormat; - QTextCharFormat quotationFormat; - - void highlightBlock( const QString& ); - void insertBracketsData( char, char, TextBlockData*, const QString& ); - void insertBracketsData( Brackets, TextBlockData*, const QString& ); -}; - -#endif // PYEDITOR_PYHIGHLIGHTER_H diff --git a/src/PyEditor/PyEditor_Settings.cxx b/src/PyEditor/PyEditor_Settings.cxx deleted file mode 100644 index 69309d13f..000000000 --- a/src/PyEditor/PyEditor_Settings.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_Settings.cxx -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#include "PyEditor_Settings.h" - -#include - -#include -#include -#include - -/*! - \class PyEditor_Settings - \brief Manager of setting values. -*/ - -/*! - \brief Constructor. - \param isSingle flag determined single application or reccesed. -*/ -PyEditor_Settings::PyEditor_Settings( QtxResourceMgr* theMgr, bool isSingle ) - : p_HighlightCurrentLine( true ), - p_LineNumberArea( true ), - p_TextWrapping( false ), - p_CenterCursorOnScroll( true ), - p_TabSpaceVisible( true ), - p_TabSize( 4 ), - p_VerticalEdge( true ), - p_NumberColumns( 80 ), - p_Font( "Courier", 10 ), - m_ResourceMgr(theMgr), - m_Single(isSingle) - -{ - if ( m_Single ) - { - m_Settings = new QSettings( "config.ini", QSettings::IniFormat ); - if ( !QFile::exists( m_Settings->fileName() ) ) - toSettings( PY_EDITOR ); - } - - readSettings(); -} - -/*! - \brief Reads the setting values. - */ -void PyEditor_Settings::readSettings() -{ - if ( isSingle() ) - fromSettings( PY_EDITOR ); - else - readPreferences(); -} - -/*! - \brief Writes the setting values. - */ -void PyEditor_Settings::writeSettings() -{ - if ( isSingle() ) - toSettings( PY_EDITOR ); - else - writePreferences(); -} - -/*! - \return \c true if the application is single - */ -bool PyEditor_Settings::isSingle() -{ - return m_Single; -} - -/*! - \brief Loads the setting values from file settings. - */ -void PyEditor_Settings::fromSettings( const QString &theCategory ) -{ - QString aGroup = theCategory; - aGroup += "/"; - - p_HighlightCurrentLine = m_Settings->value(aGroup + QLatin1String( HIGHLIGHT_CURRLINE ), p_HighlightCurrentLine).toBool(); - p_LineNumberArea = m_Settings->value(aGroup + QLatin1String( LINE_NUMBER_AREA ), p_LineNumberArea).toBool(); - p_TextWrapping = m_Settings->value(aGroup + QLatin1String( TEXT_WRAP ), p_TextWrapping).toBool(); - p_CenterCursorOnScroll = m_Settings->value(aGroup + QLatin1String( CURSOR_SCROLL ), p_CenterCursorOnScroll).toBool(); - p_TabSpaceVisible = m_Settings->value(aGroup + QLatin1String( TAB_WHITESPACES ), p_TabSpaceVisible).toBool(); - p_TabSize = m_Settings->value(aGroup + QLatin1String( TAB_SIZE ), p_TabSize).toInt(); - p_VerticalEdge = m_Settings->value(aGroup + QLatin1String( VERTICAL_EDGE ), p_VerticalEdge).toBool(); - p_NumberColumns = m_Settings->value(aGroup + QLatin1String( NUM_COLUMNS ), p_NumberColumns).toInt(); - p_Font = QFont( m_Settings->value(aGroup + QLatin1String( FONT_FAMILY ), p_Font.family()).toString(), - m_Settings->value(aGroup + QLatin1String( FONT_SIZE ), p_Font.pointSize()).toInt() ); -} - -/*! - \brief Saves the setting values into file settings. - */ -void PyEditor_Settings::toSettings( const QString &theCategory ) const -{ - m_Settings->beginGroup( theCategory ); - m_Settings->setValue( QLatin1String( HIGHLIGHT_CURRLINE ), p_HighlightCurrentLine ); - m_Settings->setValue( QLatin1String( LINE_NUMBER_AREA ), p_LineNumberArea ); - m_Settings->setValue( QLatin1String( TEXT_WRAP ), p_TextWrapping ); - m_Settings->setValue( QLatin1String( CURSOR_SCROLL ), p_CenterCursorOnScroll ); - m_Settings->setValue( QLatin1String( TAB_WHITESPACES ), p_TabSpaceVisible ); - m_Settings->setValue( QLatin1String( TAB_SIZE ), p_TabSize ); - m_Settings->setValue( QLatin1String( VERTICAL_EDGE ), p_VerticalEdge ); - m_Settings->setValue( QLatin1String( NUM_COLUMNS ), p_NumberColumns ); - m_Settings->setValue( QLatin1String( FONT_FAMILY ), p_Font.family() ); - m_Settings->setValue( QLatin1String( FONT_SIZE ), p_Font.pointSize() ); - m_Settings->endGroup(); -} - -/*! - \brief Loads the setting values from setting resources. - */ -void PyEditor_Settings::readPreferences() -{ - if(m_ResourceMgr) - { - p_HighlightCurrentLine = m_ResourceMgr->booleanValue( "PyEditor", "HighlightCurrentLine", p_HighlightCurrentLine ); - p_LineNumberArea = m_ResourceMgr->booleanValue( "PyEditor", "LineNumberArea", p_LineNumberArea ); - p_TextWrapping = m_ResourceMgr->booleanValue( "PyEditor", "TextWrapping", p_TextWrapping ); - p_CenterCursorOnScroll = m_ResourceMgr->booleanValue( "PyEditor", "CenterCursorOnScroll", p_CenterCursorOnScroll ); - p_TabSpaceVisible = m_ResourceMgr->booleanValue( "PyEditor", "TabSpaceVisible", p_TabSpaceVisible ); - p_TabSize = m_ResourceMgr->integerValue( "PyEditor", "TabSize", p_TabSize ); - p_VerticalEdge = m_ResourceMgr->booleanValue( "PyEditor", "VerticalEdge", p_VerticalEdge ); - p_NumberColumns = m_ResourceMgr->integerValue( "PyEditor", "NumberColumns", p_NumberColumns ); - p_Font = m_ResourceMgr->fontValue( "PyEditor", "Font", p_Font ); - } -} - -/*! - \brief Saves the setting values into setting resources. - */ -void PyEditor_Settings::writePreferences() -{ - if(m_ResourceMgr) - { - m_ResourceMgr->setValue( "PyEditor", "HighlightCurrentLine", p_HighlightCurrentLine ); - m_ResourceMgr->setValue( "PyEditor", "LineNumberArea", p_LineNumberArea ); - m_ResourceMgr->setValue( "PyEditor", "TextWrapping", p_TextWrapping ); - m_ResourceMgr->setValue( "PyEditor", "CenterCursorOnScroll", p_CenterCursorOnScroll ); - m_ResourceMgr->setValue( "PyEditor", "TabSpaceVisible", p_TabSpaceVisible ); - m_ResourceMgr->setValue( "PyEditor", "TabSize", p_TabSize ); - m_ResourceMgr->setValue( "PyEditor", "VerticalEdge", p_VerticalEdge ); - m_ResourceMgr->setValue( "PyEditor", "NumberColumns", p_NumberColumns ); - m_ResourceMgr->setValue( "PyEditor", "Font", p_Font ); - } -} diff --git a/src/PyEditor/PyEditor_Settings.h b/src/PyEditor/PyEditor_Settings.h deleted file mode 100644 index d7b11d8ea..000000000 --- a/src/PyEditor/PyEditor_Settings.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_Settings.h -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#ifndef PYEDITOR_SETTINGS_H -#define PYEDITOR_SETTINGS_H - -#include -#include "PyEditor.h" - -class QSettings; -class QtxResourceMgr; - -const char* const PY_EDITOR = "PythonEditor"; -const char* const HIGHLIGHT_CURRLINE = "HighlightCurrentLine"; -const char* const LINE_NUMBER_AREA = "LineNumberArea"; -const char* const TEXT_WRAP = "TextWrapping"; -const char* const CURSOR_SCROLL = "CenterCursorOnScroll"; -const char* const TAB_WHITESPACES = "TabSpaceVisible"; -const char* const TAB_SIZE = "TabSize"; -const char* const VERTICAL_EDGE = "VerticalEdge"; -const char* const NUM_COLUMNS = "NumberColumns"; -const char* const FONT_FAMILY = "FontFamily"; -const char* const FONT_SIZE = "FontSize"; - -class PYEDITOR_EXPORT PyEditor_Settings -{ -public: - PyEditor_Settings( QtxResourceMgr* = 0 , bool isSingle = true ); - - void readSettings(); - void writeSettings(); - - void fromSettings( const QString& ); - void toSettings( const QString& ) const; - - void readPreferences(); - void writePreferences(); - - bool isSingle(); - - // Display settings - bool p_HighlightCurrentLine; - bool p_TextWrapping; - bool p_CenterCursorOnScroll; - bool p_LineNumberArea; - - // Vertical edge settings - bool p_VerticalEdge; - int p_NumberColumns; - - // Tab settings - bool p_TabSpaceVisible; - int p_TabSize; - - // Font settings - QFont p_Font; - -private: - QSettings* m_Settings; - QtxResourceMgr* m_ResourceMgr; - bool m_Single; -}; - -#endif // PYEDITOR_SETTINGS_H diff --git a/src/PyEditor/PyEditor_SettingsDlg.cxx b/src/PyEditor/PyEditor_SettingsDlg.cxx deleted file mode 100644 index 47a519ffa..000000000 --- a/src/PyEditor/PyEditor_SettingsDlg.cxx +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_SettingsDlg.cxx -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#include "PyEditor_SettingsDlg.h" - -#include "PyEditor_Editor.h" -#include "PyEditor_Settings.h" - -#include -#include -#include -#include -#include -#include -#include - -/*! - \class PyEditor_SettingsDlg - \brief Dialog settings for python editor. -*/ - -/*! - \brief Constructor. - \param theEditor widget that is used to edit and display text - \param theParent parent widget -*/ -PyEditor_SettingsDlg::PyEditor_SettingsDlg( PyEditor_Editor* theEditor, QWidget* theParent ) : - QDialog( theParent ), - my_Editor( theEditor ) -{ - setWindowTitle( tr("TIT_PY_PREF") ); - QVBoxLayout* aMainLayout = new QVBoxLayout( this ); - - // . Font settings - QGroupBox* aFontSetBox = new QGroupBox( tr( "GR_FONT_SET" ) ); - QHBoxLayout* aFontSetLayout = new QHBoxLayout( aFontSetBox ); - w_FontWidget = new QtxFontEdit( QtxFontEdit::Family|QtxFontEdit::Size|QtxFontEdit::UserSize, this ); - aFontSetLayout->addWidget( w_FontWidget ); - // . Font settings - - // . Display settings - QGroupBox* aDisplaySetBox = new QGroupBox( tr( "GR_DISP_SET" ) ); - QVBoxLayout* aDisplaySetLayout = new QVBoxLayout; - w_HighlightCurrentLine = new QCheckBox( tr( "LBL_CURRLINE_HIGHLIGHT" ) ); - w_TextWrapping = new QCheckBox( tr( "LBL_TEXT_WRAP" ) ); - w_CenterCursorOnScroll = new QCheckBox( tr( "LBL_CURSOR_SCROLL" ) ); - w_LineNumberArea = new QCheckBox( tr( "LBL_LINE_NUMBS_AREA" ) ); - aDisplaySetLayout->addWidget( w_HighlightCurrentLine ); - aDisplaySetLayout->addWidget( w_TextWrapping ); - aDisplaySetLayout->addWidget( w_CenterCursorOnScroll ); - aDisplaySetLayout->addWidget( w_LineNumberArea ); - aDisplaySetLayout->addStretch( 1 ); - aDisplaySetBox->setLayout( aDisplaySetLayout ); - // . Display settings - - QHBoxLayout* aTabVertEdgeLayout = new QHBoxLayout; - - // . Tab settings - QGroupBox* aTabSetBox = new QGroupBox( tr( "GR_TAB_SET" ) ); - QVBoxLayout* aTabSetLayout = new QVBoxLayout; - w_TabSpaceVisible = new QCheckBox( tr( "LBL_TAB_SPACES" ) ); - QHBoxLayout* aTabSizeLayout = new QHBoxLayout; - QLabel* aTabSizeLabel = new QLabel( tr( "LBL_TAB_SIZE" ) ); - w_TabSize = new QSpinBox; - w_TabSize->setMinimum( 0 ); - w_TabSize->setSingleStep( 1 ); - aTabSizeLayout->addWidget( aTabSizeLabel ); - aTabSizeLayout->addWidget( w_TabSize ); - aTabSizeLayout->addStretch( 1 ); - aTabSetLayout->addWidget( w_TabSpaceVisible ); - aTabSetLayout->addLayout( aTabSizeLayout ); - aTabSetBox->setLayout( aTabSetLayout ); - // . Tab settings - - // . Vertical edge settings - QGroupBox* aVertEdgeSetBox = new QGroupBox( tr( "GR_VERT_EDGE_SET" ) ); - QVBoxLayout* aVertEdgeLayout = new QVBoxLayout; - w_VerticalEdge = new QCheckBox( tr( "LBL_VERT_EDGE" ) ); - QHBoxLayout* aNumberColLayout = new QHBoxLayout; - lbl_NumColumns = new QLabel( tr( "LBL_NUM_COLUMNS" ) ); - w_NumberColumns = new QSpinBox; - w_NumberColumns->setMinimum( 0 ); - w_NumberColumns->setSingleStep( 1 ); - aNumberColLayout->addWidget( lbl_NumColumns ); - aNumberColLayout->addWidget( w_NumberColumns ); - aNumberColLayout->addStretch( 1 ); - aVertEdgeLayout->addWidget( w_VerticalEdge ); - aVertEdgeLayout->addLayout( aNumberColLayout ); - aVertEdgeSetBox->setLayout( aVertEdgeLayout ); - connect( w_VerticalEdge, SIGNAL( clicked( bool ) ), - this, SLOT( onVerticalEdgeChecked( bool ) ) ); - // . Vertical edge settings - - aTabVertEdgeLayout->addWidget( aTabSetBox ); - aTabVertEdgeLayout->addWidget( aVertEdgeSetBox ); - - // . "Set as default" check box - w_DefaultCheck = new QCheckBox( tr( "WDG_SET_AS_DEFAULT_CHECK" ), this ); - - aMainLayout->addWidget( aFontSetBox ); - aMainLayout->addWidget( aDisplaySetBox ); - aMainLayout->addLayout( aTabVertEdgeLayout ); - aMainLayout->addWidget( w_DefaultCheck ); - aMainLayout->addStretch( 1 ); - - myOkBtn = new QPushButton( tr( "BUT_OK" ), this ); - myOkBtn->setAutoDefault( true ); - myOkBtn->setDefault( true ); - myCancelBtn = new QPushButton( tr( "BUT_CANCEL" ), this ); - myCancelBtn->setAutoDefault( true ); - myHelpBtn = new QPushButton( tr( "BUT_HELP" ), this ); - myHelpBtn->setAutoDefault( true ); - QHBoxLayout* aButtonLayout = new QHBoxLayout; - aButtonLayout->addWidget( myOkBtn ); - aButtonLayout->addStretch(); - aButtonLayout->addWidget( myCancelBtn ); - aButtonLayout->addWidget( myHelpBtn ); - aMainLayout->addLayout( aButtonLayout ); - - connect( myOkBtn, SIGNAL( clicked() ), this, SLOT( onOk() ) ); - connect( myCancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); - connect( myHelpBtn, SIGNAL( clicked() ), this, SLOT( onHelp() ) ); - - settingsToGui(); -} - -/*! - \brief Get "Set settings as default" check box value. - \return \c true if "Set settings as default" check box is on -*/ -bool PyEditor_SettingsDlg::isSetAsDefault() -{ - return w_DefaultCheck->isChecked(); -} - -/*! - SLOT: Changes the widget visibility depending on the set theState flag. - \param theState flag of visibility - */ -void PyEditor_SettingsDlg::onVerticalEdgeChecked( bool theState ) -{ - lbl_NumColumns->setEnabled( theState ); - w_NumberColumns->setEnabled( theState ); -} - -/*! - \brief Sets settings from preferences dialog. - */ -void PyEditor_SettingsDlg::settingsFromGui() -{ - my_Editor->settings()->p_HighlightCurrentLine = w_HighlightCurrentLine->isChecked(); - my_Editor->settings()->p_TextWrapping = w_TextWrapping->isChecked(); - my_Editor->settings()->p_CenterCursorOnScroll = w_CenterCursorOnScroll->isChecked(); - my_Editor->settings()->p_LineNumberArea = w_LineNumberArea->isChecked(); - my_Editor->settings()->p_TabSpaceVisible = w_TabSpaceVisible->isChecked(); - my_Editor->settings()->p_TabSize = w_TabSize->value(); - my_Editor->settings()->p_VerticalEdge = w_VerticalEdge->isChecked(); - my_Editor->settings()->p_NumberColumns = w_NumberColumns->value(); - my_Editor->settings()->p_Font = w_FontWidget->currentFont(); -} - -/*! - \brief Sets settings into preferences dialog. - */ -void PyEditor_SettingsDlg::settingsToGui() -{ - w_HighlightCurrentLine->setChecked( my_Editor->settings()->p_HighlightCurrentLine ); - w_TextWrapping->setChecked( my_Editor->settings()->p_TextWrapping ); - w_CenterCursorOnScroll->setChecked( my_Editor->settings()->p_CenterCursorOnScroll ); - w_LineNumberArea->setChecked( my_Editor->settings()->p_LineNumberArea ); - w_TabSpaceVisible->setChecked( my_Editor->settings()->p_TabSpaceVisible ); - w_TabSize->setValue( my_Editor->settings()->p_TabSize ); - w_VerticalEdge->setChecked( my_Editor->settings()->p_VerticalEdge ); - w_NumberColumns->setValue( my_Editor->settings()->p_NumberColumns ); - w_FontWidget->setCurrentFont( my_Editor->settings()->p_Font ); - w_FontWidget->setSizes(); - - onVerticalEdgeChecked( my_Editor->settings()->p_VerticalEdge ); -} - -/*! - \brief Sets settings into the setting resources or file - if the flag is set as default is true. - */ -void PyEditor_SettingsDlg::setSettings() -{ - if ( isSetAsDefault() ) - my_Editor->settings()->writeSettings(); - - my_Editor->updateStatement(); -} - -/*! - Slot, called when user clicks "OK" button -*/ -void PyEditor_SettingsDlg::onOk() -{ - settingsFromGui(); - setSettings(); - accept(); -} - -/*! - Slot, called when user clicks "Help" button. -*/ -void PyEditor_SettingsDlg::onHelp() -{ - emit onHelpClicked(); -} diff --git a/src/PyEditor/PyEditor_SettingsDlg.h b/src/PyEditor/PyEditor_SettingsDlg.h deleted file mode 100644 index 9c486c45a..000000000 --- a/src/PyEditor/PyEditor_SettingsDlg.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyEditor_SettingsDlg.h -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#ifndef PYEDITOR_SETTINGSDLG_H -#define PYEDITOR_SETTINGSDLG_H - -#include -#include "PyEditor.h" - -class PyEditor_Editor; -class QCheckBox; -class QLabel; -class QPushButton; -class QSpinBox; -class QtxFontEdit; - -class PYEDITOR_EXPORT PyEditor_SettingsDlg : public QDialog -{ - Q_OBJECT - -public: - PyEditor_SettingsDlg( PyEditor_Editor*, QWidget* = 0 ); - - bool isSetAsDefault(); - -private Q_SLOTS: - void onVerticalEdgeChecked( bool ); - void onOk(); - void onHelp(); - -Q_SIGNALS: - void onHelpClicked(); - -private: - void settingsToGui(); - void settingsFromGui(); - void setSettings(); - - QCheckBox* w_HighlightCurrentLine; - QCheckBox* w_TextWrapping; - QCheckBox* w_CenterCursorOnScroll; - QCheckBox* w_LineNumberArea; - - QCheckBox* w_TabSpaceVisible; - QSpinBox* w_TabSize; - - QCheckBox* w_VerticalEdge; - QSpinBox* w_NumberColumns; - QLabel* lbl_NumColumns; - - QtxFontEdit* w_FontWidget; - - QCheckBox* w_DefaultCheck; - - QPushButton* myOkBtn; - QPushButton* myCancelBtn; - QPushButton* myHelpBtn; - - PyEditor_Editor* my_Editor; -}; - -#endif // PYEDITOR_SETTINGSDLG_H diff --git a/src/PyEditor/resources/translations/PyEditor_msg_en.ts b/src/PyEditor/resources/translations/PyEditor_msg_en.ts deleted file mode 100644 index 047f66180..000000000 --- a/src/PyEditor/resources/translations/PyEditor_msg_en.ts +++ /dev/null @@ -1,71 +0,0 @@ - - - - - PyEditor_SettingsDlg - - TIT_PY_PREF - Preferences - - - GR_FONT_SET - Font settings - - - LBL_FONT_FAM - Family: - - - LBL_FONT_SIZE - Size: - - - GR_DISP_SET - Display settings - - - LBL_CURRLINE_HIGHLIGHT - Enable current line highlight - - - LBL_TEXT_WRAP - Enable text wrapping - - - LBL_CURSOR_SCROLL - Center cursor on scroll - - - LBL_LINE_NUMBS_AREA - Display line numbers area - - - GR_TAB_SET - Tab settings - - - LBL_TAB_SPACES - Display tab white spaces - - - LBL_TAB_SIZE - Tab size: - - - GR_VERT_EDGE_SET - Vertical edge settings - - - LBL_VERT_EDGE - Display vertical edge - - - LBL_NUM_COLUMNS - Number of columns: - - - WDG_SET_AS_DEFAULT_CHECK - Save settings as default - - - diff --git a/src/PyEditor/resources/translations/PyEditor_msg_fr.ts b/src/PyEditor/resources/translations/PyEditor_msg_fr.ts deleted file mode 100644 index 3a2fcfb01..000000000 --- a/src/PyEditor/resources/translations/PyEditor_msg_fr.ts +++ /dev/null @@ -1,71 +0,0 @@ - - - - - PyEditor_SettingsDlg - - TIT_PY_PREF - Préférences - - - GR_FONT_SET - Paramètres de la fonte - - - LBL_FONT_FAM - Famille: - - - LBL_FONT_SIZE - Taille: - - - GR_DISP_SET - Paramètres d'affichage - - - LBL_CURRLINE_HIGHLIGHT - Met en surbrillance de la ligne actuelle - - - LBL_TEXT_WRAP - Retour à la ligne dynamique - - - LBL_CURSOR_SCROLL - Centre le curseur lors du scroll - - - LBL_LINE_NUMBS_AREA - Affiche les numéros de ligne - - - GR_TAB_SET - Indentation - - - LBL_TAB_SPACES - Affiche les guides d'indentation - - - LBL_TAB_SIZE - Largeur d'intentation: - - - GR_VERT_EDGE_SET - Marqueur de retour à la ligne - - - LBL_VERT_EDGE - Afficher la ligne verticale - - - LBL_NUM_COLUMNS - Nombre de colonnes: - - - WDG_SET_AS_DEFAULT_CHECK - Sauver en tant que paramètres par défaut - - - diff --git a/src/PyEditor/resources/translations/PyEditor_msg_ja.ts b/src/PyEditor/resources/translations/PyEditor_msg_ja.ts deleted file mode 100644 index 4b3280184..000000000 --- a/src/PyEditor/resources/translations/PyEditor_msg_ja.ts +++ /dev/null @@ -1,71 +0,0 @@ - - - - - PyEditor_SettingsDlg - - TIT_PY_PREF - 環境設定 - - - GR_FONT_SET - フォント設定 - - - LBL_FONT_FAM - Family: - - - LBL_FONT_SIZE - Size: - - - GR_DISP_SET - 表示設定 - - - LBL_CURRLINE_HIGHLIGHT - カレントラインのハイライト有効 - - - LBL_TEXT_WRAP - テキストラッピングの有効 - - - LBL_CURSOR_SCROLL - スクロール上の中心カーソル - - - LBL_LINE_NUMBS_AREA - ライン番号エリアの表示 - - - GR_TAB_SET - タブ設定 - - - LBL_TAB_SPACES - タブ空白の表示 - - - LBL_TAB_SIZE - Tab size: - - - GR_VERT_EDGE_SET - 垂直エッジ設定 - - - LBL_VERT_EDGE - 垂直エッジの表示 - - - LBL_NUM_COLUMNS - 列数: - - - WDG_SET_AS_DEFAULT_CHECK - デフォルトとして設定を保存 - - - diff --git a/src/PyViewer/CMakeLists.txt b/src/PyViewer/CMakeLists.txt index 90c645fc6..bc4fbe352 100644 --- a/src/PyViewer/CMakeLists.txt +++ b/src/PyViewer/CMakeLists.txt @@ -21,12 +21,14 @@ INCLUDE(UseQtExt) +# --- options --- + # additional include directories INCLUDE_DIRECTORIES( ${QT_INCLUDES} ${PROJECT_SOURCE_DIR}/src/Qtx ${PROJECT_SOURCE_DIR}/src/SUIT - ${PROJECT_SOURCE_DIR}/src/PyEditor + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src ) # additional preprocessor / compiler flags @@ -35,6 +37,8 @@ ADD_DEFINITIONS(${QT_DEFINITIONS}) # libraries to link to SET(_link_LIBRARIES ${PLATFORM_LIBS} ${QT_LIBRARIES} qtx suit PyEditor) +# --- headers --- + # header files / to be processed by moc SET(_moc_HEADERS PyViewer_ViewManager.h @@ -45,33 +49,46 @@ SET(_moc_HEADERS # header files / no moc processing SET(_other_HEADERS PyViewer.h + PyViewer_Settings.h ) # header files / to install SET(PyViewer_HEADERS ${_moc_HEADERS} ${_other_HEADERS}) -# resource files / to be processed by lrelease -SET(RESOURCES_PATH resources) +# --- resources --- SET(_ts_RESOURCES - ${RESOURCES_PATH}/translations/PyViewer_msg_en.ts - ${RESOURCES_PATH}/translations/PyViewer_msg_fr.ts - ${RESOURCES_PATH}/translations/PyViewer_msg_ja.ts + resources/PyViewer_msg_en.ts + resources/PyViewer_msg_fr.ts + resources/PyViewer_msg_ja.ts + resources/PyViewer_images.ts ) -# resource files / to be processed by rcc -SET(_rcc_RESOURCES ${RESOURCES_PATH}/PyEditor.qrc) +# resource files / static +SET(_other_RESOURCES + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_copy.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_cut.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_delete.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_help.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_new.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_open.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_paste.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_preferences.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_redo.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_save.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_save_as.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_select_all.png + ${PROJECT_SOURCE_DIR}/tools/PyEditor/src/resources/images/py_undo.png +) # --- sources --- # sources / moc wrappings QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS}) -# sources / rcc wrappings -QT_ADD_RESOURCES(_rcc_SOURCES ${_rcc_RESOURCES}) - # sources / static SET(_other_SOURCES + PyViewer_Settings.cxx PyViewer_ViewManager.cxx PyViewer_ViewModel.cxx PyViewer_ViewWindow.cxx @@ -81,14 +98,11 @@ SET(_other_SOURCES SET(PyViewer_SOURCES ${_other_SOURCES} ${_moc_SOURCES}) # --- rules --- -ADD_LIBRARY(PyViewer ${PyViewer_SOURCES} ${_rcc_SOURCES}) + +ADD_LIBRARY(PyViewer ${PyViewer_SOURCES}) TARGET_LINK_LIBRARIES(PyViewer ${_link_LIBRARIES}) INSTALL(TARGETS PyViewer EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS}) -ADD_EXECUTABLE(DummyPyEditor PyViewer.cxx) -SET_TARGET_PROPERTIES(DummyPyEditor PROPERTIES OUTPUT_NAME "PyEditor") -TARGET_LINK_LIBRARIES(DummyPyEditor ${_link_LIBRARIES} PyEditor PyViewer) -INSTALL(TARGETS DummyPyEditor EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_BINS}) - INSTALL(FILES ${PyViewer_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS}) QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${SALOME_GUI_INSTALL_RES_DATA}") +INSTALL(FILES ${_other_RESOURCES} DESTINATION ${SALOME_GUI_INSTALL_RES_DATA}) diff --git a/src/PyViewer/PyViewer.cxx b/src/PyViewer/PyViewer.cxx deleted file mode 100644 index 81062889b..000000000 --- a/src/PyViewer/PyViewer.cxx +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2015-2016 OPEN CASCADE -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// File : PyViewer.cxx -// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) -// - -#include -#include -#include -#include - -#include "PyViewer_ViewWindow.h" - -#include - -int main( int argc, char *argv[] ) -{ - QApplication anApplication( argc, argv ); - - // Load translations - QtxTranslator aTranslatorEd , aTranslatorVi, aTranslatorQt; - QString aLanguage = QLocale::system().name().split('_', QString::SkipEmptyParts)[0]; - if ( !aLanguage.isEmpty() ) - { - if ( aTranslatorQt.load( QString( "qt_%1" ).arg( aLanguage ), QLibraryInfo::location( QLibraryInfo::TranslationsPath ) ) ) - anApplication.installTranslator( &aTranslatorQt ); - - QDir appDir = QApplication::applicationDirPath(); - appDir.cdUp(); appDir.cdUp(); - - if ( aTranslatorEd.load( QString( "PyEditor_msg_%1" ).arg( aLanguage ), appDir.filePath( "share/salome/resources/gui" ) ) ) - anApplication.installTranslator( &aTranslatorEd ); - - if ( aTranslatorVi.load( QString( "PyViewer_msg_%1" ).arg( aLanguage ), appDir.filePath( "share/salome/resources/gui" ) ) ) - anApplication.installTranslator( &aTranslatorVi ); - } - - PyViewer_ViewWindow aViewWin; - aViewWin.resize( 650, 700 ); - aViewWin.show(); - - return anApplication.exec(); -} diff --git a/src/PyViewer/PyViewer_Settings.cxx b/src/PyViewer/PyViewer_Settings.cxx new file mode 100644 index 000000000..d86c8373e --- /dev/null +++ b/src/PyViewer/PyViewer_Settings.cxx @@ -0,0 +1,68 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyViewer_Settings.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#include "PyViewer_Settings.h" + +#include + +PyViewer_Settings::PyViewer_Settings( QtxResourceMgr* resMgr ) : + myResMgr( resMgr ) +{ + load(); +} + +PyViewer_Settings::PyViewer_Settings( QtxResourceMgr* resMgr, const QString& group ) : + myResMgr( resMgr ), + myGroup( group ) +{ + load(); +} + +void PyViewer_Settings::load() +{ + if ( !myResMgr ) return; + QString group = myGroup.isEmpty() ? option( snEditor ) : myGroup; + setHighlightCurrentLine( myResMgr->booleanValue( group, option( snHighlightCurrentLine ), highlightCurrentLine() ) ); + setTextWrapping( myResMgr->booleanValue( group, option( snTextWrapping ), textWrapping() ) ); + setCenterCursorOnScroll( myResMgr->booleanValue( group, option( snCenterCursorOnScroll ), centerCursorOnScroll() ) ); + setLineNumberArea( myResMgr->booleanValue( group, option( snLineNumberArea ), lineNumberArea() ) ); + setVerticalEdge( myResMgr->booleanValue( group, option( snVerticalEdge ), verticalEdge() ) ); + setNumberColumns( myResMgr->integerValue( group, option( snNumberColumns ), numberColumns() ) ); + setTabSpaceVisible( myResMgr->booleanValue( group, option( snTabSpaceVisible ), tabSpaceVisible() ) ); + setTabSize( myResMgr->integerValue( group, option( snTabSize ), tabSize() ) ); + setFont( myResMgr->fontValue( group, option( snFont ), font() ) ); +} + +void PyViewer_Settings::save() +{ + if ( !myResMgr ) return; + QString group = myGroup.isEmpty() ? option( snEditor ) : myGroup; + myResMgr->setValue( group, option( snHighlightCurrentLine ), highlightCurrentLine() ); + myResMgr->setValue( group, option( snTextWrapping ), textWrapping() ); + myResMgr->setValue( group, option( snCenterCursorOnScroll ), centerCursorOnScroll() ); + myResMgr->setValue( group, option( snLineNumberArea ), lineNumberArea() ); + myResMgr->setValue( group, option( snVerticalEdge ), verticalEdge() ); + myResMgr->setValue( group, option( snNumberColumns ), numberColumns() ); + myResMgr->setValue( group, option( snTabSpaceVisible ), tabSpaceVisible() ); + myResMgr->setValue( group, option( snTabSize ), tabSize() ); + myResMgr->setValue( group, option( snFont ), font() ); +} diff --git a/src/PyViewer/PyViewer_Settings.h b/src/PyViewer/PyViewer_Settings.h new file mode 100644 index 000000000..2e09552d7 --- /dev/null +++ b/src/PyViewer/PyViewer_Settings.h @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyViewer_Settings.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#ifndef PYVIEWER_SETTINGS_H +#define PYVIEWER_SETTINGS_H + +#include "PyViewer.h" +#include "PyEditor_Settings.h" + +class QtxResourceMgr; + +class PYVIEWER_EXPORT PyViewer_Settings : public PyEditor_Settings +{ +public: + PyViewer_Settings( QtxResourceMgr* ); + PyViewer_Settings( QtxResourceMgr*, const QString& ); + + void load(); + void save(); + +private: + QtxResourceMgr* myResMgr; + QString myGroup; +}; + +#endif // PYVIEWER_SETTINGS_H diff --git a/src/PyViewer/PyViewer_ViewModel.cxx b/src/PyViewer/PyViewer_ViewModel.cxx index c0360da68..1e0be87de 100644 --- a/src/PyViewer/PyViewer_ViewModel.cxx +++ b/src/PyViewer/PyViewer_ViewModel.cxx @@ -21,8 +21,11 @@ // #include "PyViewer_ViewModel.h" - #include "PyViewer_ViewWindow.h" +#include "PyViewer_Settings.h" + +#include "SUIT_ResourceMgr.h" +#include "SUIT_Session.h" /*! \class PyViewer_Viewer @@ -34,6 +37,8 @@ */ PyViewer_Viewer::PyViewer_Viewer() : SUIT_ViewModel() { + if ( !PyEditor_Settings::settings() ) + PyEditor_Settings::setSettings( new PyViewer_Settings( SUIT_Session::session()->resourceMgr(), "PyEditor" ) ); } /*! @@ -49,17 +54,5 @@ PyViewer_Viewer::~PyViewer_Viewer() */ SUIT_ViewWindow* PyViewer_Viewer::createView( SUIT_Desktop* theDesktop ) { - PyViewer_ViewWindow* aPyViewer = new PyViewer_ViewWindow( theDesktop, this ); - initView( aPyViewer ); - return aPyViewer; -} - -/*! - Start initialization of view window - \param view - view window to be initialized -*/ -void PyViewer_Viewer::initView( PyViewer_ViewWindow* theViewModel ) -{ - if ( theViewModel ) - theViewModel->initLayout(); + return new PyViewer_ViewWindow( theDesktop ); } diff --git a/src/PyViewer/PyViewer_ViewModel.h b/src/PyViewer/PyViewer_ViewModel.h index 830a16c45..1a519b817 100644 --- a/src/PyViewer/PyViewer_ViewModel.h +++ b/src/PyViewer/PyViewer_ViewModel.h @@ -43,9 +43,6 @@ public: virtual QString getType() const { return Type(); } static QString Type() { return "PyViewer"; } - -protected: - void initView( PyViewer_ViewWindow* theViewModel ); }; #endif // PYVIEWER_VIEWMODEL_H diff --git a/src/PyViewer/PyViewer_ViewWindow.cxx b/src/PyViewer/PyViewer_ViewWindow.cxx index 5d68c48fb..f7c37be7e 100644 --- a/src/PyViewer/PyViewer_ViewWindow.cxx +++ b/src/PyViewer/PyViewer_ViewWindow.cxx @@ -23,22 +23,17 @@ #include "PyViewer_ViewWindow.h" #include "PyEditor_Editor.h" -#include "PyEditor_Settings.h" #include "PyEditor_SettingsDlg.h" -#include -#include +#include "SUIT_Session.h" +#include "SUIT_ResourceMgr.h" -#include -#include -#include +#include "QtxAction.h" +#include "QtxActionToolMgr.h" -#include +#include #include #include -#include -#include -#include #include /*! @@ -48,291 +43,220 @@ /*! \brief Constructor. - \param theParent parent widget + \param desktop SALOME desktop window */ -PyViewer_ViewWindow::PyViewer_ViewWindow( SUIT_Desktop* theDesktop , PyViewer_Viewer* theModel ) : - SUIT_ViewWindow(theDesktop), - myModel(theModel) -{ - my_IsExternal = (theDesktop == NULL); - - if( isExternal() ) - initLayout(); -} - -void PyViewer_ViewWindow::initLayout() +PyViewer_ViewWindow::PyViewer_ViewWindow( SUIT_Desktop* desktop ) : + SUIT_ViewWindow( desktop ) { - my_TextEditor = new PyEditor_Editor( my_IsExternal ,SUIT_Session::session()->resourceMgr(), this ); - setCentralWidget( my_TextEditor ); - - createActions(); - createToolBar(); + // Create editor and set it as a central widget. + myTextEditor = new PyEditor_Editor( this ); + setCentralWidget( myTextEditor ); + + // Create actions. + SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); + QtxAction* action; + + // . New + action = new QtxAction( tr( "TTP_NEW" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_NEW" ) ), + tr( "ACT_NEW" ), 0, this ); + action->setStatusTip( tr( "DSC_NEW" ) ); + action->setShortcut( QKeySequence::New ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) ); + toolMgr()->registerAction( action, NewId ); + + // . Open + action = new QtxAction( tr( "TTP_OPEN" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_OPEN" ) ), + tr( "ACT_OPEN" ), 0, this ); + action->setStatusTip( tr( "DSC_OPEN" ) ); + action->setShortcut( QKeySequence::Open ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) ); + toolMgr()->registerAction( action, OpenId ); + + // . Save + action = new QtxAction( tr( "TTP_SAVE" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_SAVE" ) ), + tr( "ACT_SAVE" ), 0, this ); + action->setStatusTip( tr( "DSC_SAVE" ) ); + action->setShortcut( QKeySequence::Save ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) ); + action->setEnabled( false ); + connect( myTextEditor->document(), SIGNAL( modificationChanged( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + toolMgr()->registerAction( action, SaveId ); + + // . SaveAs + action = new QtxAction( tr( "TTP_SAVEAS" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_SAVEAS" ) ), + tr( "ACT_SAVEAS" ), 0, this ); + action->setStatusTip( tr( "DSC_SAVEAS" ) ); + action->setShortcut( QKeySequence::SaveAs ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) ); + toolMgr()->registerAction( action, SaveAsId ); + + // . Undo + action = new QtxAction( tr( "TTP_UNDO" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_UNDO" ) ), + tr( "ACT_UNDO" ), 0, this ); + action->setStatusTip( tr( "DSC_UNDO" ) ); + action->setShortcut( QKeySequence::Undo ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( undo() ) ); + action->setEnabled( false ); + connect( myTextEditor->document(), SIGNAL( undoAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + toolMgr()->registerAction( action, UndoId ); + + // . Redo + action = new QtxAction( tr( "TTP_REDO" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_REDO" ) ), + tr( "ACT_REDO" ), 0, this ); + action->setStatusTip( tr( "DSC_REDO" ) ); + action->setShortcut( QKeySequence::Redo ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( redo() ) ); + action->setEnabled( false ); + connect( myTextEditor->document(), SIGNAL( redoAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + toolMgr()->registerAction( action, RedoId ); + + // . Cut + action = new QtxAction( tr( "TTP_CUT" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_CUT" ) ), + tr( "ACT_CUT" ), 0, this ); + action->setStatusTip( tr( "DSC_CUT" ) ); + action->setShortcut( QKeySequence::Cut ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( cut() ) ); + action->setEnabled( false ); + connect( myTextEditor, SIGNAL( copyAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + toolMgr()->registerAction( action, CutId ); + + // . Copy + action = new QtxAction( tr( "TTP_COPY" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_COPY" ) ), + tr( "ACT_COPY" ), 0, this ); + action->setStatusTip( tr( "DSC_COPY" ) ); + action->setShortcut( QKeySequence::Copy ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( copy() ) ); + action->setEnabled( false ); + connect( myTextEditor, SIGNAL( copyAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + toolMgr()->registerAction( action, CopyId ); + + // . Paste + action = new QtxAction( tr( "TTP_PASTE" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_PASTE" ) ), + tr( "ACT_PASTE" ), 0, this ); + action->setStatusTip( tr( "DSC_PASTE" ) ); + action->setShortcut( QKeySequence::Paste ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( paste() ) ); + toolMgr()->registerAction( action, PasteId ); + + // . Delete + action = new QtxAction( tr( "TTP_DELETE" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_DELETE" ) ), + tr( "ACT_DELETE" ), 0, this ); + action->setStatusTip( tr( "DSC_DELETE" ) ); + action->setShortcut( QKeySequence::Delete ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( deleteSelected() ) ); + action->setEnabled( false ); + connect( myTextEditor, SIGNAL( copyAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + toolMgr()->registerAction( action, DeleteId ); + + // . SelectAll + action = new QtxAction( tr( "TTP_SELECT_ALL" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_SELECT_ALL" ) ), + tr( "ACT_SELECT_ALL" ), 0, this ); + action->setStatusTip( tr( "DSC_SELECT_ALL" ) ); + action->setShortcut( QKeySequence::SelectAll ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( selectAll() ) ); + toolMgr()->registerAction( action, SelectAllId ); + + // . Preferences + action = new QtxAction( tr( "TTP_PREFERENCES" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_PREFERENCES" ) ), + tr( "ACT_PREFERENCES" ), 0, this ); + action->setStatusTip( tr( "DSC_PREFERENCES" ) ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) ); + toolMgr()->registerAction( action, PreferencesId ); + + // . Help + action = new QtxAction( tr( "TTP_HELP" ), + resMgr->loadPixmap( "PyViewer", tr( "ICON_HELP" ) ), + tr( "ACT_HELP" ), 0, this ); + action->setStatusTip( tr( "DSC_HELP" ) ); + connect( action, SIGNAL( triggered() ), this, SLOT( onHelp() ) ); + toolMgr()->registerAction( action, HelpId ); + + // Create toolbar. + int idTB = toolMgr()->createToolBar( tr("TOOLBAR_LABEL"), QString( "PythonEditor" ), false ); + toolMgr()->append( NewId, idTB ); + toolMgr()->append( OpenId, idTB ); + toolMgr()->append( SaveId, idTB ); + toolMgr()->append( SaveAsId, idTB ); + toolMgr()->append( toolMgr()->separator(), idTB ); + toolMgr()->append( UndoId, idTB ); + toolMgr()->append( RedoId, idTB ); + toolMgr()->append( toolMgr()->separator(), idTB ); + toolMgr()->append( CutId, idTB ); + toolMgr()->append( CopyId, idTB ); + toolMgr()->append( PasteId, idTB ); + toolMgr()->append( DeleteId, idTB ); + toolMgr()->append( SelectAllId, idTB ); + toolMgr()->append( toolMgr()->separator(), idTB ); + toolMgr()->append( PreferencesId, idTB ); + toolMgr()->append( toolMgr()->separator(), idTB ); + toolMgr()->append( HelpId, idTB ); + + // Set current file. setCurrentFile( QString() ); - - if ( isExternal() ) - { - connect( my_TextEditor->document(), SIGNAL( modificationChanged( bool ) ), - this, SLOT( setWindowModified( bool ) ) ); - - statusBar()->showMessage( tr("STS_READY") ); - } } /*! \brief Destructor. - */ -PyViewer_ViewWindow::~PyViewer_ViewWindow() -{ - my_CurrentFile.clear(); - delete my_TextEditor; -} - -/*! - \return \c true if the application is external - */ -bool PyViewer_ViewWindow::isExternal() -{ - return my_IsExternal; -} - -/*! - \brief Creates actions of Python view window. */ -void PyViewer_ViewWindow::createActions() -{ - QtxActionToolMgr* aMgr = toolMgr(); - QtxAction* anAction; - - // 1. File operations - // 1.1. Create New action - anAction = new QtxAction( tr( "MNU_PY_NEW" ), QIcon( ":/images/py_new.png" ), - tr( "MNU_PY_NEW" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_NEW" ) ); - anAction->setShortcuts( QKeySequence::New ); - connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) ); - aMgr->registerAction( anAction, NewId ); - - // 1.2 Create Open action - anAction = new QtxAction( tr( "MNU_PY_OPEN" ), QIcon( ":/images/py_open.png" ), - tr( "MNU_PY_OPEN" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_OPEN" ) ); - anAction->setShortcuts( QKeySequence::Open ); - connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) ); - aMgr->registerAction( anAction, OpenId ); - - // 1.3. Create Save action - anAction = new QtxAction( tr( "MNU_PY_SAVE" ), QIcon( ":/images/py_save.png" ), - tr( "MNU_PY_SAVE" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_SAVE" ) ); - anAction->setShortcuts( QKeySequence::Save ); - connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) ); - aMgr->registerAction( anAction, SaveId ); - // Set default statement for Save action - anAction->setEnabled( my_TextEditor->document()->isModified() ); - connect( my_TextEditor->document(), SIGNAL( modificationChanged( bool ) ), - anAction, SLOT( setEnabled( bool ) ) ); - - // 1.4. Create SaveAs action - anAction = new QtxAction( tr( "MNU_PY_SAVEAS" ), QIcon( ":/images/py_save_as.png" ), - tr( "MNU_PY_SAVEAS" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_SAVEAS" ) ); - anAction->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_S ); - connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) ); - aMgr->registerAction( anAction, SaveAsId ); - - // 1.5 Create multi-action for file operations - /*QtxMultiAction* aFileAction = new QtxMultiAction( this ); - aFileAction->insertAction( aMgr->action( NewId ) ); - aFileAction->insertAction( aMgr->action( OpenId ) ); - aFileAction->insertAction( aMgr->action( SaveId ) ); - aFileAction->insertAction( aMgr->action( SaveAsId ) ); - aMgr->registerAction( aFileAction, FileOpId );*/ - - // 1.6. Create Close action - if (isExternal()) - { - anAction = new QtxAction( tr( "MNU_PY_CLOSE" ), QIcon( ":/images/py_close.png" ), - tr( "MNU_PY_CLOSE" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_CLOSE" ) ); - anAction->setShortcut( Qt::CTRL + Qt::Key_Q ); - connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( close() ) ); - aMgr->registerAction( anAction, CloseId ); - } - - // 2. Edit operations - // 2.1. Create Undo action - anAction = new QtxAction( tr( "MNU_PY_UNDO" ), QIcon( ":/images/py_undo.png" ), - tr( "MNU_PY_UNDO" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_UNDO" ) ); - anAction->setShortcuts( QKeySequence::Undo ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( undo() ) ); - aMgr->registerAction( anAction, UndoId ); - // Set default statement for Undo action - anAction->setEnabled( my_TextEditor->document()->isUndoAvailable() ); - connect( my_TextEditor->document(), SIGNAL( undoAvailable( bool ) ), - anAction, SLOT( setEnabled( bool ) ) ); - - // 2.2. Create Redo action - anAction = new QtxAction( tr( "MNU_PY_REDO" ), QIcon( ":/images/py_redo.png" ), - tr( "MNU_PY_REDO" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_REDO" ) ); - anAction->setShortcuts( QKeySequence::Redo ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( redo() ) ); - aMgr->registerAction( anAction, RedoId ); - // Set default statement for Redo action - anAction->setEnabled( my_TextEditor->document()->isRedoAvailable() ); - connect( my_TextEditor->document(), SIGNAL( redoAvailable( bool ) ), - anAction, SLOT( setEnabled( bool ) ) ); - - // 2.3. Create Cut action - anAction = new QtxAction( tr( "MNU_PY_CUT" ), QIcon( ":/images/py_cut.png" ), - tr( "MNU_PY_CUT" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_CUT" ) ); - anAction->setShortcuts( QKeySequence::Cut ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( cut() ) ); - aMgr->registerAction( anAction, CutId ); - // Set default statement for Cut action - anAction->setEnabled( false ); - connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ), - anAction, SLOT( setEnabled( bool ) ) ); - - // 2.4. Create Copy action - anAction = new QtxAction( tr( "MNU_PY_COPY" ), QIcon( ":/images/py_copy.png" ), - tr( "MNU_PY_COPY" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_COPY" ) ); - anAction->setShortcuts( QKeySequence::Copy ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( copy() ) ); - aMgr->registerAction( anAction, CopyId ); - // Set default statement for Copy action - anAction->setEnabled( false ); - connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ), - anAction, SLOT( setEnabled( bool ) ) ); - - // 2.5. Create Paste action - anAction = new QtxAction( tr( "MNU_PY_PASTE" ), QIcon( ":/images/py_paste.png" ), - tr( "MNU_PY_PASTE" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_PASTE" ) ); - anAction->setShortcuts( QKeySequence::Paste ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( paste() ) ); - aMgr->registerAction( anAction, PasteId ); - - // 2.6. Create Delete action - anAction = new QtxAction( tr( "MNU_PY_DELETE" ), QIcon( ":/images/py_delete.png" ), - tr( "MNU_PY_DELETE" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_DELETE" ) ); - anAction->setShortcuts( QKeySequence::Delete ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( deleteSelected() ) ); - aMgr->registerAction( anAction, DeleteId ); - // Set default statement for Delete action - anAction->setEnabled( false ); - connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ), - anAction, SLOT( setEnabled( bool ) ) ); - - // 2.7. Create SelectAll action - anAction = new QtxAction( tr( "MNU_PY_SELECTALL" ), QIcon( ":/images/py_select_all.png" ), - tr( "MNU_PY_SELECTALL" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_SELECT_ALL" ) ); - anAction->setShortcuts( QKeySequence::SelectAll ); - connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( selectAll() ) ); - aMgr->registerAction( anAction, SelectAllId ); - - // 2.8. Create multi-action for edit operations - /*QtxMultiAction* anEditAction = new QtxMultiAction( this ); - anEditAction->insertAction( aMgr->action( UndoId ) ); - anEditAction->insertAction( aMgr->action( RedoId ) ); - anEditAction->insertAction( aMgr->action( CutId ) ); - anEditAction->insertAction( aMgr->action( CopyId ) ); - anEditAction->insertAction( aMgr->action( PasteId ) ); - anEditAction->insertAction( aMgr->action( DeleteId ) ); - anEditAction->insertAction( aMgr->action( SelectAllId ) ); - aMgr->registerAction( anEditAction, EditOpId );*/ - - // 3. Create Preference action - anAction = new QtxAction( tr( "MNU_PY_PREFERENCES" ), QIcon( ":/images/py_preferences.png" ), - tr( "MNU_PY_PREFERENCES" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_PREFERENCES" ) ); - connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) ); - aMgr->registerAction( anAction, PreferencesId ); - - // 4. Help operations - - // 4.1. Create Help action - anAction = new QtxAction( tr( "MNU_PY_BROWSER" ), QIcon( ":/images/py_browser.png" ), - tr( "MNU_PY_BROWSER" ), 0, this ); - anAction->setStatusTip( tr( "DSC_PY_BROWSER" ) ); - connect( anAction, SIGNAL( triggered() ), this, SLOT( onBrowser() ) ); - //aMgr->registerAction( anAction, BrowserId ); - - // 4.2. Create multi-action for help operations - /*QtxMultiAction* aHelpAction = new QtxMultiAction( this ); - aHelpAction->insertAction( aMgr->action( BrowserId ) ); - aMgr->registerAction( aHelpAction, HelpOpId );*/ -} - -/*! - \brief Create toolbar for the python view window. -*/ -void PyViewer_ViewWindow::createToolBar() +PyViewer_ViewWindow::~PyViewer_ViewWindow() { - QtxActionToolMgr* aMgr = toolMgr(); - int idTB = aMgr->createToolBar( tr("LBL_TOOLBAR_LABEL"), // title (language-dependent) - QString( "PyEditorOperations" ), // name (language-independent) - false ); // disable floatable toolbar - aMgr->append( NewId, idTB ); - aMgr->append( OpenId, idTB ); - aMgr->append( SaveId, idTB ); - aMgr->append( SaveAsId, idTB ); - if ( isExternal() ) - aMgr->append( CloseId, idTB ); - aMgr->append( aMgr->separator(), idTB ); - aMgr->append( UndoId, idTB ); - aMgr->append( RedoId, idTB ); - aMgr->append( aMgr->separator(), idTB ); - aMgr->append( CutId, idTB ); - aMgr->append( CopyId, idTB ); - aMgr->append( PasteId, idTB ); - aMgr->append( DeleteId, idTB ); - aMgr->append( SelectAllId, idTB ); - aMgr->append( aMgr->separator(), idTB ); - aMgr->append( PreferencesId, idTB ); - aMgr->append( aMgr->separator(), idTB ); - aMgr->append( BrowserId, idTB ); - } /*! - \brief Reimplemented class is to receive a window close request. - \param theEvent event + \brief Manage window close request. + \param event close event */ -void PyViewer_ViewWindow::closeEvent( QCloseEvent* theEvent ) +void PyViewer_ViewWindow::closeEvent( QCloseEvent* event ) { if ( whetherSave() ) - theEvent->accept(); + event->accept(); else - theEvent->ignore(); + event->ignore(); } /*! - SLOT: Creates a new document - */ + SLOT: Create new document +*/ void PyViewer_ViewWindow::onNew() { if ( whetherSave() ) { - my_TextEditor->clear(); + myTextEditor->clear(); setCurrentFile( QString() ); } } /*! - SLOT: Open an existing python file - */ + SLOT: Open existing Python file +*/ void PyViewer_ViewWindow::onOpen() { if ( whetherSave() ) { - QString aFilePath = QFileDialog::getOpenFileName( - this, tr( "TIT_DLG_OPEN" ), QDir::currentPath(), "Python Files (*.py)" ); + QString filter = tr( "TIT_PY_FILES" ); + filter += " (*.py)"; + QString aFilePath = QFileDialog::getOpenFileName( this, + tr( "TIT_DLG_OPEN" ), + QDir::currentPath(), + filter ); if ( !aFilePath.isEmpty() ) loadFile( aFilePath ); @@ -340,24 +264,29 @@ void PyViewer_ViewWindow::onOpen() } /*! - SLOT: Save the current file - */ + SLOT: Save current document +*/ bool PyViewer_ViewWindow::onSave() { - if ( my_CurrentFile.isEmpty() ) + if ( myURL.isEmpty() ) return onSaveAs(); else - return saveFile( my_CurrentFile ); + return saveFile( myURL ); } /*! - SLOT: Save the current file under a new name - */ + SLOT: Save current document under a new name +*/ bool PyViewer_ViewWindow::onSaveAs() { - QString aFilePath = QFileDialog::getSaveFileName( - this, tr( "TIT_DLG_SAVEAS" ), QDir::currentPath(), "Python Files (*.py)" ); + QString filter = tr( "TIT_PY_FILES" ); + filter += " (*.py)"; + QString url = myURL.isEmpty() ? defaultName() : myURL; + QString aFilePath = QFileDialog::getSaveFileName( this, + tr( "TIT_DLG_SAVE" ), + url, + filter ); if ( !aFilePath.isEmpty() ) return saveFile( aFilePath ); @@ -367,143 +296,120 @@ bool PyViewer_ViewWindow::onSaveAs() /*! SLOT: Open preferences dialog - */ +*/ void PyViewer_ViewWindow::onPreferences() { - PyEditor_SettingsDlg* aPage = new PyEditor_SettingsDlg( my_TextEditor, this ); - connect( aPage, SIGNAL( onHelpClicked() ), - this, SLOT( onHelp() ) ); - aPage->exec(); - delete aPage; + PyEditor_SettingsDlg dlg( myTextEditor, true, this ); + connect( &dlg, SIGNAL( help() ), this, SLOT( onHelp() ) ); + dlg.exec(); } /*! - \brief Set preferece values for view. - */ -void PyViewer_ViewWindow::setPreferences() + \brief Associate \a filePath with the current document + \param filePath document's file path +*/ +void PyViewer_ViewWindow::setCurrentFile( const QString& filePath ) { - my_TextEditor->settings()->readSettings(); - my_TextEditor->updateStatement(); + myURL = filePath; + myTextEditor->document()->setModified( false ); } /*! - \brief Associates the theFilePath with the python view. - \param theFilePath file path - */ -void PyViewer_ViewWindow::setCurrentFile( const QString &theFilePath ) -{ - my_CurrentFile = theFilePath; - my_TextEditor->document()->setModified( false ); - - if ( isExternal() ) - { - setWindowModified( false ); - - QString aShownName = my_CurrentFile; - if ( my_CurrentFile.isEmpty() ) - aShownName = "untitled.py"; - setWindowFilePath( aShownName ); - - // Set window title with associated file path - QFileInfo anInfo( aShownName ); - setWindowTitle( "Python Viewer - " + anInfo.fileName() + "[*]" ); - } -} - -/*! - \brief Checks whether the file is modified. + \brief Check whether the file is modified. If it has the modifications then ask the user to save it. \return true if the document is saved. - */ +*/ bool PyViewer_ViewWindow::whetherSave() { - if ( my_TextEditor->document()->isModified() ) + if ( myTextEditor->document()->isModified() ) { - QMessageBox::StandardButton aReturn; - aReturn = QMessageBox::warning( - this, tr( "TIT_DLG_SAVE" ),tr( "WRN_PY_SAVE_FILE" ), - QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel ); - - if ( aReturn == QMessageBox::Save ) + QMessageBox::StandardButton answer = QMessageBox::warning( this, + tr( "NAME_PYEDITOR" ), + tr( "WRN_SAVE_FILE" ), + QMessageBox::Save | + QMessageBox::Discard | + QMessageBox::Cancel ); + switch( answer ) + { + case QMessageBox::Save: return onSave(); - else if ( aReturn == QMessageBox::Cancel ) + case QMessageBox::Cancel: return false; + default: + break; + } } return true; } /*! - \brief Opens file. - \param theFilePath file path - */ -void PyViewer_ViewWindow::loadFile( const QString &theFilePath ) + \brief Open file. + \param filePath file path +*/ +void PyViewer_ViewWindow::loadFile( const QString& filePath ) { - QFile aFile( theFilePath ); + QFile aFile( filePath ); if ( !aFile.open(QFile::ReadOnly | QFile::Text) ) { QMessageBox::warning( this, tr( "NAME_PYEDITOR" ), - tr( "WRN_PY_READ_FILE" ).arg( theFilePath ).arg( aFile.errorString() ) ); + tr( "WRN_READ_FILE" ).arg( filePath ).arg( aFile.errorString() ) ); return; } QTextStream anInput( &aFile ); QApplication::setOverrideCursor( Qt::WaitCursor ); - my_TextEditor->setPlainText( anInput.readAll() ); + myTextEditor->setPlainText( anInput.readAll() ); QApplication::restoreOverrideCursor(); - setCurrentFile( theFilePath ); + setCurrentFile( filePath ); aFile.close(); - if ( isExternal() ) - statusBar()->showMessage( tr( "STS_F_LOADED" ), 2000 ); + } /*! \brief Saves file. \param theFilePath file path - */ -bool PyViewer_ViewWindow::saveFile( const QString &theFilePath ) +*/ +bool PyViewer_ViewWindow::saveFile( const QString& filePath ) { - QFile aFile( theFilePath ); + QFile aFile( filePath ); if ( !aFile.open( QFile::WriteOnly | QFile::Text ) ) { QMessageBox::warning( this, tr( "NAME_PYEDITOR" ), - tr( "WRN_PY_WRITE_FILE" ).arg( theFilePath ).arg( aFile.errorString() ) ); + tr( "WRN_WRITE_FILE" ).arg( filePath ).arg( aFile.errorString() ) ); return false; } QTextStream anOutput( &aFile ); QApplication::setOverrideCursor( Qt::WaitCursor ); - anOutput << my_TextEditor->toPlainText(); + anOutput << myTextEditor->toPlainText(); QApplication::restoreOverrideCursor(); - setCurrentFile( theFilePath ); + setCurrentFile( filePath ); aFile.close(); - if ( isExternal() ) - statusBar()->showMessage( tr( "STS_F_SAVED" ), 2000 ); - return true; } /*! - \brief Opens help browser with python view help information. - */ -void PyViewer_ViewWindow::onBrowser() + Slot, called when user clicks "Help" button in "Preferences" dialog box. +*/ +void PyViewer_ViewWindow::onHelp() { - QDir appDir = QApplication::applicationDirPath(); - QStringList parameters; - parameters << QString( "--file=%1" ).arg( appDir.filePath( "pyeditor.html" ) ); - QProcess::startDetached( "HelpBrowser", parameters ); + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if ( app ) { + QString page = "python_viewer_page.html"; + if ( qobject_cast( sender() ) ) + page += "#custom_python_preferences"; + app->onHelpContextModule( "GUI", page ); + } } /*! - Slot, called when user clicks "Help" button in "Preferences" dialog box. + Get default name for Python file + \return default name */ -void PyViewer_ViewWindow::onHelp() +QString PyViewer_ViewWindow::defaultName() const { -#ifndef NO_SUIT - SUIT_Application* app = SUIT_Session::session()->activeApplication(); - if ( app ) - app->onHelpContextModule( "GUI", "python_viewer_page.html", "custom_python_preferences" ); -#endif + return tr( "NONAME" ); } diff --git a/src/PyViewer/PyViewer_ViewWindow.h b/src/PyViewer/PyViewer_ViewWindow.h index c7c207f13..b96ea8b2c 100644 --- a/src/PyViewer/PyViewer_ViewWindow.h +++ b/src/PyViewer/PyViewer_ViewWindow.h @@ -28,25 +28,19 @@ #include class PyEditor_Editor; -class PyViewer_Viewer; class PYVIEWER_EXPORT PyViewer_ViewWindow : public SUIT_ViewWindow { Q_OBJECT public: - enum { NewId, OpenId, SaveId, SaveAsId, CloseId, FileOpId, - UndoId, RedoId, CutId, CopyId, PasteId, DeleteId, SelectAllId, EditOpId, - PreferencesId, BrowserId, HelpOpId }; + enum { NewId, OpenId, SaveId, SaveAsId, + UndoId, RedoId, CutId, CopyId, PasteId, DeleteId, SelectAllId, + PreferencesId, HelpId }; - PyViewer_ViewWindow( SUIT_Desktop* theDesktop = 0, PyViewer_Viewer* theModel = 0 ); + PyViewer_ViewWindow( SUIT_Desktop* = 0 ); ~PyViewer_ViewWindow(); - virtual void initLayout(); - - bool isExternal(); - void setPreferences(); - protected: virtual void closeEvent( QCloseEvent* ); @@ -56,7 +50,6 @@ private Q_SLOTS: bool onSave(); bool onSaveAs(); void onPreferences(); - void onBrowser(); void onHelp(); private: @@ -65,16 +58,11 @@ private: void setCurrentFile( const QString& ); bool whetherSave(); + QString defaultName() const; private: - void createActions(); - void createToolBar(); - -private: - PyViewer_Viewer* myModel; - PyEditor_Editor* my_TextEditor; - QString my_CurrentFile; - bool my_IsExternal; + PyEditor_Editor* myTextEditor; + QString myURL; }; #endif // PYVIEWER_VIEWWINDOW_H diff --git a/src/PyViewer/resources/PyEditor.qrc b/src/PyViewer/resources/PyEditor.qrc deleted file mode 100644 index 2f703f92c..000000000 --- a/src/PyViewer/resources/PyEditor.qrc +++ /dev/null @@ -1,18 +0,0 @@ - - - images/py_browser.png - images/py_close.png - images/py_copy.png - images/py_cut.png - images/py_delete.png - images/py_new.png - images/py_open.png - images/py_paste.png - images/py_preferences.png - images/py_redo.png - images/py_save.png - images/py_save_as.png - images/py_select_all.png - images/py_undo.png - - diff --git a/src/PyViewer/resources/PyViewer_images.ts b/src/PyViewer/resources/PyViewer_images.ts new file mode 100644 index 000000000..639f1b584 --- /dev/null +++ b/src/PyViewer/resources/PyViewer_images.ts @@ -0,0 +1,59 @@ + + + + + PyViewer_ViewWindow + + ICON_NEW + py_new.png + + + ICON_OPEN + py_open.png + + + ICON_SAVE + py_save.png + + + ICON_SAVEAS + py_save_as.png + + + ICON_UNDO + py_undo.png + + + ICON_REDO + py_redo.png + + + ICON_CUT + py_cut.png + + + ICON_COPY + py_copy.png + + + ICON_PASTE + py_paste.png + + + ICON_DELETE + py_delete.png + + + ICON_SELECT_ALL + py_select_all.png + + + ICON_PREFERENCES + py_preferences.png + + + ICON_HELP + py_help.png + + + diff --git a/src/PyViewer/resources/PyViewer_msg_en.ts b/src/PyViewer/resources/PyViewer_msg_en.ts new file mode 100644 index 000000000..0f4355ee3 --- /dev/null +++ b/src/PyViewer/resources/PyViewer_msg_en.ts @@ -0,0 +1,206 @@ + + + + + PyViewer_ViewManager + + PYVIEWER_VIEW_TITLE + Python viewer:%M - viewer:%V + + + + PyViewer_ViewWindow + + NAME_PYEDITOR + Python Editor + + + ACT_NEW + &New + + + TTP_NEW + New + + + DSC_NEW + Create new document + + + ACT_OPEN + &Open... + + + TTP_OPEN + Open + + + DSC_OPEN + Open an existing document + + + ACT_SAVE + &Save + + + TTP_SAVE + Save + + + DSC_SAVE + Save the document to a file + + + ACT_SAVEAS + Save &As... + + + TTP_SAVEAS + Save As + + + DSC_SAVEAS + Save the document to a file with the new name + + + ACT_UNDO + &Undo + + + TTP_UNDO + Undo + + + DSC_UNDO + Undo last operation + + + ACT_REDO + &Redo + + + TTP_REDO + Redo + + + DSC_REDO + Redo last undone operation + + + ACT_CUT + Cu&t + + + TTP_CUT + Cut + + + DSC_CUT + Cut the current selection's contents to the clipboard + + + ACT_COPY + &Copy + + + TTP_COPY + Copy + + + DSC_COPY + Copy the current selection's contents to the clipboard + + + ACT_PASTE + &Paste + + + TTP_PASTE + Paste + + + DSC_PASTE + Paste the clipboard's contents into the current selection + + + ACT_DELETE + &Delete + + + TTP_DELETE + Delete + + + DSC_DELETE + Delete the current selection's contents + + + ACT_SELECT_ALL + Select &All + + + TTP_SELECT_ALL + Select All + + + DSC_SELECT_ALL + Select all the contents + + + ACT_PREFERENCES + Pre&ferences + + + TTP_PREFERENCES + Preferences + + + DSC_PREFERENCES + Show the Preferences dialog + + + ACT_HELP + &Help + + + TTP_HELP + Help + + + DSC_HELP + Show the help on the Python Editor + + + TOOLBAR_LABEL + Edit Operations + + + TIT_PY_FILES + Python files + + + TIT_DLG_OPEN + Open file + + + TIT_DLG_SAVE + Save file + + + WRN_SAVE_FILE + The document has been modified.<br>Do you want to save changes? + + + WRN_READ_FILE + Cannot read file %1:\n%2. + + + WRN_WRITE_FILE + Cannot write file %1:\n%2. + + + NONAME + Noname.py + + + diff --git a/src/PyViewer/resources/PyViewer_msg_fr.ts b/src/PyViewer/resources/PyViewer_msg_fr.ts new file mode 100644 index 000000000..c0fc973cd --- /dev/null +++ b/src/PyViewer/resources/PyViewer_msg_fr.ts @@ -0,0 +1,206 @@ + + + + + PyViewer_ViewManager + + PYVIEWER_VIEW_TITLE + Editeur Python:%M - visualiseur:%V + + + + PyViewer_ViewWindow + + NAME_PYEDITOR + Editeur python + + + ACT_NEW + Nouveau + + + TTP_NEW + Nouveau + + + DSC_NEW + Crée un nouveau fichier python + + + ACT_OPEN + Ouvrir + + + TTP_OPEN + Ouvrir + + + DSC_OPEN + Ouvre un fichier python existant + + + ACT_SAVE + Enregistrer + + + TTP_SAVE + Enregistrer + + + DSC_SAVE + Enregistre le fichier python sur le système de fichiers + + + ACT_SAVEAS + Enregistrer sous... + + + TTP_SAVEAS + Enregistrer sous... + + + DSC_SAVEAS + >Enregistre le fichier python sous un nouveau nom + + + ACT_UNDO + Annuler + + + TTP_UNDO + Annuler + + + DSC_UNDO + Annule la dernière opération + + + ACT_REDO + Refaire + + + TTP_REDO + Refaire + + + DSC_REDO + Répète la dernière opération + + + ACT_CUT + Coupe + + + TTP_CUT + Coupe + + + DSC_CUT + Coupe le contenu de la sélection vers le presse-papier + + + ACT_COPY + Copier + + + TTP_COPY + Copier + + + DSC_COPY + Copie le contenu de la sélection vers le presse-papier + + + ACT_PASTE + Coller + + + TTP_PASTE + Coller + + + DSC_PASTE + Colle le contenu de la sélection vers le presse-papier + + + ACT_DELETE + Supprime + + + TTP_DELETE + Supprime + + + DSC_DELETE + Supprime le contenu de la sélection + + + ACT_SELECT_ALL + Sélectionner tout + + + TTP_SELECT_ALL + Sélectionner tout + + + DSC_SELECT_ALL + Sélectionne tout le contenu + + + ACT_PREFERENCES + Préférences + + + TTP_PREFERENCES + Préférences + + + DSC_PREFERENCES + Affiche la boîte de dialogue des préférences + + + ACT_HELP + Aide + + + TTP_HELP + Aide + + + DSC_HELP + Afficher l'aide + + + TOOLBAR_LABEL + Opérations d'édition + + + TIT_PY_FILES + Fichiers Python + + + TIT_DLG_OPEN + Ouvrir le fichier + + + TIT_DLG_SAVE + Enregistrer le fichier + + + WRN_SAVE_FILE + Le document a été modifié.<br>Voulez-vous sauvegarder vos changements? + + + WRN_READ_FILE + Impossible de lire le fichier %1:\n%2. + + + WRN_WRITE_FILE + Impossible d'écrire le fichier %1:\n%2. + + + NONAME + Noname.py + + + diff --git a/src/PyViewer/resources/PyViewer_msg_ja.ts b/src/PyViewer/resources/PyViewer_msg_ja.ts new file mode 100644 index 000000000..38c7a5a54 --- /dev/null +++ b/src/PyViewer/resources/PyViewer_msg_ja.ts @@ -0,0 +1,206 @@ + + + + + PyViewer_ViewManager + + PYVIEWER_VIEW_TITLE + Python viewer:%M - viewer:%V + + + + PyViewer_ViewWindow + + NAME_PYEDITOR + Python Editor + + + ACT_NEW + 新規 + + + TTP_NEW + 新規 + + + DSC_NEW + 新規 python ファイルの作成 + + + ACT_OPEN + 開く + + + TTP_OPEN + 開く + + + DSC_OPEN + 存在する python ファイルを開く + + + ACT_SAVE + 保存 + + + TTP_SAVE + 保存 + + + DSC_SAVE + python ドキュメントをディスクに保存 + + + ACT_SAVEAS + 別名保存 + + + TTP_SAVEAS + 別名保存 + + + DSC_SAVEAS + 新しい名前で python ドキュメントを保存 + + + ACT_UNDO + 元に戻す + + + TTP_UNDO + 元に戻す + + + DSC_UNDO + 最後の操作を元に戻す + + + ACT_REDO + やり直し + + + TTP_REDO + やり直し + + + DSC_REDO + 最後の操作をやり直す + + + ACT_CUT + カット + + + TTP_CUT + カット + + + DSC_CUT + 現在選択中の内容をクリップボードにカット + + + ACT_COPY + コピー + + + TTP_COPY + コピー + + + DSC_COPY + 現在選択中の内容をクリップボードにコピー + + + ACT_PASTE + ペースト + + + TTP_PASTE + ペースト + + + DSC_PASTE + クリップボードの内容を現在の選択にペースト + + + ACT_DELETE + 削除 + + + TTP_DELETE + 削除 + + + DSC_DELETE + 現在選択中の内容を削除 + + + ACT_SELECT_ALL + すべて選択 + + + TTP_SELECT_ALL + すべて選択 + + + DSC_SELECT_ALL + すべての内容を選択 + + + ACT_PREFERENCES + 環境設定 + + + TTP_PREFERENCES + 環境設定 + + + DSC_PREFERENCES + 環境設定ボックスの表示 + + + ACT_HELP + ヘルプ + + + TTP_HELP + ヘルプ + + + DSC_HELP + ヘルプ + + + TOOLBAR_LABEL + 操作の編集 + + + TIT_PY_FILES + ã..ã.¡ã.¤ã.« Python + + + TIT_DLG_OPEN + ファイルを開く + + + TIT_DLG_SAVE + ファイルを保存 + + + WRN_SAVE_FILE + ドキュメントは修正済みです。<br>変更を保存しますか? + + + WRN_READ_FILE + Cannot read file %1:\n%2. + + + WRN_WRITE_FILE + Cannot write file %1:\n%2. + + + NONAME + Noname.py + + + diff --git a/src/PyViewer/resources/images/py_browser.png b/src/PyViewer/resources/images/py_browser.png deleted file mode 100644 index 6fb0c81b7..000000000 Binary files a/src/PyViewer/resources/images/py_browser.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_close.png b/src/PyViewer/resources/images/py_close.png deleted file mode 100644 index 52efbf028..000000000 Binary files a/src/PyViewer/resources/images/py_close.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_copy.png b/src/PyViewer/resources/images/py_copy.png deleted file mode 100644 index 385b2c4e8..000000000 Binary files a/src/PyViewer/resources/images/py_copy.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_cut.png b/src/PyViewer/resources/images/py_cut.png deleted file mode 100644 index 77edc8ab8..000000000 Binary files a/src/PyViewer/resources/images/py_cut.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_delete.png b/src/PyViewer/resources/images/py_delete.png deleted file mode 100644 index 38581d16f..000000000 Binary files a/src/PyViewer/resources/images/py_delete.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_new.png b/src/PyViewer/resources/images/py_new.png deleted file mode 100644 index 2a39dff50..000000000 Binary files a/src/PyViewer/resources/images/py_new.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_open.png b/src/PyViewer/resources/images/py_open.png deleted file mode 100644 index 26e0a2ce4..000000000 Binary files a/src/PyViewer/resources/images/py_open.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_paste.png b/src/PyViewer/resources/images/py_paste.png deleted file mode 100644 index 09cae7563..000000000 Binary files a/src/PyViewer/resources/images/py_paste.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_preferences.png b/src/PyViewer/resources/images/py_preferences.png deleted file mode 100644 index f8c4c05ff..000000000 Binary files a/src/PyViewer/resources/images/py_preferences.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_redo.png b/src/PyViewer/resources/images/py_redo.png deleted file mode 100644 index 8e685b684..000000000 Binary files a/src/PyViewer/resources/images/py_redo.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_save.png b/src/PyViewer/resources/images/py_save.png deleted file mode 100644 index 7a70c3475..000000000 Binary files a/src/PyViewer/resources/images/py_save.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_save_as.png b/src/PyViewer/resources/images/py_save_as.png deleted file mode 100644 index 4cb114750..000000000 Binary files a/src/PyViewer/resources/images/py_save_as.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_select_all.png b/src/PyViewer/resources/images/py_select_all.png deleted file mode 100644 index d7b1c730f..000000000 Binary files a/src/PyViewer/resources/images/py_select_all.png and /dev/null differ diff --git a/src/PyViewer/resources/images/py_undo.png b/src/PyViewer/resources/images/py_undo.png deleted file mode 100644 index d6701f502..000000000 Binary files a/src/PyViewer/resources/images/py_undo.png and /dev/null differ diff --git a/src/PyViewer/resources/translations/PyViewer_msg_en.ts b/src/PyViewer/resources/translations/PyViewer_msg_en.ts deleted file mode 100644 index 26a70613c..000000000 --- a/src/PyViewer/resources/translations/PyViewer_msg_en.ts +++ /dev/null @@ -1,170 +0,0 @@ - - - - - PyViewer_ViewManager - - PYVIEWER_VIEW_TITLE - Python viewer:%M - viewer:%V - - - - PyViewer_ViewWindow - - NAME_PYEDITOR - Python Viewer - - - LBL_TOOLBAR_LABEL - Edit Operations - - - MNU_PY_NEW - New - - - DSC_PY_NEW - Create a new python file - - - MNU_PY_OPEN - Open - - - DSC_PY_OPEN - Open an existing python file - - - MNU_PY_SAVE - Save - - - DSC_PY_SAVE - Save the python document to disk - - - MNU_PY_SAVEAS - Save As... - - - DSC_PY_SAVEAS - Save the python document under a new name - - - MNU_PY_CLOSE - Close - - - DSC_PY_CLOSE - Close the python document - - - MNU_PY_UNDO - Undo - - - DSC_PY_UNDO - Undoes the last operation - - - MNU_PY_REDO - Redo - - - DSC_PY_REDO - Redoes the last operation - - - MNU_PY_CUT - Cut - - - DSC_PY_CUT - Cut the current selection's contents to the clipboard - - - MNU_PY_COPY - Copy - - - DSC_PY_COPY - Copy the current selection's contents to the clipboard - - - MNU_PY_PASTE - Paste - - - DSC_PY_PASTE - Paste the clipboard's contents into the current selection - - - MNU_PY_DELETE - Delete - - - DSC_PY_DELETE - Delete the current selection's contents - - - MNU_PY_SELECTALL - Select All - - - DSC_PY_SELECT_ALL - Select all the contents - - - MNU_PY_PREFERENCES - Preferences - - - DSC_PY_PREFERENCES - Show the Preferences box - - - MNU_PY_BROWSER - Help Browser - - - DSC_PY_BROWSER - Show the Help browser - - - WRN_PY_READ_FILE - Cannot read file %1:\n%2. - - - WRN_PY_WRITE_FILE - Cannot write file %1:\n%2. - - - WRN_PY_SAVE_FILE - The document has been modified.<br>Do you want to save your changes? - - - TIT_DLG_SAVE - Save file - - - TIT_DLG_SAVEAS - Save file as - - - TIT_DLG_OPEN - Open file - - - STS_READY - Ready - - - STS_F_LOADED - File is loaded - - - STS_F_SAVED - File is saved - - - diff --git a/src/PyViewer/resources/translations/PyViewer_msg_fr.ts b/src/PyViewer/resources/translations/PyViewer_msg_fr.ts deleted file mode 100644 index 117b51784..000000000 --- a/src/PyViewer/resources/translations/PyViewer_msg_fr.ts +++ /dev/null @@ -1,170 +0,0 @@ - - - - - PyViewer_ViewManager - - PYVIEWER_VIEW_TITLE - Editeur Python:%M - visualiseur:%V - - - - PyViewer_ViewWindow - - NAME_PYEDITOR - Editeur python - - - LBL_TOOLBAR_LABEL - Opérations d'édition - - - MNU_PY_NEW - Nouveau - - - DSC_PY_NEW - Crée un nouveau fichier python - - - MNU_PY_OPEN - Ouvrir - - - DSC_PY_OPEN - Ouvre un fichier python existant - - - MNU_PY_SAVE - Enregistrer - - - DSC_PY_SAVE - Enregistre le fichier python sur le système de fichiers - - - MNU_PY_SAVEAS - Enregistrer sous... - - - DSC_PY_SAVEAS - >Enregistre le fichier python sous un nouveau nom - - - MNU_PY_CLOSE - Fermer - - - DSC_PY_CLOSE - Ferme le fichier python - - - MNU_PY_UNDO - Annuler - - - DSC_PY_UNDO - Annule la dernière opération - - - MNU_PY_REDO - Refaire - - - DSC_PY_REDO - Répète la dernière opération - - - MNU_PY_CUT - Coupe - - - DSC_PY_CUT - Coupe le contenu de la sélection vers le presse-papier - - - MNU_PY_COPY - Copier - - - DSC_PY_COPY - Copie le contenu de la sélection vers le presse-papier - - - MNU_PY_PASTE - Coller - - - DSC_PY_PASTE - Colle le contenu de la sélection vers le presse-papier - - - MNU_PY_DELETE - Supprime - - - DSC_PY_DELETE - Supprime le contenu de la sélection - - - MNU_PY_SELECTALL - Sélectionner tout - - - DSC_PY_SELECT_ALL - Sélectionne tout le contenu - - - MNU_PY_PREFERENCES - Préférences - - - DSC_PY_PREFERENCES - Affiche la boîte de dialogue des préférences - - - MNU_PY_BROWSER - Aide - - - DSC_PY_BROWSER - Afficher l'aide - - - WRN_PY_READ_FILE - Impossible de lire le fichier %1:\n%2. - - - WRN_PY_WRITE_FILE - Impossible d'écrire le fichier %1:\n%2. - - - WRN_PY_SAVE_FILE - Le document a été modifié.<br>Voulez-vous sauvegarder vos changements? - - - TIT_DLG_SAVE - Enregistrer le fichier - - - TIT_DLG_SAVEAS - Enregistrer le fichier sous - - - TIT_DLG_OPEN - Ouvrir le fichier - - - STS_READY - Prêt - - - STS_F_LOADED - Le fichier est chargé - - - STS_F_SAVED - Le fichier est sauvé - - - diff --git a/src/PyViewer/resources/translations/PyViewer_msg_ja.ts b/src/PyViewer/resources/translations/PyViewer_msg_ja.ts deleted file mode 100644 index 4747251bf..000000000 --- a/src/PyViewer/resources/translations/PyViewer_msg_ja.ts +++ /dev/null @@ -1,170 +0,0 @@ - - - - - PyViewer_ViewManager - - PYVIEWER_VIEW_TITLE - Python viewer:%M - viewer:%V - - - - PyViewer_ViewWindow - - NAME_PYEDITOR - Python Viewer - - - LBL_TOOLBAR_LABEL - 操作の編集 - - - MNU_PY_NEW - 新規 - - - DSC_PY_NEW - 新規 python ファイルの作成 - - - MNU_PY_OPEN - 開く - - - DSC_PY_OPEN - 存在する python ファイルを開く - - - MNU_PY_SAVE - 保存 - - - DSC_PY_SAVE - python ドキュメントをディスクに保存 - - - MNU_PY_SAVEAS - 別名保存 - - - DSC_PY_SAVEAS - 新しい名前で python ドキュメントを保存 - - - MNU_PY_CLOSE - 閉じる - - - DSC_PY_CLOSE - python ドキュメントを閉じる - - - MNU_PY_UNDO - 元に戻す - - - DSC_PY_UNDO - 最後の操作を元に戻す - - - MNU_PY_REDO - やり直し - - - DSC_PY_REDO - 最後の操作をやり直す - - - MNU_PY_CUT - カット - - - DSC_PY_CUT - 現在選択中の内容をクリップボードにカット - - - MNU_PY_COPY - コピー - - - DSC_PY_COPY - 現在選択中の内容をクリップボードにコピー - - - MNU_PY_PASTE - ペースト - - - DSC_PY_PASTE - クリップボードの内容を現在の選択にペースト - - - MNU_PY_DELETE - 削除 - - - DSC_PY_DELETE - 現在選択中の内容を削除 - - - MNU_PY_SELECTALL - すべて選択 - - - DSC_PY_SELECT_ALL - すべての内容を選択 - - - MNU_PY_PREFERENCES - 環境設定 - - - DSC_PY_PREFERENCES - 環境設定ボックスの表示 - - - MNU_PY_BROWSER - ヘルプブラウザ - - - DSC_PY_BROWSER - ヘルプブラウザの表示 - - - WRN_PY_READ_FILE - Cannot read file %1:\n%2. - - - WRN_PY_WRITE_FILE - Cannot write file %1:\n%2. - - - WRN_PY_SAVE_FILE - ドキュメントは修正済みです。<br>変更を保存しますか? - - - TIT_DLG_SAVE - ファイルを保存 - - - TIT_DLG_SAVEAS - 別名でファイルを保存 - - - TIT_DLG_OPEN - ファイルを開く - - - STS_READY - 準備 - - - STS_F_LOADED - ファイルは読み込まれました - - - STS_F_SAVED - ファイルは保存されました - - - diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8013abd2d..8d608b708 100755 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -26,14 +26,26 @@ ENDIF() ## # Python-based packages, part 1 (generic) ## + IF(SALOME_USE_PYCONSOLE) # Include sub-project PyConsole: SET(TOOLS_EXPORT_NAME ${PROJECT_NAME}) SET(PYCONSOLE_INSTALL_LIBS "${SALOME_INSTALL_LIBS}" CACHE PATH "") SET(PYCONSOLE_INSTALL_HEADERS "${SALOME_INSTALL_HEADERS}" CACHE PATH "") SET(PYCONSOLE_INSTALL_RES "${SALOME_GUI_INSTALL_RES_DATA}" CACHE PATH "") - OPTION(PYCONSOLE_BUILD_WITH_QT5 "Build PYCONSOLE with Qt 5" ${SALOME_BUILD_WITH_QT5}) + OPTION(PYCONSOLE_BUILD_WITH_QT5 "Build PyConsole with Qt 5" ${SALOME_BUILD_WITH_QT5}) ADD_SUBDIRECTORY(../tools/PyConsole) # will bring in PyInterp automatically ENDIF(SALOME_USE_PYCONSOLE) +IF(SALOME_USE_PYVIEWER) + # Include sub-project PyEditor: + SET(TOOLS_EXPORT_NAME ${PROJECT_NAME}) + SET(PYEDITOR_INSTALL_BINS "${SALOME_INSTALL_BINS}" CACHE PATH "") + SET(PYEDITOR_INSTALL_LIBS "${SALOME_INSTALL_LIBS}" CACHE PATH "") + SET(PYEDITOR_INSTALL_HEADERS "${SALOME_INSTALL_HEADERS}" CACHE PATH "") + SET(PYEDITOR_INSTALL_RES "${SALOME_GUI_INSTALL_RES_DATA}" CACHE PATH "") + OPTION(PYEDITOR_BUILD_WITH_QT5 "Build PyEditor with Qt 5" ${SALOME_BUILD_WITH_QT5}) + ADD_SUBDIRECTORY(PyEditor) +ENDIF(SALOME_USE_PYVIEWER) + diff --git a/tools/PyEditor/CMakeLists.txt b/tools/PyEditor/CMakeLists.txt new file mode 100644 index 000000000..3a7f37867 --- /dev/null +++ b/tools/PyEditor/CMakeLists.txt @@ -0,0 +1,104 @@ +# Copyright (C) 2015-2016 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR) +PROJECT(PyEditor C CXX) + +# Versioning +# =========== +# Project name, upper case +STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC) + +# To be changed once externalized CMake procedure: +################### +SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL") +IF(EXISTS ${KERNEL_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${KERNEL_ROOT_DIR}/salome_adm/cmake_files") + INCLUDE(SalomeMacros) +ELSE(EXISTS ${KERNEL_ROOT_DIR}) + MESSAGE(FATAL_ERROR "We absolutely need a Salome KERNEL, please define KERNEL_ROOT_DIR") +ENDIF(EXISTS ${KERNEL_ROOT_DIR}) +# From GUI - again to be changed once externalized: +LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../adm_local/cmake_files") +################### + +# Platform setup +# ============== +INCLUDE(SalomeSetupPlatform) + +# Options +# ======= +OPTION(PYEDITOR_BUILD_WITH_QT5 "Build PyEditor with Qt 5" ON) +OPTION(PYEDITOR_BUILD_SHARED_LIBS "Build shared libraries for PyEditor" ON) +OPTION(PYEDITOR_BUILD_EXE "Build PyEditor's executable" ON) +OPTION(PYEDITOR_BUILD_PYTHON "Build Python wrapping for PyEditor" ON) + +# +# Set list of prerequisites +# ========================= + +IF(PYEDITOR_BUILD_SHARED_LIBS) + SET(BUILD_SHARED_LIBS TRUE) +ELSE(PYEDITOR_BUILD_SHARED_LIBS) + SET(BUILD_SHARED_LIBS FALSE) +ENDIF(PYEDITOR_BUILD_SHARED_LIBS) + +# Qt +IF(NOT PYEDITOR_BUILD_WITH_QT5) + FIND_PACKAGE(SalomeQt4 REQUIRED) +ELSE() + FIND_PACKAGE(SalomeQt5 REQUIRED) +ENDIF() + +IF(PYEDITOR_BUILD_PYTHON) + # Python + FIND_PACKAGE(SalomePythonInterp REQUIRED) + FIND_PACKAGE(SalomePythonLibs REQUIRED) + SALOME_LOG_OPTIONAL_PACKAGE(SalomePythonInterp PYEDITOR_BUILD_PYTHON) + SALOME_LOG_OPTIONAL_PACKAGE(SalomePythonLibs PYEDITOR_BUILD_PYTHON) + # Sip + FIND_PACKAGE(SalomeSIP REQUIRED) # should come after Python and before PyQt + SALOME_LOG_OPTIONAL_PACKAGE(SalomeSIP PYEDITOR_BUILD_PYTHON) + # PyQt + IF (NOT PYEDITOR_BUILD_WITH_QT5) + FIND_PACKAGE(SalomePyQt4 REQUIRED) + SALOME_LOG_OPTIONAL_PACKAGE(SalomePyQt4 PYEDITOR_BUILD_PYTHON) + ELSE() + FIND_PACKAGE(SalomePyQt5 REQUIRED) + SALOME_LOG_OPTIONAL_PACKAGE(SalomePyQt5 PYEDITOR_BUILD_PYTHON) + ENDIF() +ENDIF(PYEDITOR_BUILD_PYTHON) + +# Detection report +SALOME_PACKAGE_REPORT_AND_CHECK() + +# Directories +# +# Directories have to be given after prerequisites (to be able to use +# Python version string for example). +# =========== +SET(PYEDITOR_INSTALL_BINS bin CACHE PATH "Install path: PyEditor binaries") +SET(PYEDITOR_INSTALL_LIBS lib CACHE PATH "Install path: PyEditor libraries") +SET(PYEDITOR_INSTALL_HEADERS include CACHE PATH "Install path: PyEditor headers") +SET(PYEDITOR_INSTALL_RES share/resources CACHE PATH "Install path: PyEditor resources") + +# Sources +# ======== +ADD_SUBDIRECTORY(src) + diff --git a/tools/PyEditor/src/CMakeLists.txt b/tools/PyEditor/src/CMakeLists.txt new file mode 100644 index 000000000..b8e10e409 --- /dev/null +++ b/tools/PyEditor/src/CMakeLists.txt @@ -0,0 +1,113 @@ +# Copyright (C) 2015-2016 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 : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +# + +INCLUDE(UseQtExt) + +IF(PYEDITOR_BUILD_PYTHON) + ADD_SUBDIRECTORY(python) +ENDIF(PYEDITOR_BUILD_PYTHON) + +# --- options --- + +# additional include directories +INCLUDE_DIRECTORIES( + ${QT_INCLUDES} +) + +# additional preprocessor / compiler flags +ADD_DEFINITIONS(${QT_DEFINITIONS}) + +# libraries to link to +SET(_link_LIBRARIES ${PLATFORM_LIBS} ${QT_LIBRARIES}) + +# --- headers --- + +# header files / to be processed by moc +SET(_moc_HEADERS + PyEditor_Editor.h + PyEditor_LineNumberArea.h + PyEditor_PyHighlighter.h + PyEditor_SettingsDlg.h + PyEditor_Window.h +) + +# header files / no moc processing +SET(_other_HEADERS + PyEditor.h + PyEditor_Settings.h + PyEditor_StdSettings.h +) + +# header files / to install +SET(PyEditor_HEADERS ${_moc_HEADERS} ${_other_HEADERS}) + +# --- resources --- + +# resource files / to be processed by lrelease +SET(_ts_RESOURCES + resources/translations/PyEditor_msg_en.ts + resources/translations/PyEditor_msg_fr.ts + resources/translations/PyEditor_msg_ja.ts +) + +# resource files / to be processed by rcc +SET(_rcc_RESOURCES resources/PyEditor.qrc) + +# --- sources --- + +# sources / moc wrappings +QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS}) + +# sources / rcc wrappings +QT_ADD_RESOURCES(_rcc_SOURCES ${_rcc_RESOURCES}) + +# sources / static +SET(_other_SOURCES + PyEditor_Editor.cxx + PyEditor_LineNumberArea.cxx + PyEditor_PyHighlighter.cxx + PyEditor_Settings.cxx + PyEditor_SettingsDlg.cxx + PyEditor_StdSettings.cxx + PyEditor_Window.cxx +) + +# sources / to compile +# - for library +SET(PyEditor_SOURCES ${_other_SOURCES} ${_moc_SOURCES} ${_rcc_SOURCES}) +# - for executable +SET(pyeditorexe_SOURCES ${PyEditor_SOURCES} PyEditor.cxx) + +# --- rules --- + +ADD_LIBRARY(PyEditor ${PyEditor_SOURCES}) +TARGET_LINK_LIBRARIES(PyEditor ${_link_LIBRARIES}) +INSTALL(TARGETS PyEditor EXPORT ${TOOLS_EXPORT_NAME}TargetGroup DESTINATION ${PYEDITOR_INSTALL_LIBS}) + +IF(PYEDITOR_BUILD_EXE) + ADD_EXECUTABLE(pyeditorexe ${pyeditorexe_SOURCES}) + SET_TARGET_PROPERTIES(pyeditorexe PROPERTIES OUTPUT_NAME "pyeditor") + TARGET_LINK_LIBRARIES(pyeditorexe ${_link_LIBRARIES}) + INSTALL(TARGETS pyeditorexe EXPORT ${TOOLS_EXPORT_NAME}TargetGroup DESTINATION ${PYEDITOR_INSTALL_BINS}) +ENDIF(PYEDITOR_BUILD_EXE) + +INSTALL(FILES ${PyEditor_HEADERS} DESTINATION ${PYEDITOR_INSTALL_HEADERS}) +QT_INSTALL_TS_RESOURCES("${_ts_RESOURCES}" "${PYEDITOR_INSTALL_RES}") diff --git a/tools/PyEditor/src/PyEditor.cxx b/tools/PyEditor/src/PyEditor.cxx new file mode 100644 index 000000000..03a29b8e9 --- /dev/null +++ b/tools/PyEditor/src/PyEditor.cxx @@ -0,0 +1,109 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#include "PyEditor_Window.h" +#include "PyEditor_StdSettings.h" + +#include +#include +#include +#include +#include +#include + +QString qtTrDir() +{ + const char* vars[] = { "QT5_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" }; + QString qtPath; + for ( uint i = 0; i < sizeof( vars ) / sizeof( vars[0] ) && qtPath.isEmpty(); i++ ) + qtPath = qgetenv( vars[i] ); + if ( !qtPath.isEmpty() ) + qtPath = QDir( qtPath ).absoluteFilePath( "translations" ); + return qtPath; +} + +QString resourceDir() +{ + // Try standalone application's dir. + QDir appDir = QApplication::applicationDirPath(); + appDir.cdUp(); + QFileInfo resFile( appDir.filePath( "share/resources/PyEditor_msg_en.qm" ) ); + if ( resFile.exists() ) + return resFile.absolutePath(); + + // Try salome dir. + appDir = QApplication::applicationDirPath(); + appDir.cdUp(); appDir.cdUp(); + resFile.setFile( appDir.filePath( "share/salome/resources/gui/PyEditor_msg_en.qm" ) ); + if ( resFile.exists() ) + return resFile.absolutePath(); + + return QString(); +} + +int main( int argc, char *argv[] ) +{ + QApplication app( argc, argv ); + app.setOrganizationName( "salome" ); + app.setOrganizationDomain( "www.salome-platform.org" ); + app.setApplicationName( "pyeditor" ); + + PyEditor_StdSettings* settings = new PyEditor_StdSettings(); + PyEditor_Settings::setSettings( settings ); + + QString language = settings->language(); + + // Load Qt translations. + QString qtDirTrSet = QLibraryInfo::location( QLibraryInfo::TranslationsPath ); + QString qtDirTrEnv = qtTrDir(); + + QStringList qtTrFiles; + qtTrFiles << "qt" << "qtbase"; + QStringList qtTrDirs; + qtTrDirs << QLibraryInfo::location( QLibraryInfo::TranslationsPath ); + qtTrDirs << qtTrDir(); + + foreach( QString qtTrFile, qtTrFiles ) { + foreach ( QString qtTrDir, qtTrDirs ) { + QTranslator* translator = new QTranslator; + if ( translator->load( QString("%1_%2").arg( qtTrFile ).arg( language ), qtTrDir ) ) { + app.installTranslator( translator ); + break; + } + else { + delete translator; + } + } + } + + // Load application's translations. + QTranslator translator; + if ( translator.load( QString( "PyEditor_msg_%1" ).arg( language ), resourceDir() ) ) + app.installTranslator( &translator ); + + PyEditor_Window window; + window.setWindowIcon( QIcon( ":/images/py_editor.png" ) ); + window.resize( 650, 700 ); + window.show(); + + return app.exec(); +} diff --git a/tools/PyEditor/src/PyEditor.h b/tools/PyEditor/src/PyEditor.h new file mode 100644 index 000000000..165f53a77 --- /dev/null +++ b/tools/PyEditor/src/PyEditor.h @@ -0,0 +1,33 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor.h +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#ifdef WIN32 + +#if defined PYEDITOR_EXPORTS || defined PyEditor_EXPORTS +#define PYEDITOR_EXPORT __declspec(dllexport) +#else +#define PYEDITOR_EXPORT __declspec(dllimport) +#endif + +#else +#define PYEDITOR_EXPORT +#endif // WIN32 diff --git a/tools/PyEditor/src/PyEditor_Editor.cxx b/tools/PyEditor/src/PyEditor_Editor.cxx new file mode 100644 index 000000000..fff2e0425 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_Editor.cxx @@ -0,0 +1,826 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_Editor.cxx +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#include "PyEditor_Editor.h" +#include "PyEditor_LineNumberArea.h" +#include "PyEditor_PyHighlighter.h" +#include "PyEditor_Settings.h" + +#include +#include + +/*! + \class PyEditor_Editor + \brief Widget to show / edit Python scripts. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +PyEditor_Editor::PyEditor_Editor( QWidget* parent ) + : QPlainTextEdit( parent ) +{ + // Set up line number area + myLineNumberArea = new PyEditor_LineNumberArea( this ); + myLineNumberArea->setMouseTracking( true ); + + // Set up syntax highighter + mySyntaxHighlighter = new PyEditor_PyHighlighter( this->document() ); + + // Set-up settings + PyEditor_Settings* settings = PyEditor_Settings::settings(); + if ( settings ) + setSettings( *settings ); + + // Connect signals + connect( this, SIGNAL( blockCountChanged( int ) ), this, SLOT( updateLineNumberAreaWidth( int ) ) ); + connect( this, SIGNAL( updateRequest( QRect, int ) ), this, SLOT( updateLineNumberArea( QRect, int ) ) ); + connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( updateHighlightCurrentLine() ) ); + connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( matchParentheses() ) ); +} + +/*! + \brief Destructor. +*/ +PyEditor_Editor::~PyEditor_Editor() +{ +} + +/*! + \brief Get editor settings. + \return settings object +*/ +const PyEditor_Settings& PyEditor_Editor::settings() const +{ + return mySettings; +} + +/*! + \brief Set editor settings. + \param settings new settings +*/ +void PyEditor_Editor::setSettings( const PyEditor_Settings& settings ) +{ + mySettings.copyFrom( settings ); + + // Set font size + QFont aFont = font(); + aFont.setFamily( mySettings.font().family() ); + aFont.setPointSize( mySettings.font().pointSize() ); + setFont( aFont ); + + // Set line wrap mode + setLineWrapMode( mySettings.textWrapping() ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap ); + + // Center the cursor on screen + setCenterOnScroll( mySettings.centerCursorOnScroll() ); + + // Set size white spaces + setTabStopWidth( mySettings.tabSize() * 10 ); + + // Update current line highlight + updateHighlightCurrentLine(); + + // Update line numbers area + updateLineNumberAreaWidth( 0 ); + + mySyntaxHighlighter->rehighlight(); + viewport()->update(); +} + +/*! + Delete current selection contents. +*/ +void PyEditor_Editor::deleteSelected() +{ + QTextCursor aCursor = textCursor(); + if ( aCursor.hasSelection() ) + aCursor.removeSelectedText(); + setTextCursor( aCursor ); +} + +/*! + \brief Process key press event. + Reimplemented from QPlainTextEdit. + \param event key press event +*/ +void PyEditor_Editor::keyPressEvent( QKeyEvent* event ) +{ + if ( event->type() == QEvent::KeyPress ) + { + int aKey = event->key(); + Qt::KeyboardModifiers aCtrl = event->modifiers() & Qt::ControlModifier; + Qt::KeyboardModifiers aShift = event->modifiers() & Qt::ShiftModifier; + + if ( aKey == Qt::Key_Tab || ( aKey == Qt::Key_Backtab || ( aKey == Qt::Key_Tab && aShift ) ) ) + { + QTextCursor aCursor = textCursor(); + aCursor.beginEditBlock(); + tabIndentation( aKey == Qt::Key_Backtab ); + aCursor.endEditBlock(); + event->accept(); + } + else if ( aKey == Qt::Key_Enter || aKey == Qt::Key_Return ) + { + QTextCursor aCursor = textCursor(); + aCursor.beginEditBlock(); + if ( lineIndent() == 0 ) + { + QPlainTextEdit::keyPressEvent( event ); + } + aCursor.endEditBlock(); + event->accept(); + } + else if ( event == QKeySequence::MoveToStartOfLine || event == QKeySequence::SelectStartOfLine ) + { + QTextCursor aCursor = this->textCursor(); + if ( QTextLayout* aLayout = aCursor.block().layout() ) + { + if ( aLayout->lineForTextPosition( aCursor.position() - aCursor.block().position() ).lineNumber() == 0 ) + { + handleHome( event == QKeySequence::SelectStartOfLine ); + } + } + } + else if ( ( aKey == Qt::Key_Colon || ( aKey == Qt::Key_Space && !aCtrl && !aShift ) ) && + !textCursor().hasSelection() ) + { + QTextCursor aCursor = textCursor(); + aCursor.movePosition( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor ); + + QString aSelectedText = aCursor.selectedText(); + int numSpaces = findFirstNonSpace( aSelectedText ); + int amountChars = aSelectedText.size() - findFirstNonSpace( aSelectedText ); + QString aLeadingText = aSelectedText.right( amountChars ); + + QStringList aReservedWords; + aReservedWords.append( "except" ); + if ( aKey == Qt::Key_Colon ) + { + aReservedWords.append( "else" ); + aReservedWords.append( "finally" ); + } + else if ( aKey == Qt::Key_Space ) + { + aReservedWords.append( "elif" ); + } + + if ( aReservedWords.contains( aLeadingText ) ) + { + QString aPreviousText = aCursor.block().previous().text(); + int numSpacesPrevious = findFirstNonSpace( aPreviousText ); + if ( numSpaces == numSpacesPrevious ) + { + tabIndentation( true ); + aCursor.movePosition( QTextCursor::EndOfBlock ); + setTextCursor( aCursor ); + } + } + QPlainTextEdit::keyPressEvent( event ); + } + else + { + QPlainTextEdit::keyPressEvent( event ); + } + } +} + +/*! + \brief Handle resize event. + Reimplemented from QPlainTextEdit. + \param event resize event +*/ +void PyEditor_Editor::resizeEvent( QResizeEvent* event ) +{ + QPlainTextEdit::resizeEvent( event ); + + // Change size geometry of line number area + QRect aContentsRect = contentsRect(); + myLineNumberArea->setGeometry( QRect( aContentsRect.left(), + aContentsRect.top(), + lineNumberAreaWidth(), + aContentsRect.height() ) ); +} + +/*! + \brief Paint event. + Reimplemented from QPlainTextEdit. + \param event paint event +*/ +void PyEditor_Editor::paintEvent( QPaintEvent* event ) +{ + QPlainTextEdit::paintEvent( event ); + + QTextBlock aBlock( firstVisibleBlock() ); + QPointF anOffset( contentOffset() ); + QPainter aPainter( this->viewport() ); + + int aTabSpaces = this->tabStopWidth() / 10; + + // Visualization tab spaces + if ( mySettings.tabSpaceVisible() ) + { + qreal aTop = blockBoundingGeometry( aBlock ).translated( anOffset ).top(); + while ( aBlock.isValid() && aTop <= event->rect().bottom() ) + { + if ( aBlock.isVisible() && blockBoundingGeometry( aBlock ).translated( anOffset ).toRect().intersects( event->rect() ) ) + { + QString aText = aBlock.text(); + if ( aText.contains( QRegExp( "\\w+" ) ) ) + aText.remove( QRegExp( "(?!\\w+)\\s+$" ) ); + + int aColumn = 0; + int anIndex = 0; + while ( anIndex != -1 ) + { + anIndex = aText.indexOf( QRegExp( QString( "^\\s{%1}" ).arg( aTabSpaces ) ), 0 ); + if ( anIndex != -1 ) + { + aColumn = aColumn + aTabSpaces; + aText = aText.mid( aTabSpaces ); + + if ( aText.startsWith( ' ' ) ) + { + QTextCursor aCursor( aBlock ); + aCursor.setPosition( aBlock.position() + aColumn ); + + QRect aRect = cursorRect( aCursor ); + aPainter.setPen( QPen( Qt::darkGray, 1, Qt::DotLine ) ); + aPainter.drawLine( aRect.x() + 1, aRect.top(), aRect.x() + 1, aRect.bottom() ); + } + } + } + } + aBlock = aBlock.next(); + } + } + + // Vertical edge line + if ( mySettings.verticalEdge() ) + { + const QRect aRect = event->rect(); + const QFont aFont = currentCharFormat().font(); + int aNumberColumn = QFontMetrics( aFont ).averageCharWidth() * mySettings.numberColumns() + anOffset.x() + document()->documentMargin(); + aPainter.setPen( QPen( Qt::lightGray, 1, Qt::SolidLine ) ); + aPainter.drawLine( aNumberColumn, aRect.top(), aNumberColumn, aRect.bottom() ); + } +} + +/*! + \brief Indent and tab text. + \param isShift flag defines reverse tab direction +*/ +void PyEditor_Editor::tabIndentation( bool isShift ) +{ + QTextCursor aCursor = textCursor(); + int aTabSpaces = this->tabStopWidth()/10; + + if ( !aCursor.hasSelection() ) + { + if ( !isShift ) + { + int N = aCursor.columnNumber() % aTabSpaces; + aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) ); + } + else + { + QTextBlock aCurrentBlock = document()->findBlock( aCursor.position() ); + int anIndentPos = findFirstNonSpace( aCurrentBlock.text() ); + aCursor.setPosition( aCurrentBlock.position() + anIndentPos ); + setTextCursor( aCursor ); + + //if ( aCurrCursorColumnPos <= anIndentPos ) + //{ + int aColumnPos = aCursor.columnNumber(); + if ( aColumnPos != 0 ) + { + int N = aCursor.columnNumber() % aTabSpaces; + if ( N == 0 ) N = aTabSpaces; + aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, N ); + aCursor.removeSelectedText(); + } + setTextCursor( aCursor ); + //} + } + } + else + { + indentSelection( isShift ); + } +} + +/*! + \brief Indent and tab selected text. + \param isShift flag defines reverse tab direction +*/ +void PyEditor_Editor::indentSelection( bool isShift ) +{ + QTextCursor aCursor = this->textCursor(); + + int aCursorStart = aCursor.selectionStart(); + int aCursorEnd = aCursor.selectionEnd(); + + QTextBlock aStartBlock = document()->findBlock( aCursorStart ); + QTextBlock anEndBlock = document()->findBlock( aCursorEnd - 1 ).next(); + + int aTabSpaces = this->tabStopWidth()/10; + + for ( QTextBlock aBlock = aStartBlock; aBlock.isValid() && aBlock != anEndBlock; aBlock = aBlock.next() ) + { + QString aText = aBlock.text(); + int anIndentPos = findFirstNonSpace( aText ); + int N = ( anIndentPos % aTabSpaces ); + + aCursor.setPosition( aBlock.position() + anIndentPos ); + if ( !isShift ) + { + aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) ); + setTextCursor( aCursor ); + } + else + { + int aColumnPos = aCursor.columnNumber(); + if ( aColumnPos != 0 ) + { + int blockN = aColumnPos % aTabSpaces; + if ( blockN == 0 ) blockN = aTabSpaces; + aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, blockN ); + aCursor.removeSelectedText(); + setTextCursor( aCursor ); + } + } + } + + // Reselect the selected lines + aCursor.setPosition( aStartBlock.position() ); + aCursor.setPosition( anEndBlock.previous().position(), QTextCursor::KeepAnchor ); + aCursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor ); + setTextCursor( aCursor ); +} + +/*! + \brief Find first non white-space symbol in text. + \param text input text + \return index of first non white-space symbol +*/ +int PyEditor_Editor::findFirstNonSpace( const QString& text ) +{ + int i = 0; + while ( i < text.size() ) + { + if ( !text.at(i).isSpace() ) + return i; + ++i; + } + return i; +} + +/*! + \brief Indent line. + \return error code +*/ +int PyEditor_Editor::lineIndent() +{ + int aTabSpaces = this->tabStopWidth() / 10; + + QTextCursor aCursor = textCursor(); + aCursor.insertBlock(); + setTextCursor( aCursor ); + + QTextBlock aCurrentBlock = aCursor.block(); + if ( aCurrentBlock == document()->begin() ) + return 0; + + QTextBlock aPreviousBlock = aCurrentBlock.previous(); + + QString aPreviousText; + forever + { + if ( aPreviousBlock == document()->begin() ) + { + aPreviousText = aPreviousBlock.text(); + if ( aPreviousText.isEmpty() && aPreviousText.trimmed().isEmpty() ) + return -1; + break; + } + + // If the text of this block is not empty then break the loop. + aPreviousText = aPreviousBlock.text(); + if ( !aPreviousText.isEmpty() && !aPreviousText.trimmed().isEmpty() ) + break; + + aPreviousBlock = aPreviousBlock.previous(); + } + + int aTabIndentation = 0; + int anAmountIndentation = -1; + int i = 0; + while ( i < aPreviousText.size() ) + { + if ( !aPreviousText.at(i).isSpace() ) + { + anAmountIndentation = findFirstNonSpace( aPreviousText ); + break; + } + else + { + ++aTabIndentation; + } + ++i; + } + + if ( anAmountIndentation == -1 ) + { + if ( aTabIndentation > 0 ) + anAmountIndentation = aTabIndentation; + else + return 0; + } + + const QString aPreviousTrimmed = aPreviousText.trimmed(); + if ( aPreviousTrimmed.endsWith( ":" ) ) + { + anAmountIndentation += aTabSpaces; + } + else + { + if ( aPreviousTrimmed == "continue" + || aPreviousTrimmed == "break" + || aPreviousTrimmed == "pass" + || aPreviousTrimmed == "return" + || aPreviousTrimmed == "raise" + || aPreviousTrimmed.startsWith( "raise " ) + || aPreviousTrimmed.startsWith( "return " ) ) + anAmountIndentation -= aTabSpaces; + } + + aCursor.insertText( QString( anAmountIndentation, QLatin1Char(' ') ) ); + setTextCursor( aCursor ); + + return 1; +} + +/*! + \brief Set text cursor on home position. + \param isExtendLine \c true to keep current anchor position +*/ +void PyEditor_Editor::handleHome( bool isExtendLine ) +{ + QTextCursor aCursor = textCursor(); + QTextCursor::MoveMode aMode = QTextCursor::MoveAnchor; + + if ( isExtendLine ) + aMode = QTextCursor::KeepAnchor; + + int anInitPos = aCursor.position(); + int aBlockPos = aCursor.block().position(); + + QChar aCharacter = document()->characterAt( aBlockPos ); + while ( aCharacter.category() == QChar::Separator_Space ) + { + ++aBlockPos; + if ( aBlockPos == anInitPos ) + break; + aCharacter = document()->characterAt( aBlockPos ); + } + + if ( aBlockPos == anInitPos ) + aBlockPos = aCursor.block().position(); + + aCursor.setPosition( aBlockPos, aMode ); + setTextCursor( aCursor ); +} + +/*! + \brief Update current line highlighting. +*/ +void PyEditor_Editor::updateHighlightCurrentLine() +{ + QList anExtraSelections; + if ( !isReadOnly() && mySettings.highlightCurrentLine() ) + { + QTextEdit::ExtraSelection selection; + + QColor lineColor = QColor( Qt::gray ).lighter( 155 ); + + selection.format.setBackground( lineColor ); + selection.format.setProperty( QTextFormat::FullWidthSelection, QVariant( true ) ); + selection.cursor = textCursor(); + selection.cursor.clearSelection(); + anExtraSelections.append( selection ); + } + setExtraSelections( anExtraSelections ); +} + +/*! + \brief Draw linne number area. + \param event paint event +*/ +void PyEditor_Editor::lineNumberAreaPaintEvent( QPaintEvent* event ) +{ + QPainter aPainter( myLineNumberArea ); + aPainter.fillRect( event->rect(), QColor( Qt::lightGray ).lighter( 125 ) ); + + QTextBlock aBlock = firstVisibleBlock(); + int aBlockNumber = aBlock.blockNumber(); + int aTop = (int)blockBoundingGeometry( aBlock ).translated( contentOffset() ).top(); + int aBottom = aTop + (int)blockBoundingRect( aBlock ).height(); + int aCurrentLine = document()->findBlock( textCursor().position() ).blockNumber(); + + QFont aFont = aPainter.font(); + aPainter.setPen( this->palette().color( QPalette::Text ) ); + + while ( aBlock.isValid() && aTop <= event->rect().bottom() ) + { + if ( aBlock.isVisible() && aBottom >= event->rect().top() ) + { + if ( aBlockNumber == aCurrentLine ) + { + aPainter.setPen( Qt::darkGray ); + aFont.setBold( true ); + aPainter.setFont( aFont ); + } + else + { + aPainter.setPen( Qt::gray ) ; + aFont.setBold( false ); + aPainter.setFont( aFont ); + } + QString aNumber = QString::number( aBlockNumber + 1 ); + aPainter.drawText( 0, aTop, myLineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, aNumber ); + } + + aBlock = aBlock.next(); + aTop = aBottom; + aBottom = aTop + (int)blockBoundingRect( aBlock ).height(); + ++aBlockNumber; + } +} + +/*! + \brief Get with of line number area. + \return width of line number area +*/ +int PyEditor_Editor::lineNumberAreaWidth() +{ + int aSpace = 0; + + int aDigits = 1; + int aMaximum = qMax( 1, blockCount() ); + while ( aMaximum >= 10 ) + { + aMaximum /= 10; + ++aDigits; + } + + if ( mySettings.lineNumberArea() ) + aSpace += 5 + fontMetrics().width( QLatin1Char( '9' ) ) * aDigits; + + return aSpace; +} + +/*! + \brief Update width of the line number area. + \param newBlockCount (not used) +*/ +void PyEditor_Editor::updateLineNumberAreaWidth( int /*newBlockCount*/ ) +{ + setViewportMargins( lineNumberAreaWidth(), 0, 0, 0 ); +} + +/*! + \brief Update line number area (when editor viewport is scrolled). + \param rect area being updated + \param dy scroll factor +*/ +void PyEditor_Editor::updateLineNumberArea( const QRect& rect, int dy ) +{ + if ( dy ) + myLineNumberArea->scroll( 0, dy ); + else + myLineNumberArea->update( 0, rect.y(), myLineNumberArea->width(), rect.height() ); + + if ( rect.contains( viewport()->rect() ) ) + updateLineNumberAreaWidth( 0 ); +} + +/*! + \brief Manage parentheses. +*/ +void PyEditor_Editor::matchParentheses() +{ + PyEditor_PyHighlighter::TextBlockData* data = + static_cast( textCursor().block().userData() ); + + if ( data ) + { + QVector infoEntries = data->parentheses(); + + int aPos = textCursor().block().position(); + bool ignore = false; + for ( int i = 0; i < infoEntries.size(); ++i ) + { + PyEditor_PyHighlighter::ParenthesisInfo* info = infoEntries.at(i); + + int currentColumnPosition = textCursor().columnNumber(); + if ( info->position == currentColumnPosition - 1 && isLeftBrackets( info->character ) ) + { + if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) ) + createParenthesisSelection( aPos + info->position ); + } + else if ( info->position == currentColumnPosition && isLeftBrackets( info->character ) ) + { + if ( !ignore ) + { + if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) ) + createParenthesisSelection( aPos + info->position ); + } + } + else if ( info->position == currentColumnPosition - 1 && isRightBrackets( info->character ) ) + { + if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) ) + createParenthesisSelection( aPos + info->position ); + ignore = true; + } + else if ( info->position == currentColumnPosition && isRightBrackets( info->character ) ) + { + if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) ) + createParenthesisSelection( aPos + info->position ); + } + } + } +} + +/*! + \brief Match left brackets. + \param currentBlock text block + \param idx index + \param numLeftParentheses number of left parentheses + \return \c true if the left match +*/ +bool PyEditor_Editor::matchLeftParenthesis( const QTextBlock& currentBlock, + int idx, int numLeftParentheses ) +{ + PyEditor_PyHighlighter::TextBlockData* data = + static_cast( currentBlock.userData() ); + QVector infos = data->parentheses(); + + int docPos = currentBlock.position(); + for ( ; idx < infos.size(); ++idx ) + { + PyEditor_PyHighlighter::ParenthesisInfo* info = infos.at( idx ); + + if ( isLeftBrackets( info->character ) ) + { + ++numLeftParentheses; + continue; + } + + if ( isRightBrackets( info->character ) && numLeftParentheses == 0 ) + { + createParenthesisSelection( docPos + info->position ); + return true; + } + else + --numLeftParentheses; + } + + QTextBlock nextBlock = currentBlock.next(); + if ( nextBlock.isValid() ) + return matchLeftParenthesis( nextBlock, 0, numLeftParentheses ); + + return false; +} + +/*! + \brief Match right brackets. + \param currentBlock text block + \param idx index + \param numRightParentheses number of right parentheses + \return \c true if the right match +*/ +bool PyEditor_Editor::matchRightParenthesis( const QTextBlock& currentBlock, + int idx, int numRightParentheses ) +{ + PyEditor_PyHighlighter::TextBlockData* data = static_cast( currentBlock.userData() ); + QVector parentheses = data->parentheses(); + + int docPos = currentBlock.position(); + for ( ; idx > -1 && parentheses.size() > 0; --idx ) + { + PyEditor_PyHighlighter::ParenthesisInfo* info = parentheses.at( idx ); + if ( isRightBrackets( info->character ) ) + { + ++numRightParentheses; + continue; + } + if ( isLeftBrackets( info->character ) && numRightParentheses == 0 ) + { + createParenthesisSelection( docPos + info->position ); + return true; + } + else + --numRightParentheses; + } + + QTextBlock prevBlock = currentBlock.previous(); + if ( prevBlock.isValid() ) + { + PyEditor_PyHighlighter::TextBlockData* data = static_cast( prevBlock.userData() ); + QVector parentheses = data->parentheses(); + return matchRightParenthesis( prevBlock, parentheses.size() - 1, numRightParentheses ); + } + + return false; +} + +/*! + \brief Create brackets selection. + \param position cursor position +*/ +void PyEditor_Editor::createParenthesisSelection( int position ) +{ + QList selections = extraSelections(); + + QTextEdit::ExtraSelection selection; + + QTextCharFormat format = selection.format; + format.setForeground( Qt::red ); + format.setBackground( Qt::white ); + selection.format = format; + + QTextCursor cursor = textCursor(); + cursor.setPosition( position ); + cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor ); + selection.cursor = cursor; + + selections.append( selection ); + setExtraSelections( selections ); +} + +/*! + \brief Check if symbol is a left bracket. + \param symbol text symbol + \return \c true if symbol is any left bracket +*/ +bool PyEditor_Editor::isLeftBrackets( QChar symbol ) +{ + return symbol == '(' || symbol == '{' || symbol == '['; +} + +/*! + \brief Check if symbol is a right bracket. + \param symbol text symbol + \return \c true if symbol is any right bracket +*/ +bool PyEditor_Editor::isRightBrackets( QChar symbol ) +{ + return symbol == ')' || symbol == '}' || symbol == ']'; +} + +/*! + \brief Append new paragraph to the end of the editor's text. + \param text paragraph text +*/ +void PyEditor_Editor::append( const QString& text ) +{ + appendPlainText( text ); +} + +/*! + \brief Set text to the editor. + \param text new text +*/ +void PyEditor_Editor::setText( const QString& text ) +{ + setPlainText( text ); +} + +/*! + \brief Get current editor's content. + \return current text +*/ +QString PyEditor_Editor::text() const +{ + return toPlainText(); +} diff --git a/tools/PyEditor/src/PyEditor_Editor.h b/tools/PyEditor/src/PyEditor_Editor.h new file mode 100644 index 000000000..026635673 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_Editor.h @@ -0,0 +1,85 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_Editor.h +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#ifndef PYEDITOR_EDITOR_H +#define PYEDITOR_EDITOR_H + +#include "PyEditor.h" +#include "PyEditor_Settings.h" + +#include + +class PyEditor_PyHighlighter; + +class PYEDITOR_EXPORT PyEditor_Editor : public QPlainTextEdit +{ + Q_OBJECT + +public: + PyEditor_Editor( QWidget* = 0 ); + virtual ~PyEditor_Editor(); + + void setSettings( const PyEditor_Settings& ); + const PyEditor_Settings& settings() const; + QString text() const; + +public Q_SLOTS: + void deleteSelected(); + void append( const QString& ); + void setText( const QString& text ); + +protected: + virtual void keyPressEvent( QKeyEvent* ); + virtual void resizeEvent( QResizeEvent* ); + virtual void paintEvent( QPaintEvent* ); + +private Q_SLOTS: + void updateHighlightCurrentLine(); + void matchParentheses(); + + void updateLineNumberAreaWidth( int ); + void updateLineNumberArea( const QRect&, int ); + +private: + bool matchLeftParenthesis( const QTextBlock&, int, int ); + bool matchRightParenthesis( const QTextBlock&, int, int ); + void createParenthesisSelection( int ); + bool isLeftBrackets( QChar ); + bool isRightBrackets( QChar ); + void lineNumberAreaPaintEvent( QPaintEvent* ); + int lineNumberAreaWidth(); + + void handleHome( bool ); + int lineIndent(); + void tabIndentation( bool ); + void indentSelection( bool ); + + int findFirstNonSpace( const QString& ); + + QWidget* myLineNumberArea; + PyEditor_PyHighlighter* mySyntaxHighlighter; + PyEditor_Settings mySettings; + + friend class PyEditor_LineNumberArea; +}; + +#endif // PYEDITOR_EDITOR_H diff --git a/tools/PyEditor/src/PyEditor_LineNumberArea.cxx b/tools/PyEditor/src/PyEditor_LineNumberArea.cxx new file mode 100644 index 000000000..066ad4e55 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_LineNumberArea.cxx @@ -0,0 +1,51 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_LineNumberArea.cxx +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#include "PyEditor_LineNumberArea.h" + +#include "PyEditor_Editor.h" + +/*! + \class PyEditor_LineNumberArea + \brief Widget shows line number. +*/ + +/*! + \brief Constructor. + \param theCodeEditor parent widget +*/ +PyEditor_LineNumberArea::PyEditor_LineNumberArea( PyEditor_Editor* theCodeEditor ) : + QWidget( theCodeEditor ) +{ + myCodeEditor = theCodeEditor; +} + +QSize PyEditor_LineNumberArea::sizeHint() const +{ + return QSize( myCodeEditor->lineNumberAreaWidth(), 0 ); +} + +void PyEditor_LineNumberArea::paintEvent( QPaintEvent* theEvent ) +{ + myCodeEditor->lineNumberAreaPaintEvent( theEvent ); + QWidget::paintEvent( theEvent ); +} diff --git a/tools/PyEditor/src/PyEditor_LineNumberArea.h b/tools/PyEditor/src/PyEditor_LineNumberArea.h new file mode 100644 index 000000000..e0092698e --- /dev/null +++ b/tools/PyEditor/src/PyEditor_LineNumberArea.h @@ -0,0 +1,46 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_LineNumberArea.h +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#ifndef PYEDITOR_LINENUMBERAREA_H +#define PYEDITOR_LINENUMBERAREA_H + +#include + +class PyEditor_Editor; + +class PyEditor_LineNumberArea : public QWidget +{ + Q_OBJECT + +public: + explicit PyEditor_LineNumberArea( PyEditor_Editor* ); + + QSize sizeHint() const; + +protected: + void paintEvent( QPaintEvent* ); + +private: + PyEditor_Editor* myCodeEditor; +}; + +#endif // PYEDITOR_LINENUMBERAREA_H diff --git a/tools/PyEditor/src/PyEditor_PyHighlighter.cxx b/tools/PyEditor/src/PyEditor_PyHighlighter.cxx new file mode 100644 index 000000000..70ff0186a --- /dev/null +++ b/tools/PyEditor/src/PyEditor_PyHighlighter.cxx @@ -0,0 +1,355 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_PyHighlighter.cxx +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#include "PyEditor_PyHighlighter.h" + +#define NORMAL 0 +#define TRIPLESINGLE 1 +#define TRIPLEDOUBLE 2 + +/*! + \class PyEditor_PyHighlighter + \brief Python highlighter class defines the syntax highlighting rules. +*/ + +PyEditor_PyHighlighter::TextBlockData::TextBlockData() +{ +} + +QVector PyEditor_PyHighlighter::TextBlockData::parentheses() +{ + return myParentheses; +} + +void PyEditor_PyHighlighter::TextBlockData::insert( PyEditor_PyHighlighter::ParenthesisInfo* theInfo ) +{ + int i = 0; + while ( i < myParentheses.size() && theInfo->position > myParentheses.at(i)->position ) + ++i; + + myParentheses.insert( i, theInfo ); +} + +/*! + \brief Constructor. + \param theDocument container for structured rich text documents. +*/ +PyEditor_PyHighlighter::PyEditor_PyHighlighter( QTextDocument* theDocument ) + : QSyntaxHighlighter( theDocument ) +{ + initialize(); +} + +/*! + \brief Initialization rules. +*/ +void PyEditor_PyHighlighter::initialize() +{ + HighlightingRule aRule; + + // Keywords + keywordFormat.setForeground( Qt::blue ); + QStringList aKeywords = keywords(); + foreach ( const QString& keyword, aKeywords ) + { + aRule.pattern = QRegExp( QString( "\\b%1\\b" ).arg( keyword ) ); + aRule.format = keywordFormat; + aRule.capture = 0; + highlightingRules.append( aRule ); + } + + // Special keywords + specialFromat.setForeground( Qt::magenta ); + QStringList aSpecialKeywords = specialKeywords(); + foreach ( const QString& keyword, aSpecialKeywords ) + { + aRule.pattern = QRegExp( QString( "\\b%1\\b" ).arg( keyword ) ); + aRule.format = specialFromat; + aRule.capture = 0; + highlightingRules.append( aRule ); + } + + // Reference to the current instance of the class + referenceClassFormat.setForeground( QColor( 179, 143, 0 ) ); + referenceClassFormat.setFontItalic( true ); + aRule.pattern = QRegExp( "\\bself\\b" ); + aRule.format = referenceClassFormat; + aRule.capture = 0; + highlightingRules.append( aRule ); + + // Numbers + numberFormat.setForeground( Qt::darkMagenta ); + aRule.pattern = QRegExp( "\\b([-+])?(\\d+(\\.)?\\d*|\\d*(\\.)?\\d+)(([eE]([-+])?)?\\d+)?\\b" ); + aRule.format = numberFormat; + aRule.capture = 0; + highlightingRules.append( aRule ); + + // String qoutation + quotationFormat.setForeground( Qt::darkGreen ); + aRule.pattern = QRegExp( "(?:'[^']*'|\"[^\"]*\")" ); + aRule.pattern.setMinimal( true ); + aRule.format = quotationFormat; + aRule.capture = 0; + highlightingRules.append( aRule ); + + // Function names + functionFormat.setFontWeight( QFont::Bold ); + aRule.pattern = QRegExp( "(?:def\\s*)(\\b[A-Za-z0-9_]+)(?=[\\W])" ); + aRule.capture = 1; + aRule.format = functionFormat; + highlightingRules.append( aRule ); + + // Class names + classFormat.setForeground( Qt::darkBlue ); + classFormat.setFontWeight( QFont::Bold ); + aRule.pattern = QRegExp( "(?:class\\s*)(\\b[A-Za-z0-9_]+)(?=[\\W])" ); + aRule.capture = 1; + aRule.format = classFormat; + highlightingRules.append( aRule ); + + // Multi line comments + multiLineCommentFormat.setForeground( Qt::darkRed ); + tripleQuotesExpression = QRegExp( "(:?\"[\"]\".*\"[\"]\"|'''.*''')" ); + aRule.pattern = tripleQuotesExpression; + aRule.pattern.setMinimal( true ); + aRule.format = multiLineCommentFormat; + aRule.capture = 0; + highlightingRules.append( aRule ); + + tripleSingleExpression = QRegExp( "'''(?!\")" ); + tripleDoubleExpression = QRegExp( "\"\"\"(?!')" ); + + // Single comments + singleLineCommentFormat.setForeground( Qt::darkGray ); + aRule.pattern = QRegExp( "#[^\n]*" ); + aRule.format = singleLineCommentFormat; + aRule.capture = 0; + highlightingRules.append( aRule ); +} + +/*! + \return string list of Python keywords. + */ +QStringList PyEditor_PyHighlighter::keywords() +{ + QStringList aKeywords; + aKeywords << "and" + << "as" + << "assert" + << "break" + << "class" + << "continue" + << "def" + << "elif" + << "else" + << "except" + << "exec" + << "finally" + << "False" + << "for" + << "from" + << "global" + << "if" + << "import" + << "in" + << "is" + << "lambda" + << "None" + << "not" + << "or" + << "pass" + << "print" + << "raise" + << "return" + << "True" + << "try" + << "while" + << "with" + << "yield"; + return aKeywords; +} + +/*! + \return string list of special Python keywords. +*/ +QStringList PyEditor_PyHighlighter::specialKeywords() +{ + QStringList aSpecialKeywords; + aSpecialKeywords << "ArithmeticError" + << "AssertionError" + << "AttributeError" + << "EnvironmentError" + << "EOFError" + << "Exception" + << "FloatingPointError" + << "ImportError" + << "IndentationError" + << "IndexError" + << "IOError" + << "KeyboardInterrupt" + << "KeyError" + << "LookupError" + << "MemoryError" + << "NameError" + << "NotImplementedError" + << "OSError" + << "OverflowError" + << "ReferenceError" + << "RuntimeError" + << "StandardError" + << "StopIteration" + << "SyntaxError" + << "SystemError" + << "SystemExit" + << "TabError" + << "TypeError" + << "UnboundLocalError" + << "UnicodeDecodeError" + << "UnicodeEncodeError" + << "UnicodeError" + << "UnicodeTranslateError" + << "ValueError" + << "WindowsError" + << "ZeroDivisionError" + << "Warning" + << "UserWarning" + << "DeprecationWarning" + << "PendingDeprecationWarning" + << "SyntaxWarning" + << "OverflowWarning" + << "RuntimeWarning" + << "FutureWarning"; + return aSpecialKeywords; +} + +void PyEditor_PyHighlighter::highlightBlock( const QString& theText ) +{ + TextBlockData* aData = new TextBlockData; + + insertBracketsData( RoundBrackets, aData, theText ); + insertBracketsData( CurlyBrackets, aData, theText ); + insertBracketsData( SquareBrackets, aData, theText ); + + setCurrentBlockUserData( aData ); + + foreach ( const HighlightingRule& rule, highlightingRules ) + { + QRegExp expression( rule.pattern ); + int anIndex = expression.indexIn( theText ); + while ( anIndex >= 0 ) + { + anIndex = expression.pos( rule.capture ); + int aLength = expression.cap( rule.capture ).length(); + setFormat( anIndex, aLength, rule.format ); + anIndex = expression.indexIn( theText, anIndex + aLength ); + } + } + + setCurrentBlockState( NORMAL ); + + if ( theText.indexOf( tripleQuotesExpression ) != -1 ) + return; + + QList aTripleSingle; + aTripleSingle << theText.indexOf( tripleSingleExpression ) << TRIPLESINGLE; + + QList aTripleDouble; + aTripleDouble << theText.indexOf( tripleDoubleExpression ) << TRIPLEDOUBLE; + + QList< QList > aTripleExpressions; + aTripleExpressions << aTripleSingle << aTripleDouble; + + for ( int i = 0; i < aTripleExpressions.length(); i++ ) + { + QList aBlock = aTripleExpressions[i]; + int anIndex = aBlock[0]; + int aState = aBlock[1]; + if ( previousBlockState() == aState ) + { + if ( anIndex == -1 ) + { + anIndex = theText.length(); + setCurrentBlockState( aState ); + } + setFormat( 0, anIndex + 3, multiLineCommentFormat ); + } + else if ( anIndex > -1 ) + { + setCurrentBlockState( aState ); + setFormat( anIndex, theText.length(), multiLineCommentFormat ); + } + } +} + +void PyEditor_PyHighlighter::insertBracketsData( char theLeftSymbol, + char theRightSymbol, + TextBlockData* theData, + const QString& theText ) +{ + int leftPosition = theText.indexOf( theLeftSymbol ); + while( leftPosition != -1 ) + { + ParenthesisInfo* info = new ParenthesisInfo(); + info->character = theLeftSymbol; + info->position = leftPosition; + + theData->insert( info ); + leftPosition = theText.indexOf( theLeftSymbol, leftPosition + 1 ); + } + + int rightPosition = theText.indexOf( theRightSymbol ); + while( rightPosition != -1 ) + { + ParenthesisInfo* info = new ParenthesisInfo(); + info->character = theRightSymbol; + info->position = rightPosition; + + theData->insert( info ); + rightPosition = theText.indexOf( theRightSymbol, rightPosition + 1 ); + } +} + +void PyEditor_PyHighlighter::insertBracketsData( Brackets theBrackets, + TextBlockData* theData, + const QString& theText ) +{ + char leftChar = '0'; + char rightChar = '0'; + + switch( theBrackets ) + { + case RoundBrackets: + leftChar = '('; + rightChar = ')'; + break; + case CurlyBrackets: + leftChar = '{'; + rightChar = '}'; + break; + case SquareBrackets: + leftChar = '['; + rightChar = ']'; + break; + } + + insertBracketsData( leftChar, rightChar, theData, theText ); +} diff --git a/tools/PyEditor/src/PyEditor_PyHighlighter.h b/tools/PyEditor/src/PyEditor_PyHighlighter.h new file mode 100644 index 000000000..961616fa2 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_PyHighlighter.h @@ -0,0 +1,91 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_PyHighlighter.h +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#ifndef PYEDITOR_PYHIGHLIGHTER_H +#define PYEDITOR_PYHIGHLIGHTER_H + +#include + +class QTextDocument; + +class PyEditor_PyHighlighter : public QSyntaxHighlighter +{ + Q_OBJECT + +public: + + struct ParenthesisInfo + { + char character; + int position; + }; + + class TextBlockData : public QTextBlockUserData + { + public: + TextBlockData(); + + QVector parentheses(); + void insert( ParenthesisInfo* ); + + private: + QVector myParentheses; + }; + +public: + PyEditor_PyHighlighter( QTextDocument* = 0 ); + + void initialize(); + QStringList keywords(); + QStringList specialKeywords(); + +protected: + struct HighlightingRule + { + QRegExp pattern; + QTextCharFormat format; + int capture; + }; + QVector highlightingRules; + + enum Brackets { RoundBrackets, CurlyBrackets, SquareBrackets }; + + QRegExp tripleQuotesExpression; + QRegExp tripleSingleExpression; + QRegExp tripleDoubleExpression; + + QTextCharFormat classFormat; + QTextCharFormat referenceClassFormat; + QTextCharFormat functionFormat; + QTextCharFormat keywordFormat; + QTextCharFormat specialFromat; + QTextCharFormat numberFormat; + QTextCharFormat singleLineCommentFormat; + QTextCharFormat multiLineCommentFormat; + QTextCharFormat quotationFormat; + + void highlightBlock( const QString& ); + void insertBracketsData( char, char, TextBlockData*, const QString& ); + void insertBracketsData( Brackets, TextBlockData*, const QString& ); +}; + +#endif // PYEDITOR_PYHIGHLIGHTER_H diff --git a/tools/PyEditor/src/PyEditor_Settings.cxx b/tools/PyEditor/src/PyEditor_Settings.cxx new file mode 100644 index 000000000..d9fd52fd1 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_Settings.cxx @@ -0,0 +1,283 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_Settings.cxx +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#include "PyEditor_Settings.h" + +/*! + \class PyEditor_Settings + \brief Manager of setting values. +*/ + +PyEditor_Settings* PyEditor_Settings::myGlobalSettings = 0; + +/*! + Get global settings. + \return reference to global settings object +*/ +PyEditor_Settings* PyEditor_Settings::settings() +{ + return myGlobalSettings; +} + +/*! + Set global settings. + \param settings reference to global settings object +*/ +void PyEditor_Settings::setSettings( PyEditor_Settings* settings ) +{ + if ( myGlobalSettings ) + delete myGlobalSettings; + myGlobalSettings = settings; +} + +/*! + \brief Constructor. +*/ +PyEditor_Settings::PyEditor_Settings() + : myHighlightCurrentLine( true ), + myTextWrapping( false ), + myCenterCursorOnScroll( true ), + myLineNumberArea( true ), + myVerticalEdge( true ), + myNumberColumns( 80 ), + myTabSpaceVisible( true ), + myTabSize( 4 ), + myFont( "Courier", 10 ) +{ +} + +/*! + \brief Set "highlight current line" option. + \param on option value +*/ +void PyEditor_Settings::setHighlightCurrentLine( bool on ) +{ + myHighlightCurrentLine = on; +} + +/*! + \brief Get "highlight current line" option. + \return option value +*/ +bool PyEditor_Settings::highlightCurrentLine() const +{ + return myHighlightCurrentLine; +} + +/*! + \brief Set "text wrapping" option. + \param on option value +*/ +void PyEditor_Settings::setTextWrapping( bool on ) +{ + myTextWrapping = on; +} + +/*! + \brief Get "text wrapping line" option. + \return option value +*/ +bool PyEditor_Settings::textWrapping() const +{ + return myTextWrapping; +} + +/*! + \brief Set "center cursor on scroll" option. + \param on option value +*/ +void PyEditor_Settings::setCenterCursorOnScroll( bool on ) +{ + myCenterCursorOnScroll = on; +} + +/*! + \brief Get "center cursor on scroll" option. + \return option value +*/ +bool PyEditor_Settings::centerCursorOnScroll() const +{ + return myCenterCursorOnScroll; +} + +/*! + \brief Set "show line number area" option. + \param on option value +*/ +void PyEditor_Settings::setLineNumberArea( bool on ) +{ + myLineNumberArea = on; +} + +/*! + \brief Get "show line number area" option. + \return option value +*/ +bool PyEditor_Settings::lineNumberArea() const +{ + return myLineNumberArea; +} + +/*! + \brief Set "show vertical edge" option. + \param on option value +*/ +void PyEditor_Settings::setVerticalEdge( bool on ) +{ + myVerticalEdge = on; +} + +/*! + \brief Get "show vertical edge" option. + \return option value +*/ +bool PyEditor_Settings::verticalEdge() const +{ + return myVerticalEdge; +} + +/*! + \brief Set "number of columns" option. + \param value option value +*/ +void PyEditor_Settings::setNumberColumns( int value ) +{ + myNumberColumns = value; +} + +/*! + \brief Get "number of columns" option. + \return option value +*/ +int PyEditor_Settings::numberColumns() const +{ + return myNumberColumns; +} + +/*! + \brief Set "show tab spaces" option. + \param on option value +*/ +void PyEditor_Settings::setTabSpaceVisible( bool on ) +{ + myTabSpaceVisible = on; +} + +/*! + \brief Get "show tab spaces" option. + \return option value +*/ +bool PyEditor_Settings::tabSpaceVisible() const +{ + return myTabSpaceVisible; +} + +/*! + \brief Set "tab size" option. + \param value option value +*/ +void PyEditor_Settings::setTabSize( int value ) +{ + myTabSize = value; +} + +/*! + \brief Get "tab size" option. + \return option value +*/ +int PyEditor_Settings::tabSize() const +{ + return myTabSize; +} + +/*! + \brief Set "font" option. + \param font option value +*/ +void PyEditor_Settings::setFont( const QFont& font ) +{ + myFont = font; +} + +/*! + \brief Get "font" option. + \return option value +*/ +QFont PyEditor_Settings::font() const +{ + return myFont; +} + +/*! + \brief Read settings from the persistence storage. + Base implementation does nothing; it should be reimplemented in successors. +*/ +void PyEditor_Settings::load() +{ +} + +/*! + \brief Write settings to the persistence storage. + Base implementation does nothing; it should be reimplemented in successors. +*/ +void PyEditor_Settings::save() +{ +} + +/*! + \brief Copy settings from another object. + \param other source settings object +*/ +void PyEditor_Settings::copyFrom( const PyEditor_Settings& other ) +{ + setHighlightCurrentLine( other.highlightCurrentLine() ); + setTextWrapping( other.textWrapping() ); + setCenterCursorOnScroll( other.centerCursorOnScroll() ); + setLineNumberArea( other.lineNumberArea() ); + setTabSpaceVisible( other.tabSpaceVisible() ); + setTabSize( other.tabSize() ); + setVerticalEdge( other.verticalEdge() ); + setNumberColumns( other.numberColumns() ); + setFont( other.font() ); + save(); +} + +/*! + \brief Get preference item's identifier. + \return string identifier +*/ +QString PyEditor_Settings::option( Option option ) +{ + static const char* options[] = { + "PythonEditor", + "HighlightCurrentLine", + "TextWrapping", + "CenterCursorOnScroll", + "LineNumberArea", + "VerticalEdge", + "NumberColumns", + "TabSpaceVisible", + "TabSize", + "Font", + }; + return option >= 0 && option <= snFont ? options[option] : "Unknown"; +} diff --git a/tools/PyEditor/src/PyEditor_Settings.h b/tools/PyEditor/src/PyEditor_Settings.h new file mode 100644 index 000000000..2f1c9be6c --- /dev/null +++ b/tools/PyEditor/src/PyEditor_Settings.h @@ -0,0 +1,106 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_Settings.h +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#ifndef PYEDITOR_SETTINGS_H +#define PYEDITOR_SETTINGS_H + +#include "PyEditor.h" + +#include + +class PYEDITOR_EXPORT PyEditor_Settings +{ +protected: + enum Option { snEditor, + snHighlightCurrentLine, + snTextWrapping, + snCenterCursorOnScroll, + snLineNumberArea, + snVerticalEdge, + snNumberColumns, + snTabSpaceVisible, + snTabSize, + snFont }; + +public: + static PyEditor_Settings* settings(); + static void setSettings( PyEditor_Settings* ); + + PyEditor_Settings(); + + void setHighlightCurrentLine( bool ); + bool highlightCurrentLine() const; + + void setTextWrapping( bool ); + bool textWrapping() const; + + void setCenterCursorOnScroll( bool ); + bool centerCursorOnScroll() const; + + void setLineNumberArea( bool ); + bool lineNumberArea() const; + + void setVerticalEdge( bool ); + bool verticalEdge() const; + + void setNumberColumns( int ); + int numberColumns() const; + + void setTabSpaceVisible( bool ); + bool tabSpaceVisible() const; + + void setTabSize( int ); + int tabSize() const; + + void setFont( const QFont& ); + QFont font() const; + + virtual void load(); + virtual void save(); + + void copyFrom( const PyEditor_Settings& ); + +protected: + QString option( Option ); + +private: + // Display settings + bool myHighlightCurrentLine; + bool myTextWrapping; + bool myCenterCursorOnScroll; + bool myLineNumberArea; + + // Vertical edge settings + bool myVerticalEdge; + int myNumberColumns; + + // Tab settings + bool myTabSpaceVisible; + int myTabSize; + + // Font settings + QFont myFont; + + static PyEditor_Settings* myGlobalSettings; +}; + +#endif // PYEDITOR_SETTINGS_H diff --git a/tools/PyEditor/src/PyEditor_SettingsDlg.cxx b/tools/PyEditor/src/PyEditor_SettingsDlg.cxx new file mode 100644 index 000000000..fc2c94b64 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_SettingsDlg.cxx @@ -0,0 +1,326 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_SettingsDlg.cxx +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#include "PyEditor_SettingsDlg.h" + +#include "PyEditor_Editor.h" +#include "PyEditor_Settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/*! + \class PyEditor_SettingsDlg + \brief Dialog settings for python editor. +*/ + +/*! + \brief Constructor. + \param theEditor widget that is used to edit and display text + \param theParent parent widget +*/ +PyEditor_SettingsDlg::PyEditor_SettingsDlg( PyEditor_Editor* theEditor, + bool showHelp, QWidget* theParent ) : + QDialog( theParent ), + myEditor( theEditor ) +{ + setWindowTitle( tr("TIT_PREFERENCES") ); + QVBoxLayout* aMainLayout = new QVBoxLayout( this ); + + // . Font settings + QGroupBox* aFontSetBox = new QGroupBox( tr( "GR_FONT_SET" ), this ); + QHBoxLayout* aFontSetLayout = new QHBoxLayout( aFontSetBox ); + myFontFamily = new QFontComboBox( aFontSetBox ); + myFontFamily->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + myFontSize = new QComboBox( aFontSetBox ); + myFontSize->setInsertPolicy( QComboBox::NoInsert ); + myFontSize->setEditable( true ); + myFontSize->setValidator( new QIntValidator( 1, 250, myFontSize ) ); + myFontSize->setSizeAdjustPolicy( QComboBox::AdjustToContents ); + myFontSize->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ); + aFontSetLayout->addWidget( myFontFamily ); + aFontSetLayout->addWidget( myFontSize ); + connect( myFontFamily, SIGNAL( currentFontChanged( QFont ) ), + this, SLOT( onFontChanged() ) ); + aMainLayout->addWidget( aFontSetBox ); + // . Font settings + + // . Display settings + QGroupBox* aDisplaySetBox = new QGroupBox( tr( "GR_DISP_SET" ), this ); + QVBoxLayout* aDisplaySetLayout = new QVBoxLayout( aDisplaySetBox ); + myHighlightCurrentLine = new QCheckBox( tr( "LBL_CURRLINE_HIGHLIGHT" ), aDisplaySetBox ); + myTextWrapping = new QCheckBox( tr( "LBL_TEXT_WRAP" ), aDisplaySetBox ); + myCenterCursorOnScroll = new QCheckBox( tr( "LBL_CURSOR_SCROLL" ), aDisplaySetBox ); + myLineNumberArea = new QCheckBox( tr( "LBL_LINE_NUMBS_AREA" ), aDisplaySetBox ); + aDisplaySetLayout->addWidget( myHighlightCurrentLine ); + aDisplaySetLayout->addWidget( myTextWrapping ); + aDisplaySetLayout->addWidget( myCenterCursorOnScroll ); + aDisplaySetLayout->addWidget( myLineNumberArea ); + aDisplaySetLayout->addStretch( 1 ); + aMainLayout->addWidget( aDisplaySetBox ); + // . Display settings + + // . Tab settings + QGroupBox* aTabSetBox = new QGroupBox( tr( "GR_TAB_SET" ), this ); + QVBoxLayout* aTabSetLayout = new QVBoxLayout( aTabSetBox ); + myTabSpaceVisible = new QCheckBox( tr( "LBL_TAB_SPACES" ), aTabSetBox ); + QHBoxLayout* aTabSizeLayout = new QHBoxLayout; + QLabel* aTabSizeLabel = new QLabel( tr( "LBL_TAB_SIZE" ), aTabSetBox ); + myTabSize = new QSpinBox( aTabSetBox ); + myTabSize->setMinimum( 0 ); + myTabSize->setSingleStep( 1 ); + aTabSizeLayout->addWidget( aTabSizeLabel ); + aTabSizeLayout->addWidget( myTabSize ); + aTabSizeLayout->addStretch( 1 ); + aTabSetLayout->addWidget( myTabSpaceVisible ); + aTabSetLayout->addLayout( aTabSizeLayout ); + // . Tab settings + + // . Vertical edge settings + QGroupBox* aVertEdgeSetBox = new QGroupBox( tr( "GR_VERT_EDGE_SET" ), this ); + QVBoxLayout* aVertEdgeLayout = new QVBoxLayout( aVertEdgeSetBox ); + myVerticalEdge = new QCheckBox( tr( "LBL_VERT_EDGE" ), aVertEdgeSetBox ); + QHBoxLayout* aNumberColLayout = new QHBoxLayout; + myNumberColumnsLbl = new QLabel( tr( "LBL_NUM_COLUMNS" ), aVertEdgeSetBox ); + myNumberColumns = new QSpinBox( aVertEdgeSetBox ); + myNumberColumns->setMinimum( 0 ); + myNumberColumns->setSingleStep( 1 ); + aNumberColLayout->addWidget( myNumberColumnsLbl ); + aNumberColLayout->addWidget( myNumberColumns ); + aNumberColLayout->addStretch( 1 ); + aVertEdgeLayout->addWidget( myVerticalEdge ); + aVertEdgeLayout->addLayout( aNumberColLayout ); + connect( myVerticalEdge, SIGNAL( clicked( bool ) ), + this, SLOT( onVerticalEdgeChecked() ) ); + // . Vertical edge settings + + QHBoxLayout* aTabVertEdgeLayout = new QHBoxLayout; + aTabVertEdgeLayout->addWidget( aTabSetBox ); + aTabVertEdgeLayout->addWidget( aVertEdgeSetBox ); + aMainLayout->addLayout( aTabVertEdgeLayout ); + + // . "Set as default" check box + if ( PyEditor_Settings::settings() ) + { + myDefaultCheck = new QCheckBox( tr( "WDG_SET_AS_DEFAULT_CHECK" ), this ); + aMainLayout->addWidget( myDefaultCheck ); + } + else + { + myDefaultCheck = 0; + } + // . "Set as default" check box + + // . Control buttons + QHBoxLayout* aButtonLayout = new QHBoxLayout; + + QPushButton* okBtn = new QPushButton( tr( "BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + connect( okBtn, SIGNAL( clicked() ), this, SLOT( onOk() ) ); + aButtonLayout->addWidget( okBtn ); + + if ( PyEditor_Settings::settings() ) + { + QPushButton* defBtn = new QPushButton( tr( "BUT_DEFAULTS" ), this ); + defBtn->setAutoDefault( true ); + connect( defBtn, SIGNAL( clicked() ), this, SLOT( onDefault() ) ); + aButtonLayout->addStretch(); + aButtonLayout->addWidget( defBtn ); + } + + QPushButton* cancelBtn = new QPushButton( tr( "BUT_CANCEL" ), this ); + cancelBtn->setAutoDefault( true ); + connect( cancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + aButtonLayout->addStretch(); + aButtonLayout->addWidget( cancelBtn ); + + if ( showHelp ) + { + QPushButton* helpBtn = new QPushButton( tr( "BUT_HELP" ), this ); + helpBtn->setAutoDefault( true ); + connect( helpBtn, SIGNAL( clicked() ), this, SLOT( onHelp() ) ); + aButtonLayout->addWidget( helpBtn ); + } + aMainLayout->addStretch( 1 ); + aMainLayout->addLayout( aButtonLayout ); + // . Control buttons + + settingsToGui(); +} + +/*! + Destructor. +*/ +PyEditor_SettingsDlg::~PyEditor_SettingsDlg() +{ +} + +/*! + SLOT: Changes the widget visibility depending on the set theState flag. + \param theState flag of visibility + */ +void PyEditor_SettingsDlg::onVerticalEdgeChecked() +{ + myNumberColumnsLbl->setEnabled( myVerticalEdge->isChecked() ); + myNumberColumns->setEnabled( myVerticalEdge->isChecked() ); +} + +/*! + SLOT: Fills font sizesc combo-box with available values depending on the + chosen font family. + */ +void PyEditor_SettingsDlg::onFontChanged() +{ + bool blocked = myFontSize->blockSignals( true ); + + QString oldSize = myFontSize->currentText(); + + QList szList = QFontDatabase().pointSizes( myFontFamily->currentFont().family() ); + QStringList sizes; + foreach ( int size, szList ) + sizes.append( QString::number( size ) ); + + myFontSize->clear(); + myFontSize->addItems( sizes ); + setFontSize( oldSize ); + + myFontSize->blockSignals( blocked ); +} + +/*! + \brief Sets settings from preferences dialog. + */ +void PyEditor_SettingsDlg::settingsFromGui() +{ + const PyEditor_Settings& oldSettings = myEditor->settings(); + PyEditor_Settings settings; + + QFont font = oldSettings.font(); + font.setFamily( myFontFamily->currentFont().family() ); + bool ok; + int size = myFontSize->currentText().toInt( &ok ); + if ( ok ) + font.setPointSize( size ); + + settings.setHighlightCurrentLine( myHighlightCurrentLine->isChecked() ); + settings.setTextWrapping( myTextWrapping->isChecked() ); + settings.setCenterCursorOnScroll( myCenterCursorOnScroll->isChecked() ); + settings.setLineNumberArea( myLineNumberArea->isChecked() ); + settings.setTabSpaceVisible( myTabSpaceVisible->isChecked() ); + settings.setTabSize( myTabSize->value() ); + settings.setVerticalEdge( myVerticalEdge->isChecked() ); + settings.setNumberColumns( myNumberColumns->value() ); + settings.setFont( font ); + myEditor->setSettings(settings); // updateContent() + + PyEditor_Settings* globals = PyEditor_Settings::settings(); + if ( globals && myDefaultCheck && myDefaultCheck->isChecked() ) + globals->copyFrom( settings ); +} + +/*! + \brief Sets settings into preferences dialog. + */ +void PyEditor_SettingsDlg::settingsToGui() +{ + const PyEditor_Settings& settings = myEditor->settings(); + + myHighlightCurrentLine->setChecked( settings.highlightCurrentLine() ); + myTextWrapping->setChecked( settings.textWrapping() ); + myCenterCursorOnScroll->setChecked( settings.centerCursorOnScroll() ); + myLineNumberArea->setChecked( settings.lineNumberArea() ); + myTabSpaceVisible->setChecked( settings.tabSpaceVisible() ); + myTabSize->setValue( settings.tabSize() ); + myVerticalEdge->setChecked( settings.verticalEdge() ); + myNumberColumns->setValue( settings.numberColumns() ); + myFontFamily->setCurrentFont( settings.font() ); + setFontSize( QString::number( settings.font().pointSize() ) ); + + onVerticalEdgeChecked(); + onFontChanged(); +} + +/*! + \brief Set font size value to the combo box. + \param size new size value +*/ +void PyEditor_SettingsDlg::setFontSize( const QString& size ) +{ + int idx = myFontSize->findText( size ); + if ( idx != -1 ) + myFontSize->setCurrentIndex( idx ); + else + myFontSize->setEditText( size ); +} + +/*! + Slot, called when user clicks "OK" button +*/ +void PyEditor_SettingsDlg::onOk() +{ + settingsFromGui(); + accept(); +} + +/*! + Slot, called when user clicks "Defaults" button +*/ +void PyEditor_SettingsDlg::onDefault() +{ + PyEditor_Settings* settings = PyEditor_Settings::settings(); + if ( settings ) + { + settings->load(); // to reload from the resources + + QFont font = settings->font(); + + myHighlightCurrentLine->setChecked( settings->highlightCurrentLine() ); + myTextWrapping->setChecked( settings->textWrapping() ); + myCenterCursorOnScroll->setChecked( settings->centerCursorOnScroll() ); + myLineNumberArea->setChecked( settings->lineNumberArea() ); + myTabSpaceVisible->setChecked( settings->tabSpaceVisible() ); + myTabSize->setValue( settings->tabSize() ); + myVerticalEdge->setChecked( settings->verticalEdge() ); + myNumberColumns->setValue( settings->numberColumns() ); + myFontFamily->setCurrentFont( font ); + setFontSize( QString::number( font.pointSize() ) ); + + onVerticalEdgeChecked(); + onFontChanged(); + } +} + +/*! + Slot, called when user clicks "Help" button. + Emits help() signal. +*/ +void PyEditor_SettingsDlg::onHelp() +{ + emit help(); +} diff --git a/tools/PyEditor/src/PyEditor_SettingsDlg.h b/tools/PyEditor/src/PyEditor_SettingsDlg.h new file mode 100644 index 000000000..9f3dfa986 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_SettingsDlg.h @@ -0,0 +1,79 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_SettingsDlg.h +// Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com) +// + +#ifndef PYEDITOR_SETTINGSDLG_H +#define PYEDITOR_SETTINGSDLG_H + +#include +#include "PyEditor.h" + +class PyEditor_Editor; +class QCheckBox; +class QComboBox; +class QFontComboBox; +class QLabel; +class QSpinBox; + +class PYEDITOR_EXPORT PyEditor_SettingsDlg : public QDialog +{ + Q_OBJECT + +public: + PyEditor_SettingsDlg( PyEditor_Editor*, bool = false, QWidget* = 0 ); + ~PyEditor_SettingsDlg(); + +private Q_SLOTS: + void onVerticalEdgeChecked(); + void onFontChanged(); + void onOk(); + void onDefault(); + void onHelp(); + +Q_SIGNALS: + void help(); + +private: + void settingsToGui(); + void settingsFromGui(); + void setFontSize( const QString& ); + + QCheckBox* myHighlightCurrentLine; + QCheckBox* myTextWrapping; + QCheckBox* myCenterCursorOnScroll; + QCheckBox* myLineNumberArea; + + QCheckBox* myTabSpaceVisible; + QSpinBox* myTabSize; + + QCheckBox* myVerticalEdge; + QSpinBox* myNumberColumns; + QLabel* myNumberColumnsLbl; + + QFontComboBox* myFontFamily; + QComboBox* myFontSize; + + QCheckBox* myDefaultCheck; + + PyEditor_Editor* myEditor; +}; + +#endif // PYEDITOR_SETTINGSDLG_H diff --git a/tools/PyEditor/src/PyEditor_StdSettings.cxx b/tools/PyEditor/src/PyEditor_StdSettings.cxx new file mode 100644 index 000000000..816db3653 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_StdSettings.cxx @@ -0,0 +1,92 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_StdSettings.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#include "PyEditor_StdSettings.h" + +PyEditor_StdSettings::PyEditor_StdSettings() : + myLanguage( "en" ) +{ + load(); +} + +PyEditor_StdSettings::PyEditor_StdSettings( const QString& group ) : + myGroup( group ), + myLanguage( "en" ) +{ + load(); +} + +PyEditor_StdSettings::PyEditor_StdSettings( const QString& group, + const QString& filename, + QSettings::Format format ) : + mySettings( filename, format ), + myGroup( group ), + myLanguage( "en" ) +{ + load(); +} + +void PyEditor_StdSettings::setLanguage( const QString& language ) +{ + myLanguage = language; +} + +QString PyEditor_StdSettings::language() const +{ + return myLanguage; +} + +void PyEditor_StdSettings::load() +{ + mySettings.beginGroup( myGroup.isEmpty() ? option( snEditor ) : myGroup ); + + setHighlightCurrentLine( mySettings.value( option( snHighlightCurrentLine ), highlightCurrentLine() ).toBool() ); + setTextWrapping( mySettings.value( option( snTextWrapping ), textWrapping() ).toBool() ); + setCenterCursorOnScroll( mySettings.value( option( snCenterCursorOnScroll ), centerCursorOnScroll() ).toBool() ); + setLineNumberArea( mySettings.value( option( snLineNumberArea ), lineNumberArea() ).toBool() ); + setVerticalEdge( mySettings.value( option( snVerticalEdge ), verticalEdge() ).toBool() ); + setNumberColumns( mySettings.value( option( snNumberColumns ), numberColumns() ).toInt() ); + setTabSpaceVisible( mySettings.value( option( snTabSpaceVisible ), tabSpaceVisible() ).toBool() ); + setTabSize( mySettings.value( option( snTabSize ), tabSize() ).toInt() ); + setFont( mySettings.value( option( snFont ), font() ).value() ); + setLanguage( mySettings.value( "language", language() ).toString() ); + + mySettings.endGroup(); +} + +void PyEditor_StdSettings::save() +{ + mySettings.beginGroup( myGroup.isEmpty() ? option( snEditor ) : myGroup ); + + mySettings.setValue( option( snHighlightCurrentLine ), highlightCurrentLine() ); + mySettings.setValue( option( snTextWrapping ), textWrapping() ); + mySettings.setValue( option( snCenterCursorOnScroll ), centerCursorOnScroll() ); + mySettings.setValue( option( snLineNumberArea ), lineNumberArea() ); + mySettings.setValue( option( snVerticalEdge ), verticalEdge() ); + mySettings.setValue( option( snNumberColumns ), numberColumns() ); + mySettings.setValue( option( snTabSpaceVisible ), tabSpaceVisible() ); + mySettings.setValue( option( snTabSize ), tabSize() ); + mySettings.setValue( option( snFont ), font() ); + mySettings.setValue( "language", language() ); + + mySettings.endGroup(); +} diff --git a/tools/PyEditor/src/PyEditor_StdSettings.h b/tools/PyEditor/src/PyEditor_StdSettings.h new file mode 100644 index 000000000..dc102fd96 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_StdSettings.h @@ -0,0 +1,50 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_StdSettings.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#ifndef PYEDITOR_STDSETTINGS_H +#define PYEDITOR_STDSETTINGS_H + +#include "PyEditor.h" +#include "PyEditor_Settings.h" + +#include + +class PYEDITOR_EXPORT PyEditor_StdSettings : public PyEditor_Settings +{ +public: + PyEditor_StdSettings(); + PyEditor_StdSettings( const QString& ); + PyEditor_StdSettings( const QString&, const QString&, QSettings::Format = QSettings::IniFormat ); + + void setLanguage( const QString& ); + QString language() const; + + void load(); + void save(); + +private: + QSettings mySettings; + QString myGroup; + QString myLanguage; +}; + +#endif // PYEDITOR_STDSETTINGS_H diff --git a/tools/PyEditor/src/PyEditor_Window.cxx b/tools/PyEditor/src/PyEditor_Window.cxx new file mode 100644 index 000000000..74c0be042 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_Window.cxx @@ -0,0 +1,467 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_Window.cxx +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#include "PyEditor_Window.h" +#include "PyEditor_Editor.h" +#include "PyEditor_Settings.h" +#include "PyEditor_SettingsDlg.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/*! + \class PyEditor_Window + \brief Python view window. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +PyEditor_Window::PyEditor_Window( QWidget* parent ) : + QMainWindow( parent ) +{ + Q_INIT_RESOURCE( PyEditor ); + + // Create editor and set it as a central widget. + myTextEditor = new PyEditor_Editor( this ); + setCentralWidget( myTextEditor ); + + // Create actions. + QAction* action; + + // . New + action = new QAction( QIcon( ":/images/py_new.png" ), + tr( "ACT_NEW" ), this ); + action->setToolTip( tr( "TTP_NEW" ) ); + action->setStatusTip( tr( "DSC_NEW" ) ); + action->setShortcut( QKeySequence::New ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) ); + myActions[ NewId ] = action; + + // . Open + action = new QAction( QIcon( ":/images/py_open.png" ), + tr( "ACT_OPEN" ), this ); + action->setToolTip( tr( "TTP_OPEN" ) ); + action->setStatusTip( tr( "DSC_OPEN" ) ); + action->setShortcut( QKeySequence::Open ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) ); + myActions[ OpenId ] = action; + + // . Save + action = new QAction( QIcon( ":/images/py_save.png" ), + tr( "ACT_SAVE" ), this ); + action->setToolTip( tr( "TTP_SAVE" ) ); + action->setStatusTip( tr( "DSC_SAVE" ) ); + action->setShortcut( QKeySequence::Save ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) ); + action->setEnabled( false ); + connect( myTextEditor->document(), SIGNAL( modificationChanged( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + myActions[ SaveId ] = action; + + // . SaveAs + action = new QAction( QIcon( ":/images/py_save_as.png" ), + tr( "ACT_SAVEAS" ), this ); + action->setToolTip( tr( "TTP_SAVEAS" ) ); + action->setStatusTip( tr( "DSC_SAVEAS" ) ); + action->setShortcut( QKeySequence::SaveAs ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) ); + myActions[ SaveAsId ] = action; + + // . Exit + action = new QAction( QIcon( ":/images/py_exit.png" ), + tr( "ACT_EXIT" ), this ); + action->setToolTip( tr( "TTP_EXIT" ) ); + action->setStatusTip( tr( "DSC_EXIT" ) ); + action->setShortcut( QKeySequence::Quit ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( close() ) ); + myActions[ ExitId ] = action; + + // . Undo + action = new QAction( QIcon( ":/images/py_undo.png" ), + tr( "ACT_UNDO" ), this ); + action->setToolTip( tr( "TTP_UNDO" ) ); + action->setStatusTip( tr( "DSC_UNDO" ) ); + action->setShortcut( QKeySequence::Undo ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( undo() ) ); + action->setEnabled( false ); + connect( myTextEditor->document(), SIGNAL( undoAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + myActions[ UndoId ] = action; + + // . Redo + action = new QAction( QIcon( ":/images/py_redo.png" ), + tr( "ACT_REDO" ), this ); + action->setToolTip( tr( "TTP_REDO" ) ); + action->setStatusTip( tr( "DSC_REDO" ) ); + action->setShortcut( QKeySequence::Redo ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( redo() ) ); + action->setEnabled( false ); + connect( myTextEditor->document(), SIGNAL( redoAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + myActions[ RedoId ] = action; + + // . Cut + action = new QAction( QIcon( ":/images/py_cut.png" ), + tr( "ACT_CUT" ), this ); + action->setToolTip( tr( "TTP_CUT" ) ); + action->setStatusTip( tr( "DSC_CUT" ) ); + action->setShortcut( QKeySequence::Cut ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( cut() ) ); + action->setEnabled( false ); + connect( myTextEditor, SIGNAL( copyAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + myActions[ CutId ] = action; + + // . Copy + action = new QAction( QIcon( ":/images/py_copy.png" ), + tr( "ACT_COPY" ), this ); + action->setToolTip( tr( "TTP_COPY" ) ); + action->setStatusTip( tr( "DSC_COPY" ) ); + action->setShortcut( QKeySequence::Copy ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( copy() ) ); + action->setEnabled( false ); + connect( myTextEditor, SIGNAL( copyAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + myActions[ CopyId ] = action; + + // . Paste + action = new QAction( QIcon( ":/images/py_paste.png" ), + tr( "ACT_PASTE" ), this ); + action->setToolTip( tr( "TTP_PASTE" ) ); + action->setStatusTip( tr( "DSC_PASTE" ) ); + action->setShortcut( QKeySequence::Paste ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( paste() ) ); + myActions[ PasteId ] = action; + + // . Delete + action = new QAction( QIcon( ":/images/py_delete.png" ), + tr( "ACT_DELETE" ), this ); + action->setToolTip( tr( "TTP_DELETE" ) ); + action->setStatusTip( tr( "DSC_DELETE" ) ); + action->setShortcut( QKeySequence::Delete ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( deleteSelected() ) ); + action->setEnabled( false ); + connect( myTextEditor, SIGNAL( copyAvailable( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + myActions[ DeleteId ] = action; + + // . SelectAll + action = new QAction( QIcon( ":/images/py_select_all.png" ), + tr( "ACT_SELECT_ALL" ), this ); + action->setToolTip( tr( "TTP_SELECT_ALL" ) ); + action->setStatusTip( tr( "DSC_SELECT_ALL" ) ); + action->setShortcut( QKeySequence::SelectAll ); + connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( selectAll() ) ); + myActions[ SelectAllId ] = action; + + // . Preferences + action = new QAction( QIcon( ":/images/py_preferences.png" ), + tr( "ACT_PREFERENCES" ), this ); + action->setToolTip( tr( "TTP_PREFERENCES" ) ); + action->setStatusTip( tr( "DSC_PREFERENCES" ) ); + connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) ); + myActions[ PreferencesId ] = action; + + // . Help + action = new QAction( QIcon( ":/images/py_help.png" ), + tr( "ACT_HELP" ), this ); + action->setToolTip( tr( "TTP_HELP" ) ); + action->setStatusTip( tr( "DSC_HELP" ) ); + connect( action, SIGNAL( triggered() ), this, SLOT( onHelp() ) ); + myActions[ HelpId ] = action; + + // Create menu. + QMenu* menu = menuBar()->addMenu( tr( "MNU_FILE" ) ); + menu->addAction( myActions[ NewId ] ); + menu->addAction( myActions[ OpenId ] ); + menu->addSeparator(); + menu->addAction( myActions[ SaveId ] ); + menu->addAction( myActions[ SaveAsId ] ); + menu->addSeparator(); + menu->addAction( myActions[ ExitId ] ); + + menu = menuBar()->addMenu( tr( "MNU_EDIT" ) ); + menu->addAction( myActions[ UndoId ] ); + menu->addAction( myActions[ RedoId ] ); + menu->addSeparator(); + menu->addAction( myActions[ CutId ] ); + menu->addAction( myActions[ CopyId ] ); + menu->addAction( myActions[ PasteId ] ); + menu->addAction( myActions[ DeleteId ] ); + menu->addSeparator(); + menu->addAction( myActions[ SelectAllId ] ); + menu->addSeparator(); + menu->addAction( myActions[ PreferencesId ] ); + + menu = menuBar()->addMenu( tr( "MNU_HELP" ) ); + menu->addAction( myActions[ HelpId ] ); + + // Create toolbar. + QToolBar* toolbar = addToolBar( tr( "TOOLBAR_LABEL" ) ); + toolbar->setObjectName("PythonEditor"); + toolbar->addAction( myActions[ NewId ] ); + toolbar->addAction( myActions[ OpenId ] ); + toolbar->addAction( myActions[ SaveId ] ); + toolbar->addAction( myActions[ SaveAsId ] ); + toolbar->addSeparator(); + toolbar->addAction( myActions[ ExitId ] ); + toolbar->addSeparator(); + toolbar->addAction( myActions[ UndoId ] ); + toolbar->addAction( myActions[ RedoId ] ); + toolbar->addSeparator(); + toolbar->addAction( myActions[ CutId ] ); + toolbar->addAction( myActions[ CopyId ] ); + toolbar->addAction( myActions[ PasteId ] ); + toolbar->addAction( myActions[ DeleteId ] ); + toolbar->addAction( myActions[ SelectAllId ] ); + toolbar->addSeparator(); + toolbar->addAction( myActions[ PreferencesId ] ); + toolbar->addSeparator(); + toolbar->addAction( myActions[ HelpId ] ); + + // Set current file. + setCurrentFile( QString() ); + + // Additional set-up for main window. + connect( myTextEditor->document(), SIGNAL( modificationChanged( bool ) ), + this, SLOT( setWindowModified( bool ) ) ); + + // Initialize status bar. + statusBar()->showMessage( tr( "STS_READY" ) ); +} + +/*! + \brief Destructor. +*/ +PyEditor_Window::~PyEditor_Window() +{ +} + +/*! + \brief Manage window close request. + \param event close event +*/ +void PyEditor_Window::closeEvent( QCloseEvent* event ) +{ + if ( whetherSave() ) + event->accept(); + else + event->ignore(); +} + +/*! + SLOT: Create new document +*/ +void PyEditor_Window::onNew() +{ + if ( whetherSave() ) + { + myTextEditor->clear(); + setCurrentFile( QString() ); + } +} + +/*! + SLOT: Open existing Python file +*/ +void PyEditor_Window::onOpen() +{ + if ( whetherSave() ) + { + QString filter = tr( "TIT_PY_FILES" ); + filter += " (*.py)"; + QString aFilePath = QFileDialog::getOpenFileName( this, + tr( "TIT_DLG_OPEN" ), + QDir::currentPath(), + filter ); + + if ( !aFilePath.isEmpty() ) + loadFile( aFilePath ); + } +} + +/*! + SLOT: Save current document +*/ +bool PyEditor_Window::onSave() +{ + if ( myURL.isEmpty() ) + return onSaveAs(); + else + return saveFile( myURL ); +} + + +/*! + SLOT: Save current document under a new name +*/ +bool PyEditor_Window::onSaveAs() +{ + QString filter = tr( "TIT_PY_FILES" ); + filter += " (*.py)"; + QString url = myURL.isEmpty() ? defaultName() : myURL; + QString aFilePath = QFileDialog::getSaveFileName( this, + tr( "TIT_DLG_SAVE" ), + url, + filter ); + + if ( !aFilePath.isEmpty() ) + return saveFile( aFilePath ); + + return false; +} + +/*! + SLOT: Open preferences dialog +*/ +void PyEditor_Window::onPreferences() +{ + PyEditor_SettingsDlg dlg( myTextEditor, true, this ); + connect( &dlg, SIGNAL( help() ), this, SLOT( onHelp() ) ); + dlg.exec(); +} + +/*! + \brief Associate \a filePath with the current document + \param filePath document's file path +*/ +void PyEditor_Window::setCurrentFile( const QString& filePath ) +{ + myURL = filePath; + myTextEditor->document()->setModified( false ); + + setWindowModified( false ); + + setWindowFilePath( myURL.isEmpty() ? defaultName() : myURL ); +} + +/*! + \brief Check whether the file is modified. + If it has the modifications then ask the user to save it. + \return true if the document is saved. +*/ +bool PyEditor_Window::whetherSave() +{ + if ( myTextEditor->document()->isModified() ) + { + QMessageBox::StandardButton answer = QMessageBox::warning( this, + tr( "NAME_PYEDITOR" ), + tr( "WRN_SAVE_FILE" ), + QMessageBox::Save | + QMessageBox::Discard | + QMessageBox::Cancel ); + switch( answer ) + { + case QMessageBox::Save: + return onSave(); + case QMessageBox::Cancel: + return false; + default: + break; + } + } + return true; +} + +/*! + \brief Open file. + \param filePath file path +*/ +void PyEditor_Window::loadFile( const QString& filePath ) +{ + QFile aFile( filePath ); + if ( !aFile.open(QFile::ReadOnly | QFile::Text) ) + { + QMessageBox::warning( this, tr( "NAME_PYEDITOR" ), + tr( "WRN_READ_FILE" ).arg( filePath ).arg( aFile.errorString() ) ); + return; + } + + QTextStream anInput( &aFile ); + QApplication::setOverrideCursor( Qt::WaitCursor ); + myTextEditor->setPlainText( anInput.readAll() ); + QApplication::restoreOverrideCursor(); + + setCurrentFile( filePath ); + aFile.close(); + + statusBar()->showMessage( tr( "STS_F_LOADED" ), 2000 ); +} + +/*! + \brief Save file. + \param filePath file path +*/ +bool PyEditor_Window::saveFile( const QString& filePath ) +{ + QFile aFile( filePath ); + if ( !aFile.open( QFile::WriteOnly | QFile::Text ) ) + { + QMessageBox::warning( this, tr( "NAME_PYEDITOR" ), + tr( "WRN_WRITE_FILE" ).arg( filePath ).arg( aFile.errorString() ) ); + return false; + } + + QTextStream anOutput( &aFile ); + QApplication::setOverrideCursor( Qt::WaitCursor ); + anOutput << myTextEditor->toPlainText(); + QApplication::restoreOverrideCursor(); + + setCurrentFile( filePath ); + aFile.close(); + + statusBar()->showMessage( tr( "STS_F_SAVED" ), 2000 ); + + return true; +} + +/*! + Slot, called when user clicks "Help" button in "Preferences" dialog box. +*/ +void PyEditor_Window::onHelp() +{ + QWidget* w = qobject_cast( sender() ); + if ( !w ) w = this; + QFile file(":/about.txt"); + file.open(QFile::ReadOnly | QFile::Text); + QTextStream stream( &file ); + QString about = stream.readAll(); + file.close(); + QMessageBox::about( w, tr( "NAME_PYEDITOR" ), about ); +} + +/*! + Get default name for Python file + \return default name +*/ +QString PyEditor_Window::defaultName() const +{ + return tr( "NONAME" ); +} diff --git a/tools/PyEditor/src/PyEditor_Window.h b/tools/PyEditor/src/PyEditor_Window.h new file mode 100644 index 000000000..209739e77 --- /dev/null +++ b/tools/PyEditor/src/PyEditor_Window.h @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2016 OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyEditor_Window.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +#ifndef PYEDITOR_WINDOW_H +#define PYEDITOR_WINDOW_H + +#include "PyEditor.h" + +#include +#include + +class QAction; +class PyEditor_Editor; + +class PYEDITOR_EXPORT PyEditor_Window : public QMainWindow +{ + Q_OBJECT + +public: + enum { NewId, OpenId, SaveId, SaveAsId, ExitId, + UndoId, RedoId, CutId, CopyId, PasteId, DeleteId, SelectAllId, + PreferencesId, HelpId }; + + PyEditor_Window( QWidget* = 0 ); + ~PyEditor_Window(); + +protected: + virtual void closeEvent( QCloseEvent* ); + +private Q_SLOTS: + void onNew(); + void onOpen(); + bool onSave(); + bool onSaveAs(); + void onPreferences(); + void onHelp(); + +private: + void loadFile( const QString& ); + bool saveFile( const QString& ); + + void setCurrentFile( const QString& ); + bool whetherSave(); + QString defaultName() const; + +private: + PyEditor_Editor* myTextEditor; + QString myURL; + QMap myActions; +}; + +#endif // PYEDITOR_WINDOW_H diff --git a/tools/PyEditor/src/python/CMakeLists.txt b/tools/PyEditor/src/python/CMakeLists.txt new file mode 100644 index 000000000..fcde6e16a --- /dev/null +++ b/tools/PyEditor/src/python/CMakeLists.txt @@ -0,0 +1,62 @@ +# Copyright (C) 2015-2016 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 : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +# + +INCLUDE(UseQtExt) +INCLUDE(UsePyQt) + +# --- options --- + +# additional include directories +INCLUDE_DIRECTORIES( + $(QT_INCLUDES) + ${PYTHON_INCLUDE_DIRS} + ${SIP_INCLUDE_DIR} + ${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) + +# additional preprocessor / compiler flags +ADD_DEFINITIONS(${QT_DEFINITIONS}) + +# libraries to link to +SET(_link_LIBRARIES ${QT_LIBRARIES} ${PYTHON_LIBRARIES} PyEditor) + +# --- sources --- + +# sip files / to be processed by sip +SET(_sip_files PyEditorPy.sip) + +# sources / sip wrappings +PYQT_WRAP_SIP(_sip_SOURCES ${_sip_files}) + +# sources / to compile +SET(PyEditorPy_SOURCES ${_sip_SOURCES}) + +# --- rules --- + +ADD_LIBRARY(PyEditorPy ${PyEditorPy_SOURCES}) +IF(WIN32) + SET_TARGET_PROPERTIES(PyEditorPy PROPERTIES SUFFIX ".pyd" DEBUG_OUTPUT_NAME PyEditorPy_d RELEASE_OUTPUT_NAME PyEditorPy) +ELSE() + SET_TARGET_PROPERTIES(PyEditorPy PROPERTIES PREFIX "") +ENDIF() +TARGET_LINK_LIBRARIES(PyEditorPy ${_link_LIBRARIES}) +INSTALL(TARGETS PyEditorPy EXPORT ${TOOLS_EXPORT_NAME}TargetGroup DESTINATION ${PYEDITOR_INSTALL_LIBS}) diff --git a/tools/PyEditor/src/python/PyEditorPy.sip b/tools/PyEditor/src/python/PyEditorPy.sip new file mode 100644 index 000000000..372cc2898 --- /dev/null +++ b/tools/PyEditor/src/python/PyEditorPy.sip @@ -0,0 +1,98 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SalomePyQt.sip +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) +// + +%Module PyEditorPy + +%Import QtCore/QtCoremod.sip +%Import QtGui/QtGuimod.sip +%If (Qt_5_0_0 -) +%Import QtWidgets/QtWidgetsmod.sip +%End + +class PyEditor_Settings +{ +%TypeHeaderCode +#include +%End + +public: + PyEditor_Settings(); + + void setHighlightCurrentLine( bool ); + bool highlightCurrentLine() const; + + void setTextWrapping( bool ); + bool textWrapping() const; + + void setCenterCursorOnScroll( bool ); + bool centerCursorOnScroll() const; + + void setLineNumberArea( bool ); + bool lineNumberArea() const; + + void setVerticalEdge( bool ); + bool verticalEdge() const; + + void setNumberColumns( int ); + int numberColumns() const; + + void setTabSpaceVisible( bool ); + bool tabSpaceVisible() const; + + void setTabSize( int ); + int tabSize() const; + + void setFont( const QFont& ); + QFont font() const; +}; + +class PyEditor_Editor : QPlainTextEdit +{ +%TypeHeaderCode +#include +%End + +public: + explicit PyEditor_Editor( QWidget* /TransferThis/ = 0 ); + virtual ~PyEditor_Editor(); + + void setSettings( const PyEditor_Settings& ); + const PyEditor_Settings& settings() const; + QString text() const; + +public slots: + void deleteSelected(); + void append( const QString& ); + void setText( const QString& text ); + +protected: + virtual void keyPressEvent( QKeyEvent* ); + virtual void resizeEvent( QResizeEvent* ); + virtual void paintEvent( QPaintEvent* ); + +private: + PyEditor_Editor( const PyEditor_Editor& ); + PyEditor_Editor& operator=( const PyEditor_Editor& ); +}; diff --git a/tools/PyEditor/src/resources/PyEditor.qrc b/tools/PyEditor/src/resources/PyEditor.qrc new file mode 100644 index 000000000..7df3d3208 --- /dev/null +++ b/tools/PyEditor/src/resources/PyEditor.qrc @@ -0,0 +1,20 @@ + + + images/py_copy.png + images/py_cut.png + images/py_delete.png + images/py_editor.png + images/py_exit.png + images/py_help.png + images/py_new.png + images/py_open.png + images/py_paste.png + images/py_preferences.png + images/py_redo.png + images/py_save.png + images/py_save_as.png + images/py_select_all.png + images/py_undo.png + about.txt + + diff --git a/tools/PyEditor/src/resources/about.txt b/tools/PyEditor/src/resources/about.txt new file mode 100644 index 000000000..8fe8dc6d9 --- /dev/null +++ b/tools/PyEditor/src/resources/about.txt @@ -0,0 +1,36 @@ +Python Editor +
+ +Python Editor is a simple program for writing Python scripts. +Program provides standard editing operations like copy/cut/paste, undo/redo, select all, delete, etc. +Also it supports syntax highlighting and auto-indentation of Python code. + +Most often used editing operations are available via the toolbar: +
    +
  • New: creates new document.
  • +
  • Open: opens existing Python script for editing.
  • +
  • Save: saves current document to a file.
  • +
  • Save As: allows saving current document with a new name.
  • +
  • Exit: quits application.
  • +
  • Undo: undoes the last operation.
  • +
  • Redo: redoes the previously undone operation.
  • +
  • Cut: cuts selected text into the clipboard.
  • +
  • Copy: copies selected text into the clipboard.
  • +
  • Paste: pastes text from the clipboard into the current cursor position.
  • +
  • Delete: removes selected text.
  • +
  • Select All: selects the whole text in the editor.
  • +
  • Preferences: opens Preferences dialog that allows specifying advanced parameters for the program.
  • +
  • Help: shows this help information.
  • +
+ +The behavior of the editor can be customized via the Preferences dialog. The following options can be customized: +
    +
  • Font settings: choose the font.
  • +
  • Enable current line highlight: switches on background coloring of the line under the cursor.
  • +
  • Enable text wrapping: allows wrapping text at the border of the editor's window.
  • +
  • Center cursor on scroll: allows scrolling the script vertically to make the cursor visible at the center of the viewer.
  • +
  • Display line numbers area: shows line numbers at the left border of the editor.
  • +
  • Vertical edge settings: draws vertical line at the specified column of the viewer.
  • +
  • Display tab white spaces: displays tab indentations at a given number of white spaces.
  • +
  • Save settings as default: saves chosen options as a default ones. These settings will be restored after application restart.
  • +
diff --git a/tools/PyEditor/src/resources/images/py_copy.png b/tools/PyEditor/src/resources/images/py_copy.png new file mode 100644 index 000000000..385b2c4e8 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_copy.png differ diff --git a/tools/PyEditor/src/resources/images/py_cut.png b/tools/PyEditor/src/resources/images/py_cut.png new file mode 100644 index 000000000..77edc8ab8 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_cut.png differ diff --git a/tools/PyEditor/src/resources/images/py_delete.png b/tools/PyEditor/src/resources/images/py_delete.png new file mode 100644 index 000000000..38581d16f Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_delete.png differ diff --git a/tools/PyEditor/src/resources/images/py_editor.png b/tools/PyEditor/src/resources/images/py_editor.png new file mode 100644 index 000000000..183e1390d Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_editor.png differ diff --git a/tools/PyEditor/src/resources/images/py_exit.png b/tools/PyEditor/src/resources/images/py_exit.png new file mode 100644 index 000000000..52efbf028 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_exit.png differ diff --git a/tools/PyEditor/src/resources/images/py_help.png b/tools/PyEditor/src/resources/images/py_help.png new file mode 100644 index 000000000..6fb0c81b7 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_help.png differ diff --git a/tools/PyEditor/src/resources/images/py_new.png b/tools/PyEditor/src/resources/images/py_new.png new file mode 100644 index 000000000..2a39dff50 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_new.png differ diff --git a/tools/PyEditor/src/resources/images/py_open.png b/tools/PyEditor/src/resources/images/py_open.png new file mode 100644 index 000000000..26e0a2ce4 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_open.png differ diff --git a/tools/PyEditor/src/resources/images/py_paste.png b/tools/PyEditor/src/resources/images/py_paste.png new file mode 100644 index 000000000..09cae7563 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_paste.png differ diff --git a/tools/PyEditor/src/resources/images/py_preferences.png b/tools/PyEditor/src/resources/images/py_preferences.png new file mode 100644 index 000000000..f8c4c05ff Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_preferences.png differ diff --git a/tools/PyEditor/src/resources/images/py_redo.png b/tools/PyEditor/src/resources/images/py_redo.png new file mode 100644 index 000000000..8e685b684 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_redo.png differ diff --git a/tools/PyEditor/src/resources/images/py_save.png b/tools/PyEditor/src/resources/images/py_save.png new file mode 100644 index 000000000..7a70c3475 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_save.png differ diff --git a/tools/PyEditor/src/resources/images/py_save_as.png b/tools/PyEditor/src/resources/images/py_save_as.png new file mode 100644 index 000000000..4cb114750 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_save_as.png differ diff --git a/tools/PyEditor/src/resources/images/py_select_all.png b/tools/PyEditor/src/resources/images/py_select_all.png new file mode 100644 index 000000000..d7b1c730f Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_select_all.png differ diff --git a/tools/PyEditor/src/resources/images/py_undo.png b/tools/PyEditor/src/resources/images/py_undo.png new file mode 100644 index 000000000..d6701f502 Binary files /dev/null and b/tools/PyEditor/src/resources/images/py_undo.png differ diff --git a/tools/PyEditor/src/resources/translations/PyEditor_msg_en.ts b/tools/PyEditor/src/resources/translations/PyEditor_msg_en.ts new file mode 100644 index 000000000..ed2e32172 --- /dev/null +++ b/tools/PyEditor/src/resources/translations/PyEditor_msg_en.ts @@ -0,0 +1,310 @@ + + + + + PyEditor_SettingsDlg + + TIT_PREFERENCES + Preferences + + + GR_FONT_SET + Font settings + + + GR_DISP_SET + Display settings + + + LBL_CURRLINE_HIGHLIGHT + Enable current line highlight + + + LBL_TEXT_WRAP + Enable text wrapping + + + LBL_CURSOR_SCROLL + Center cursor on scroll + + + LBL_LINE_NUMBS_AREA + Display line numbers area + + + GR_TAB_SET + Tab settings + + + LBL_TAB_SPACES + Display tab white spaces + + + LBL_TAB_SIZE + Tab size: + + + GR_VERT_EDGE_SET + Vertical edge settings + + + LBL_VERT_EDGE + Display vertical edge + + + LBL_NUM_COLUMNS + Number of columns: + + + WDG_SET_AS_DEFAULT_CHECK + Save settings as default + + + BUT_OK + &OK + + + BUT_DEFAULTS + &Defaults + + + BUT_CANCEL + &Cancel + + + BUT_HELP + &Help + + + + PyEditor_Window + + NAME_PYEDITOR + Python Editor + + + ACT_NEW + &New + + + TTP_NEW + New + + + DSC_NEW + Create new document + + + ACT_OPEN + &Open... + + + TTP_OPEN + Open + + + DSC_OPEN + Open an existing document + + + ACT_SAVE + &Save + + + TTP_SAVE + Save + + + DSC_SAVE + Save the document to a file + + + ACT_SAVEAS + Save &As... + + + TTP_SAVEAS + Save As + + + DSC_SAVEAS + Save the document to a file with the new name + + + ACT_EXIT + E&xit + + + TTP_EXIT + Exit + + + DSC_EXIT + Exit application + + + ACT_UNDO + &Undo + + + TTP_UNDO + Undo + + + DSC_UNDO + Undo last operation + + + ACT_REDO + &Redo + + + TTP_REDO + Redo + + + DSC_REDO + Redo last undone operation + + + ACT_CUT + Cu&t + + + TTP_CUT + Cut + + + DSC_CUT + Cut the current selection's contents to the clipboard + + + ACT_COPY + &Copy + + + TTP_COPY + Copy + + + DSC_COPY + Copy the current selection's contents to the clipboard + + + ACT_PASTE + &Paste + + + TTP_PASTE + Paste + + + DSC_PASTE + Paste the clipboard's contents into the current selection + + + ACT_DELETE + &Delete + + + TTP_DELETE + Delete + + + DSC_DELETE + Delete the current selection's contents + + + ACT_SELECT_ALL + Select &All + + + TTP_SELECT_ALL + Select All + + + DSC_SELECT_ALL + Select all the contents + + + ACT_PREFERENCES + Pre&ferences + + + TTP_PREFERENCES + Preferences + + + DSC_PREFERENCES + Show the Preferences dialog + + + ACT_HELP + &Help + + + TTP_HELP + Help + + + DSC_HELP + Show the help on the Python Editor + + + MNU_FILE + &File + + + MNU_EDIT + &Edit + + + MNU_HELP + &Help + + + TOOLBAR_LABEL + Edit Operations + + + TIT_PY_FILES + Python files + + + TIT_DLG_OPEN + Open file + + + TIT_DLG_SAVE + Save file + + + WRN_SAVE_FILE + The document has been modified.<br>Do you want to save changes? + + + WRN_READ_FILE + Cannot read file %1:\n%2. + + + WRN_WRITE_FILE + Cannot write file %1:\n%2. + + + STS_READY + Ready + + + STS_F_LOADED + Document is loaded + + + STS_F_SAVED + Document is saved + + + NONAME + Noname.py + + + diff --git a/tools/PyEditor/src/resources/translations/PyEditor_msg_fr.ts b/tools/PyEditor/src/resources/translations/PyEditor_msg_fr.ts new file mode 100644 index 000000000..96cd1e001 --- /dev/null +++ b/tools/PyEditor/src/resources/translations/PyEditor_msg_fr.ts @@ -0,0 +1,310 @@ + + + + + PyEditor_SettingsDlg + + TIT_PREFERENCES + Préférences + + + GR_FONT_SET + Paramètres de la fonte + + + GR_DISP_SET + Paramètres d'affichage + + + LBL_CURRLINE_HIGHLIGHT + Met en surbrillance de la ligne actuelle + + + LBL_TEXT_WRAP + Retour à la ligne dynamique + + + LBL_CURSOR_SCROLL + Centre le curseur lors du scroll + + + LBL_LINE_NUMBS_AREA + Affiche les numéros de ligne + + + GR_TAB_SET + Indentation + + + LBL_TAB_SPACES + Affiche les guides d'indentation + + + LBL_TAB_SIZE + Largeur d'intentation: + + + GR_VERT_EDGE_SET + Marqueur de retour à la ligne + + + LBL_VERT_EDGE + Afficher la ligne verticale + + + LBL_NUM_COLUMNS + Nombre de colonnes: + + + WDG_SET_AS_DEFAULT_CHECK + Sauver en tant que paramètres par défaut + + + BUT_OK + &OK + + + BUT_DEFAULTS + Défauts + + + BUT_CANCEL + &Annuler + + + BUT_HELP + A&ide + + + + PyEditor_Window + + NAME_PYEDITOR + Editeur python + + + ACT_NEW + Nouveau + + + TTP_NEW + Nouveau + + + DSC_NEW + Crée un nouveau fichier python + + + ACT_OPEN + Ouvrir + + + TTP_OPEN + Ouvrir + + + DSC_OPEN + Ouvre un fichier python existant + + + ACT_SAVE + Enregistrer + + + TTP_SAVE + Enregistrer + + + DSC_SAVE + Enregistre le fichier python sur le système de fichiers + + + ACT_SAVEAS + Enregistrer sous... + + + TTP_SAVEAS + Enregistrer sous... + + + DSC_SAVEAS + >Enregistre le fichier python sous un nouveau nom + + + ACT_EXIT + Fermer + + + TTP_EXIT + Fermer + + + DSC_EXIT + Ferme le fichier python + + + ACT_UNDO + Annuler + + + TTP_UNDO + Annuler + + + DSC_UNDO + Annule la dernière opération + + + ACT_REDO + Refaire + + + TTP_REDO + Refaire + + + DSC_REDO + Répète la dernière opération + + + ACT_CUT + Coupe + + + TTP_CUT + Coupe + + + DSC_CUT + Coupe le contenu de la sélection vers le presse-papier + + + ACT_COPY + Copier + + + TTP_COPY + Copier + + + DSC_COPY + Copie le contenu de la sélection vers le presse-papier + + + ACT_PASTE + Coller + + + TTP_PASTE + Coller + + + DSC_PASTE + Colle le contenu de la sélection vers le presse-papier + + + ACT_DELETE + Supprime + + + TTP_DELETE + Supprime + + + DSC_DELETE + Supprime le contenu de la sélection + + + ACT_SELECT_ALL + Sélectionner tout + + + TTP_SELECT_ALL + Sélectionner tout + + + DSC_SELECT_ALL + Sélectionne tout le contenu + + + ACT_PREFERENCES + Préférences + + + TTP_PREFERENCES + Préférences + + + DSC_PREFERENCES + Affiche la boîte de dialogue des préférences + + + ACT_HELP + Aide + + + TTP_HELP + Aide + + + DSC_HELP + Afficher l'aide + + + MNU_FILE + Fic&hier + + + MNU_EDIT + &Edition + + + MNU_HELP + A&ide + + + TOOLBAR_LABEL + Opérations d'édition + + + TIT_PY_FILES + Fichiers Python + + + TIT_DLG_OPEN + Ouvrir le fichier + + + TIT_DLG_SAVE + Enregistrer le fichier + + + WRN_SAVE_FILE + Le document a été modifié.<br>Voulez-vous sauvegarder vos changements? + + + WRN_READ_FILE + Impossible de lire le fichier %1:\n%2. + + + WRN_WRITE_FILE + Impossible d'écrire le fichier %1:\n%2. + + + STS_READY + Prêt + + + STS_F_LOADED + Le fichier est chargé + + + STS_F_SAVED + Le fichier est sauvé + + + NONAME + Noname.py + + + diff --git a/tools/PyEditor/src/resources/translations/PyEditor_msg_ja.ts b/tools/PyEditor/src/resources/translations/PyEditor_msg_ja.ts new file mode 100644 index 000000000..6851ed722 --- /dev/null +++ b/tools/PyEditor/src/resources/translations/PyEditor_msg_ja.ts @@ -0,0 +1,310 @@ + + + + + PyEditor_SettingsDlg + + TIT_PREFERENCES + 環境設定 + + + GR_FONT_SET + フォント設定 + + + GR_DISP_SET + 表示設定 + + + LBL_CURRLINE_HIGHLIGHT + カレントラインのハイライト有効 + + + LBL_TEXT_WRAP + テキストラッピングの有効 + + + LBL_CURSOR_SCROLL + スクロール上の中心カーソル + + + LBL_LINE_NUMBS_AREA + ライン番号エリアの表示 + + + GR_TAB_SET + タブ設定 + + + LBL_TAB_SPACES + タブ空白の表示 + + + LBL_TAB_SIZE + Tab size: + + + GR_VERT_EDGE_SET + 垂直エッジ設定 + + + LBL_VERT_EDGE + 垂直エッジの表示 + + + LBL_NUM_COLUMNS + 列数: + + + WDG_SET_AS_DEFAULT_CHECK + デフォルトとして設定を保存 + + + BUT_OK + &OK + + + BUT_DEFAULTS + デフォルト(&D) + + + BUT_CANCEL + キャンセル(&C) + + + BUT_HELP + ヘルプ(&H) + + + + PyEditor_Window + + NAME_PYEDITOR + Python Editor + + + ACT_NEW + 新規 + + + TTP_NEW + 新規 + + + DSC_NEW + 新規 python ファイルの作成 + + + ACT_OPEN + 開く + + + TTP_OPEN + 開く + + + DSC_OPEN + 存在する python ファイルを開く + + + ACT_SAVE + 保存 + + + TTP_SAVE + 保存 + + + DSC_SAVE + python ドキュメントをディスクに保存 + + + ACT_SAVEAS + 別名保存 + + + TTP_SAVEAS + 別名保存 + + + DSC_SAVEAS + 新しい名前で python ドキュメントを保存 + + + ACT_EXIT + 終 + + + TTP_EXIT + 終 + + + DSC_EXIT + アプリケーションを終了 + + + ACT_UNDO + 元に戻す + + + TTP_UNDO + 元に戻す + + + DSC_UNDO + 最後の操作を元に戻す + + + ACT_REDO + やり直し + + + TTP_REDO + やり直し + + + DSC_REDO + 最後の操作をやり直す + + + ACT_CUT + カット + + + TTP_CUT + カット + + + DSC_CUT + 現在選択中の内容をクリップボードにカット + + + ACT_COPY + コピー + + + TTP_COPY + コピー + + + DSC_COPY + 現在選択中の内容をクリップボードにコピー + + + ACT_PASTE + ペースト + + + TTP_PASTE + ペースト + + + DSC_PASTE + クリップボードの内容を現在の選択にペースト + + + ACT_DELETE + 削除 + + + TTP_DELETE + 削除 + + + DSC_DELETE + 現在選択中の内容を削除 + + + ACT_SELECT_ALL + すべて選択 + + + TTP_SELECT_ALL + すべて選択 + + + DSC_SELECT_ALL + すべての内容を選択 + + + ACT_PREFERENCES + 環境設定 + + + TTP_PREFERENCES + 環境設定 + + + DSC_PREFERENCES + 環境設定ボックスの表示 + + + ACT_HELP + ヘルプ + + + TTP_HELP + ヘルプ + + + DSC_HELP + ヘルプ + + + MNU_FILE + ファイル(&F) + + + MNU_EDIT + 編集(&E) + + + MNU_HELP + ヘルプ(&H) + + + TOOLBAR_LABEL + 操作の編集 + + + TIT_PY_FILES + ã..ã.¡ã.¤ã.« Python + + + TIT_DLG_OPEN + ファイルを開く + + + TIT_DLG_SAVE + ファイルを保存 + + + WRN_SAVE_FILE + ドキュメントは修正済みです。<br>変更を保存しますか? + + + WRN_READ_FILE + Cannot read file %1:\n%2. + + + WRN_WRITE_FILE + Cannot write file %1:\n%2. + + + STS_READY + 準備 + + + STS_F_LOADED + ファイルは読み込まれました + + + STS_F_SAVED + ファイルは保存されました + + + NONAME + Noname.py + + +