New Python Console
@ -97,6 +97,9 @@ SET (QGIS_PYTHON_DIR ${PYTHON_SITE_PACKAGES_DIR}/qgis)
|
|||||||
|
|
||||||
ADD_CUSTOM_TARGET(compile_python_files ALL)
|
ADD_CUSTOM_TARGET(compile_python_files ALL)
|
||||||
|
|
||||||
|
ADD_SUBDIRECTORY(iconConsole)
|
||||||
|
ADD_SUBDIRECTORY(helpConsole)
|
||||||
|
|
||||||
ADD_CUSTOM_COMMAND(TARGET compile_python_files
|
ADD_CUSTOM_COMMAND(TARGET compile_python_files
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QGIS_PYTHON_OUTPUT_DIRECTORY}
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${QGIS_PYTHON_OUTPUT_DIRECTORY}
|
||||||
@ -115,3 +118,6 @@ ENDFOREACH(file)
|
|||||||
PYTHON_INSTALL(__init__.py ${QGIS_PYTHON_DIR})
|
PYTHON_INSTALL(__init__.py ${QGIS_PYTHON_DIR})
|
||||||
PYTHON_INSTALL(utils.py ${QGIS_PYTHON_DIR})
|
PYTHON_INSTALL(utils.py ${QGIS_PYTHON_DIR})
|
||||||
PYTHON_INSTALL(console.py ${QGIS_PYTHON_DIR})
|
PYTHON_INSTALL(console.py ${QGIS_PYTHON_DIR})
|
||||||
|
PYTHON_INSTALL(console_sci.py ${QGIS_PYTHON_DIR})
|
||||||
|
PYTHON_INSTALL(help.py ${QGIS_PYTHON_DIR})
|
||||||
|
|
||||||
|
@ -1,36 +1,32 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
# 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 managerR plugin.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Implementation of interactive Python console widget for QGIS.
|
/***************************************************************************
|
||||||
|
Python Conosle for QGIS
|
||||||
Has +- the same behaviour as command-line interactive console:
|
-------------------
|
||||||
- runs commands one by one
|
begin : 2012-09-xx
|
||||||
- supports expressions that span through more lines
|
copyright : (C) 2012 by Salvatore Larosa
|
||||||
- has command history, accessible using up/down keys
|
email : lrssvtml (at) gmail (dot) com
|
||||||
- supports pasting of commands
|
***************************************************************************/
|
||||||
|
|
||||||
TODO:
|
|
||||||
- configuration - init commands, font, ...
|
|
||||||
- python code highlighting
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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.QtCore import *
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from qgis.utils import iface
|
from qgis.utils import iface
|
||||||
|
from console_sci import PythonEdit
|
||||||
|
from help import HelpDialog
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import os
|
||||||
import code
|
|
||||||
|
|
||||||
|
|
||||||
_init_commands = ["from qgis.core import *", "import qgis.utils"]
|
|
||||||
|
|
||||||
_console = None
|
_console = None
|
||||||
|
|
||||||
@ -47,18 +43,9 @@ def show_console():
|
|||||||
_console.activateWindow()
|
_console.activateWindow()
|
||||||
_console.edit.setFocus()
|
_console.edit.setFocus()
|
||||||
|
|
||||||
|
|
||||||
_old_stdout = sys.stdout
|
_old_stdout = sys.stdout
|
||||||
_console_output = None
|
_console_output = None
|
||||||
|
|
||||||
|
|
||||||
def clearConsole():
|
|
||||||
global _console
|
|
||||||
if _console is None:
|
|
||||||
return
|
|
||||||
_console.edit.clearConsole()
|
|
||||||
|
|
||||||
|
|
||||||
# hook for python console so all output will be redirected
|
# hook for python console so all output will be redirected
|
||||||
# and then shown in console
|
# and then shown in console
|
||||||
def console_displayhook(obj):
|
def console_displayhook(obj):
|
||||||
@ -79,30 +66,6 @@ class QgisOutputCatcher:
|
|||||||
|
|
||||||
sys.stdout = QgisOutputCatcher()
|
sys.stdout = QgisOutputCatcher()
|
||||||
|
|
||||||
class PythonConsole(QDockWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
QDockWidget.__init__(self, parent)
|
|
||||||
self.setObjectName("Python Console")
|
|
||||||
self.setAllowedAreas(Qt.BottomDockWidgetArea)
|
|
||||||
self.widget = QWidget()
|
|
||||||
self.l = QVBoxLayout(self.widget)
|
|
||||||
self.l.setMargin(0)
|
|
||||||
self.edit = PythonEdit()
|
|
||||||
self.l.addWidget(self.edit)
|
|
||||||
self.setWidget(self.widget)
|
|
||||||
self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))
|
|
||||||
# try to restore position from stored main window state
|
|
||||||
if not iface.mainWindow().restoreDockWidget(self):
|
|
||||||
iface.mainWindow().addDockWidget(Qt.BottomDockWidgetArea, self)
|
|
||||||
|
|
||||||
|
|
||||||
def sizeHint(self):
|
|
||||||
return QSize(500,300)
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
QWidget.closeEvent(self, event)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleHighlighter(QSyntaxHighlighter):
|
class ConsoleHighlighter(QSyntaxHighlighter):
|
||||||
EDIT_LINE, ERROR, OUTPUT, INIT = range(4)
|
EDIT_LINE, ERROR, OUTPUT, INIT = range(4)
|
||||||
def __init__(self, doc):
|
def __init__(self, doc):
|
||||||
@ -125,206 +88,180 @@ class ConsoleHighlighter(QSyntaxHighlighter):
|
|||||||
if state == self.EDIT_LINE:
|
if state == self.EDIT_LINE:
|
||||||
self.setFormat(0,3, self.f[self.EDIT_LINE])
|
self.setFormat(0,3, self.f[self.EDIT_LINE])
|
||||||
|
|
||||||
|
class PythonConsole(QDockWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QDockWidget.__init__(self, parent)
|
||||||
|
self.setObjectName("Python Console")
|
||||||
|
#self.setAllowedAreas(Qt.BottomDockWidgetArea)
|
||||||
|
|
||||||
class PythonEdit(QTextEdit, code.InteractiveInterpreter):
|
self.widgetButton = QWidget()
|
||||||
|
self.widgetEdit = QWidget()
|
||||||
|
|
||||||
def __init__(self,parent=None):
|
self.toolBar = QToolBar()
|
||||||
QTextEdit.__init__(self, parent)
|
self.toolBar.setEnabled(True)
|
||||||
code.InteractiveInterpreter.__init__(self, locals=None)
|
#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.setTextInteractionFlags(Qt.TextEditorInteraction)
|
self.b = QVBoxLayout(self.widgetButton)
|
||||||
self.setAcceptDrops(False)
|
self.e = QHBoxLayout(self.widgetEdit)
|
||||||
self.setMinimumSize(30, 30)
|
|
||||||
self.setUndoRedoEnabled(False)
|
|
||||||
self.setAcceptRichText(False)
|
|
||||||
monofont = QFont("Monospace")
|
|
||||||
monofont.setStyleHint(QFont.TypeWriter)
|
|
||||||
self.setFont(monofont)
|
|
||||||
|
|
||||||
self.buffer = []
|
self.e.setMargin(0)
|
||||||
|
self.b.setMargin(0)
|
||||||
|
|
||||||
self.insertInitText()
|
## Action for Clear button
|
||||||
|
self.clearButton = QAction(parent)
|
||||||
|
self.clearButton.setCheckable(False)
|
||||||
|
self.clearButton.setEnabled(True)
|
||||||
|
self.clearButton.setIcon(QIcon("icon/iconClearConsole.png"))
|
||||||
|
self.clearButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.clearButton.setIconVisibleInMenu(True)
|
||||||
|
self.clearButton.setToolTip('Clear console')
|
||||||
|
## Action for paste snippets code
|
||||||
|
self.clearButton = QAction(parent)
|
||||||
|
self.clearButton.setCheckable(False)
|
||||||
|
self.clearButton.setEnabled(True)
|
||||||
|
self.clearButton.setIcon(QIcon(os.path.dirname(__file__) + "/iconConsole/iconClearConsole.png"))
|
||||||
|
self.clearButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.clearButton.setIconVisibleInMenu(True)
|
||||||
|
self.clearButton.setToolTip('Clear console')
|
||||||
|
## Action for paste snippets code
|
||||||
|
# self.currentLayerButton = QAction(parent)
|
||||||
|
# self.currentLayerButton.setCheckable(False)
|
||||||
|
# self.currentLayerButton.setEnabled(True)
|
||||||
|
# self.currentLayerButton.setIcon(QIcon("icon/iconTempConsole.png"))
|
||||||
|
# self.currentLayerButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
# self.currentLayerButton.setIconVisibleInMenu(True)
|
||||||
|
##
|
||||||
|
self.loadIfaceButton = QAction(parent)
|
||||||
|
self.loadIfaceButton.setCheckable(False)
|
||||||
|
self.loadIfaceButton.setEnabled(True)
|
||||||
|
self.loadIfaceButton.setIcon(QIcon(os.path.dirname(__file__) + "/iconConsole/iconTempConsole.png"))
|
||||||
|
self.loadIfaceButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.loadIfaceButton.setIconVisibleInMenu(True)
|
||||||
|
self.loadIfaceButton.setToolTip('Import iface class')
|
||||||
|
## Action for Open File
|
||||||
|
self.openFileButton = QAction(parent)
|
||||||
|
self.openFileButton.setCheckable(False)
|
||||||
|
self.openFileButton.setEnabled(True)
|
||||||
|
self.openFileButton.setIcon(QIcon(os.path.dirname(__file__) + "/iconConsole/iconOpenConsole.png"))
|
||||||
|
self.openFileButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.openFileButton.setIconVisibleInMenu(True)
|
||||||
|
self.openFileButton.setToolTip('Open script file')
|
||||||
|
## Action for Save File
|
||||||
|
self.saveFileButton = QAction(parent)
|
||||||
|
self.saveFileButton.setCheckable(False)
|
||||||
|
self.saveFileButton.setEnabled(True)
|
||||||
|
self.saveFileButton.setIcon(QIcon(os.path.dirname(__file__) + "/iconConsole/iconSaveConsole.png"))
|
||||||
|
self.saveFileButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.saveFileButton.setIconVisibleInMenu(True)
|
||||||
|
self.saveFileButton.setToolTip('Save to file')
|
||||||
|
## Action for Run script
|
||||||
|
self.runButton = QAction(parent)
|
||||||
|
self.runButton.setCheckable(False)
|
||||||
|
self.runButton.setEnabled(True)
|
||||||
|
self.runButton.setIcon(QIcon(os.path.dirname(__file__) + "/iconConsole/iconRunConsole.png"))
|
||||||
|
self.runButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.runButton.setIconVisibleInMenu(True)
|
||||||
|
self.runButton.setToolTip('Run command')
|
||||||
|
## Help action
|
||||||
|
self.helpButton = QAction(parent)
|
||||||
|
self.helpButton.setCheckable(False)
|
||||||
|
self.helpButton.setEnabled(True)
|
||||||
|
self.helpButton.setIcon(QIcon(os.path.dirname(__file__) + "/iconConsole/iconHelpConsole.png"))
|
||||||
|
self.helpButton.setMenuRole(QAction.PreferencesRole)
|
||||||
|
self.helpButton.setIconVisibleInMenu(True)
|
||||||
|
self.helpButton.setToolTip('Help')
|
||||||
|
|
||||||
for line in _init_commands:
|
self.toolBar.addAction(self.clearButton)
|
||||||
self.runsource(line)
|
#self.toolBar.addAction(self.currentLayerButton)
|
||||||
|
self.toolBar.addAction(self.loadIfaceButton)
|
||||||
|
self.toolBar.addAction(self.openFileButton)
|
||||||
|
self.toolBar.addAction(self.saveFileButton)
|
||||||
|
self.toolBar.addAction(self.helpButton)
|
||||||
|
self.toolBar.addAction(self.runButton)
|
||||||
|
|
||||||
self.displayPrompt(False)
|
self.b.addWidget(self.toolBar)
|
||||||
|
self.edit = PythonEdit()
|
||||||
|
|
||||||
self.history = QStringList()
|
self.setWidget(self.widgetEdit)
|
||||||
self.historyIndex = 0
|
|
||||||
|
|
||||||
self.high = ConsoleHighlighter(self)
|
self.e.addWidget(self.widgetButton)
|
||||||
|
self.e.addWidget(self.edit)
|
||||||
|
|
||||||
def insertInitText(self):
|
self.edit.setFocus()
|
||||||
self.insertTaggedText(QCoreApplication.translate("PythonConsole", "To access Quantum GIS environment from this console\n"
|
|
||||||
"use qgis.utils.iface object (instance of QgisInterface class).\n\n"),
|
self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))
|
||||||
ConsoleHighlighter.INIT)
|
self.clearButton.activated.connect(self.edit.clearConsole)
|
||||||
|
#self.currentLayerButton.activated.connect(self.cLayer)
|
||||||
|
self.loadIfaceButton.activated.connect(self.iface)
|
||||||
|
self.runButton.activated.connect(self.edit.entered)
|
||||||
|
self.openFileButton.activated.connect(self.openScriptFile)
|
||||||
|
self.saveFileButton.activated.connect(self.saveScriptFile)
|
||||||
|
self.helpButton.activated.connect(self.openHelp)
|
||||||
|
# try to restore position from stored main window state
|
||||||
|
if not iface.mainWindow().restoreDockWidget(self):
|
||||||
|
iface.mainWindow().addDockWidget(Qt.BottomDockWidgetArea, self)
|
||||||
|
|
||||||
|
def cLayer(self):
|
||||||
|
self.edit.commandConsole('cLayer')
|
||||||
|
|
||||||
|
def iface(self):
|
||||||
|
self.edit.commandConsole('iface')
|
||||||
|
|
||||||
|
def openScriptFile(self):
|
||||||
|
scriptFile = QFileDialog.getOpenFileName(
|
||||||
|
self, "Open File", "", "Script file (*.py)")
|
||||||
|
if scriptFile.isEmpty() == False:
|
||||||
|
oF = open(scriptFile, 'r')
|
||||||
|
listScriptFile = []
|
||||||
|
for line in oF:
|
||||||
|
if line != "\n":
|
||||||
|
listScriptFile.append(line)
|
||||||
|
self.edit.insertTextFromFile(listScriptFile)
|
||||||
|
|
||||||
|
|
||||||
def clearConsole(self):
|
def saveScriptFile(self):
|
||||||
self.clear()
|
scriptFile = QFileDialog()
|
||||||
self.insertInitText()
|
scriptFile.setDefaultSuffix(".py")
|
||||||
|
fName = scriptFile.getSaveFileName(
|
||||||
|
self, "Save file", QString(), "Script file (*.py)")
|
||||||
|
|
||||||
def displayPrompt(self, more=False):
|
if fName.isEmpty() == False:
|
||||||
self.currentPrompt = "... " if more else ">>> "
|
filename = str(fName)
|
||||||
self.currentPromptLength = len(self.currentPrompt)
|
if not filename.endswith(".py"):
|
||||||
self.insertTaggedLine(self.currentPrompt, ConsoleHighlighter.EDIT_LINE)
|
fName += ".py"
|
||||||
self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
|
sF = open(fName,'w')
|
||||||
|
listText = self.edit.getTextFromEditor()
|
||||||
def isCursorInEditionZone(self):
|
is_first_line = True
|
||||||
cursor = self.textCursor()
|
for s in listText:
|
||||||
pos = cursor.position()
|
if s[0:3] in (">>>", "..."):
|
||||||
block = self.document().lastBlock()
|
s.replace(">>> ", "")
|
||||||
last = block.position() + self.currentPromptLength
|
s.replace("... ", "")
|
||||||
return pos >= last
|
if is_first_line:
|
||||||
|
# see, no write() in this branch
|
||||||
def currentCommand(self):
|
is_first_line = False
|
||||||
block = self.cursor.block()
|
|
||||||
text = block.text()
|
|
||||||
return text.right(text.length()-self.currentPromptLength)
|
|
||||||
|
|
||||||
def showPrevious(self):
|
|
||||||
if self.historyIndex < len(self.history) and not self.history.isEmpty():
|
|
||||||
self.cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.MoveAnchor)
|
|
||||||
self.cursor.movePosition(QTextCursor.StartOfBlock, QTextCursor.KeepAnchor)
|
|
||||||
self.cursor.removeSelectedText()
|
|
||||||
self.cursor.insertText(self.currentPrompt)
|
|
||||||
self.historyIndex += 1
|
|
||||||
if self.historyIndex == len(self.history):
|
|
||||||
self.insertPlainText("")
|
|
||||||
else:
|
else:
|
||||||
self.insertPlainText(self.history[self.historyIndex])
|
# we've just written a line; add a newline
|
||||||
|
sF.write('\n')
|
||||||
|
sF.write(s)
|
||||||
|
sF.close()
|
||||||
|
|
||||||
def showNext(self):
|
def openHelp(self):
|
||||||
if self.historyIndex > 0 and not self.history.isEmpty():
|
dlg = HelpDialog()
|
||||||
self.cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.MoveAnchor)
|
dlg.exec_()
|
||||||
self.cursor.movePosition(QTextCursor.StartOfBlock, QTextCursor.KeepAnchor)
|
|
||||||
self.cursor.removeSelectedText()
|
|
||||||
self.cursor.insertText(self.currentPrompt)
|
|
||||||
self.historyIndex -= 1
|
|
||||||
if self.historyIndex == len(self.history):
|
|
||||||
self.insertPlainText("")
|
|
||||||
else:
|
|
||||||
self.insertPlainText(self.history[self.historyIndex])
|
|
||||||
|
|
||||||
def updateHistory(self, command):
|
def closeEvent(self, event):
|
||||||
if isinstance(command, QStringList):
|
QWidget.closeEvent(self, event)
|
||||||
for line in command:
|
|
||||||
self.history.append(line)
|
|
||||||
elif not command == "":
|
|
||||||
if len(self.history) <= 0 or \
|
|
||||||
not command == self.history[-1]:
|
|
||||||
self.history.append(command)
|
|
||||||
self.historyIndex = len(self.history)
|
|
||||||
|
|
||||||
def keyPressEvent(self, e):
|
|
||||||
self.cursor = self.textCursor()
|
|
||||||
# if the cursor isn't in the edition zone, don't do anything except Ctrl+C
|
|
||||||
if not self.isCursorInEditionZone():
|
|
||||||
if e.modifiers() & Qt.ControlModifier or e.modifiers() & Qt.MetaModifier:
|
|
||||||
if e.key() == Qt.Key_C or e.key() == Qt.Key_A:
|
|
||||||
QTextEdit.keyPressEvent(self, e)
|
|
||||||
else:
|
|
||||||
# all other keystrokes get sent to the input line
|
|
||||||
self.cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
|
|
||||||
else:
|
|
||||||
# if Return is pressed, then perform the commands
|
|
||||||
if e.key() == Qt.Key_Return or e.key() == Qt.Key_Enter:
|
|
||||||
self.entered()
|
|
||||||
# if Up or Down is pressed
|
|
||||||
elif e.key() == Qt.Key_Down:
|
|
||||||
self.showPrevious()
|
|
||||||
elif e.key() == Qt.Key_Up:
|
|
||||||
self.showNext()
|
|
||||||
# if backspace is pressed, delete until we get to the prompt
|
|
||||||
elif e.key() == Qt.Key_Backspace:
|
|
||||||
if not self.cursor.hasSelection() and self.cursor.columnNumber() == self.currentPromptLength:
|
|
||||||
return
|
|
||||||
QTextEdit.keyPressEvent(self, e)
|
|
||||||
# if the left key is pressed, move left until we get to the prompt
|
|
||||||
elif e.key() == Qt.Key_Left and self.cursor.position() > self.document().lastBlock().position() + self.currentPromptLength:
|
|
||||||
anchor = QTextCursor.KeepAnchor if e.modifiers() & Qt.ShiftModifier else QTextCursor.MoveAnchor
|
|
||||||
move = QTextCursor.WordLeft if e.modifiers() & Qt.ControlModifier or e.modifiers() & Qt.MetaModifier else QTextCursor.Left
|
|
||||||
self.cursor.movePosition(move, anchor)
|
|
||||||
# use normal operation for right key
|
|
||||||
elif e.key() == Qt.Key_Right:
|
|
||||||
anchor = QTextCursor.KeepAnchor if e.modifiers() & Qt.ShiftModifier else QTextCursor.MoveAnchor
|
|
||||||
move = QTextCursor.WordRight if e.modifiers() & Qt.ControlModifier or e.modifiers() & Qt.MetaModifier else QTextCursor.Right
|
|
||||||
self.cursor.movePosition(move, anchor)
|
|
||||||
# if home is pressed, move cursor to right of prompt
|
|
||||||
elif e.key() == Qt.Key_Home:
|
|
||||||
anchor = QTextCursor.KeepAnchor if e.modifiers() & Qt.ShiftModifier else QTextCursor.MoveAnchor
|
|
||||||
self.cursor.movePosition(QTextCursor.StartOfBlock, anchor, 1)
|
|
||||||
self.cursor.movePosition(QTextCursor.Right, anchor, self.currentPromptLength)
|
|
||||||
# use normal operation for end key
|
|
||||||
elif e.key() == Qt.Key_End:
|
|
||||||
anchor = QTextCursor.KeepAnchor if e.modifiers() & Qt.ShiftModifier else QTextCursor.MoveAnchor
|
|
||||||
self.cursor.movePosition(QTextCursor.EndOfBlock, anchor, 1)
|
|
||||||
# use normal operation for all remaining keys
|
|
||||||
else:
|
|
||||||
QTextEdit.keyPressEvent(self, e)
|
|
||||||
self.setTextCursor(self.cursor)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def insertFromMimeData(self, source):
|
|
||||||
self.cursor = self.textCursor()
|
|
||||||
if source.hasText():
|
|
||||||
pasteList = QStringList()
|
|
||||||
pasteList = source.text().split("\n")
|
|
||||||
# move the cursor to the end only if the text is multi-line or is going to be pasted not into the last line
|
|
||||||
if (len(pasteList) > 1) or (not self.isCursorInEditionZone()):
|
|
||||||
self.cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor, 1)
|
|
||||||
self.setTextCursor(self.cursor)
|
|
||||||
# with multi-line text also run the commands
|
|
||||||
for line in pasteList[:-1]:
|
|
||||||
self.insertPlainText(line)
|
|
||||||
self.runCommand(unicode(self.currentCommand()))
|
|
||||||
# last line: only paste the text, do not run it
|
|
||||||
self.insertPlainText(unicode(pasteList[-1]))
|
|
||||||
|
|
||||||
def entered(self):
|
|
||||||
self.cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
|
|
||||||
self.setTextCursor(self.cursor)
|
|
||||||
self.runCommand( unicode(self.currentCommand()) )
|
|
||||||
|
|
||||||
def insertTaggedText(self, txt, tag):
|
|
||||||
|
|
||||||
if len(txt) > 0 and txt[-1] == '\n': # remove trailing newline to avoid one more empty line
|
|
||||||
txt = txt[0:-1]
|
|
||||||
|
|
||||||
c = self.textCursor()
|
|
||||||
for line in txt.split('\n'):
|
|
||||||
b = c.block()
|
|
||||||
b.setUserState(tag)
|
|
||||||
c.insertText(line)
|
|
||||||
c.insertBlock()
|
|
||||||
|
|
||||||
def insertTaggedLine(self, txt, tag):
|
|
||||||
c = self.textCursor()
|
|
||||||
b = c.block()
|
|
||||||
b.setUserState(tag)
|
|
||||||
c.insertText(txt)
|
|
||||||
|
|
||||||
def runCommand(self, cmd):
|
|
||||||
|
|
||||||
self.updateHistory(cmd)
|
|
||||||
|
|
||||||
self.insertPlainText("\n")
|
|
||||||
|
|
||||||
self.buffer.append(cmd)
|
|
||||||
src = "\n".join(self.buffer)
|
|
||||||
more = self.runsource(src, "<input>")
|
|
||||||
if not more:
|
|
||||||
self.buffer = []
|
|
||||||
|
|
||||||
output = sys.stdout.get_and_clean_data()
|
|
||||||
if output:
|
|
||||||
self.insertTaggedText(output, ConsoleHighlighter.OUTPUT)
|
|
||||||
self.displayPrompt(more)
|
|
||||||
|
|
||||||
def write(self, txt):
|
|
||||||
""" reimplementation from code.InteractiveInterpreter """
|
|
||||||
self.insertTaggedText(txt, ConsoleHighlighter.ERROR)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
a = QApplication(sys.argv)
|
a = QApplication(sys.argv)
|
||||||
|
456
python/console_sci.py
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
/***************************************************************************
|
||||||
|
Python Conosle for QGIS
|
||||||
|
-------------------
|
||||||
|
begin : 2012-09-xx
|
||||||
|
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 *
|
||||||
|
from PyQt4.Qsci import QsciScintilla, QsciScintillaBase, QsciLexerPython
|
||||||
|
#from qgis.utils import iface
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import code
|
||||||
|
|
||||||
|
_init_commands = ["from qgis.core import *", "import qgis.utils"]
|
||||||
|
|
||||||
|
_console = None
|
||||||
|
|
||||||
|
_old_stdout = sys.stdout
|
||||||
|
_console_output = None
|
||||||
|
|
||||||
|
class PythonEdit(QsciScintilla, code.InteractiveInterpreter):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
#QsciScintilla.__init__(self, parent)
|
||||||
|
super(PythonEdit,self).__init__(parent)
|
||||||
|
code.InteractiveInterpreter.__init__(self, locals=None)
|
||||||
|
|
||||||
|
self.current_prompt_pos = None
|
||||||
|
self.new_input_line = True
|
||||||
|
|
||||||
|
self.setMarginWidth(0, 0)
|
||||||
|
self.setMarginWidth(1, 0)
|
||||||
|
self.setMarginWidth(2, 0)
|
||||||
|
|
||||||
|
self.buffer = []
|
||||||
|
|
||||||
|
self.insertInitText()
|
||||||
|
|
||||||
|
self.setCursorPosition(4,4)
|
||||||
|
|
||||||
|
self.displayPrompt(False)
|
||||||
|
|
||||||
|
for line in _init_commands:
|
||||||
|
self.runsource(line)
|
||||||
|
|
||||||
|
self.history = QStringList()
|
||||||
|
self.historyIndex = 0
|
||||||
|
|
||||||
|
# Brace matching: enable for a brace immediately before or after
|
||||||
|
# the current position
|
||||||
|
self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
|
||||||
|
#self.moveToMatchingBrace()
|
||||||
|
#self.selectToMatchingBrace()
|
||||||
|
|
||||||
|
# Current line visible with special background color
|
||||||
|
self.setCaretLineVisible(True)
|
||||||
|
self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
|
||||||
|
self.setCaretWidth(2)
|
||||||
|
|
||||||
|
# Set Python lexer
|
||||||
|
# Set style for Python comments (style number 1) to a fixed-width
|
||||||
|
# courier.
|
||||||
|
self.setLexers(True)
|
||||||
|
|
||||||
|
# Indentation
|
||||||
|
#self.setAutoIndent(True)
|
||||||
|
#self.setIndentationsUseTabs(False)
|
||||||
|
#self.setIndentationWidth(4)
|
||||||
|
#self.setTabIndents(True)
|
||||||
|
#self.setBackspaceUnindents(True)
|
||||||
|
#self.setTabWidth(4)
|
||||||
|
|
||||||
|
self.setAutoCompletionThreshold(1)
|
||||||
|
self.setAutoCompletionSource(self.AcsAPIs)
|
||||||
|
|
||||||
|
# Don't want to see the horizontal scrollbar at all
|
||||||
|
# Use raw message to Scintilla here (all messages are documented
|
||||||
|
# here: http://www.scintilla.org/ScintillaDoc.html)
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
|
||||||
|
|
||||||
|
# not too small
|
||||||
|
#self.setMinimumSize(500, 300)
|
||||||
|
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 1)
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)
|
||||||
|
|
||||||
|
def clearConsole(self):
|
||||||
|
"""Clear the contents of the console."""
|
||||||
|
self.setText('')
|
||||||
|
self.insertInitText()
|
||||||
|
self.displayPrompt(False)
|
||||||
|
self.setFocus()
|
||||||
|
|
||||||
|
def commandConsole(self, command):
|
||||||
|
line, pos = self.getCurLine()
|
||||||
|
selCmd= self.text(line).length()
|
||||||
|
self.setSelection(line, 4, line, selCmd)
|
||||||
|
self.removeSelectedText()
|
||||||
|
if command == "iface":
|
||||||
|
"""Import QgisInterface class"""
|
||||||
|
self.append('from qgis.utils import iface')
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
elif command == "cLayer":
|
||||||
|
"""Retrive current Layer from map camvas"""
|
||||||
|
self.append('cLayer = iface.mapCanvas().currentLayer()')
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
self.setFocus()
|
||||||
|
|
||||||
|
def setLexers(self, lexer):
|
||||||
|
if lexer:
|
||||||
|
font = QFont()
|
||||||
|
font.setFamily('Courier New') ## Courier New
|
||||||
|
font.setFixedPitch(True)
|
||||||
|
font.setPointSize(10)
|
||||||
|
self.setFont(font)
|
||||||
|
self.setMarginsFont(font)
|
||||||
|
self.lexer = QsciLexerPython()
|
||||||
|
self.lexer.setDefaultFont(font)
|
||||||
|
#self.lexer.setDefaultFont(QFont('Mono', 10, 0, False))
|
||||||
|
#self.lexer.setDefaultColor(Qt.darkGray)
|
||||||
|
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, 3)
|
||||||
|
self.lexer.setFont(font, 4)
|
||||||
|
self.api = QsciAPIs(self.lexer)
|
||||||
|
self.api.load("API/PyQGIS_1.8.api")
|
||||||
|
self.api.load("API/osgeo_gdal-ogr_1.9.1-1.api")
|
||||||
|
|
||||||
|
self.api.prepare()
|
||||||
|
self.lexer.setAPIs(self.api)
|
||||||
|
self.setLexer(self.lexer)
|
||||||
|
|
||||||
|
## TODO: show completion list for file and directory
|
||||||
|
# def show_completion_list(self, completions, text):
|
||||||
|
# """Private method to display the possible completions"""
|
||||||
|
# if len(completions) == 0:
|
||||||
|
# return
|
||||||
|
# if len(completions) > 1:
|
||||||
|
# self.showUserList(1, QStringList(sorted(completions)))
|
||||||
|
# self.completion_chars = 1
|
||||||
|
# else:
|
||||||
|
# txt = completions[0]
|
||||||
|
# if text != "":
|
||||||
|
# txt = txt.replace(text, "")
|
||||||
|
# self.insert(txt)
|
||||||
|
# self.completion_chars = 0
|
||||||
|
#
|
||||||
|
# def show_file_completion(self):
|
||||||
|
# """Display a completion list for files and directories"""
|
||||||
|
# cwd = os.getcwdu()
|
||||||
|
# self.show_completion_list(self.listdir_fullpath('/'), cwd)
|
||||||
|
#
|
||||||
|
# def listdir_fullpath(self, d):
|
||||||
|
# return [os.path.join(d, f) for f in os.listdir(d)]
|
||||||
|
|
||||||
|
|
||||||
|
def insertInitText(self):
|
||||||
|
#self.setLexers(False)
|
||||||
|
txtInit = ("## To access Quantum GIS environment from this console\n"
|
||||||
|
"## use qgis.utils.iface object (instance of QgisInterface class).\n\n")
|
||||||
|
initText = self.setText(txtInit)
|
||||||
|
|
||||||
|
def getCurrentPos(self):
|
||||||
|
""" Get the position (as an int) of the cursor.
|
||||||
|
getCursorPosition() returns a (linenr, index) tuple.
|
||||||
|
"""
|
||||||
|
return self.SendScintilla(self.SCI_GETCURRENTPOS)
|
||||||
|
|
||||||
|
def getText(self):
|
||||||
|
""" Get the text as a unicode string. """
|
||||||
|
value = self.getBytes().decode('utf-8')
|
||||||
|
# print (value) printing can give an error because the console font
|
||||||
|
# may not have all unicode characters
|
||||||
|
return value
|
||||||
|
|
||||||
|
def getBytes(self):
|
||||||
|
""" Get the text as bytes (utf-8 encoded). This is how
|
||||||
|
the data is stored internally. """
|
||||||
|
len = self.SendScintilla(self.SCI_GETLENGTH)+1
|
||||||
|
bb = QByteArray(len,'0')
|
||||||
|
N = self.SendScintilla(self.SCI_GETTEXT, len, bb)
|
||||||
|
return bytes(bb)[:-1]
|
||||||
|
|
||||||
|
def getTextLength(self):
|
||||||
|
return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)
|
||||||
|
|
||||||
|
def getLine(self, linenr):
|
||||||
|
""" Get the bytes on the given line number. """
|
||||||
|
len = self.SendScintilla(QsciScintilla.SCI_LINELENGTH)+1
|
||||||
|
bb = QByteArray(len,'0')
|
||||||
|
N = self.SendScintilla(QsciScintilla.SCI_GETLINE, len, bb)
|
||||||
|
return bytes(bb)[:-1]
|
||||||
|
|
||||||
|
def getCurLine(self):
|
||||||
|
""" Get the current line (as a string) and the
|
||||||
|
position of the cursor in it. """
|
||||||
|
linenr, index = self.getCursorPosition()
|
||||||
|
#line = self.getLine(linenr) #.decode('utf-8')
|
||||||
|
return linenr, index
|
||||||
|
|
||||||
|
def get_end_pos(self):
|
||||||
|
"""Return (line, index) position of the last character"""
|
||||||
|
line = self.lines() - 1
|
||||||
|
return (line, self.text(line).length())
|
||||||
|
|
||||||
|
def is_cursor_at_end(self):
|
||||||
|
"""Return True if cursor is at the end of text"""
|
||||||
|
cline, cindex = self.getCursorPosition()
|
||||||
|
return (cline, cindex) == self.get_end_pos()
|
||||||
|
|
||||||
|
def move_cursor_to_end(self):
|
||||||
|
"""Move cursor to end of text"""
|
||||||
|
line, index = self.get_end_pos()
|
||||||
|
self.setCursorPosition(line, index)
|
||||||
|
self.ensureCursorVisible()
|
||||||
|
|
||||||
|
def on_new_line(self):
|
||||||
|
"""On new input line"""
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
self.current_prompt_pos = self.getCursorPosition()
|
||||||
|
self.new_input_line = False
|
||||||
|
|
||||||
|
def is_cursor_on_last_line(self):
|
||||||
|
"""Return True if cursor is on the last line"""
|
||||||
|
cline, _ = self.getCursorPosition()
|
||||||
|
return cline == self.lines() - 1
|
||||||
|
|
||||||
|
def new_prompt(self, prompt):
|
||||||
|
"""
|
||||||
|
Print a new prompt and save its (line, index) position
|
||||||
|
"""
|
||||||
|
self.write(prompt, prompt=True)
|
||||||
|
# now we update our cursor giving end of prompt
|
||||||
|
self.current_prompt_pos = self.getCursorPosition()
|
||||||
|
self.ensureCursorVisible()
|
||||||
|
|
||||||
|
def check_selection(self):
|
||||||
|
"""
|
||||||
|
Check if selected text is r/w,
|
||||||
|
otherwise remove read-only parts of selection
|
||||||
|
"""
|
||||||
|
if self.current_prompt_pos is None:
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
return
|
||||||
|
line_from, index_from, line_to, index_to = self.getSelection()
|
||||||
|
pline, pindex = self.current_prompt_pos
|
||||||
|
if line_from < pline or \
|
||||||
|
(line_from == pline and index_from < pindex):
|
||||||
|
self.setSelection(pline, pindex, line_to, index_to)
|
||||||
|
|
||||||
|
def displayPrompt(self, more=False):
|
||||||
|
self.append("... ") if more else self.append(">>> ")
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
|
||||||
|
def updateHistory(self, command):
|
||||||
|
if isinstance(command, QStringList):
|
||||||
|
for line in command:
|
||||||
|
self.history.append(line)
|
||||||
|
elif not command == "":
|
||||||
|
if len(self.history) <= 0 or \
|
||||||
|
not command == self.history[-1]:
|
||||||
|
self.history.append(command)
|
||||||
|
self.historyIndex = len(self.history)
|
||||||
|
|
||||||
|
def showPrevious(self):
|
||||||
|
if self.historyIndex < len(self.history) and not self.history.isEmpty():
|
||||||
|
line, pos = self.getCurLine()
|
||||||
|
selCmd= self.text(line).length()
|
||||||
|
self.setSelection(line, 4, line, selCmd)
|
||||||
|
self.removeSelectedText()
|
||||||
|
self.historyIndex += 1
|
||||||
|
if self.historyIndex == len(self.history):
|
||||||
|
self.insert("")
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.insert(self.history[self.historyIndex])
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
#self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
|
||||||
|
|
||||||
|
|
||||||
|
def showNext(self):
|
||||||
|
if self.historyIndex > 0 and not self.history.isEmpty():
|
||||||
|
line, pos = self.getCurLine()
|
||||||
|
selCmd = self.text(line).length()
|
||||||
|
self.setSelection(line, 4, line, selCmd)
|
||||||
|
self.removeSelectedText()
|
||||||
|
self.historyIndex -= 1
|
||||||
|
if self.historyIndex == len(self.history):
|
||||||
|
self.insert("")
|
||||||
|
else:
|
||||||
|
self.insert(self.history[self.historyIndex])
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
#self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
|
||||||
|
|
||||||
|
def keyPressEvent(self, e):
|
||||||
|
linenr, index = self.getCurLine()
|
||||||
|
if not self.is_cursor_on_last_line() or index < 4:
|
||||||
|
if e.modifiers() & Qt.ControlModifier or e.modifiers() & Qt.MetaModifier:
|
||||||
|
if e.key() == Qt.Key_C or e.key() == Qt.Key_A:
|
||||||
|
QsciScintilla.keyPressEvent(self, e)
|
||||||
|
else:
|
||||||
|
# all other keystrokes get sent to the input line
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
#pass
|
||||||
|
else:
|
||||||
|
if (e.key() == Qt.Key_Return or e.key() == Qt.Key_Enter) and not self.isListActive():
|
||||||
|
self.entered()
|
||||||
|
elif e.key() == Qt.Key_Backspace:
|
||||||
|
curPos, pos = self.getCursorPosition()
|
||||||
|
line = self.lines() -1
|
||||||
|
if curPos < line -1 or pos < 5:
|
||||||
|
return
|
||||||
|
#else:
|
||||||
|
#self.move_cursor_to_end()
|
||||||
|
QsciScintilla.keyPressEvent(self, e)
|
||||||
|
elif e.key() == Qt.Key_Delete:
|
||||||
|
if self.hasSelectedText():
|
||||||
|
self.check_selection()
|
||||||
|
self.removeSelectedText()
|
||||||
|
elif self.is_cursor_on_last_line():
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_CLEAR)
|
||||||
|
e.accept()
|
||||||
|
elif e.key() == Qt.Key_Down and not self.isListActive():
|
||||||
|
self.showPrevious()
|
||||||
|
elif e.key() == Qt.Key_Up and not self.isListActive():
|
||||||
|
self.showNext()
|
||||||
|
elif e.key() == Qt.Key_Left:
|
||||||
|
e.accept()
|
||||||
|
if e.modifiers() & Qt.ShiftModifier:
|
||||||
|
if e.modifiers() & Qt.ControlModifier:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_WORDLEFTEXTEND)
|
||||||
|
else:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_CHARLEFTEXTEND)
|
||||||
|
else:
|
||||||
|
if e.modifiers() & Qt.ControlModifier:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_WORDLEFT)
|
||||||
|
else:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_CHARLEFT)
|
||||||
|
elif e.key() == Qt.Key_Right:
|
||||||
|
e.accept()
|
||||||
|
if e.modifiers() & Qt.ShiftModifier:
|
||||||
|
if e.modifiers() & Qt.ControlModifier:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_WORDRIGHTEXTEND)
|
||||||
|
else:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_CHARRIGHTEXTEND)
|
||||||
|
else:
|
||||||
|
if e.modifiers() & Qt.ControlModifier:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_WORDRIGHT)
|
||||||
|
else:
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_CHARRIGHT)
|
||||||
|
## TODO: press event for auto-completion file directory
|
||||||
|
#elif e.key() == Qt.Key_Tab:
|
||||||
|
#self.show_file_completion()
|
||||||
|
#else:
|
||||||
|
#self.on_new_line()
|
||||||
|
else:
|
||||||
|
QsciScintilla.keyPressEvent(self, e)
|
||||||
|
|
||||||
|
def paste(self):
|
||||||
|
"""Reimplement QScintilla method"""
|
||||||
|
# Moving cursor to the end of the last line
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
#QsciScintilla.paste(self)
|
||||||
|
QMessageBox.warning(self, "Python Console",
|
||||||
|
"Currently the action paste in console is not supported!")
|
||||||
|
return
|
||||||
|
|
||||||
|
## Drag and drop
|
||||||
|
def dragEnterEvent(self, e):
|
||||||
|
if e.mimeData().hasFormat('text/plain'):
|
||||||
|
e.accept()
|
||||||
|
else:
|
||||||
|
e.ignore()
|
||||||
|
|
||||||
|
def dropEvent(self, e):
|
||||||
|
stringDrag = e.mimeData().text()
|
||||||
|
pasteList = QStringList()
|
||||||
|
pasteList = stringDrag.split("\n")
|
||||||
|
for line in pasteList[:-1]:
|
||||||
|
self.append(line)
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
#self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
|
||||||
|
self.runCommand(unicode(self.currentCommand()))
|
||||||
|
self.append(unicode(pasteList[-1]))
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
|
||||||
|
def getTextFromEditor(self):
|
||||||
|
text = self.text()
|
||||||
|
textList = QStringList()
|
||||||
|
textList = text.split("\n")
|
||||||
|
return textList
|
||||||
|
|
||||||
|
def insertTextFromFile(self, listOpenFile):
|
||||||
|
for line in listOpenFile[:-1]:
|
||||||
|
self.append(line)
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
|
||||||
|
self.runCommand(unicode(self.currentCommand()))
|
||||||
|
self.append(unicode(listOpenFile[-1]))
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
|
||||||
|
|
||||||
|
def entered(self):
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
self.runCommand( unicode(self.currentCommand()) )
|
||||||
|
self.setFocus()
|
||||||
|
#self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)
|
||||||
|
|
||||||
|
def currentCommand(self):
|
||||||
|
linenr, index = self.getCurLine()
|
||||||
|
#for i in range(0, linenr):
|
||||||
|
txtLength = self.text(linenr).length()
|
||||||
|
string = self.text()
|
||||||
|
cmdLine = string.right(txtLength - 4)
|
||||||
|
cmd = str(cmdLine)
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def runCommand(self, cmd):
|
||||||
|
self.updateHistory(cmd)
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_NEWLINE)
|
||||||
|
self.buffer.append(cmd)
|
||||||
|
src = "\n".join(self.buffer)
|
||||||
|
more = self.runsource(src, "<input>")
|
||||||
|
if not more:
|
||||||
|
self.buffer = []
|
||||||
|
|
||||||
|
output = sys.stdout.get_and_clean_data()
|
||||||
|
if output:
|
||||||
|
self.append(output)
|
||||||
|
|
||||||
|
self.move_cursor_to_end()
|
||||||
|
self.displayPrompt(more)
|
||||||
|
|
||||||
|
def write(self, txt):
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
|
||||||
|
self.append(txt)
|
||||||
|
self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
|
37
python/help.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from PyQt4 import QtCore, QtGui, QtWebKit
|
||||||
|
from PyQt4.QtCore import *
|
||||||
|
from PyQt4.QtGui import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
class HelpDialog(QtGui.QDialog):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QtGui.QDialog.__init__(self)
|
||||||
|
self.setModal(True)
|
||||||
|
self.setupUi()
|
||||||
|
|
||||||
|
def setupUi(self):
|
||||||
|
self.resize(500, 300)
|
||||||
|
self.webView = QtWebKit.QWebView()
|
||||||
|
self.setWindowTitle("Help Python Console")
|
||||||
|
self.verticalLayout= QtGui.QVBoxLayout()
|
||||||
|
self.verticalLayout.setSpacing(2)
|
||||||
|
self.verticalLayout.setMargin(0)
|
||||||
|
self.verticalLayout.addWidget(self.webView)
|
||||||
|
self.closeButton = QtGui.QPushButton()
|
||||||
|
self.closeButton.setText("Close")
|
||||||
|
self.closeButton.setMaximumWidth(150)
|
||||||
|
self.horizontalLayout= QtGui.QHBoxLayout()
|
||||||
|
self.horizontalLayout.setSpacing(2)
|
||||||
|
self.horizontalLayout.setMargin(0)
|
||||||
|
self.horizontalLayout.addStretch(1000)
|
||||||
|
self.horizontalLayout.addWidget(self.closeButton)
|
||||||
|
QObject.connect(self.closeButton, QtCore.SIGNAL("clicked()"), self.closeWindow)
|
||||||
|
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||||
|
self.setLayout(self.verticalLayout)
|
||||||
|
filename = os.path.dirname(__file__) + "/helpConsole/help.htm"
|
||||||
|
url = QtCore.QUrl(filename)
|
||||||
|
self.webView.load(url)
|
||||||
|
|
||||||
|
def closeWindow(self):
|
||||||
|
self.close()
|
2
python/helpConsole/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
FILE(GLOB HTML_FILES *.htm)
|
||||||
|
INSTALL(FILES ${HTML_FILES} DESTINATION ${QGIS_PYTHON_DIR}/helpConsole)
|
59
python/helpConsole/help.htm
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>Help Python Console</title>
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
font-family: verdana,arial,helvetica,sans-serif;
|
||||||
|
/*font-family:Verdana,Geneva,sans-serif;*/
|
||||||
|
font-size : 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="../iconConsole/imgHelpDialog.png" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<h2>Python Console for QGIS</h2>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p align="justify">
|
||||||
|
To access Quantum GIS environment from this console
|
||||||
|
use qgis.utils.iface object (instance of QgisInterface class).
|
||||||
|
To import the class QgisInterface can also use the dedicated
|
||||||
|
button on the toolbar on the left.
|
||||||
|
<br><br>
|
||||||
|
The following is a description of the tools in the toolbar:
|
||||||
|
</p>
|
||||||
|
<table width="100%" bordercolor="#000" border="1">
|
||||||
|
<tr>
|
||||||
|
<td><img src="../iconConsole/iconClearConsole.png" /></td>
|
||||||
|
<td>Tool to clear python console</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="../iconConsole/iconTempConsole.png" /></td>
|
||||||
|
<td>Tool to import iface class</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="../iconConsole/iconOpenConsole.png" /></td>
|
||||||
|
<td>Tool to open a python script and load in console</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="../iconConsole/iconSaveConsole.png" /></td>
|
||||||
|
<td>Tool to save a python script</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="../iconConsole/iconHelpConsole.png" /></td>
|
||||||
|
<td>This! ;-)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="../iconConsole/iconRunConsole.png" /></td>
|
||||||
|
<td>Run commnand (like Enter key pressed)</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
python/iconConsole/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
SET(ICON_FILES
|
||||||
|
iconClearConsole.png
|
||||||
|
iconOpenConsole.png
|
||||||
|
iconRunConsole.png
|
||||||
|
iconTempConsole.png
|
||||||
|
iconSaveConsole.png
|
||||||
|
iconHelpConsole.png
|
||||||
|
imgHelpDialog.png
|
||||||
|
)
|
||||||
|
|
||||||
|
FILE(GLOB ICON_FILES *.png)
|
||||||
|
INSTALL(FILES ${ICON_FILES} DESTINATION ${QGIS_PYTHON_DIR}/iconConsole)
|
BIN
python/iconConsole/iconClearConsole.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
python/iconConsole/iconHelpConsole.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
python/iconConsole/iconOpenConsole.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
python/iconConsole/iconRunConsole.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
python/iconConsole/iconSaveConsole.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
python/iconConsole/iconTempConsole.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
python/iconConsole/imgHelpDialog.png
Normal file
After Width: | Height: | Size: 3.6 KiB |