Skip to content

Commit f15b4e1

Browse files
committed
[FEATURE] - Split-pane entry and output for PyQGIS console
1 parent 1fdaa04 commit f15b4e1

File tree

4 files changed

+227
-47
lines changed

4 files changed

+227
-47
lines changed

python/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ SET(PY_FILES
147147
console_sci.py
148148
console_help.py
149149
console_settings.py
150+
console_output.py
150151
utils.py
151152
)
152153
FILE(GLOB UI_FILES *.ui)

python/console.py

+48-26
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from PyQt4.QtGui import *
2424
from qgis.utils import iface
2525
from console_sci import PythonEdit
26+
from console_output import EditorOutput
2627
from console_help import HelpDialog
2728
from console_settings import optionsDialog
2829

@@ -58,20 +59,6 @@ def console_displayhook(obj):
5859
global _console_output
5960
_console_output = obj
6061

61-
class QgisOutputCatcher:
62-
def __init__(self):
63-
self.data = ''
64-
def write(self, stuff):
65-
self.data += stuff
66-
def get_and_clean_data(self):
67-
tmp = self.data
68-
self.data = ''
69-
return tmp
70-
def flush(self):
71-
pass
72-
73-
sys.stdout = QgisOutputCatcher()
74-
7562
class PythonConsole(QDockWidget):
7663
def __init__(self, parent=None):
7764
QDockWidget.__init__(self, parent)
@@ -96,11 +83,19 @@ def activate(self):
9683
class PythonConsoleWidget(QWidget):
9784
def __init__(self, parent=None):
9885
QWidget.__init__(self, parent)
99-
self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))
100-
86+
self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))
10187
self.widgetButton = QWidget()
88+
#self.widgetEditors = QWidget()
89+
10290
self.options = optionsDialog(self)
10391

92+
self.splitter = QSplitter(self)
93+
self.splitter.setOrientation(Qt.Vertical)
94+
self.splitter.setHandleWidth(3)
95+
self.splitter.setChildrenCollapsible(False)
96+
97+
#self.textEdit = QTextEdit()
98+
10499
self.toolBar = QToolBar()
105100
self.toolBar.setEnabled(True)
106101
#self.toolBar.setFont(font)
@@ -115,12 +110,18 @@ def __init__(self, parent=None):
115110
#self.toolBar.setAllowedAreas(Qt.RightToolBarArea)
116111
#self.toolBar.setObjectName(_fromUtf8("toolMappa"))
117112

118-
self.b = QVBoxLayout(self.widgetButton)
119-
self.e = QHBoxLayout(self)
113+
#self.gridLayout = QGridLayout(self)
114+
115+
self.b = QGridLayout(self.widgetButton)
116+
#self.e = QGridLayout(self.widgetEditors)
117+
self.f = QGridLayout(self)
120118

121-
self.e.setMargin(0)
122-
self.e.setSpacing(0)
119+
#self.e.setMargin(0)
120+
#self.e.setSpacing(0)
121+
self.f.setMargin(0)
122+
self.f.setSpacing(0)
123123
self.b.setMargin(0)
124+
self.b.setSpacing(0)
124125

125126
## Action for Clear button
126127
clearBt = QCoreApplication.translate("PythonConsole", "Clear console")
@@ -268,12 +269,32 @@ def __init__(self, parent=None):
268269

269270
self.b.addWidget(self.toolBar)
270271
self.edit = PythonEdit()
271-
self.setFocusProxy( self.edit )
272+
self.textEditOut = EditorOutput()
272273

273-
self.e.addWidget(self.widgetButton)
274-
self.e.addWidget(self.edit)
274+
#self.textEdit = PythonEditOutput()
275+
#self.textEdit.setReadOnly(True)
276+
#self.textEdit.setMinimumHeight(80)
275277

276-
self.clearButton.triggered.connect(self.edit.clearConsole)
278+
self.setFocusProxy(self.edit)
279+
280+
sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
281+
sizePolicy.setHorizontalStretch(0)
282+
sizePolicy.setVerticalStretch(0)
283+
sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth())
284+
self.widgetButton.setSizePolicy(sizePolicy)
285+
#self.e.addWidget(self.textEdit)
286+
#self.e.addWidget(self.edit)
287+
288+
self.splitter.addWidget(self.textEditOut)
289+
self.splitter.addWidget(self.edit)
290+
self.f.addWidget(self.widgetButton, 0, 0, 1, 1)
291+
self.f.addWidget(self.splitter, 0, 1, 1, 1)
292+
#self.f.addWidget(self.widgetEditors)
293+
294+
#self.f.setStretchFactor(self.widgetEditors, 1)
295+
296+
297+
self.clearButton.triggered.connect(self.textEditOut.clearConsole)
277298
self.optionsButton.triggered.connect(self.openSettings)
278299
self.loadIfaceButton.triggered.connect(self.iface)
279300
self.loadSextanteButton.triggered.connect(self.sextante)
@@ -326,7 +347,7 @@ def saveScriptFile(self):
326347
if not filename.endswith(".py"):
327348
fName += ".py"
328349
sF = open(fName,'w')
329-
listText = self.edit.getTextFromEditor()
350+
listText = self.textEditOut.getTextFromEditor()
330351
is_first_line = True
331352
for s in listText:
332353
if s[0:3] in (">>>", "..."):
@@ -337,7 +358,7 @@ def saveScriptFile(self):
337358
sF.write('\n')
338359
sF.write(s)
339360
sF.close()
340-
361+
341362
def openHelp(self):
342363
dlg = HelpDialog()
343364
dlg.exec_()
@@ -348,6 +369,7 @@ def openSettings(self):
348369

349370
def prefChanged(self):
350371
self.edit.refreshLexerProperties()
372+
self.textEditOut.refreshLexerProperties()
351373

352374
def closeEvent(self, event):
353375
self.edit.writeHistoryFile()

python/console_output.py

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# -*- coding:utf-8 -*-
2+
"""
3+
/***************************************************************************
4+
Python Conosle for QGIS
5+
-------------------
6+
begin : 2012-09-10
7+
copyright : (C) 2012 by Salvatore Larosa
8+
email : lrssvtml (at) gmail (dot) com
9+
***************************************************************************/
10+
11+
/***************************************************************************
12+
* *
13+
* This program is free software; you can redistribute it and/or modify *
14+
* it under the terms of the GNU General Public License as published by *
15+
* the Free Software Foundation; either version 2 of the License, or *
16+
* (at your option) any later version. *
17+
* *
18+
***************************************************************************/
19+
Some portions of code were taken from https://code.google.com/p/pydee/
20+
"""
21+
22+
from PyQt4.QtCore import *
23+
from PyQt4.QtGui import *
24+
from PyQt4.Qsci import (QsciScintilla,
25+
QsciScintillaBase,
26+
QsciLexerPython)
27+
28+
import sys
29+
30+
class writeOut:
31+
def __init__(self, edit, out=None, style=None):
32+
"""
33+
This class allow to write stdout and stderr
34+
"""
35+
self.editor = edit
36+
self.out = None
37+
self.style = style
38+
39+
def write(self, m):
40+
if self.style == "traceback":
41+
self.editor.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), 1)
42+
self.editor.append(m)
43+
self.editor.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), 1)
44+
else:
45+
self.editor.append(m)
46+
self.move_cursor_to_end()
47+
48+
if self.out:
49+
self.out.write(m)
50+
51+
def move_cursor_to_end(self):
52+
"""Move cursor to end of text"""
53+
line, index = self.get_end_pos()
54+
self.editor.setCursorPosition(line, index)
55+
self.editor.ensureCursorVisible()
56+
self.editor.ensureLineVisible(line)
57+
58+
def get_end_pos(self):
59+
"""Return (line, index) position of the last character"""
60+
line = self.editor.lines() - 1
61+
return (line, self.editor.text(line).length())
62+
63+
def flush(self):
64+
pass
65+
66+
class EditorOutput(QsciScintilla):
67+
def __init__(self, parent=None):
68+
#QsciScintilla.__init__(self, parent)
69+
super(EditorOutput,self).__init__(parent)
70+
# Enable non-ascii chars for editor
71+
self.setUtf8(True)
72+
73+
sys.stdout = writeOut(self, sys.stdout)
74+
sys.stderr = writeOut(self, sys.stderr, "traceback")
75+
76+
self.setLexers()
77+
self.setReadOnly(True)
78+
79+
# Set the default font
80+
font = QFont()
81+
font.setFamily('Courier')
82+
font.setFixedPitch(True)
83+
font.setPointSize(10)
84+
self.setFont(font)
85+
self.setMarginsFont(font)
86+
# Margin 0 is used for line numbers
87+
#fm = QFontMetrics(font)
88+
self.setMarginsFont(font)
89+
self.setMarginWidth(1, "000")
90+
self.setMarginLineNumbers(1, True)
91+
self.setMarginsBackgroundColor(QColor("#ffe4e4"))
92+
93+
# Folding
94+
#self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
95+
#self.setFoldMarginColors(QColor("#99CC66"),QColor("#333300"))
96+
#self.setWrapMode(QsciScintilla.WrapCharacter)
97+
98+
## Edge Mode : does not seems to work
99+
#self.setEdgeMode(QsciScintilla.EdgeLine)
100+
#self.setEdgeColumn(80)
101+
#self.setEdgeColor(QColor("#FF0000"))
102+
103+
self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 2)
104+
self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
105+
106+
def refreshLexerProperties(self):
107+
self.setLexers()
108+
109+
def setLexers(self):
110+
self.lexer = QsciLexerPython()
111+
112+
settings = QSettings()
113+
loadFont = settings.value("pythonConsole/fontfamilytext").toString()
114+
fontSize = settings.value("pythonConsole/fontsize").toInt()[0]
115+
font = QFont(loadFont)
116+
font.setFixedPitch(True)
117+
font.setPointSize(fontSize)
118+
119+
self.lexer.setDefaultFont(font)
120+
self.lexer.setColor(Qt.red, 1)
121+
self.lexer.setColor(Qt.darkGreen, 5)
122+
self.lexer.setColor(Qt.darkBlue, 15)
123+
self.lexer.setFont(font, 1)
124+
self.lexer.setFont(font, 2)
125+
self.lexer.setFont(font, 3)
126+
self.lexer.setFont(font, 4)
127+
128+
self.setLexer(self.lexer)
129+
130+
def getTextFromEditor(self):
131+
text = self.text()
132+
textList = text.split("\n")
133+
return textList
134+
135+
def clearConsole(self):
136+
#self.SendScintilla(QsciScintilla.SCI_CLEARALL)
137+
self.setText('')

0 commit comments

Comments
 (0)