Skip to content

Commit

Permalink
Merge pull request #303 from slarosa/master
Browse files Browse the repository at this point in the history
[FEATURE] - Split-pane entry and output for PyQGIS console
  • Loading branch information
dakcarto committed Oct 27, 2012
2 parents 34f677a + 9fb1c11 commit ff1431c
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 71 deletions.
1 change: 1 addition & 0 deletions python/CMakeLists.txt
Expand Up @@ -147,6 +147,7 @@ SET(PY_FILES
console_sci.py
console_help.py
console_settings.py
console_output.py
utils.py
)
FILE(GLOB UI_FILES *.ui)
Expand Down
74 changes: 42 additions & 32 deletions python/console.py
Expand Up @@ -23,6 +23,7 @@
from PyQt4.QtGui import *
from qgis.utils import iface
from console_sci import PythonEdit
from console_output import EditorOutput
from console_help import HelpDialog
from console_settings import optionsDialog

Expand Down Expand Up @@ -58,20 +59,6 @@ def console_displayhook(obj):
global _console_output
_console_output = obj

class QgisOutputCatcher:
def __init__(self):
self.data = ''
def write(self, stuff):
self.data += stuff
def get_and_clean_data(self):
tmp = self.data
self.data = ''
return tmp
def flush(self):
pass

sys.stdout = QgisOutputCatcher()

class PythonConsole(QDockWidget):
def __init__(self, parent=None):
QDockWidget.__init__(self, parent)
Expand All @@ -92,35 +79,32 @@ def activate(self):
self.raise_()
QDockWidget.setFocus(self)


class PythonConsoleWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))

self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))
self.widgetButton = QWidget()
#self.widgetEditors = QWidget()

self.options = optionsDialog(self)

self.toolBar = QToolBar()
self.toolBar.setEnabled(True)
#self.toolBar.setFont(font)
self.toolBar.setFocusPolicy(Qt.NoFocus)
self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu)
self.toolBar.setLayoutDirection(Qt.LeftToRight)
self.toolBar.setIconSize(QSize(24, 24))
self.toolBar.setOrientation(Qt.Vertical)
self.toolBar.setMovable(True)
self.toolBar.setFloatable(True)
#self.toolBar.setAllowedAreas(Qt.LeftToolBarArea)
#self.toolBar.setAllowedAreas(Qt.RightToolBarArea)
#self.toolBar.setObjectName(_fromUtf8("toolMappa"))

self.b = QVBoxLayout(self.widgetButton)
self.e = QHBoxLayout(self)
self.b = QGridLayout(self.widgetButton)
self.f = QGridLayout(self)

self.e.setMargin(0)
self.e.setSpacing(0)
self.f.setMargin(0)
self.f.setSpacing(0)
self.b.setMargin(0)
self.b.setSpacing(0)

## Action for Clear button
clearBt = QCoreApplication.translate("PythonConsole", "Clear console")
Expand Down Expand Up @@ -268,12 +252,37 @@ def __init__(self, parent=None):

self.b.addWidget(self.toolBar)
self.edit = PythonEdit()
self.setFocusProxy( self.edit )

self.e.addWidget(self.widgetButton)
self.e.addWidget(self.edit)
self.textEditOut = EditorOutput()

self.setFocusProxy(self.edit)

sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth())
self.widgetButton.setSizePolicy(sizePolicy)

self.consoleFrame = QFrame(self)
self.consoleFrame.setObjectName("consoleFrame")
self.consoleLayout = QVBoxLayout(self.consoleFrame)
self.consoleLayout.setSpacing(0)
self.consoleLayout.setMargin(0)

sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textEditOut.sizePolicy().hasHeightForWidth())
self.textEditOut.setSizePolicy(sizePolicy)
self.consoleLayout.addWidget(self.textEditOut)

self.edit.setMinimumSize(QSize(0, 32))
self.edit.setMaximumSize(QSize(16777215, 32))
self.consoleLayout.addWidget(self.edit)

self.f.addWidget(self.widgetButton, 0, 0)
self.f.addWidget(self.consoleFrame, 0, 1)

self.clearButton.triggered.connect(self.edit.clearConsole)
self.clearButton.triggered.connect(self.textEditOut.clearConsole)
self.optionsButton.triggered.connect(self.openSettings)
self.loadIfaceButton.triggered.connect(self.iface)
self.loadSextanteButton.triggered.connect(self.sextante)
Expand Down Expand Up @@ -326,7 +335,7 @@ def saveScriptFile(self):
if not filename.endswith(".py"):
fName += ".py"
sF = open(fName,'w')
listText = self.edit.getTextFromEditor()
listText = self.textEditOut.getTextFromEditor()
is_first_line = True
for s in listText:
if s[0:3] in (">>>", "..."):
Expand All @@ -337,7 +346,7 @@ def saveScriptFile(self):
sF.write('\n')
sF.write(s)
sF.close()

def openHelp(self):
dlg = HelpDialog()
dlg.exec_()
Expand All @@ -348,6 +357,7 @@ def openSettings(self):

def prefChanged(self):
self.edit.refreshLexerProperties()
self.textEditOut.refreshLexerProperties()

def closeEvent(self, event):
self.edit.writeHistoryFile()
Expand Down
167 changes: 167 additions & 0 deletions python/console_output.py
@@ -0,0 +1,167 @@
# -*- coding:utf-8 -*-
"""
/***************************************************************************
Python Conosle for QGIS
-------------------
begin : 2012-09-10
copyright : (C) 2012 by Salvatore Larosa
email : lrssvtml (at) gmail (dot) com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Some portions of code were taken from https://code.google.com/p/pydee/
"""

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.Qsci import (QsciScintilla,
QsciScintillaBase,
QsciLexerPython)
from console_sci import PythonEdit
import sys

class writeOut:
def __init__(self, edit, out=None, style=None):
"""
This class allow to write stdout and stderr
"""
self.editor = edit
self.out = None
self.style = style

def write(self, m):
if self.style == "traceback":
self.editor.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), 1)
self.editor.append(m)
self.editor.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), 1)
else:
self.editor.append(m)
self.move_cursor_to_end()

if self.out:
self.out.write(m)

def move_cursor_to_end(self):
"""Move cursor to end of text"""
line, index = self.get_end_pos()
self.editor.setCursorPosition(line, index)
self.editor.ensureCursorVisible()
self.editor.ensureLineVisible(line)

def get_end_pos(self):
"""Return (line, index) position of the last character"""
line = self.editor.lines() - 1
return (line, self.editor.text(line).length())

def flush(self):
pass

class EditorOutput(QsciScintilla):
def __init__(self, parent=None):
#QsciScintilla.__init__(self, parent)
super(EditorOutput,self).__init__(parent)
# Enable non-ascii chars for editor
self.setUtf8(True)

sys.stdout = writeOut(self, sys.stdout)
sys.stderr = writeOut(self, sys.stderr, "traceback")

self.edit = PythonEdit()
self.setLexers()
self.setReadOnly(True)

# Set the default font
font = QFont()
font.setFamily('Courier')
font.setFixedPitch(True)
font.setPointSize(10)
self.setFont(font)
self.setMarginsFont(font)
# Margin 0 is used for line numbers
#fm = QFontMetrics(font)
self.setMarginsFont(font)
self.setMarginWidth(1, "00000")
self.setMarginLineNumbers(1, True)
self.setMarginsForegroundColor(QColor("#3E3EE3"))
self.setMarginsBackgroundColor(QColor("#f9f9f9"))
self.setCaretLineVisible(True)
self.setCaretLineBackgroundColor(QColor("#fcf3ed"))


# Folding
#self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
#self.setFoldMarginColors(QColor("#99CC66"),QColor("#333300"))
#self.setWrapMode(QsciScintilla.WrapCharacter)

## Edge Mode : does not seems to work
#self.setEdgeMode(QsciScintilla.EdgeLine)
#self.setEdgeColumn(80)
#self.setEdgeColor(QColor("#FF0000"))

self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 2)
self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

def refreshLexerProperties(self):
self.setLexers()

def setLexers(self):
self.lexer = QsciLexerPython()

settings = QSettings()
loadFont = settings.value("pythonConsole/fontfamilytext").toString()
fontSize = settings.value("pythonConsole/fontsize").toInt()[0]
font = QFont(loadFont)
font.setFixedPitch(True)
font.setPointSize(fontSize)

self.lexer.setDefaultFont(font)
self.lexer.setColor(Qt.red, 1)
self.lexer.setColor(Qt.darkGreen, 5)
self.lexer.setColor(Qt.darkBlue, 15)
self.lexer.setFont(font, 1)
self.lexer.setFont(font, 2)
self.lexer.setFont(font, 3)
self.lexer.setFont(font, 4)

self.setLexer(self.lexer)

def getTextFromEditor(self):
text = self.text()
textList = text.split("\n")
return textList

def clearConsole(self):
#self.SendScintilla(QsciScintilla.SCI_CLEARALL)
self.setText('')

def contextMenuEvent(self, e):
menu = QMenu(self)
runAction = menu.addAction("Enter Selected")
copyAction = menu.addAction("Copy CTRL+C")
runAction.setEnabled(False)
if self.hasSelectedText():
runAction.setEnabled(True)
action = menu.exec_(self.mapToGlobal(e.pos()))
if action == runAction:
cmd = self.selectedText()
self.edit.insertFromDropPaste(cmd)
self.edit.entered()
if action == copyAction:
self.copy()

def copy(self):
"""Copy text to clipboard... or keyboard interrupt"""
if self.hasSelectedText():
text = unicode(self.selectedText())
text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts
QApplication.clipboard().setText(text)
else:
self.emit(SIGNAL("keyboard_interrupt()"))

0 comments on commit ff1431c

Please sign in to comment.