class ShellOutputScintilla(QsciScintilla): def __init__(self, parent=None): super(ShellOutputScintilla, self).__init__(parent) self.parent = parent self.shell = self.parent.shell self.settings = QgsSettings() # Creates layout for message bar self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.layout.addItem(spacerItem, 1, 0, 1, 1) # messageBar instance self.infoBar = QgsMessageBar() sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.infoBar.setSizePolicy(sizePolicy) self.layout.addWidget(self.infoBar, 0, 0, 1, 1) # Enable non-ascii chars for editor self.setUtf8(True) sys.stdout = writeOut(self, sys.stdout) sys.stderr = writeOut(self, sys.stderr, "_traceback") self.insertInitText() self.refreshSettingsOutput() self.setReadOnly(True) # Set the default font font = QFontDatabase.systemFont(QFontDatabase.FixedFont) self.setFont(font) self.setMarginsFont(font) # Margin 0 is used for line numbers self.setMarginWidth(0, 0) self.setMarginWidth(1, 0) self.setMarginWidth(2, 0) #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.setCaretWidth(0) self.setMinimumHeight(120) self.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) self.runScut.setContext(Qt.WidgetShortcut) self.runScut.activated.connect(self.enteredSelected) # Reimplemented copy action to prevent paste prompt (>>>,...) in command view self.copyShortcut = QShortcut(QKeySequence.Copy, self) self.copyShortcut.activated.connect(self.copy) self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self) self.selectAllShortcut.activated.connect(self.selectAll) def insertInitText(self): txtInit = QCoreApplication.translate( "PythonConsole", "Python Console \n" "Use iface to access QGIS API interface or Type help(iface) for more info" ) # some translation string for the console header ends without '\n' # and the first command in console will be appended at the header text. # The following code add a '\n' at the end of the string if not present. if txtInit.endswith('\n'): self.setText(txtInit) else: self.setText(txtInit + '\n') def refreshSettingsOutput(self): # Set Python lexer self.setLexers() caretLineColor = self.settings.value("pythonConsole/caretLineColor", QColor("#fcf3ed")) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(Qt.black)) self.setCaretLineBackgroundColor(caretLineColor) self.setCaretForegroundColor(cursorColor) def setLexers(self): self.lexer = QsciLexerPython() font = QFontDatabase.systemFont(QFontDatabase.FixedFont) loadFont = self.settings.value("pythonConsole/fontfamilytext") if loadFont: font.setFamily(loadFont) fontSize = self.settings.value("pythonConsole/fontsize", type=int) if fontSize: font.setPointSize(fontSize) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor( QColor( self.settings.value("pythonConsole/defaultFontColor", QColor(Qt.black)))) self.lexer.setColor( QColor( self.settings.value("pythonConsole/commentFontColor", QColor(Qt.gray))), 1) self.lexer.setColor( QColor( self.settings.value("pythonConsole/keywordFontColor", QColor(Qt.darkGreen))), 5) self.lexer.setColor( QColor( self.settings.value("pythonConsole/classFontColor", QColor(Qt.blue))), 8) self.lexer.setColor( QColor( self.settings.value("pythonConsole/methodFontColor", QColor(Qt.darkGray))), 9) self.lexer.setColor( QColor( self.settings.value("pythonConsole/decorFontColor", QColor(Qt.darkBlue))), 15) self.lexer.setColor( QColor( self.settings.value("pythonConsole/commentBlockFontColor", QColor(Qt.gray))), 12) self.lexer.setColor( QColor( self.settings.value("pythonConsole/singleQuoteFontColor", QColor(Qt.blue))), 4) self.lexer.setColor( QColor( self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(Qt.blue))), 3) self.lexer.setColor( QColor( self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(Qt.blue))), 6) self.lexer.setColor( QColor( self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(Qt.blue))), 7) self.lexer.setColor(QColor(Qt.red), 14) self.lexer.setFont(font, 1) self.lexer.setFont(font, 2) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) for style in range(0, 33): paperColor = QColor( self.settings.value("pythonConsole/paperBackgroundColor", QColor(Qt.white))) self.lexer.setPaper(paperColor, style) self.setLexer(self.lexer) def clearConsole(self): self.setText('') self.insertInitText() self.shell.setFocus() def contextMenuEvent(self, e): menu = QMenu(self) iconRun = QgsApplication.getThemeIcon("console/mIconRunConsole.svg") iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.png") iconHideTool = QgsApplication.getThemeIcon( "console/iconHideToolConsole.png") iconSettings = QgsApplication.getThemeIcon( "console/iconSettingsConsole.png") menu.addAction( iconHideTool, QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), self.hideToolBar) menu.addSeparator() showEditorAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Show Editor"), self.showEditor) menu.addSeparator() runAction = menu.addAction( iconRun, QCoreApplication.translate("PythonConsole", "Enter Selected"), self.enteredSelected, QKeySequence(Qt.CTRL + Qt.Key_E)) clearAction = menu.addAction( iconClear, QCoreApplication.translate("PythonConsole", "Clear Console"), self.clearConsole) menu.addSeparator() copyAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) selectAllAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Select All"), self.selectAll, QKeySequence.SelectAll) menu.addSeparator() menu.addAction( iconSettings, QCoreApplication.translate("PythonConsole", "Options..."), self.parent.openSettings) runAction.setEnabled(False) clearAction.setEnabled(False) copyAction.setEnabled(False) selectAllAction.setEnabled(False) showEditorAction.setEnabled(True) if self.hasSelectedText(): runAction.setEnabled(True) copyAction.setEnabled(True) if not self.text(3) == '': selectAllAction.setEnabled(True) clearAction.setEnabled(True) if self.parent.tabEditorWidget.isVisible(): showEditorAction.setEnabled(False) menu.exec_(self.mapToGlobal(e.pos())) def hideToolBar(self): tB = self.parent.toolBar tB.hide() if tB.isVisible() else tB.show() self.shell.setFocus() def showEditor(self): Ed = self.parent.splitterObj if not Ed.isVisible(): Ed.show() self.parent.showEditorButton.setChecked(True) self.shell.setFocus() def copy(self): """Copy text to clipboard... or keyboard interrupt""" if self.hasSelectedText(): text = self.selectedText() text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts QApplication.clipboard().setText(text) else: raise KeyboardInterrupt def enteredSelected(self): cmd = self.selectedText() self.shell.insertFromDropPaste(cmd) self.shell.entered() def keyPressEvent(self, e): # empty text indicates possible shortcut key sequence so stay in output txt = e.text() if len(txt) and txt >= " ": self.shell.append(txt) self.shell.move_cursor_to_end() self.shell.setFocus() e.ignore() else: # possible shortcut key sequence, accept it e.accept() def widgetMessageBar(self, iface, text): timeout = iface.messageTimeout() self.infoBar.pushMessage(text, QgsMessageBar.INFO, timeout)
class ScriptEdit(QsciScintilla): DEFAULT_COLOR = "#4d4d4c" KEYWORD_COLOR = "#8959a8" CLASS_COLOR = "#4271ae" METHOD_COLOR = "#4271ae" DECORATION_COLOR = "#3e999f" NUMBER_COLOR = "#c82829" COMMENT_COLOR = "#8e908c" COMMENT_BLOCK_COLOR = "#8e908c" BACKGROUND_COLOR = "#ffffff" CURSOR_COLOR = "#636363" CARET_LINE_COLOR = "#efefef" SINGLE_QUOTE_COLOR = "#718c00" DOUBLE_QUOTE_COLOR = "#718c00" TRIPLE_SINGLE_QUOTE_COLOR = "#eab700" TRIPLE_DOUBLE_QUOTE_COLOR = "#eab700" MARGIN_BACKGROUND_COLOR = "#efefef" MARGIN_FOREGROUND_COLOR = "#636363" SELECTION_BACKGROUND_COLOR = "#d7d7d7" SELECTION_FOREGROUND_COLOR = "#303030" MATCHED_BRACE_BACKGROUND_COLOR = "#b7f907" MATCHED_BRACE_FOREGROUND_COLOR = "#303030" EDGE_COLOR = "#efefef" FOLD_COLOR = "#efefef" def __init__(self, parent=None): super().__init__(parent) self.lexer = None self.api = None self.setCommonOptions() self.initShortcuts() def setCommonOptions(self): # Enable non-ASCII characters self.setUtf8(True) settings = QgsSettings() # Default font font = QFontDatabase.systemFont(QFontDatabase.FixedFont) self.setFont(font) self.setMarginsFont(font) self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setMatchedBraceBackgroundColor(QColor(settings.value("pythonConsole/matchedBraceBackgroundColorEditor", QColor(self.MATCHED_BRACE_BACKGROUND_COLOR)))) self.setMatchedBraceForegroundColor(QColor(settings.value("pythonConsole/matchedBraceForegroundColorEditor", QColor(self.MATCHED_BRACE_FOREGROUND_COLOR)))) #self.setWrapMode(QsciScintilla.WrapWord) #self.setWrapVisualFlags(QsciScintilla.WrapFlagByText, # QsciScintilla.WrapFlagNone, 4) self.setSelectionForegroundColor(QColor(settings.value("pythonConsole/selectionForegroundColorEditor", QColor(self.SELECTION_FOREGROUND_COLOR)))) self.setSelectionBackgroundColor(QColor(settings.value("pythonConsole/selectionBackgroundColorEditor", QColor(self.SELECTION_BACKGROUND_COLOR)))) # Show line numbers fontmetrics = QFontMetrics(font) self.setMarginWidth(1, fontmetrics.width("0000") + 5) self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor(QColor(settings.value("pythonConsole/marginForegroundColorEditor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setMarginsBackgroundColor(QColor(settings.value("pythonConsole/marginBackgroundColorEditor", QColor(self.MARGIN_BACKGROUND_COLOR)))) self.setIndentationGuidesForegroundColor(QColor(settings.value("pythonConsole/marginForegroundColorEditor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setIndentationGuidesBackgroundColor(QColor(settings.value("pythonConsole/marginBackgroundColorEditor", QColor(self.MARGIN_BACKGROUND_COLOR)))) # Highlight current line caretLineColorEditor = settings.value("pythonConsole/caretLineColorEditor", QColor(self.CARET_LINE_COLOR)) cursorColorEditor = settings.value("pythonConsole/cursorColorEditor", QColor(self.CURSOR_COLOR)) self.setCaretLineVisible(True) self.setCaretWidth(2) self.setCaretLineBackgroundColor(caretLineColorEditor) self.setCaretForegroundColor(cursorColorEditor) # Folding self.setFolding(QsciScintilla.PlainFoldStyle) foldColor = QColor(settings.value("pythonConsole/foldColorEditor", QColor(self.FOLD_COLOR))) self.setFoldMarginColors(foldColor, foldColor) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(QColor(settings.value("pythonConsole/edgeColorEditor", QColor(self.EDGE_COLOR)))) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) self.setIndentationGuides(True) # Autocompletion self.setAutoCompletionThreshold(2) self.setAutoCompletionSource(QsciScintilla.AcsAPIs) self.setFonts(10) self.initLexer() def setFonts(self, size): # Load font from Python console settings settings = QgsSettings() fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') fontSize = int(settings.value('pythonConsole/fontsize', size)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) self.defaultFont.setPointSize(fontSize) self.defaultFont.setStyleHint(QFont.TypeWriter) self.defaultFont.setBold(False) self.boldFont = QFont(self.defaultFont) self.boldFont.setBold(True) self.italicFont = QFont(self.defaultFont) self.italicFont.setItalic(True) self.setFont(self.defaultFont) self.setMarginsFont(self.defaultFont) def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.shortcutAutocomplete.setContext(Qt.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) def autoComplete(self): self.autoCompleteFromAll() def initLexer(self): settings = QgsSettings() self.lexer = QsciLexerPython() font = QFontDatabase.systemFont(QFontDatabase.FixedFont) loadFont = settings.value("pythonConsole/fontfamilytextEditor") if loadFont: font.setFamily(loadFont) fontSize = settings.value("pythonConsole/fontsizeEditor", type=int) if fontSize: font.setPointSize(fontSize) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor(QColor(settings.value("pythonConsole/defaultFontColorEditor", QColor(self.DEFAULT_COLOR)))) self.lexer.setColor(QColor(settings.value("pythonConsole/commentFontColorEditor", QColor(self.COMMENT_COLOR))), 1) self.lexer.setColor(QColor(settings.value("pythonConsole/numberFontColorEditor", QColor(self.NUMBER_COLOR))), 2) self.lexer.setColor(QColor(settings.value("pythonConsole/keywordFontColorEditor", QColor(self.KEYWORD_COLOR))), 5) self.lexer.setColor(QColor(settings.value("pythonConsole/classFontColorEditor", QColor(self.CLASS_COLOR))), 8) self.lexer.setColor(QColor(settings.value("pythonConsole/methodFontColorEditor", QColor(self.METHOD_COLOR))), 9) self.lexer.setColor(QColor(settings.value("pythonConsole/decorFontColorEditor", QColor(self.DECORATION_COLOR))), 15) self.lexer.setColor(QColor(settings.value("pythonConsole/commentBlockFontColorEditor", QColor(self.COMMENT_BLOCK_COLOR))), 12) self.lexer.setColor(QColor(settings.value("pythonConsole/singleQuoteFontColorEditor", QColor(self.SINGLE_QUOTE_COLOR))), 4) self.lexer.setColor(QColor(settings.value("pythonConsole/doubleQuoteFontColorEditor", QColor(self.DOUBLE_QUOTE_COLOR))), 3) self.lexer.setColor(QColor(settings.value("pythonConsole/tripleSingleQuoteFontColorEditor", QColor(self.TRIPLE_SINGLE_QUOTE_COLOR))), 6) self.lexer.setColor(QColor(settings.value("pythonConsole/tripleDoubleQuoteFontColorEditor", QColor(self.TRIPLE_DOUBLE_QUOTE_COLOR))), 7) self.lexer.setColor(QColor(settings.value("pythonConsole/defaultFontColorEditor", QColor(self.DEFAULT_COLOR))), 13) self.lexer.setFont(font, 1) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) self.lexer.setFont(font, QsciLexerPython.UnclosedString) for style in range(0, 33): paperColor = QColor(settings.value("pythonConsole/paperBackgroundColorEditor", QColor(self.BACKGROUND_COLOR))) self.lexer.setPaper(paperColor, style) self.api = QsciAPIs(self.lexer) useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI', True)) if useDefaultAPI: # Load QGIS API shipped with Python console self.api.loadPrepared( os.path.join(QgsApplication.pkgDataPath(), 'python', 'qsci_apis', 'pyqgis.pap')) else: # Load user-defined API files apiPaths = settings.value('pythonConsole/userAPI', []) for path in apiPaths: self.api.load(path) self.api.prepare() self.lexer.setAPIs(self.api) self.setLexer(self.lexer)
class SqlEdit(QsciScintilla): LEXER_PYTHON = 0 LEXER_R = 1 def __init__(self, parent=None): QsciScintilla.__init__(self, parent) self.mylexer = None self.api = None self.setCommonOptions() self.initShortcuts() def setCommonOptions(self): # Enable non-ASCII characters self.setUtf8(True) # Default font font = QFont() font.setFamily('Courier') font.setFixedPitch(True) font.setPointSize(10) self.setFont(font) self.setMarginsFont(font) self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setWrapMode(QsciScintilla.WrapWord) self.setWrapVisualFlags(QsciScintilla.WrapFlagByText, QsciScintilla.WrapFlagNone, 4) self.setSelectionForegroundColor(QColor('#2e3436')) self.setSelectionBackgroundColor(QColor('#babdb6')) # Show line numbers self.setMarginWidth(1, '000') self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor(QColor('#2e3436')) self.setMarginsBackgroundColor(QColor('#babdb6')) # Highlight current line self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor('#d3d7cf')) # Folding self.setFolding(QsciScintilla.BoxedTreeFoldStyle) self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf')) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(QColor('#eeeeec')) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) # Autocomletion self.setAutoCompletionThreshold(2) self.setAutoCompletionSource(QsciScintilla.AcsAPIs) self.setAutoCompletionCaseSensitivity(False) # Load font from Python console settings settings = QgsSettings() fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') fontSize = int(settings.value('pythonConsole/fontsize', 10)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) self.defaultFont.setPointSize(fontSize) self.defaultFont.setStyleHint(QFont.TypeWriter) self.defaultFont.setStretch(QFont.SemiCondensed) self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0) self.defaultFont.setBold(False) self.boldFont = QFont(self.defaultFont) self.boldFont.setBold(True) self.italicFont = QFont(self.defaultFont) self.italicFont.setItalic(True) self.setFont(self.defaultFont) self.setMarginsFont(self.defaultFont) self.initLexer() def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.shortcutAutocomplete.setContext(Qt.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) def autoComplete(self): self.autoCompleteFromAll() def initLexer(self): self.mylexer = QsciLexerSQL() colorDefault = QColor('#2e3436') colorComment = QColor('#c00') colorCommentBlock = QColor('#3465a4') colorNumber = QColor('#4e9a06') colorType = QColor('#4e9a06') colorKeyword = QColor('#204a87') colorString = QColor('#ce5c00') self.mylexer.setDefaultFont(self.defaultFont) self.mylexer.setDefaultColor(colorDefault) self.mylexer.setColor(colorComment, 1) self.mylexer.setColor(colorNumber, 2) self.mylexer.setColor(colorString, 3) self.mylexer.setColor(colorString, 4) self.mylexer.setColor(colorKeyword, 5) self.mylexer.setColor(colorString, 6) self.mylexer.setColor(colorString, 7) self.mylexer.setColor(colorType, 8) self.mylexer.setColor(colorCommentBlock, 12) self.mylexer.setColor(colorString, 15) self.mylexer.setFont(self.italicFont, 1) self.mylexer.setFont(self.boldFont, 5) self.mylexer.setFont(self.boldFont, 8) self.mylexer.setFont(self.italicFont, 12) self.setLexer(self.mylexer) def lexer(self): return self.mylexer def setMarginVisible(self, visible): pass
class ShellScintilla(QsciScintilla, code.InteractiveInterpreter): def __init__(self, parent=None): super(ShellScintilla, self).__init__(parent) code.InteractiveInterpreter.__init__(self, locals=None) self.parent = parent self.opening = ['(', '{', '[', "'", '"'] self.closing = [')', '}', ']', "'", '"'] self.settings = QSettings() # Enable non-ascii chars for editor self.setUtf8(True) self.new_input_line = True self.setMarginWidth(0, 0) self.setMarginWidth(1, 0) self.setMarginWidth(2, 0) self.buffer = [] self.displayPrompt(False) for line in _init_commands: self.runsource(line) self.history = [] self.historyIndex = 0 # Read history command file self.readHistoryFile() self.historyDlg = HistoryDialog(self) # Brace matching: enable for a brace immediately before or after # the current position self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setMatchedBraceBackgroundColor(QColor("#b7f907")) # Current line visible with special background color self.setCaretWidth(2) self.refreshSettingsShell() # 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.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER) ## Disable command key ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16 self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) ## New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete self.newShortcutCSS = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Space), self) self.newShortcutCAS = QShortcut(QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self) self.newShortcutCSS.setContext(Qt.WidgetShortcut) self.newShortcutCAS.setContext(Qt.WidgetShortcut) self.newShortcutCAS.activated.connect(self.autoCompleteKeyBinding) self.newShortcutCSS.activated.connect(self.showHistory) def _setMinimumHeight(self): fnt = self.settings.value("pythonConsole/fontfamilytext", "Monospace") fntSize = self.settings.value("pythonConsole/fontsize", 10, type=int) fm = QFontMetrics(QFont(fnt, fntSize)) self.setMinimumHeight(fm.height() + 10) def refreshSettingsShell(self): # Set Python lexer self.setLexers() threshold = self.settings.value("pythonConsole/autoCompThreshold", 2, type=int) self.setAutoCompletionThreshold(threshold) radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", 'fromAPI') autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True, type=bool) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.setAutoCompletionSource(self.AcsDocument) elif radioButtonSource == 'fromAPI': self.setAutoCompletionSource(self.AcsAPIs) elif radioButtonSource == 'fromDocAPI': self.setAutoCompletionSource(self.AcsAll) else: self.setAutoCompletionSource(self.AcsNone) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(Qt.black)) self.setCaretForegroundColor(cursorColor) # Sets minimum height for input area based of font metric self._setMinimumHeight() def showHistory(self): if not self.historyDlg.isVisible(): self.historyDlg.show() self.historyDlg._reloadHistory() self.historyDlg.activateWindow() def autoCompleteKeyBinding(self): radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", 'fromAPI') autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True, type=bool) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.autoCompleteFromDocument() elif radioButtonSource == 'fromAPI': self.autoCompleteFromAPIs() elif radioButtonSource == 'fromDocAPI': self.autoCompleteFromAll() def commandConsole(self, commands): if not self.is_cursor_on_last_line(): self.move_cursor_to_end() line, pos = self.getCursorPosition() selCmdLenght = len(self.text(line)) self.setSelection(line, 4, line, selCmdLenght) self.removeSelectedText() for cmd in commands: self.append(cmd) self.entered() self.move_cursor_to_end() self.setFocus() def setLexers(self): self.lexer = QsciLexerPython() loadFont = self.settings.value("pythonConsole/fontfamilytext", "Monospace") fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int) font = QFont(loadFont) font.setFixedPitch(True) font.setPointSize(fontSize) font.setStyleHint(QFont.TypeWriter) font.setStretch(QFont.SemiCondensed) font.setLetterSpacing(QFont.PercentageSpacing, 87.0) font.setBold(False) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor(QColor(self.settings.value("pythonConsole/defaultFontColor", QColor(Qt.black)))) self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentFontColor", QColor(Qt.gray))), 1) self.lexer.setColor(QColor(self.settings.value("pythonConsole/keywordFontColor", QColor(Qt.darkGreen))), 5) self.lexer.setColor(QColor(self.settings.value("pythonConsole/classFontColor", QColor(Qt.blue))), 8) self.lexer.setColor(QColor(self.settings.value("pythonConsole/methodFontColor", QColor(Qt.darkGray))), 9) self.lexer.setColor(QColor(self.settings.value("pythonConsole/decorFontColor", QColor(Qt.darkBlue))), 15) self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentBlockFontColor", QColor(Qt.gray))), 12) self.lexer.setColor(QColor(self.settings.value("pythonConsole/singleQuoteFontColor", QColor(Qt.blue))), 4) self.lexer.setColor(QColor(self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(Qt.blue))), 3) self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(Qt.blue))), 6) self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(Qt.blue))), 7) self.lexer.setFont(font, 1) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) for style in range(0, 33): paperColor = QColor(self.settings.value("pythonConsole/paperBackgroundColor", QColor(Qt.white))) self.lexer.setPaper(paperColor, style) self.api = QsciAPIs(self.lexer) chekBoxAPI = self.settings.value("pythonConsole/preloadAPI", True, type=bool) chekBoxPreparedAPI = self.settings.value("pythonConsole/usePreparedAPIFile", False, type=bool) if chekBoxAPI: pap = os.path.join(QgsApplication.pkgDataPath(), "python", "qsci_apis", "pyqgis.pap") self.api.loadPrepared(pap) elif chekBoxPreparedAPI: self.api.loadPrepared(self.settings.value("pythonConsole/preparedAPIFile")) else: apiPath = self.settings.value("pythonConsole/userAPI", []) for i in range(0, len(apiPath)): self.api.load(apiPath[i]) self.api.prepare() self.lexer.setAPIs(self.api) self.setLexer(self.lexer) ## TODO: show completion list for file and directory 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') self.SendScintilla(self.SCI_GETTEXT, len, bb) return bytes(bb)[:-1] def getTextLength(self): return self.SendScintilla(QsciScintilla.SCI_GETLENGTH) def get_end_pos(self): """Return (line, index) position of the last character""" line = self.lines() - 1 return (line, len(self.text(line))) 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() self.ensureLineVisible(line) 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 is_cursor_on_edition_zone(self): """ Return True if the cursor is in the edition zone """ cline, cindex = self.getCursorPosition() return cline == self.lines() - 1 and cindex >= 4 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 line, index = self.getCursorPosition() self.ensureCursorVisible() self.ensureLineVisible(line) def displayPrompt(self, more=False): self.append("... ") if more else self.append(">>> ") self.move_cursor_to_end() def updateHistory(self, command): if isinstance(command, list): for line in command: self.history.append(line) elif not command == "": if len(self.history) <= 0 or \ command != self.history[-1]: self.history.append(command) self.historyIndex = len(self.history) def writeHistoryFile(self, fromCloseConsole=False): ok = False try: wH = codecs.open(_historyFile, 'w', encoding='utf-8') for s in self.history: wH.write(s + '\n') ok = True except: raise wH.close() if ok and not fromCloseConsole: msgText = QCoreApplication.translate('PythonConsole', 'History saved successfully.') self.parent.callWidgetMessageBar(msgText) def readHistoryFile(self): fileExist = QFile.exists(_historyFile) if fileExist: with codecs.open(_historyFile, 'r', encoding='utf-8') as rH: for line in rH: if line != "\n": l = line.rstrip('\n') self.updateHistory(l) else: return def clearHistory(self, clearSession=False): if clearSession: self.history = [] msgText = QCoreApplication.translate('PythonConsole', 'Session and file history cleared successfully.') self.parent.callWidgetMessageBar(msgText) return ok = False try: cH = codecs.open(_historyFile, 'w', encoding='utf-8') ok = True except: raise cH.close() if ok: msgText = QCoreApplication.translate('PythonConsole', 'History cleared successfully.') self.parent.callWidgetMessageBar(msgText) def clearHistorySession(self): self.clearHistory(True) def showPrevious(self): if self.historyIndex < len(self.history) and self.history: line, pos = self.getCursorPosition() selCmdLenght = len(self.text(line)) self.setSelection(line, 4, line, selCmdLenght) 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 self.history: line, pos = self.getCursorPosition() selCmdLenght = len(self.text(line)) self.setSelection(line, 4, line, selCmdLenght) 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): startLine, startPos, endLine, endPos = self.getSelection() # handle invalid cursor position and multiline selections if not self.is_cursor_on_edition_zone() or startLine < endLine: # allow copying and selecting if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier): if e.key() in (Qt.Key_C, Qt.Key_A): QsciScintilla.keyPressEvent(self, e) return # allow selection if e.modifiers() & Qt.ShiftModifier: if e.key() in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Home, Qt.Key_End): QsciScintilla.keyPressEvent(self, e) return # all other keystrokes get sent to the input line self.move_cursor_to_end() line, index = self.getCursorPosition() cmd = self.text(line) if e.key() in (Qt.Key_Return, Qt.Key_Enter) and not self.isListActive(): self.entered() elif e.key() in (Qt.Key_Left, Qt.Key_Home): QsciScintilla.keyPressEvent(self, e) # check whether the cursor is moved out of the edition zone newline, newindex = self.getCursorPosition() if newline < line or newindex < 4: # fix selection and the cursor position if self.hasSelectedText(): self.setSelection(line, self.getSelection()[3], line, 4) else: self.setCursorPosition(line, 4) elif e.key() in (Qt.Key_Backspace, Qt.Key_Delete): QsciScintilla.keyPressEvent(self, e) # check whether the cursor is moved out of the edition zone _, newindex = self.getCursorPosition() if newindex < 4: # restore the prompt chars (if removed) and # fix the cursor position self.insert(cmd[:3 - newindex] + " ") self.setCursorPosition(line, 4) self.recolor() elif (e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_V) or \ (e.modifiers() & Qt.ShiftModifier and e.key() == Qt.Key_Insert): self.paste() 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() ## TODO: press event for auto-completion file directory else: t = e.text() self.autoCloseBracket = self.settings.value("pythonConsole/autoCloseBracket", False, type=bool) self.autoImport = self.settings.value("pythonConsole/autoInsertionImport", True, type=bool) txt = cmd[:index].replace('>>> ', '').replace('... ', '') ## Close bracket automatically if t in self.opening and self.autoCloseBracket: i = self.opening.index(t) if self.hasSelectedText() and startPos != 0: selText = self.selectedText() self.removeSelectedText() self.insert(self.opening[i] + selText + self.closing[i]) self.setCursorPosition(endLine, endPos + 2) return elif t == '(' and (re.match(r'^[ \t]*def \w+$', txt) or re.match(r'^[ \t]*class \w+$', txt)): self.insert('):') else: self.insert(self.closing[i]) ## FIXES #8392 (automatically removes the redundant char ## when autoclosing brackets option is enabled) elif t in [')', ']', '}'] and self.autoCloseBracket: txt = self.text(line) try: if txt[index - 1] in self.opening and t == txt[index]: self.setCursorPosition(line, index + 1) self.SendScintilla(QsciScintilla.SCI_DELETEBACK) except IndexError: pass elif t == ' ' and self.autoImport: ptrn = r'^[ \t]*from [\w.]+$' if re.match(ptrn, txt): self.insert(' import') self.setCursorPosition(line, index + 7) QsciScintilla.keyPressEvent(self, e) def contextMenuEvent(self, e): menu = QMenu(self) subMenu = QMenu(menu) titleHistoryMenu = QCoreApplication.translate("PythonConsole", "Command History") subMenu.setTitle(titleHistoryMenu) subMenu.addAction( QCoreApplication.translate("PythonConsole", "Show"), self.showHistory, 'Ctrl+Shift+SPACE') subMenu.addSeparator() subMenu.addAction( QCoreApplication.translate("PythonConsole", "Save"), self.writeHistoryFile) subMenu.addSeparator() subMenu.addAction( QCoreApplication.translate("PythonConsole", "Clear File"), self.clearHistory) subMenu.addAction( QCoreApplication.translate("PythonConsole", "Clear Session"), self.clearHistorySession) menu.addMenu(subMenu) menu.addSeparator() copyAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) pasteAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Paste"), self.paste, QKeySequence.Paste) copyAction.setEnabled(False) pasteAction.setEnabled(False) if self.hasSelectedText(): copyAction.setEnabled(True) if QApplication.clipboard().text(): pasteAction.setEnabled(True) menu.exec_(self.mapToGlobal(e.pos())) def mousePressEvent(self, e): """ Re-implemented to handle the mouse press event. e: the mouse press event (QMouseEvent) """ self.setFocus() if e.button() == Qt.MidButton: stringSel = QApplication.clipboard().text(QClipboard.Selection) if not self.is_cursor_on_last_line(): self.move_cursor_to_end() self.insertFromDropPaste(stringSel) e.accept() else: QsciScintilla.mousePressEvent(self, e) def paste(self): """ Method to display data from the clipboard. XXX: It should reimplement the virtual QScintilla.paste method, but it seems not used by QScintilla code. """ stringPaste = QApplication.clipboard().text() if self.is_cursor_on_last_line(): if self.hasSelectedText(): self.removeSelectedText() else: self.move_cursor_to_end() self.insertFromDropPaste(stringPaste) ## Drag and drop def dropEvent(self, e): if e.mimeData().hasText(): stringDrag = e.mimeData().text() self.insertFromDropPaste(stringDrag) self.setFocus() e.setDropAction(Qt.CopyAction) e.accept() else: QsciScintilla.dropEvent(self, e) def insertFromDropPaste(self, textDP): pasteList = textDP.splitlines() if pasteList: for line in pasteList[:-1]: cleanLine = line.replace(">>> ", "").replace("... ", "") self.insert(cleanLine) self.move_cursor_to_end() self.runCommand(self.currentCommand()) if pasteList[-1] != "": line = pasteList[-1] cleanLine = line.replace(">>> ", "").replace("... ", "") self.insert(cleanLine) self.move_cursor_to_end() def insertTextFromFile(self, listOpenFile): for line in listOpenFile[:-1]: self.append(line) self.move_cursor_to_end() self.SendScintilla(QsciScintilla.SCI_DELETEBACK) self.runCommand(self.currentCommand()) self.append(listOpenFile[-1]) self.move_cursor_to_end() self.SendScintilla(QsciScintilla.SCI_DELETEBACK) def entered(self): self.move_cursor_to_end() self.runCommand(self.currentCommand()) self.setFocus() self.move_cursor_to_end() def currentCommand(self): linenr, index = self.getCursorPosition() string = self.text() cmdLine = string[4:] cmd = cmdLine return cmd def runCommand(self, cmd): self.writeCMD(cmd) import webbrowser self.updateHistory(cmd) if cmd in ('_pyqgis', '_api'): if cmd == '_pyqgis': webbrowser.open("http://qgis.org/pyqgis-cookbook/") elif cmd == '_api': webbrowser.open("http://qgis.org/api/") more = False else: self.buffer.append(cmd) src = u"\n".join(self.buffer) more = self.runsource(src) if not more: self.buffer = [] ## prevents to commands with more lines to break the console ## in the case they have a eol different from '\n' self.setText('') self.move_cursor_to_end() self.displayPrompt(more) def write(self, txt): sys.stderr.write(txt) def writeCMD(self, txt): if len(txt) > 0: getCmdString = self.text() prompt = getCmdString[0:4] sys.stdout.write(prompt + txt + '\n') def runsource(self, source, filename='<input>', symbol='single'): hook = sys.excepthook try: def excepthook(etype, value, tb): self.write(u"".join(traceback.format_exception(etype, value, tb))) sys.excepthook = excepthook return super(ShellScintilla, self).runsource(source, filename, symbol) finally: sys.excepthook = hook
"First select a vector layer in the layers panel.") return if activeLayerId != aLayer.id(): activeLayerId = aLayer.id() myIt = None if not myIt: request = QgsFeatureRequest().setFlags( QgsFeatureRequest.NoGeometry).setNoAttributes() myIt = aLayer.getFeatures(request) feat = next(myIt, None) if feat: aLayer.selectByIds([feat.id()]) if aLayer.geometryType() == QgsWkbTypes.PointGeometry: iface.actionPanToSelected().trigger() # Pan to points else: iface.actionZoomToSelected().trigger() # Zoom to the rest else: iface.messageBar().pushInfo("Feature iterator", "We reached the last feature of this layer already.\n" + \ "If you want to restart press the Escape key.") shortcutEscape = QShortcut(QKeySequence(Qt.Key_Escape), iface.mapCanvas()) shortcutEscape.setContext(Qt.ApplicationShortcut) shortcutEscape.activated.connect(escapePressed) shortcutSpaceBar = QShortcut(QKeySequence(Qt.Key_Space), iface.mapCanvas()) shortcutSpaceBar.setContext(Qt.ApplicationShortcut) shortcutSpaceBar.activated.connect(spaceBarPressed)
class ScriptEdit(QsciScintilla): LEXER_PYTHON = 0 LEXER_R = 1 def __init__(self, parent=None): QsciScintilla.__init__(self, parent) self.lexer = None self.api = None self.lexerType = -1 self.setCommonOptions() self.initShortcuts() def setCommonOptions(self): # Enable non-ASCII characters self.setUtf8(True) # Default font font = QFont() font.setFamily('Courier') font.setFixedPitch(True) font.setPointSize(20) self.setFont(font) self.setMarginsFont(font) self.initLexer() self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setWrapMode(QsciScintilla.WrapWord) self.setWrapVisualFlags(QsciScintilla.WrapFlagByText, QsciScintilla.WrapFlagNone, 4) self.setSelectionForegroundColor(QColor('#2e3436')) self.setSelectionBackgroundColor(QColor('#babdb6')) # Show line numbers self.setMarginWidth(1, '000') self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor(QColor('#2e3436')) self.setMarginsBackgroundColor(QColor('#babdb6')) # Highlight current line self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor('#d3d7cf')) # Folding self.setFolding(QsciScintilla.BoxedTreeFoldStyle) self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf')) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(QColor('#eeeeec')) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) # Autocomletion self.setAutoCompletionThreshold(2) self.setAutoCompletionSource(QsciScintilla.AcsAPIs) self.setFonts(10) def setFonts(self, size): # Load font from Python console settings settings = QSettings() fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') fontSize = int(settings.value('pythonConsole/fontsize', size)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) self.defaultFont.setPointSize(fontSize) self.defaultFont.setStyleHint(QFont.TypeWriter) self.defaultFont.setStretch(QFont.SemiCondensed) self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0) self.defaultFont.setBold(False) self.boldFont = QFont(self.defaultFont) self.boldFont.setBold(True) self.italicFont = QFont(self.defaultFont) self.italicFont.setItalic(True) self.setFont(self.defaultFont) self.setMarginsFont(self.defaultFont) def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion self.shortcutAutocomplete = QShortcut( QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.shortcutAutocomplete.setContext(Qt.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) def autoComplete(self): self.autoCompleteFromAll() def setLexerType(self, lexerType): self.lexerType = lexerType self.initLexer() def initLexer(self): if self.lexerType == self.LEXER_PYTHON: self.lexer = QsciLexerPython() colorDefault = QColor('#2e3436') colorComment = QColor('#c00') colorCommentBlock = QColor('#3465a4') colorNumber = QColor('#4e9a06') colorType = QColor('#4e9a06') colorKeyword = QColor('#204a87') colorString = QColor('#ce5c00') self.lexer.setDefaultFont(self.defaultFont) self.lexer.setDefaultColor(colorDefault) self.lexer.setColor(colorComment, 1) self.lexer.setColor(colorNumber, 2) self.lexer.setColor(colorString, 3) self.lexer.setColor(colorString, 4) self.lexer.setColor(colorKeyword, 5) self.lexer.setColor(colorString, 6) self.lexer.setColor(colorString, 7) self.lexer.setColor(colorType, 8) self.lexer.setColor(colorCommentBlock, 12) self.lexer.setColor(colorString, 15) self.lexer.setFont(self.italicFont, 1) self.lexer.setFont(self.boldFont, 5) self.lexer.setFont(self.boldFont, 8) self.lexer.setFont(self.italicFont, 12) self.api = QsciAPIs(self.lexer) settings = QSettings() useDefaultAPI = bool( settings.value('pythonConsole/preloadAPI', True)) if useDefaultAPI: # Load QGIS API shipped with Python console self.api.loadPrepared( os.path.join(QgsApplication.pkgDataPath(), 'python', 'qsci_apis', 'pyqgis.pap')) else: # Load user-defined API files apiPaths = settings.value('pythonConsole/userAPI', []) for path in apiPaths: self.api.load(path) self.api.prepare() self.lexer.setAPIs(self.api) elif self.lexerType == self.LEXER_R: # R lexer self.lexer = LexerR() self.setLexer(self.lexer)
class ScriptEdit(QsciScintilla): LEXER_PYTHON = 0 LEXER_R = 1 def __init__(self, parent=None): QsciScintilla.__init__(self, parent) self.lexer = None self.api = None self.lexerType = -1 self.setCommonOptions() self.initShortcuts() def setCommonOptions(self): # Enable non-ASCII characters self.setUtf8(True) # Default font font = QFont() font.setFamily('Courier') font.setFixedPitch(True) font.setPointSize(20) self.setFont(font) self.setMarginsFont(font) self.initLexer() self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setWrapMode(QsciScintilla.WrapWord) self.setWrapVisualFlags(QsciScintilla.WrapFlagByText, QsciScintilla.WrapFlagNone, 4) self.setSelectionForegroundColor(QColor('#2e3436')) self.setSelectionBackgroundColor(QColor('#babdb6')) # Show line numbers self.setMarginWidth(1, '000') self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor(QColor('#2e3436')) self.setMarginsBackgroundColor(QColor('#babdb6')) # Highlight current line self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor('#d3d7cf')) # Folding self.setFolding(QsciScintilla.BoxedTreeFoldStyle) self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf')) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(QColor('#eeeeec')) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) # Autocomletion self.setAutoCompletionThreshold(2) self.setAutoCompletionSource(QsciScintilla.AcsAPIs) self.setFonts(10) def setFonts(self, size): # Load font from Python console settings settings = QSettings() fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') fontSize = int(settings.value('pythonConsole/fontsize', size)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) self.defaultFont.setPointSize(fontSize) self.defaultFont.setStyleHint(QFont.TypeWriter) self.defaultFont.setStretch(QFont.SemiCondensed) self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0) self.defaultFont.setBold(False) self.boldFont = QFont(self.defaultFont) self.boldFont.setBold(True) self.italicFont = QFont(self.defaultFont) self.italicFont.setItalic(True) self.setFont(self.defaultFont) self.setMarginsFont(self.defaultFont) def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.shortcutAutocomplete.setContext(Qt.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) def autoComplete(self): self.autoCompleteFromAll() def setLexerType(self, lexerType): self.lexerType = lexerType self.initLexer() def initLexer(self): if self.lexerType == self.LEXER_PYTHON: self.lexer = QsciLexerPython() colorDefault = QColor('#2e3436') colorComment = QColor('#c00') colorCommentBlock = QColor('#3465a4') colorNumber = QColor('#4e9a06') colorType = QColor('#4e9a06') colorKeyword = QColor('#204a87') colorString = QColor('#ce5c00') self.lexer.setDefaultFont(self.defaultFont) self.lexer.setDefaultColor(colorDefault) self.lexer.setColor(colorComment, 1) self.lexer.setColor(colorNumber, 2) self.lexer.setColor(colorString, 3) self.lexer.setColor(colorString, 4) self.lexer.setColor(colorKeyword, 5) self.lexer.setColor(colorString, 6) self.lexer.setColor(colorString, 7) self.lexer.setColor(colorType, 8) self.lexer.setColor(colorCommentBlock, 12) self.lexer.setColor(colorString, 15) self.lexer.setFont(self.italicFont, 1) self.lexer.setFont(self.boldFont, 5) self.lexer.setFont(self.boldFont, 8) self.lexer.setFont(self.italicFont, 12) self.api = QsciAPIs(self.lexer) settings = QSettings() useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI', True)) if useDefaultAPI: # Load QGIS API shipped with Python console self.api.loadPrepared( os.path.join(QgsApplication.pkgDataPath(), 'python', 'qsci_apis', 'pyqgis.pap')) else: # Load user-defined API files apiPaths = settings.value('pythonConsole/userAPI', []) for path in apiPaths: self.api.load(path) self.api.prepare() self.lexer.setAPIs(self.api) elif self.lexerType == self.LEXER_R: # R lexer self.lexer = LexerR() self.setLexer(self.lexer)
class ShellOutputScintilla(QgsPythonConsoleBase): def __init__(self, parent=None): super(ShellOutputScintilla, self).__init__(parent) self.parent = parent self.shell = self.parent.shell self.settings = QgsSettings() # Creates layout for message bar self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.layout.addItem(spacerItem, 1, 0, 1, 1) # messageBar instance self.infoBar = QgsMessageBar() sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.infoBar.setSizePolicy(sizePolicy) self.layout.addWidget(self.infoBar, 0, 0, 1, 1) sys.stdout = writeOut(self, sys.stdout) sys.stderr = writeOut(self, sys.stderr, "_traceback") self.insertInitText() self.refreshSettingsOutput() self.setReadOnly(True) self.setCaretWidth(0) # NO (blinking) caret in the output self.setMinimumHeight(120) self.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) self.runScut.setContext(Qt.WidgetShortcut) self.runScut.activated.connect(self.enteredSelected) # Reimplemented copy action to prevent paste prompt (>>>,...) in command view self.copyShortcut = QShortcut(QKeySequence.Copy, self) self.copyShortcut.setContext(Qt.WidgetWithChildrenShortcut) self.copyShortcut.activated.connect(self.copy) self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self) self.selectAllShortcut.setContext(Qt.WidgetWithChildrenShortcut) self.selectAllShortcut.activated.connect(self.selectAll) def insertInitText(self): txtInit = QCoreApplication.translate( "PythonConsole", "Python Console\n" "Use iface to access QGIS API interface or Type help(iface) for more info\n" "Security warning: typing commands from an untrusted source can harm your computer" ) # some translation string for the console header ends without '\n' # and the first command in console will be appended at the header text. # The following code add a '\n' at the end of the string if not present. if txtInit.endswith('\n'): self.setText(txtInit) else: self.setText(txtInit + '\n') def refreshSettingsOutput(self): # Set Python lexer self.setLexers() self.setSelectionForegroundColor( QColor( self.settings.value("pythonConsole/selectionForegroundColor", QColor(self.SELECTION_FOREGROUND_COLOR)))) self.setSelectionBackgroundColor( QColor( self.settings.value("pythonConsole/selectionBackgroundColor", QColor(self.SELECTION_BACKGROUND_COLOR)))) self.setMarginsForegroundColor( QColor( self.settings.value("pythonConsole/marginForegroundColor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setMarginsBackgroundColor( QColor( self.settings.value("pythonConsole/marginBackgroundColor", QColor(self.MARGIN_BACKGROUND_COLOR)))) caretLineColor = self.settings.value("pythonConsole/caretLineColor", QColor(self.CARET_LINE_COLOR)) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(self.CURSOR_COLOR)) self.setCaretLineBackgroundColor(caretLineColor) self.setCaretForegroundColor(cursorColor) def clearConsole(self): self.setText('') self.insertInitText() self.shell.setFocus() def contextMenuEvent(self, e): menu = QMenu(self) menu.addAction( self.iconHideTool, QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), self.hideToolBar) menu.addSeparator() showEditorAction = menu.addAction( self.iconShowEditor, QCoreApplication.translate("PythonConsole", "Show Editor"), self.showEditor) menu.addSeparator() runAction = menu.addAction( self.iconRun, QCoreApplication.translate("PythonConsole", "Enter Selected"), self.enteredSelected, QKeySequence(Qt.CTRL + Qt.Key_E)) clearAction = menu.addAction( self.iconClear, QCoreApplication.translate("PythonConsole", "Clear Console"), self.clearConsole) pyQGISHelpAction = menu.addAction( self.iconPyQGISHelp, QCoreApplication.translate("PythonConsole", "Search Selected in PyQGIS docs"), self.searchPyQGIS) menu.addSeparator() copyAction = menu.addAction( self.iconCopy, QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) selectAllAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Select All"), self.selectAll, QKeySequence.SelectAll) menu.addSeparator() menu.addAction(self.iconSettings, QCoreApplication.translate("PythonConsole", "Options…"), self.parent.openSettings) runAction.setEnabled(False) clearAction.setEnabled(False) copyAction.setEnabled(False) pyQGISHelpAction.setEnabled(False) selectAllAction.setEnabled(False) showEditorAction.setEnabled(True) if self.hasSelectedText(): runAction.setEnabled(True) copyAction.setEnabled(True) pyQGISHelpAction.setEnabled(True) if not self.text(3) == '': selectAllAction.setEnabled(True) clearAction.setEnabled(True) if self.parent.tabEditorWidget.isVisible(): showEditorAction.setEnabled(False) menu.exec_(self.mapToGlobal(e.pos())) def hideToolBar(self): tB = self.parent.toolBar tB.hide() if tB.isVisible() else tB.show() self.shell.setFocus() def showEditor(self): Ed = self.parent.splitterObj if not Ed.isVisible(): Ed.show() self.parent.showEditorButton.setChecked(True) self.shell.setFocus() def copy(self): """Copy text to clipboard... or keyboard interrupt""" if self.hasSelectedText(): text = self.selectedText() text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts QApplication.clipboard().setText(text) else: raise KeyboardInterrupt def enteredSelected(self): cmd = self.selectedText() self.shell.insertFromDropPaste(cmd) self.shell.entered() def keyPressEvent(self, e): # empty text indicates possible shortcut key sequence so stay in output txt = e.text() if len(txt) and txt >= " ": self.shell.append(txt) self.shell.move_cursor_to_end() self.shell.setFocus() e.ignore() else: # possible shortcut key sequence, accept it e.accept() def widgetMessageBar(self, iface, text): timeout = iface.messageTimeout() self.infoBar.pushMessage(text, Qgis.Info, timeout)
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle( QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QgsSettings() self.shell = ShellScintilla(self) self.setFocusProxy(self.shell) self.shellOut = ShellOutputScintilla(self) self.tabEditorWidget = EditorTabWidget(self) # ------------ UI ------------------------------- self.splitterEditor = QSplitter(self) self.splitterEditor.setOrientation(Qt.Horizontal) self.splitterEditor.setHandleWidth(6) self.splitterEditor.setChildrenCollapsible(True) self.shellOutWidget = QWidget(self) self.shellOutWidget.setLayout(QVBoxLayout()) self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0) self.shellOutWidget.layout().addWidget(self.shellOut) self.splitter = QSplitter(self.splitterEditor) self.splitter.setOrientation(Qt.Vertical) self.splitter.setHandleWidth(3) self.splitter.setChildrenCollapsible(False) self.splitter.addWidget(self.shellOutWidget) self.splitter.addWidget(self.shell) # self.splitterEditor.addWidget(self.tabEditorWidget) self.splitterObj = QSplitter(self.splitterEditor) self.splitterObj.setHandleWidth(3) self.splitterObj.setOrientation(Qt.Horizontal) # self.splitterObj.setSizes([0, 0]) # self.splitterObj.setStretchFactor(0, 1) self.widgetEditor = QWidget(self.splitterObj) self.widgetFind = QWidget(self) self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") self.listClassMethod.setHeaderLabels([objInspLabel, '']) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) # self.splitterEditor.addWidget(self.widgetEditor) # self.splitterObj.addWidget(self.listClassMethod) # self.splitterObj.addWidget(self.widgetEditor) # Hide side editor on start up self.splitterObj.hide() self.listClassMethod.hide() # Hide search widget on start up self.widgetFind.hide() icon_size = iface.iconSize( dockedToolbar=True) if iface else QSize(16, 16) sizes = self.splitter.sizes() self.splitter.setSizes(sizes) # ----------------Restore Settings------------------------------------ self.restoreSettingsConsole() # ------------------Toolbar Editor------------------------------------- # Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open Script...") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon( QgsApplication.getThemeIcon("console/iconOpenConsole.png")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate( "PythonConsole", "Open in External Editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) # Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon( QgsApplication.getThemeIcon("console/iconSaveConsole.png")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) # Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon( QgsApplication.getThemeIcon("console/iconSaveAsConsole.png")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) # Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon( QgsApplication.getThemeIcon("mActionEditCut.svg")) self.cutEditorButton.setMenuRole(QAction.PreferencesRole) self.cutEditorButton.setIconVisibleInMenu(True) self.cutEditorButton.setToolTip(cutEditorBt) self.cutEditorButton.setText(cutEditorBt) # Action Copy copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy") self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) self.copyEditorButton.setIcon( QgsApplication.getThemeIcon("mActionEditCopy.svg")) self.copyEditorButton.setMenuRole(QAction.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) self.copyEditorButton.setText(copyEditorBt) # Action Paste pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste") self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) self.pasteEditorButton.setIcon( QgsApplication.getThemeIcon("mActionEditPaste.svg")) self.pasteEditorButton.setMenuRole(QAction.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) self.pasteEditorButton.setText(pasteEditorBt) # Action Run Script (subprocess) runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run script") self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) self.runScriptEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconRunScriptConsole.png")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) # Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconCommentEditorConsole.png")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) # Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconUncommentEditorConsole.png")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) # Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector...") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled( self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon( QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) # Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon( QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) # ----------------Toolbar Console------------------------------------- # Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show Editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) # Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear Console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon( QgsApplication.getThemeIcon("console/iconClearConsole.png")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) # Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Options...") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon( QgsApplication.getThemeIcon("console/iconSettingsConsole.png")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run Command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon( QgsApplication.getThemeIcon("console/iconRunConsole.png")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help action helpBt = QCoreApplication.translate("PythonConsole", "Help...") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon( QgsApplication.getThemeIcon("console/iconHelpConsole.png")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(icon_size) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(icon_size) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # ------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) # Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...") self.lineEditFind.setPlaceholderText(placeHolderTxt) self.findNextButton = QToolButton() self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchNextEditorConsole.png")) self.findNextButton.setIconSize(QSize(24, 24)) self.findNextButton.setAutoRaise(True) self.findPrevButton = QToolButton() self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchPrevEditorConsole.png")) self.findPrevButton.setIconSize(QSize(24, 24)) self.findPrevButton.setAutoRaise(True) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1) self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1) self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1) self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1) self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1) self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.triggered.connect(self._toggleFind) self.objectListButton.toggled.connect(self.toggleObjectListWidget) self.commentEditorButton.triggered.connect(self.commentCode) self.uncommentEditorButton.triggered.connect(self.uncommentCode) self.runScriptEditorButton.triggered.connect(self.runScriptEditor) self.cutEditorButton.triggered.connect(self.cutEditor) self.copyEditorButton.triggered.connect(self.copyEditor) self.pasteEditorButton.triggered.connect(self.pasteEditor) self.showEditorButton.toggled.connect(self.toggleEditor) self.clearButton.triggered.connect(self.shellOut.clearConsole) self.optionsButton.triggered.connect(self.openSettings) self.runButton.triggered.connect(self.shell.entered) self.openFileButton.triggered.connect(self.openScriptFile) self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor) self.saveFileButton.triggered.connect(self.saveScriptFile) self.saveAsFileButton.triggered.connect(self.saveAsScriptFile) self.helpButton.triggered.connect(self.openHelp) self.listClassMethod.itemClicked.connect(self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findNext) self.findNextButton.clicked.connect(self._findNext) self.findPrevButton.clicked.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._openFind) self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor) self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut) self.findNextScut.activated.connect(self._findNext) self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor) self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut) self.findPreviousScut.activated.connect(self._findPrev) # Escape on editor hides the find bar self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._closeFind) def _toggleFind(self): self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget() def _openFind(self): self.tabEditorWidget.currentWidget().newEditor.openFindWidget() def _closeFind(self): self.tabEditorWidget.currentWidget().newEditor.closeFindWidget() def _findNext(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findPrev(self): self.tabEditorWidget.currentWidget().newEditor.findText(False) def _textFindChanged(self): if self.lineEditFind.text(): self.findNextButton.setEnabled(True) self.findPrevButton.setEnabled(True) self.tabEditorWidget.currentWidget().newEditor.findText( True, showMessage=False, findFirst=True) else: self.lineEditFind.setStyleSheet('') self.findNextButton.setEnabled(False) self.findPrevButton.setEnabled(False) def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget().newEditor if item.text(1) == 'syntaxError': check = tabEditor.syntaxCheck(fromContextMenu=False) if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) charPos = itemName.find(' ') if charPos != -1: objName = itemName[0:charPos] else: objName = itemName tabEditor.goToLine(objName, linenr) def toggleEditor(self, checked): self.splitterObj.show() if checked else self.splitterObj.hide() if not self.tabEditorWidget: self.tabEditorWidget.enableToolBarEditor(checked) self.tabEditorWidget.restoreTabsOrAddNew() def toggleObjectListWidget(self, checked): self.listClassMethod.show() if checked else self.listClassMethod.hide() def pasteEditor(self): self.tabEditorWidget.currentWidget().newEditor.paste() def cutEditor(self): self.tabEditorWidget.currentWidget().newEditor.cut() def copyEditor(self): self.tabEditorWidget.currentWidget().newEditor.copy() def runScriptEditor(self): self.tabEditorWidget.currentWidget().newEditor.runScriptCode() def commentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True) def uncommentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False) def openScriptFileExtEditor(self): tabWidget = self.tabEditorWidget.currentWidget() path = tabWidget.path import subprocess try: subprocess.Popen([os.environ['EDITOR'], path]) except KeyError: QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def openScriptFile(self): lastDirPath = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList, selected_filter = QFileDialog.getOpenFileNames( self, openFileTr, lastDirPath, "Script file (*.py)") if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): tabWidget = self.tabEditorWidget.widget(i) if tabWidget.path == pyFile: self.tabEditorWidget.setCurrentWidget(tabWidget) break else: tabName = QFileInfo(pyFile).fileName() self.tabEditorWidget.newTabEditor(tabName, pyFile) lastDirPath = QFileInfo(pyFile).path() self.settings.setValue("pythonConsole/lastDirPath", pyFile) self.updateTabListScript(pyFile, action='append') def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() except (IOError, OSError) as error: msgText = QCoreApplication.translate( 'PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format( tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) def saveAsScriptFile(self, index=None): tabWidget = self.tabEditorWidget.currentWidget() if not index: index = self.tabEditorWidget.currentIndex() if not tabWidget.path: fileName = self.tabEditorWidget.tabText(index) + '.py' folder = self.settings.value("pythonConsole/lastDirPath", QDir.home()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename, filter = QFileDialog.getSaveFileName(self, saveAsFileTr, pathFileName, "Script file (*.py)") if filename: try: tabWidget.save(filename) except (IOError, OSError) as error: msgText = QCoreApplication.translate( 'PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}' ).format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) if fileNone: tabWidget.path = None else: tabWidget.path = pathFileName return if not fileNone: self.updateTabListScript(pathFileName, action='remove') def openHelp(self): QgsHelp.openHelp("plugins/python_console.html") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState( self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState( self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState( self.settings.value("pythonConsole/splitterObj", QByteArray()))
def setup_shortcut(self, keysequence): shortcut = QShortcut(QKeySequence(keysequence), iface.mainWindow()) shortcut.setContext(Qt.ApplicationShortcut) return shortcut
class ShellScintilla(QgsPythonConsoleBase, code.InteractiveInterpreter): def __init__(self, parent=None): super(ShellScintilla, self).__init__(parent) code.InteractiveInterpreter.__init__(self, locals=None) self.parent = parent self.opening = ['(', '{', '[', "'", '"'] self.closing = [')', '}', ']', "'", '"'] self.settings = QgsSettings() self.new_input_line = True self.setCaretLineVisible(False) self.setMarginLineNumbers(0, False) # NO linenumbers for the input line self.buffer = [] self.displayPrompt(False) for line in _init_commands: self.runsource(line) self.history = [] self.softHistory = [''] self.softHistoryIndex = 0 # Read history command file self.readHistoryFile() self.historyDlg = HistoryDialog(self) # Brace matching: enable for a brace immediately before or after # the current position self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.refreshSettingsShell() # 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.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER) # Disable command key ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16 self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) # New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete self.newShortcutCSS = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Space), self) self.newShortcutCAS = QShortcut(QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self) self.newShortcutCSS.setContext(Qt.WidgetShortcut) self.newShortcutCAS.setContext(Qt.WidgetShortcut) self.newShortcutCAS.activated.connect(self.autoCompleteKeyBinding) self.newShortcutCSS.activated.connect(self.showHistory) def _setMinimumHeight(self): font = self.lexer.defaultFont(0) fm = QFontMetrics(font) self.setMinimumHeight(fm.height() + 10) def refreshSettingsShell(self): # Set Python lexer self.setLexers() threshold = self.settings.value("pythonConsole/autoCompThreshold", 2, type=int) self.setAutoCompletionThreshold(threshold) radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", 'fromAPI') autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True, type=bool) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.setAutoCompletionSource(self.AcsDocument) elif radioButtonSource == 'fromAPI': self.setAutoCompletionSource(self.AcsAPIs) elif radioButtonSource == 'fromDocAPI': self.setAutoCompletionSource(self.AcsAll) else: self.setAutoCompletionSource(self.AcsNone) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(self.CURSOR_COLOR)) self.setCaretForegroundColor(cursorColor) self.setSelectionForegroundColor(QColor( self.settings.value("pythonConsole/selectionForegroundColor", QColor(self.SELECTION_FOREGROUND_COLOR)))) self.setSelectionBackgroundColor(QColor( self.settings.value("pythonConsole/selectionBackgroundColor", QColor(self.SELECTION_BACKGROUND_COLOR)))) self.setMatchedBraceBackgroundColor(QColor(self.settings.value("pythonConsole/matchedBraceBackgroundColor", QColor(self.MATCHED_BRACE_BACKGROUND_COLOR)))) self.setMatchedBraceForegroundColor(QColor(self.settings.value("pythonConsole/matchedBraceForegroundColor", QColor(self.MATCHED_BRACE_FOREGROUND_COLOR)))) self.setMarginsBackgroundColor(QColor(self.settings.value("pythonConsole/paperBackgroundColor", QColor(self.BACKGROUND_COLOR)))) # Sets minimum height for input area based of font metric self._setMinimumHeight() def showHistory(self): if not self.historyDlg.isVisible(): self.historyDlg.show() self.historyDlg._reloadHistory() self.historyDlg.activateWindow() def autoCompleteKeyBinding(self): radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", 'fromAPI') autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True, type=bool) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.autoCompleteFromDocument() elif radioButtonSource == 'fromAPI': self.autoCompleteFromAPIs() elif radioButtonSource == 'fromDocAPI': self.autoCompleteFromAll() def commandConsole(self, commands): if not self.is_cursor_on_last_line(): self.move_cursor_to_end() for cmd in commands: self.setText(cmd) self.entered() self.move_cursor_to_end() self.setFocus() 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') self.SendScintilla(self.SCI_GETTEXT, len, bb) return bytes(bb)[:-1] def getTextLength(self): return self.SendScintilla(QsciScintilla.SCI_GETLENGTH) def get_end_pos(self): """Return (line, index) position of the last character""" line = self.lines() - 1 return line, len(self.text(line)) def is_cursor_at_start(self): """Return True if cursor is at the end of text""" cline, cindex = self.getCursorPosition() return cline == 0 and cindex == 0 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_start(self): """Move cursor to start of text""" self.setCursorPosition(0, 0) self.ensureCursorVisible() self.ensureLineVisible(0) self.displayPrompt(False) def move_cursor_to_end(self): """Move cursor to end of text""" line, index = self.get_end_pos() self.setCursorPosition(line, index) self.ensureCursorVisible() self.ensureLineVisible(line) self.displayPrompt(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 line, index = self.getCursorPosition() self.ensureCursorVisible() self.ensureLineVisible(line) def displayPrompt(self, more=False): self.SendScintilla(QsciScintilla.SCI_MARGINSETTEXT, 0, str.encode("..." if more else ">>>")) def syncSoftHistory(self): self.softHistory = self.history[:] self.softHistory.append('') self.softHistoryIndex = len(self.softHistory) - 1 def updateSoftHistory(self): self.softHistory[self.softHistoryIndex] = self.text() def updateHistory(self, command, skipSoftHistory=False): if isinstance(command, list): for line in command: self.history.append(line) elif not command == "": if len(self.history) <= 0 or \ command != self.history[-1]: self.history.append(command) if not skipSoftHistory: self.syncSoftHistory() def writeHistoryFile(self, fromCloseConsole=False): ok = False try: wH = codecs.open(_historyFile, 'w', encoding='utf-8') for s in self.history: wH.write(s + '\n') ok = True except: raise wH.close() if ok and not fromCloseConsole: msgText = QCoreApplication.translate('PythonConsole', 'History saved successfully.') self.parent.callWidgetMessageBar(msgText) def readHistoryFile(self): fileExist = QFile.exists(_historyFile) if fileExist: with codecs.open(_historyFile, 'r', encoding='utf-8') as rH: for line in rH: if line != "\n": l = line.rstrip('\n') self.updateHistory(l, True) self.syncSoftHistory() else: return def clearHistory(self, clearSession=False): if clearSession: self.history = [] self.syncSoftHistory() msgText = QCoreApplication.translate('PythonConsole', 'Session and file history cleared successfully.') self.parent.callWidgetMessageBar(msgText) return ok = False try: cH = codecs.open(_historyFile, 'w', encoding='utf-8') ok = True except: raise cH.close() if ok: msgText = QCoreApplication.translate('PythonConsole', 'History cleared successfully.') self.parent.callWidgetMessageBar(msgText) def clearHistorySession(self): self.clearHistory(True) def showPrevious(self): if self.softHistoryIndex < len(self.softHistory) - 1 and self.softHistory: self.softHistoryIndex += 1 self.setText(self.softHistory[self.softHistoryIndex]) self.move_cursor_to_end() # self.SendScintilla(QsciScintilla.SCI_DELETEBACK) def showNext(self): if self.softHistoryIndex > 0 and self.softHistory: self.softHistoryIndex -= 1 self.setText(self.softHistory[self.softHistoryIndex]) self.move_cursor_to_end() # self.SendScintilla(QsciScintilla.SCI_DELETEBACK) def keyPressEvent(self, e): # update the live history self.updateSoftHistory() startLine, startPos, endLine, endPos = self.getSelection() # handle invalid cursor position and multiline selections if startLine < endLine: # allow copying and selecting if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier): if e.key() == Qt.Key_C: # only catch and return from Ctrl-C here if there's a selection if self.hasSelectedText(): QsciScintilla.keyPressEvent(self, e) return elif e.key() == Qt.Key_A: QsciScintilla.keyPressEvent(self, e) return else: return # allow selection if e.modifiers() & Qt.ShiftModifier: if e.key() in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Home, Qt.Key_End): QsciScintilla.keyPressEvent(self, e) return # all other keystrokes get sent to the input line self.move_cursor_to_end() if e.modifiers() & ( Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_C and not self.hasSelectedText(): # keyboard interrupt sys.stdout.fire_keyboard_interrupt = True return line, index = self.getCursorPosition() cmd = self.text(line) hasSelectedText = self.hasSelectedText() if e.key() in (Qt.Key_Return, Qt.Key_Enter) and not self.isListActive(): self.entered() elif e.key() in (Qt.Key_Left, Qt.Key_Home): QsciScintilla.keyPressEvent(self, e) elif e.key() in (Qt.Key_Backspace, Qt.Key_Delete): QsciScintilla.keyPressEvent(self, e) self.recolor() elif (e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_V) or \ (e.modifiers() & Qt.ShiftModifier and e.key() == Qt.Key_Insert): self.paste() 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() # TODO: press event for auto-completion file directory else: t = e.text() self.autoCloseBracket = self.settings.value("pythonConsole/autoCloseBracket", False, type=bool) self.autoImport = self.settings.value("pythonConsole/autoInsertionImport", True, type=bool) # Close bracket automatically if t in self.opening and self.autoCloseBracket: i = self.opening.index(t) if self.hasSelectedText() and startPos != 0: selText = self.selectedText() self.removeSelectedText() self.insert(self.opening[i] + selText + self.closing[i]) self.setCursorPosition(endLine, endPos + 2) return elif t == '(' and (re.match(r'^[ \t]*def \w+$', cmd) or re.match(r'^[ \t]*class \w+$', cmd)): self.insert('):') else: self.insert(self.closing[i]) # FIXES #8392 (automatically removes the redundant char # when autoclosing brackets option is enabled) elif t in [')', ']', '}'] and self.autoCloseBracket: try: if cmd[index - 1] in self.opening and t == cmd[index]: self.setCursorPosition(line, index + 1) self.SendScintilla(QsciScintilla.SCI_DELETEBACK) except IndexError: pass elif t == ' ' and self.autoImport: ptrn = r'^[ \t]*from [\w.]+$' if re.match(ptrn, cmd): self.insert(' import') self.setCursorPosition(line, index + 7) QsciScintilla.keyPressEvent(self, e) if len(self.text(0)) == 0 or hasSelectedText: self.displayPrompt(False) def contextMenuEvent(self, e): menu = QMenu(self) subMenu = QMenu(menu) titleHistoryMenu = QCoreApplication.translate("PythonConsole", "Command History") subMenu.setTitle(titleHistoryMenu) subMenu.addAction( QCoreApplication.translate("PythonConsole", "Show"), self.showHistory, 'Ctrl+Shift+SPACE') subMenu.addAction( QCoreApplication.translate("PythonConsole", "Clear File"), self.clearHistory) subMenu.addAction( QCoreApplication.translate("PythonConsole", "Clear Session"), self.clearHistorySession) menu.addMenu(subMenu) menu.addSeparator() copyAction = menu.addAction( self.iconCopy, QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) pasteAction = menu.addAction( self.iconPaste, QCoreApplication.translate("PythonConsole", "Paste"), self.paste, QKeySequence.Paste) pyQGISHelpAction = menu.addAction(self.iconPyQGISHelp, QCoreApplication.translate("PythonConsole", "Search Selected in PyQGIS docs"), self.searchPyQGIS) copyAction.setEnabled(False) pasteAction.setEnabled(False) pyQGISHelpAction.setEnabled(False) if self.hasSelectedText(): copyAction.setEnabled(True) pyQGISHelpAction.setEnabled(True) if QApplication.clipboard().text(): pasteAction.setEnabled(True) menu.exec_(self.mapToGlobal(e.pos())) def mousePressEvent(self, e): """ Re-implemented to handle the mouse press event. e: the mouse press event (QMouseEvent) """ self.setFocus() if e.button() == Qt.MidButton: stringSel = QApplication.clipboard().text(QClipboard.Selection) if not self.is_cursor_on_last_line(): self.move_cursor_to_end() self.insertFromDropPaste(stringSel) e.accept() else: QsciScintilla.mousePressEvent(self, e) def paste(self): """ Method to display data from the clipboard. XXX: It should reimplement the virtual QScintilla.paste method, but it seems not used by QScintilla code. """ stringPaste = QApplication.clipboard().text() if self.is_cursor_on_last_line(): if self.hasSelectedText(): self.removeSelectedText() else: self.move_cursor_to_end() self.insertFromDropPaste(stringPaste) # Drag and drop def dropEvent(self, e): if e.mimeData().hasText(): stringDrag = e.mimeData().text() self.insertFromDropPaste(stringDrag) self.setFocus() e.setDropAction(Qt.CopyAction) e.accept() else: QsciScintilla.dropEvent(self, e) def insertFromDropPaste(self, textDP): pasteList = textDP.splitlines() if pasteList: for line in pasteList[:-1]: cleanLine = line.replace(">>> ", "").replace("... ", "") self.insert(cleanLine) self.move_cursor_to_end() self.runCommand(self.currentCommand()) if pasteList[-1] != "": line = pasteList[-1] cleanLine = line.replace(">>> ", "").replace("... ", "") curpos = self.getCursorPosition() self.insert(cleanLine) self.setCursorPosition(curpos[0], curpos[1] + len(cleanLine)) def insertTextFromFile(self, listOpenFile): for line in listOpenFile[:-1]: self.append(line) self.move_cursor_to_end() self.SendScintilla(QsciScintilla.SCI_DELETEBACK) self.runCommand(self.currentCommand()) self.append(listOpenFile[-1]) self.move_cursor_to_end() self.SendScintilla(QsciScintilla.SCI_DELETEBACK) def entered(self): self.move_cursor_to_end() self.runCommand(self.currentCommand()) self.setFocus() self.move_cursor_to_end() def currentCommand(self): string = self.text() cmd = string return cmd def runCommand(self, cmd): self.writeCMD(cmd) import webbrowser self.updateHistory(cmd) version = 'master' if 'master' in Qgis.QGIS_VERSION.lower() else re.findall(r'^\d.[0-9]*', Qgis.QGIS_VERSION)[0] if cmd in ('_pyqgis', '_api', '_cookbook'): if cmd == '_pyqgis': webbrowser.open("https://qgis.org/pyqgis/{}".format(version)) elif cmd == '_api': webbrowser.open("https://qgis.org/api/{}".format('' if version == 'master' else version)) elif cmd == '_cookbook': webbrowser.open("https://docs.qgis.org/{}/en/docs/pyqgis_developer_cookbook/".format( 'testing' if version == 'master' else version)) more = False else: self.buffer.append(cmd) src = "\n".join(self.buffer) more = self.runsource(src) if not more: self.buffer = [] # prevents to commands with more lines to break the console # in the case they have a eol different from '\n' self.setText('') self.move_cursor_to_end() self.displayPrompt(more) def write(self, txt): sys.stderr.write(txt) def writeCMD(self, txt): if sys.stdout: sys.stdout.fire_keyboard_interrupt = False if len(txt) > 0: getCmdString = self.text() sys.stdout.write('>>> ' + txt + '\n') def runsource(self, source, filename='<input>', symbol='single'): if sys.stdout: sys.stdout.fire_keyboard_interrupt = False hook = sys.excepthook try: def excepthook(etype, value, tb): self.write("".join(traceback.format_exception(etype, value, tb))) sys.excepthook = excepthook return super(ShellScintilla, self).runsource(source, filename, symbol) finally: sys.excepthook = hook
class ShellOutputScintilla(QsciScintilla): DEFAULT_COLOR = "#4d4d4c" KEYWORD_COLOR = "#8959a8" CLASS_COLOR = "#4271ae" METHOD_COLOR = "#4271ae" DECORATION_COLOR = "#3e999f" NUMBER_COLOR = "#c82829" COMMENT_COLOR = "#8e908c" COMMENT_BLOCK_COLOR = "#8e908c" BACKGROUND_COLOR = "#ffffff" CURSOR_COLOR = "#636363" CARET_LINE_COLOR = "#efefef" SINGLE_QUOTE_COLOR = "#718c00" DOUBLE_QUOTE_COLOR = "#718c00" TRIPLE_SINGLE_QUOTE_COLOR = "#eab700" TRIPLE_DOUBLE_QUOTE_COLOR = "#eab700" MARGIN_BACKGROUND_COLOR = "#efefef" MARGIN_FOREGROUND_COLOR = "#636363" SELECTION_BACKGROUND_COLOR = "#d7d7d7" SELECTION_FOREGROUND_COLOR = "#303030" MATCHED_BRACE_BACKGROUND_COLOR = "#b7f907" MATCHED_BRACE_FOREGROUND_COLOR = "#303030" def __init__(self, parent=None): super(ShellOutputScintilla, self).__init__(parent) self.parent = parent self.shell = self.parent.shell self.settings = QgsSettings() # Creates layout for message bar self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.layout.addItem(spacerItem, 1, 0, 1, 1) # messageBar instance self.infoBar = QgsMessageBar() sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.infoBar.setSizePolicy(sizePolicy) self.layout.addWidget(self.infoBar, 0, 0, 1, 1) # Enable non-ascii chars for editor self.setUtf8(True) sys.stdout = writeOut(self, sys.stdout) sys.stderr = writeOut(self, sys.stderr, "_traceback") self.insertInitText() self.refreshSettingsOutput() self.setReadOnly(True) # Set the default font font = QFontDatabase.systemFont(QFontDatabase.FixedFont) self.setFont(font) self.setMarginsFont(font) # Margin 0 is used for line numbers self.setMarginWidth(0, 0) self.setMarginWidth(1, 0) self.setMarginWidth(2, 0) self.setMarginsFont(font) self.setMarginWidth(1, "00000") self.setMarginLineNumbers(1, True) self.setCaretLineVisible(True) self.setCaretWidth(0) self.setMinimumHeight(120) self.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) self.runScut.setContext(Qt.WidgetShortcut) self.runScut.activated.connect(self.enteredSelected) # Reimplemented copy action to prevent paste prompt (>>>,...) in command view self.copyShortcut = QShortcut(QKeySequence.Copy, self) self.copyShortcut.setContext(Qt.WidgetWithChildrenShortcut) self.copyShortcut.activated.connect(self.copy) self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self) self.selectAllShortcut.setContext(Qt.WidgetWithChildrenShortcut) self.selectAllShortcut.activated.connect(self.selectAll) def insertInitText(self): txtInit = QCoreApplication.translate( "PythonConsole", "Python Console\n" "Use iface to access QGIS API interface or Type help(iface) for more info\n" "Security warning: typing commands from an untrusted source can lead to data loss and/or leak" ) # some translation string for the console header ends without '\n' # and the first command in console will be appended at the header text. # The following code add a '\n' at the end of the string if not present. if txtInit.endswith('\n'): self.setText(txtInit) else: self.setText(txtInit + '\n') def refreshSettingsOutput(self): # Set Python lexer self.setLexers() self.setSelectionForegroundColor( QColor( self.settings.value("pythonConsole/selectionForegroundColor", QColor(self.SELECTION_FOREGROUND_COLOR)))) self.setSelectionBackgroundColor( QColor( self.settings.value("pythonConsole/selectionBackgroundColor", QColor(self.SELECTION_BACKGROUND_COLOR)))) self.setMarginsForegroundColor( QColor( self.settings.value("pythonConsole/marginForegroundColor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setMarginsBackgroundColor( QColor( self.settings.value("pythonConsole/marginBackgroundColor", QColor(self.MARGIN_BACKGROUND_COLOR)))) caretLineColor = self.settings.value("pythonConsole/caretLineColor", QColor(self.CARET_LINE_COLOR)) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(self.CURSOR_COLOR)) self.setCaretLineBackgroundColor(caretLineColor) self.setCaretForegroundColor(cursorColor) def setLexers(self): self.lexer = QsciLexerPython() font = QFontDatabase.systemFont(QFontDatabase.FixedFont) loadFont = self.settings.value("pythonConsole/fontfamilytext") if loadFont: font.setFamily(loadFont) fontSize = self.settings.value("pythonConsole/fontsize", type=int) if fontSize: font.setPointSize(fontSize) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor( QColor( self.settings.value("pythonConsole/defaultFontColor", QColor(self.DEFAULT_COLOR)))) self.lexer.setColor( QColor( self.settings.value("pythonConsole/commentFontColor", QColor(self.COMMENT_COLOR))), 1) self.lexer.setColor( QColor( self.settings.value("pythonConsole/numberFontColor", QColor(self.NUMBER_COLOR))), 2) self.lexer.setColor( QColor( self.settings.value("pythonConsole/keywordFontColor", QColor(self.KEYWORD_COLOR))), 5) self.lexer.setColor( QColor( self.settings.value("pythonConsole/classFontColor", QColor(self.CLASS_COLOR))), 8) self.lexer.setColor( QColor( self.settings.value("pythonConsole/methodFontColor", QColor(self.METHOD_COLOR))), 9) self.lexer.setColor( QColor( self.settings.value("pythonConsole/decorFontColor", QColor(self.DECORATION_COLOR))), 15) self.lexer.setColor( QColor( self.settings.value("pythonConsole/commentBlockFontColor", QColor(self.COMMENT_BLOCK_COLOR))), 12) self.lexer.setColor( QColor( self.settings.value("pythonConsole/singleQuoteFontColor", QColor(self.SINGLE_QUOTE_COLOR))), 4) self.lexer.setColor( QColor( self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(self.DOUBLE_QUOTE_COLOR))), 3) self.lexer.setColor( QColor( self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(self.TRIPLE_SINGLE_QUOTE_COLOR))), 6) self.lexer.setColor( QColor( self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(self.TRIPLE_DOUBLE_QUOTE_COLOR))), 7) self.lexer.setColor( QColor( self.settings.value("pythonConsole/defaultFontColorEditor", QColor(self.DEFAULT_COLOR))), 13) self.lexer.setColor(QColor(Qt.red), 14) self.lexer.setFont(font, 1) self.lexer.setFont(font, 2) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) self.lexer.setFont(font, QsciLexerPython.UnclosedString) for style in range(0, 33): paperColor = QColor( self.settings.value("pythonConsole/paperBackgroundColor", QColor(self.BACKGROUND_COLOR))) self.lexer.setPaper(paperColor, style) self.setLexer(self.lexer) def clearConsole(self): self.setText('') self.insertInitText() self.shell.setFocus() def contextMenuEvent(self, e): menu = QMenu(self) iconRun = QgsApplication.getThemeIcon("console/mIconRunConsole.svg") iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.svg") iconHideTool = QgsApplication.getThemeIcon( "console/iconHideToolConsole.svg") iconSettings = QgsApplication.getThemeIcon( "console/iconSettingsConsole.svg") menu.addAction( iconHideTool, QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), self.hideToolBar) menu.addSeparator() showEditorAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Show Editor"), self.showEditor) menu.addSeparator() runAction = menu.addAction( iconRun, QCoreApplication.translate("PythonConsole", "Enter Selected"), self.enteredSelected, QKeySequence(Qt.CTRL + Qt.Key_E)) clearAction = menu.addAction( iconClear, QCoreApplication.translate("PythonConsole", "Clear Console"), self.clearConsole) menu.addSeparator() copyAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) selectAllAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Select All"), self.selectAll, QKeySequence.SelectAll) menu.addSeparator() menu.addAction(iconSettings, QCoreApplication.translate("PythonConsole", "Options…"), self.parent.openSettings) runAction.setEnabled(False) clearAction.setEnabled(False) copyAction.setEnabled(False) selectAllAction.setEnabled(False) showEditorAction.setEnabled(True) if self.hasSelectedText(): runAction.setEnabled(True) copyAction.setEnabled(True) if not self.text(3) == '': selectAllAction.setEnabled(True) clearAction.setEnabled(True) if self.parent.tabEditorWidget.isVisible(): showEditorAction.setEnabled(False) menu.exec_(self.mapToGlobal(e.pos())) def hideToolBar(self): tB = self.parent.toolBar tB.hide() if tB.isVisible() else tB.show() self.shell.setFocus() def showEditor(self): Ed = self.parent.splitterObj if not Ed.isVisible(): Ed.show() self.parent.showEditorButton.setChecked(True) self.shell.setFocus() def copy(self): """Copy text to clipboard... or keyboard interrupt""" if self.hasSelectedText(): text = self.selectedText() text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts QApplication.clipboard().setText(text) else: raise KeyboardInterrupt def enteredSelected(self): cmd = self.selectedText() self.shell.insertFromDropPaste(cmd) self.shell.entered() def keyPressEvent(self, e): # empty text indicates possible shortcut key sequence so stay in output txt = e.text() if len(txt) and txt >= " ": self.shell.append(txt) self.shell.move_cursor_to_end() self.shell.setFocus() e.ignore() else: # possible shortcut key sequence, accept it e.accept() def widgetMessageBar(self, iface, text): timeout = iface.messageTimeout() self.infoBar.pushMessage(text, Qgis.Info, timeout)
def initGui(self): for keyseq, slot in ( (Qt.CTRL + Qt.ALT + Qt.Key_K, self.__create_group), # (Qt.CTRL + Qt.ALT + Qt.Key_S, self.__select_next_group), (Qt.CTRL + Qt.ALT + Qt.Key_N, self.__next_section), (Qt.CTRL + Qt.ALT + Qt.Key_B, self.__previous_section), (Qt.CTRL + Qt.ALT + Qt.Key_J, self.__add_section_from_selection), ): short = QShortcut(QKeySequence(keyseq), self.__iface.mainWindow()) short.setContext(Qt.ApplicationShortcut) short.activated.connect(slot) self.__shortcuts.append(short) self.__menu = QMenu("Albion") self.__menu.aboutToShow.connect(self.__create_menu_entries) self.__iface.mainWindow().menuBar().addMenu(self.__menu) self.__toolbar = QToolBar("Albion") self.__iface.addToolBar(self.__toolbar) #self.__toolbar.addAction( # icon("log_strati.svg"), "stratigraphic log" #).triggered.connect(self.__log_strati_clicked) self.__toolbar.addWidget(self.__current_graph) self.__current_graph.currentIndexChanged[str].connect( self.__current_graph_changed ) self.__toolbar.addWidget(self.__current_section) self.__current_section.currentIndexChanged[str].connect( self.__current_section_changed ) self.__toolbar.addAction( icon("previous_line_big.svg"), "previous section (Ctrl+Alt+b)" ).triggered.connect(self.__previous_section) self.__toolbar.addAction( icon("previous_line.svg"), "previous sub section" ).triggered.connect(self.__previous_subsection) self.__toolbar.addAction( icon("next_line.svg"), "next sub section" ).triggered.connect(self.__next_subsection) self.__toolbar.addAction( icon("next_line_big.svg"), "next section (Ctrl+Alt+n)" ).triggered.connect(self.__next_section) self.__toolbar.addAction( icon("line_from_selected.svg"), "create temporary section" ).triggered.connect(self.__section_from_selection) self.__viewer3d = QDockWidget("3D") self.__viewer3d.setWidget(Viewer3d()) self.__iface.addDockWidget(Qt.LeftDockWidgetArea, self.__viewer3d) self.__iface.mainWindow().tabifyDockWidget( self.__iface.mainWindow().findChild(QDockWidget, "Layers"), self.__viewer3d ) self.__viewer3d_ctrl = QToolBar("3D controls") self.__viewer3d_ctrl.addWidget(ViewerControls(self.__viewer3d.widget())) self.__iface.addToolBar(self.__viewer3d_ctrl) QgsProject.instance().readProject.connect(self.__qgis__project__loaded) self.__qgis__project__loaded() # case of reload
class ShellScintilla(QsciScintilla, code.InteractiveInterpreter): def __init__(self, parent=None): super(ShellScintilla, self).__init__(parent) code.InteractiveInterpreter.__init__(self, locals=None) self.parent = parent self.opening = ['(', '{', '[', "'", '"'] self.closing = [')', '}', ']', "'", '"'] self.settings = QgsSettings() # Enable non-ascii chars for editor self.setUtf8(True) self.new_input_line = True self.setMarginWidth(0, 0) self.setMarginWidth(1, 0) self.setMarginWidth(2, 0) self.buffer = [] self.displayPrompt(False) for line in _init_commands: self.runsource(line) self.history = [] self.historyIndex = 0 # Read history command file self.readHistoryFile() self.historyDlg = HistoryDialog(self) # Brace matching: enable for a brace immediately before or after # the current position self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setMatchedBraceBackgroundColor(QColor("#b7f907")) # Current line visible with special background color self.setCaretWidth(2) self.refreshSettingsShell() # 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.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER) # Disable command key ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16 self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) # New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete self.newShortcutCSS = QShortcut( QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Space), self) self.newShortcutCAS = QShortcut( QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self) self.newShortcutCSS.setContext(Qt.WidgetShortcut) self.newShortcutCAS.setContext(Qt.WidgetShortcut) self.newShortcutCAS.activated.connect(self.autoCompleteKeyBinding) self.newShortcutCSS.activated.connect(self.showHistory) def _setMinimumHeight(self): font = self.lexer.defaultFont(0) fm = QFontMetrics(font) self.setMinimumHeight(fm.height() + 10) def refreshSettingsShell(self): # Set Python lexer self.setLexers() threshold = self.settings.value("pythonConsole/autoCompThreshold", 2, type=int) self.setAutoCompletionThreshold(threshold) radioButtonSource = self.settings.value( "pythonConsole/autoCompleteSource", 'fromAPI') autoCompEnabled = self.settings.value( "pythonConsole/autoCompleteEnabled", True, type=bool) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.setAutoCompletionSource(self.AcsDocument) elif radioButtonSource == 'fromAPI': self.setAutoCompletionSource(self.AcsAPIs) elif radioButtonSource == 'fromDocAPI': self.setAutoCompletionSource(self.AcsAll) else: self.setAutoCompletionSource(self.AcsNone) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(Qt.black)) self.setCaretForegroundColor(cursorColor) # Sets minimum height for input area based of font metric self._setMinimumHeight() def showHistory(self): if not self.historyDlg.isVisible(): self.historyDlg.show() self.historyDlg._reloadHistory() self.historyDlg.activateWindow() def autoCompleteKeyBinding(self): radioButtonSource = self.settings.value( "pythonConsole/autoCompleteSource", 'fromAPI') autoCompEnabled = self.settings.value( "pythonConsole/autoCompleteEnabled", True, type=bool) if autoCompEnabled: if radioButtonSource == 'fromDoc': self.autoCompleteFromDocument() elif radioButtonSource == 'fromAPI': self.autoCompleteFromAPIs() elif radioButtonSource == 'fromDocAPI': self.autoCompleteFromAll() def commandConsole(self, commands): if not self.is_cursor_on_last_line(): self.move_cursor_to_end() line, pos = self.getCursorPosition() selCmdLength = len(self.text(line)) self.setSelection(line, 4, line, selCmdLength) self.removeSelectedText() for cmd in commands: self.append(cmd) self.entered() self.move_cursor_to_end() self.setFocus() def setLexers(self): self.lexer = QsciLexerPython() font = QFontDatabase.systemFont(QFontDatabase.FixedFont) loadFont = self.settings.value("pythonConsole/fontfamilytext") if loadFont: font.setFamily(loadFont) fontSize = self.settings.value("pythonConsole/fontsize", type=int) if fontSize: font.setPointSize(fontSize) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor( QColor( self.settings.value("pythonConsole/defaultFontColor", QColor(Qt.black)))) self.lexer.setColor( QColor( self.settings.value("pythonConsole/commentFontColor", QColor(Qt.gray))), 1) self.lexer.setColor( QColor( self.settings.value("pythonConsole/keywordFontColor", QColor(Qt.darkGreen))), 5) self.lexer.setColor( QColor( self.settings.value("pythonConsole/classFontColor", QColor(Qt.blue))), 8) self.lexer.setColor( QColor( self.settings.value("pythonConsole/methodFontColor", QColor(Qt.darkGray))), 9) self.lexer.setColor( QColor( self.settings.value("pythonConsole/decorFontColor", QColor(Qt.darkBlue))), 15) self.lexer.setColor( QColor( self.settings.value("pythonConsole/commentBlockFontColor", QColor(Qt.gray))), 12) self.lexer.setColor( QColor( self.settings.value("pythonConsole/singleQuoteFontColor", QColor(Qt.blue))), 4) self.lexer.setColor( QColor( self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(Qt.blue))), 3) self.lexer.setColor( QColor( self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(Qt.blue))), 6) self.lexer.setColor( QColor( self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(Qt.blue))), 7) self.lexer.setFont(font, 1) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) for style in range(0, 33): paperColor = QColor( self.settings.value("pythonConsole/paperBackgroundColor", QColor(Qt.white))) self.lexer.setPaper(paperColor, style) self.api = QsciAPIs(self.lexer) checkBoxAPI = self.settings.value("pythonConsole/preloadAPI", True, type=bool) checkBoxPreparedAPI = self.settings.value( "pythonConsole/usePreparedAPIFile", False, type=bool) if checkBoxAPI: pap = os.path.join(QgsApplication.pkgDataPath(), "python", "qsci_apis", "pyqgis.pap") self.api.loadPrepared(pap) elif checkBoxPreparedAPI: self.api.loadPrepared( self.settings.value("pythonConsole/preparedAPIFile")) else: apiPath = self.settings.value("pythonConsole/userAPI", []) for i in range(0, len(apiPath)): self.api.load(apiPath[i]) self.api.prepare() self.lexer.setAPIs(self.api) self.setLexer(self.lexer) # TODO: show completion list for file and directory 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') self.SendScintilla(self.SCI_GETTEXT, len, bb) return bytes(bb)[:-1] def getTextLength(self): return self.SendScintilla(QsciScintilla.SCI_GETLENGTH) def get_end_pos(self): """Return (line, index) position of the last character""" line = self.lines() - 1 return (line, len(self.text(line))) 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() self.ensureLineVisible(line) 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 is_cursor_on_edition_zone(self): """ Return True if the cursor is in the edition zone """ cline, cindex = self.getCursorPosition() return cline == self.lines() - 1 and cindex >= 4 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 line, index = self.getCursorPosition() self.ensureCursorVisible() self.ensureLineVisible(line) def displayPrompt(self, more=False): self.append("... ") if more else self.append(">>> ") self.move_cursor_to_end() def updateHistory(self, command): if isinstance(command, list): for line in command: self.history.append(line) elif not command == "": if len(self.history) <= 0 or \ command != self.history[-1]: self.history.append(command) self.historyIndex = len(self.history) def writeHistoryFile(self, fromCloseConsole=False): ok = False try: wH = codecs.open(_historyFile, 'w', encoding='utf-8') for s in self.history: wH.write(s + '\n') ok = True except: raise wH.close() if ok and not fromCloseConsole: msgText = QCoreApplication.translate( 'PythonConsole', 'History saved successfully.') self.parent.callWidgetMessageBar(msgText) def readHistoryFile(self): fileExist = QFile.exists(_historyFile) if fileExist: with codecs.open(_historyFile, 'r', encoding='utf-8') as rH: for line in rH: if line != "\n": l = line.rstrip('\n') self.updateHistory(l) else: return def clearHistory(self, clearSession=False): if clearSession: self.history = [] msgText = QCoreApplication.translate( 'PythonConsole', 'Session and file history cleared successfully.') self.parent.callWidgetMessageBar(msgText) return ok = False try: cH = codecs.open(_historyFile, 'w', encoding='utf-8') ok = True except: raise cH.close() if ok: msgText = QCoreApplication.translate( 'PythonConsole', 'History cleared successfully.') self.parent.callWidgetMessageBar(msgText) def clearHistorySession(self): self.clearHistory(True) def showPrevious(self): if self.historyIndex < len(self.history) and self.history: line, pos = self.getCursorPosition() selCmdLength = len(self.text(line)) self.setSelection(line, 4, line, selCmdLength) 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 self.history: line, pos = self.getCursorPosition() selCmdLength = len(self.text(line)) self.setSelection(line, 4, line, selCmdLength) 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): startLine, startPos, endLine, endPos = self.getSelection() # handle invalid cursor position and multiline selections if not self.is_cursor_on_edition_zone() or startLine < endLine: # allow copying and selecting if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier): if e.key() == Qt.Key_C: # only catch and return from Ctrl-C here if there's a selection if self.hasSelectedText(): QsciScintilla.keyPressEvent(self, e) return elif e.key() == Qt.Key_A: QsciScintilla.keyPressEvent(self, e) return else: return # allow selection if e.modifiers() & Qt.ShiftModifier: if e.key() in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Home, Qt.Key_End): QsciScintilla.keyPressEvent(self, e) return # all other keystrokes get sent to the input line self.move_cursor_to_end() if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key( ) == Qt.Key_C and not self.hasSelectedText(): # keyboard interrupt sys.stdout.fire_keyboard_interrupt = True return line, index = self.getCursorPosition() cmd = self.text(line) if e.key() in (Qt.Key_Return, Qt.Key_Enter) and not self.isListActive(): self.entered() elif e.key() in (Qt.Key_Left, Qt.Key_Home): QsciScintilla.keyPressEvent(self, e) # check whether the cursor is moved out of the edition zone newline, newindex = self.getCursorPosition() if newline < line or newindex < 4: # fix selection and the cursor position if self.hasSelectedText(): self.setSelection(line, self.getSelection()[3], line, 4) else: self.setCursorPosition(line, 4) elif e.key() in (Qt.Key_Backspace, Qt.Key_Delete): QsciScintilla.keyPressEvent(self, e) # check whether the cursor is moved out of the edition zone _, newindex = self.getCursorPosition() if newindex < 4: # restore the prompt chars (if removed) and # fix the cursor position self.insert(cmd[:3 - newindex] + " ") self.setCursorPosition(line, 4) self.recolor() elif (e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_V) or \ (e.modifiers() & Qt.ShiftModifier and e.key() == Qt.Key_Insert): self.paste() 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() # TODO: press event for auto-completion file directory else: t = e.text() self.autoCloseBracket = self.settings.value( "pythonConsole/autoCloseBracket", False, type=bool) self.autoImport = self.settings.value( "pythonConsole/autoInsertionImport", True, type=bool) txt = cmd[:index].replace('>>> ', '').replace('... ', '') # Close bracket automatically if t in self.opening and self.autoCloseBracket: i = self.opening.index(t) if self.hasSelectedText() and startPos != 0: selText = self.selectedText() self.removeSelectedText() self.insert(self.opening[i] + selText + self.closing[i]) self.setCursorPosition(endLine, endPos + 2) return elif t == '(' and (re.match(r'^[ \t]*def \w+$', txt) or re.match(r'^[ \t]*class \w+$', txt)): self.insert('):') else: self.insert(self.closing[i]) # FIXES #8392 (automatically removes the redundant char # when autoclosing brackets option is enabled) elif t in [')', ']', '}'] and self.autoCloseBracket: txt = self.text(line) try: if txt[index - 1] in self.opening and t == txt[index]: self.setCursorPosition(line, index + 1) self.SendScintilla(QsciScintilla.SCI_DELETEBACK) except IndexError: pass elif t == ' ' and self.autoImport: ptrn = r'^[ \t]*from [\w.]+$' if re.match(ptrn, txt): self.insert(' import') self.setCursorPosition(line, index + 7) QsciScintilla.keyPressEvent(self, e) def contextMenuEvent(self, e): menu = QMenu(self) subMenu = QMenu(menu) titleHistoryMenu = QCoreApplication.translate("PythonConsole", "Command History") subMenu.setTitle(titleHistoryMenu) subMenu.addAction(QCoreApplication.translate("PythonConsole", "Show"), self.showHistory, 'Ctrl+Shift+SPACE') subMenu.addSeparator() subMenu.addAction(QCoreApplication.translate("PythonConsole", "Save"), self.writeHistoryFile) subMenu.addSeparator() subMenu.addAction( QCoreApplication.translate("PythonConsole", "Clear File"), self.clearHistory) subMenu.addAction( QCoreApplication.translate("PythonConsole", "Clear Session"), self.clearHistorySession) menu.addMenu(subMenu) menu.addSeparator() copyAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) pasteAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Paste"), self.paste, QKeySequence.Paste) copyAction.setEnabled(False) pasteAction.setEnabled(False) if self.hasSelectedText(): copyAction.setEnabled(True) if QApplication.clipboard().text(): pasteAction.setEnabled(True) menu.exec_(self.mapToGlobal(e.pos())) def mousePressEvent(self, e): """ Re-implemented to handle the mouse press event. e: the mouse press event (QMouseEvent) """ self.setFocus() if e.button() == Qt.MidButton: stringSel = QApplication.clipboard().text(QClipboard.Selection) if not self.is_cursor_on_last_line(): self.move_cursor_to_end() self.insertFromDropPaste(stringSel) e.accept() else: QsciScintilla.mousePressEvent(self, e) def paste(self): """ Method to display data from the clipboard. XXX: It should reimplement the virtual QScintilla.paste method, but it seems not used by QScintilla code. """ stringPaste = QApplication.clipboard().text() if self.is_cursor_on_last_line(): if self.hasSelectedText(): self.removeSelectedText() else: self.move_cursor_to_end() self.insertFromDropPaste(stringPaste) # Drag and drop def dropEvent(self, e): if e.mimeData().hasText(): stringDrag = e.mimeData().text() self.insertFromDropPaste(stringDrag) self.setFocus() e.setDropAction(Qt.CopyAction) e.accept() else: QsciScintilla.dropEvent(self, e) def insertFromDropPaste(self, textDP): pasteList = textDP.splitlines() if pasteList: for line in pasteList[:-1]: cleanLine = line.replace(">>> ", "").replace("... ", "") self.insert(cleanLine) self.move_cursor_to_end() self.runCommand(self.currentCommand()) if pasteList[-1] != "": line = pasteList[-1] cleanLine = line.replace(">>> ", "").replace("... ", "") self.insert(cleanLine) self.move_cursor_to_end() def insertTextFromFile(self, listOpenFile): for line in listOpenFile[:-1]: self.append(line) self.move_cursor_to_end() self.SendScintilla(QsciScintilla.SCI_DELETEBACK) self.runCommand(self.currentCommand()) self.append(listOpenFile[-1]) self.move_cursor_to_end() self.SendScintilla(QsciScintilla.SCI_DELETEBACK) def entered(self): self.move_cursor_to_end() self.runCommand(self.currentCommand()) self.setFocus() self.move_cursor_to_end() def currentCommand(self): linenr, index = self.getCursorPosition() string = self.text() cmdLine = string[4:] cmd = cmdLine return cmd def runCommand(self, cmd): self.writeCMD(cmd) import webbrowser self.updateHistory(cmd) if cmd in ('_pyqgis', '_api'): if cmd == '_pyqgis': webbrowser.open("http://qgis.org/pyqgis-cookbook/") elif cmd == '_api': webbrowser.open("http://qgis.org/api/") more = False else: self.buffer.append(cmd) src = u"\n".join(self.buffer) more = self.runsource(src) if not more: self.buffer = [] # prevents to commands with more lines to break the console # in the case they have a eol different from '\n' self.setText('') self.move_cursor_to_end() self.displayPrompt(more) def write(self, txt): sys.stderr.write(txt) def writeCMD(self, txt): if sys.stdout: sys.stdout.fire_keyboard_interrupt = False if len(txt) > 0: getCmdString = self.text() prompt = getCmdString[0:4] sys.stdout.write(prompt + txt + '\n') def runsource(self, source, filename='<input>', symbol='single'): if sys.stdout: sys.stdout.fire_keyboard_interrupt = False hook = sys.excepthook try: def excepthook(etype, value, tb): self.write(u"".join( traceback.format_exception(etype, value, tb))) sys.excepthook = excepthook return super(ShellScintilla, self).runsource(source, filename, symbol) finally: sys.excepthook = hook
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QgsSettings() self.shell = ShellScintilla(self) self.setFocusProxy(self.shell) self.shellOut = ShellOutputScintilla(self) self.tabEditorWidget = EditorTabWidget(self) # ------------ UI ------------------------------- self.splitterEditor = QSplitter(self) self.splitterEditor.setOrientation(Qt.Horizontal) self.splitterEditor.setHandleWidth(6) self.splitterEditor.setChildrenCollapsible(True) self.shellOutWidget = QWidget(self) self.shellOutWidget.setLayout(QVBoxLayout()) self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0) self.shellOutWidget.layout().addWidget(self.shellOut) self.splitter = QSplitter(self.splitterEditor) self.splitter.setOrientation(Qt.Vertical) self.splitter.setHandleWidth(3) self.splitter.setChildrenCollapsible(False) self.splitter.addWidget(self.shellOutWidget) self.splitter.addWidget(self.shell) # self.splitterEditor.addWidget(self.tabEditorWidget) self.splitterObj = QSplitter(self.splitterEditor) self.splitterObj.setHandleWidth(3) self.splitterObj.setOrientation(Qt.Horizontal) # self.splitterObj.setSizes([0, 0]) # self.splitterObj.setStretchFactor(0, 1) self.widgetEditor = QWidget(self.splitterObj) self.widgetFind = QWidget(self) self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") self.listClassMethod.setHeaderLabels([objInspLabel, '']) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) # self.splitterEditor.addWidget(self.widgetEditor) # self.splitterObj.addWidget(self.listClassMethod) # self.splitterObj.addWidget(self.widgetEditor) # Hide side editor on start up self.splitterObj.hide() self.listClassMethod.hide() # Hide search widget on start up self.widgetFind.hide() icon_size = iface.iconSize(dockedToolbar=True) if iface else QSize(16, 16) sizes = self.splitter.sizes() self.splitter.setSizes(sizes) # ----------------Restore Settings------------------------------------ self.restoreSettingsConsole() # ------------------Toolbar Editor------------------------------------- # Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open Script…") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.svg")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) # Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.svg")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) # Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As…") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveAsConsole.svg")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) # Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCut.svg")) self.cutEditorButton.setMenuRole(QAction.PreferencesRole) self.cutEditorButton.setIconVisibleInMenu(True) self.cutEditorButton.setToolTip(cutEditorBt) self.cutEditorButton.setText(cutEditorBt) # Action Copy copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy") self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) self.copyEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCopy.svg")) self.copyEditorButton.setMenuRole(QAction.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) self.copyEditorButton.setText(copyEditorBt) # Action Paste pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste") self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) self.pasteEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditPaste.svg")) self.pasteEditorButton.setMenuRole(QAction.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) self.pasteEditorButton.setText(pasteEditorBt) # Action Run Script (subprocess) runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run Script") self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) self.runScriptEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconRunScriptConsole.svg")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) # Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) # Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.svg")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) # Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector…") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled(self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) # Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) # ----------------Toolbar Console------------------------------------- # Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show Editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) # Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear Console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.svg")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) # Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Options…") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run Command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon(QgsApplication.getThemeIcon("console/mIconRunConsole.svg")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help action helpBt = QCoreApplication.translate("PythonConsole", "Help…") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.svg")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(icon_size) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(icon_size) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # ------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) # Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find…") self.lineEditFind.setPlaceholderText(placeHolderTxt) self.toolBarFindText = QToolBar() self.toolBarFindText.setIconSize(icon_size) self.findNextButton = QAction(self) self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.svg")) self.findPrevButton = QAction(self) self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.svg")) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.toolBarFindText.addWidget(self.lineEditFind) self.toolBarFindText.addAction(self.findPrevButton) self.toolBarFindText.addAction(self.findNextButton) self.toolBarFindText.addWidget(self.caseSensitive) self.toolBarFindText.addWidget(self.wholeWord) self.toolBarFindText.addWidget(self.wrapAround) self.layoutFind.addWidget(self.toolBarFindText, 0, 1, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.triggered.connect(self._toggleFind) self.objectListButton.toggled.connect(self.toggleObjectListWidget) self.commentEditorButton.triggered.connect(self.commentCode) self.uncommentEditorButton.triggered.connect(self.uncommentCode) self.runScriptEditorButton.triggered.connect(self.runScriptEditor) self.cutEditorButton.triggered.connect(self.cutEditor) self.copyEditorButton.triggered.connect(self.copyEditor) self.pasteEditorButton.triggered.connect(self.pasteEditor) self.showEditorButton.toggled.connect(self.toggleEditor) self.clearButton.triggered.connect(self.shellOut.clearConsole) self.optionsButton.triggered.connect(self.openSettings) self.runButton.triggered.connect(self.shell.entered) self.openFileButton.triggered.connect(self.openScriptFile) self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor) self.saveFileButton.triggered.connect(self.saveScriptFile) self.saveAsFileButton.triggered.connect(self.saveAsScriptFile) self.helpButton.triggered.connect(self.openHelp) self.listClassMethod.itemClicked.connect(self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findNext) self.findNextButton.triggered.connect(self._findNext) self.findPrevButton.triggered.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._openFind) self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor) self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut) self.findNextScut.activated.connect(self._findNext) self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor) self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut) self.findPreviousScut.activated.connect(self._findPrev) # Escape on editor hides the find bar self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._closeFind) def _toggleFind(self): self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget() def _openFind(self): self.tabEditorWidget.currentWidget().newEditor.openFindWidget() def _closeFind(self): self.tabEditorWidget.currentWidget().newEditor.closeFindWidget() def _findNext(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findPrev(self): self.tabEditorWidget.currentWidget().newEditor.findText(False) def _textFindChanged(self): if self.lineEditFind.text(): self.findNextButton.setEnabled(True) self.findPrevButton.setEnabled(True) self.tabEditorWidget.currentWidget().newEditor.findText(True, showMessage=False, findFirst=True) else: self.lineEditFind.setStyleSheet('') self.findNextButton.setEnabled(False) self.findPrevButton.setEnabled(False) def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget().newEditor if item.text(1) == 'syntaxError': check = tabEditor.syntaxCheck(fromContextMenu=False) if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) charPos = itemName.find(' ') if charPos != -1: objName = itemName[0:charPos] else: objName = itemName tabEditor.goToLine(objName, linenr) def toggleEditor(self, checked): self.splitterObj.show() if checked else self.splitterObj.hide() if not self.tabEditorWidget: self.tabEditorWidget.enableToolBarEditor(checked) self.tabEditorWidget.restoreTabsOrAddNew() def toggleObjectListWidget(self, checked): self.listClassMethod.show() if checked else self.listClassMethod.hide() def pasteEditor(self): self.tabEditorWidget.currentWidget().newEditor.paste() def cutEditor(self): self.tabEditorWidget.currentWidget().newEditor.cut() def copyEditor(self): self.tabEditorWidget.currentWidget().newEditor.copy() def runScriptEditor(self): self.tabEditorWidget.currentWidget().newEditor.runScriptCode() def commentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True) def uncommentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False) def openScriptFileExtEditor(self): tabWidget = self.tabEditorWidget.currentWidget() path = tabWidget.path import subprocess try: subprocess.Popen([os.environ['EDITOR'], path]) except KeyError: QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def openScriptFile(self): lastDirPath = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList, selected_filter = QFileDialog.getOpenFileNames( self, openFileTr, lastDirPath, "Script file (*.py)") if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): tabWidget = self.tabEditorWidget.widget(i) if tabWidget.path == pyFile: self.tabEditorWidget.setCurrentWidget(tabWidget) break else: tabName = QFileInfo(pyFile).fileName() self.tabEditorWidget.newTabEditor(tabName, pyFile) lastDirPath = QFileInfo(pyFile).path() self.settings.setValue("pythonConsole/lastDirPath", pyFile) self.updateTabListScript(pyFile, action='append') def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() except (IOError, OSError) as error: msgText = QCoreApplication.translate('PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) def saveAsScriptFile(self, index=None): tabWidget = self.tabEditorWidget.currentWidget() if not index: index = self.tabEditorWidget.currentIndex() if not tabWidget.path: fileName = self.tabEditorWidget.tabText(index) + '.py' folder = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename, filter = QFileDialog.getSaveFileName(self, saveAsFileTr, pathFileName, "Script file (*.py)") if filename: try: tabWidget.save(filename) except (IOError, OSError) as error: msgText = QCoreApplication.translate('PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) if fileNone: tabWidget.path = None else: tabWidget.path = pathFileName return if not fileNone: self.updateTabListScript(pathFileName, action='remove') def openHelp(self): QgsHelp.openHelp("plugins/python_console.html") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState(self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState(self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState(self.settings.value("pythonConsole/splitterObj", QByteArray()))
class ScriptEdit(QsciScintilla): DEFAULT_COLOR = "#4d4d4c" KEYWORD_COLOR = "#8959a8" CLASS_COLOR = "#4271ae" METHOD_COLOR = "#4271ae" DECORATION_COLOR = "#3e999f" NUMBER_COLOR = "#c82829" COMMENT_COLOR = "#8e908c" COMMENT_BLOCK_COLOR = "#8e908c" BACKGROUND_COLOR = "#ffffff" CURSOR_COLOR = "#636363" CARET_LINE_COLOR = "#efefef" SINGLE_QUOTE_COLOR = "#718c00" DOUBLE_QUOTE_COLOR = "#718c00" TRIPLE_SINGLE_QUOTE_COLOR = "#eab700" TRIPLE_DOUBLE_QUOTE_COLOR = "#eab700" MARGIN_BACKGROUND_COLOR = "#efefef" MARGIN_FOREGROUND_COLOR = "#636363" SELECTION_BACKGROUND_COLOR = "#d7d7d7" SELECTION_FOREGROUND_COLOR = "#303030" MATCHED_BRACE_BACKGROUND_COLOR = "#b7f907" MATCHED_BRACE_FOREGROUND_COLOR = "#303030" EDGE_COLOR = "#efefef" FOLD_COLOR = "#efefef" def __init__(self, parent=None): QsciScintilla.__init__(self, parent) self.lexer = None self.api = None self.setCommonOptions() self.initShortcuts() def setCommonOptions(self): # Enable non-ASCII characters self.setUtf8(True) settings = QgsSettings() # Default font font = QFontDatabase.systemFont(QFontDatabase.FixedFont) self.setFont(font) self.setMarginsFont(font) self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setMatchedBraceBackgroundColor( QColor( settings.value( "pythonConsole/matchedBraceBackgroundColorEditor", QColor(self.MATCHED_BRACE_BACKGROUND_COLOR)))) self.setMatchedBraceForegroundColor( QColor( settings.value( "pythonConsole/matchedBraceForegroundColorEditor", QColor(self.MATCHED_BRACE_FOREGROUND_COLOR)))) #self.setWrapMode(QsciScintilla.WrapWord) #self.setWrapVisualFlags(QsciScintilla.WrapFlagByText, # QsciScintilla.WrapFlagNone, 4) self.setSelectionForegroundColor( QColor( settings.value("pythonConsole/selectionForegroundColorEditor", QColor(self.SELECTION_FOREGROUND_COLOR)))) self.setSelectionBackgroundColor( QColor( settings.value("pythonConsole/selectionBackgroundColorEditor", QColor(self.SELECTION_BACKGROUND_COLOR)))) # Show line numbers fontmetrics = QFontMetrics(font) self.setMarginWidth(1, fontmetrics.width("0000") + 5) self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor( QColor( settings.value("pythonConsole/marginForegroundColorEditor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setMarginsBackgroundColor( QColor( settings.value("pythonConsole/marginBackgroundColorEditor", QColor(self.MARGIN_BACKGROUND_COLOR)))) self.setIndentationGuidesForegroundColor( QColor( settings.value("pythonConsole/marginForegroundColorEditor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setIndentationGuidesBackgroundColor( QColor( settings.value("pythonConsole/marginBackgroundColorEditor", QColor(self.MARGIN_BACKGROUND_COLOR)))) # Highlight current line caretLineColorEditor = settings.value( "pythonConsole/caretLineColorEditor", QColor(self.CARET_LINE_COLOR)) cursorColorEditor = settings.value("pythonConsole/cursorColorEditor", QColor(self.CURSOR_COLOR)) self.setCaretLineVisible(True) self.setCaretWidth(2) self.setCaretLineBackgroundColor(caretLineColorEditor) self.setCaretForegroundColor(cursorColorEditor) # Folding self.setFolding(QsciScintilla.PlainFoldStyle) foldColor = QColor( settings.value("pythonConsole/foldColorEditor", QColor(self.FOLD_COLOR))) self.setFoldMarginColors(foldColor, foldColor) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor( QColor( settings.value("pythonConsole/edgeColorEditor", QColor(self.EDGE_COLOR)))) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) self.setIndentationGuides(True) # Autocomletion self.setAutoCompletionThreshold(2) self.setAutoCompletionSource(QsciScintilla.AcsAPIs) self.setFonts(10) self.initLexer() def setFonts(self, size): # Load font from Python console settings settings = QgsSettings() fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') fontSize = int(settings.value('pythonConsole/fontsize', size)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) self.defaultFont.setPointSize(fontSize) self.defaultFont.setStyleHint(QFont.TypeWriter) self.defaultFont.setStretch(QFont.SemiCondensed) self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0) self.defaultFont.setBold(False) self.boldFont = QFont(self.defaultFont) self.boldFont.setBold(True) self.italicFont = QFont(self.defaultFont) self.italicFont.setItalic(True) self.setFont(self.defaultFont) self.setMarginsFont(self.defaultFont) def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion self.shortcutAutocomplete = QShortcut( QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.shortcutAutocomplete.setContext(Qt.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) def autoComplete(self): self.autoCompleteFromAll() def initLexer(self): settings = QgsSettings() self.lexer = QsciLexerPython() font = QFontDatabase.systemFont(QFontDatabase.FixedFont) loadFont = settings.value("pythonConsole/fontfamilytextEditor") if loadFont: font.setFamily(loadFont) fontSize = settings.value("pythonConsole/fontsizeEditor", type=int) if fontSize: font.setPointSize(fontSize) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor( QColor( settings.value("pythonConsole/defaultFontColorEditor", QColor(self.DEFAULT_COLOR)))) self.lexer.setColor( QColor( settings.value("pythonConsole/commentFontColorEditor", QColor(self.COMMENT_COLOR))), 1) self.lexer.setColor( QColor( settings.value("pythonConsole/numberFontColorEditor", QColor(self.NUMBER_COLOR))), 2) self.lexer.setColor( QColor( settings.value("pythonConsole/keywordFontColorEditor", QColor(self.KEYWORD_COLOR))), 5) self.lexer.setColor( QColor( settings.value("pythonConsole/classFontColorEditor", QColor(self.CLASS_COLOR))), 8) self.lexer.setColor( QColor( settings.value("pythonConsole/methodFontColorEditor", QColor(self.METHOD_COLOR))), 9) self.lexer.setColor( QColor( settings.value("pythonConsole/decorFontColorEditor", QColor(self.DECORATION_COLOR))), 15) self.lexer.setColor( QColor( settings.value("pythonConsole/commentBlockFontColorEditor", QColor(self.COMMENT_BLOCK_COLOR))), 12) self.lexer.setColor( QColor( settings.value("pythonConsole/singleQuoteFontColorEditor", QColor(self.SINGLE_QUOTE_COLOR))), 4) self.lexer.setColor( QColor( settings.value("pythonConsole/doubleQuoteFontColorEditor", QColor(self.DOUBLE_QUOTE_COLOR))), 3) self.lexer.setColor( QColor( settings.value( "pythonConsole/tripleSingleQuoteFontColorEditor", QColor(self.TRIPLE_SINGLE_QUOTE_COLOR))), 6) self.lexer.setColor( QColor( settings.value( "pythonConsole/tripleDoubleQuoteFontColorEditor", QColor(self.TRIPLE_DOUBLE_QUOTE_COLOR))), 7) self.lexer.setColor( QColor( settings.value("pythonConsole/defaultFontColorEditor", QColor(self.DEFAULT_COLOR))), 13) self.lexer.setFont(font, 1) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) self.lexer.setFont(font, QsciLexerPython.UnclosedString) for style in range(0, 33): paperColor = QColor( settings.value("pythonConsole/paperBackgroundColorEditor", QColor(self.BACKGROUND_COLOR))) self.lexer.setPaper(paperColor, style) self.api = QsciAPIs(self.lexer) useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI', True)) if useDefaultAPI: # Load QGIS API shipped with Python console self.api.loadPrepared( os.path.join(QgsApplication.pkgDataPath(), 'python', 'qsci_apis', 'pyqgis.pap')) else: # Load user-defined API files apiPaths = settings.value('pythonConsole/userAPI', []) for path in apiPaths: self.api.load(path) self.api.prepare() self.lexer.setAPIs(self.api) self.setLexer(self.lexer)
class ShellOutputScintilla(QsciScintilla): DEFAULT_COLOR = "#4d4d4c" KEYWORD_COLOR = "#8959a8" CLASS_COLOR = "#4271ae" METHOD_COLOR = "#4271ae" DECORATION_COLOR = "#3e999f" NUMBER_COLOR = "#c82829" COMMENT_COLOR = "#8e908c" COMMENT_BLOCK_COLOR = "#8e908c" BACKGROUND_COLOR = "#ffffff" CURSOR_COLOR = "#636363" CARET_LINE_COLOR = "#efefef" SINGLE_QUOTE_COLOR = "#718c00" DOUBLE_QUOTE_COLOR = "#718c00" TRIPLE_SINGLE_QUOTE_COLOR = "#eab700" TRIPLE_DOUBLE_QUOTE_COLOR = "#eab700" MARGIN_BACKGROUND_COLOR = "#efefef" MARGIN_FOREGROUND_COLOR = "#636363" SELECTION_BACKGROUND_COLOR = "#d7d7d7" SELECTION_FOREGROUND_COLOR = "#303030" MATCHED_BRACE_BACKGROUND_COLOR = "#b7f907" MATCHED_BRACE_FOREGROUND_COLOR = "#303030" def __init__(self, parent=None): super(ShellOutputScintilla, self).__init__(parent) self.parent = parent self.shell = self.parent.shell self.settings = QgsSettings() # Creates layout for message bar self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.layout.addItem(spacerItem, 1, 0, 1, 1) # messageBar instance self.infoBar = QgsMessageBar() sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.infoBar.setSizePolicy(sizePolicy) self.layout.addWidget(self.infoBar, 0, 0, 1, 1) # Enable non-ascii chars for editor self.setUtf8(True) sys.stdout = writeOut(self, sys.stdout) sys.stderr = writeOut(self, sys.stderr, "_traceback") self.insertInitText() self.refreshSettingsOutput() self.setReadOnly(True) # Set the default font font = QFontDatabase.systemFont(QFontDatabase.FixedFont) self.setFont(font) self.setMarginsFont(font) # Margin 0 is used for line numbers self.setMarginWidth(0, 0) self.setMarginWidth(1, 0) self.setMarginWidth(2, 0) #fm = QFontMetrics(font) self.setMarginsFont(font) self.setMarginWidth(1, "00000") self.setMarginLineNumbers(1, True) self.setCaretLineVisible(True) self.setCaretWidth(0) self.setMinimumHeight(120) self.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) self.runScut.setContext(Qt.WidgetShortcut) self.runScut.activated.connect(self.enteredSelected) # Reimplemented copy action to prevent paste prompt (>>>,...) in command view self.copyShortcut = QShortcut(QKeySequence.Copy, self) self.copyShortcut.activated.connect(self.copy) self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self) self.selectAllShortcut.activated.connect(self.selectAll) def insertInitText(self): txtInit = QCoreApplication.translate("PythonConsole", "Python Console\n" "Use iface to access QGIS API interface or Type help(iface) for more info\n" "Security warning: typing commands from an untrusted source can lead to data loss and/or leak") # some translation string for the console header ends without '\n' # and the first command in console will be appended at the header text. # The following code add a '\n' at the end of the string if not present. if txtInit.endswith('\n'): self.setText(txtInit) else: self.setText(txtInit + '\n') def refreshSettingsOutput(self): # Set Python lexer self.setLexers() self.setSelectionForegroundColor(QColor(self.settings.value("pythonConsole/selectionForegroundColor", QColor(self.SELECTION_FOREGROUND_COLOR)))) self.setSelectionBackgroundColor(QColor(self.settings.value("pythonConsole/selectionBackgroundColor", QColor(self.SELECTION_BACKGROUND_COLOR)))) self.setMarginsForegroundColor(QColor(self.settings.value("pythonConsole/marginForegroundColor", QColor(self.MARGIN_FOREGROUND_COLOR)))) self.setMarginsBackgroundColor(QColor(self.settings.value("pythonConsole/marginBackgroundColor", QColor(self.MARGIN_BACKGROUND_COLOR)))) caretLineColor = self.settings.value("pythonConsole/caretLineColor", QColor(self.CARET_LINE_COLOR)) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(self.CURSOR_COLOR)) self.setCaretLineBackgroundColor(caretLineColor) self.setCaretForegroundColor(cursorColor) def setLexers(self): self.lexer = QsciLexerPython() font = QFontDatabase.systemFont(QFontDatabase.FixedFont) loadFont = self.settings.value("pythonConsole/fontfamilytext") if loadFont: font.setFamily(loadFont) fontSize = self.settings.value("pythonConsole/fontsize", type=int) if fontSize: font.setPointSize(fontSize) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor(QColor(self.settings.value("pythonConsole/defaultFontColor", QColor(self.DEFAULT_COLOR)))) self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentFontColor", QColor(self.COMMENT_COLOR))), 1) self.lexer.setColor(QColor(self.settings.value("pythonConsole/numberFontColor", QColor(self.NUMBER_COLOR))), 2) self.lexer.setColor(QColor(self.settings.value("pythonConsole/keywordFontColor", QColor(self.KEYWORD_COLOR))), 5) self.lexer.setColor(QColor(self.settings.value("pythonConsole/classFontColor", QColor(self.CLASS_COLOR))), 8) self.lexer.setColor(QColor(self.settings.value("pythonConsole/methodFontColor", QColor(self.METHOD_COLOR))), 9) self.lexer.setColor(QColor(self.settings.value("pythonConsole/decorFontColor", QColor(self.DECORATION_COLOR))), 15) self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentBlockFontColor", QColor(self.COMMENT_BLOCK_COLOR))), 12) self.lexer.setColor(QColor(self.settings.value("pythonConsole/singleQuoteFontColor", QColor(self.SINGLE_QUOTE_COLOR))), 4) self.lexer.setColor(QColor(self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(self.DOUBLE_QUOTE_COLOR))), 3) self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(self.TRIPLE_SINGLE_QUOTE_COLOR))), 6) self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(self.TRIPLE_DOUBLE_QUOTE_COLOR))), 7) self.lexer.setColor(QColor(self.settings.value("pythonConsole/defaultFontColorEditor", QColor(self.DEFAULT_COLOR))), 13) self.lexer.setColor(QColor(Qt.red), 14) self.lexer.setFont(font, 1) self.lexer.setFont(font, 2) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) self.lexer.setFont(font, QsciLexerPython.UnclosedString) for style in range(0, 33): paperColor = QColor(self.settings.value("pythonConsole/paperBackgroundColor", QColor(self.BACKGROUND_COLOR))) self.lexer.setPaper(paperColor, style) self.setLexer(self.lexer) def clearConsole(self): self.setText('') self.insertInitText() self.shell.setFocus() def contextMenuEvent(self, e): menu = QMenu(self) iconRun = QgsApplication.getThemeIcon("console/mIconRunConsole.svg") iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.svg") iconHideTool = QgsApplication.getThemeIcon("console/iconHideToolConsole.svg") iconSettings = QgsApplication.getThemeIcon("console/iconSettingsConsole.svg") menu.addAction(iconHideTool, QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), self.hideToolBar) menu.addSeparator() showEditorAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Show Editor"), self.showEditor) menu.addSeparator() runAction = menu.addAction(iconRun, QCoreApplication.translate("PythonConsole", "Enter Selected"), self.enteredSelected, QKeySequence(Qt.CTRL + Qt.Key_E)) clearAction = menu.addAction(iconClear, QCoreApplication.translate("PythonConsole", "Clear Console"), self.clearConsole) menu.addSeparator() copyAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) selectAllAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Select All"), self.selectAll, QKeySequence.SelectAll) menu.addSeparator() menu.addAction(iconSettings, QCoreApplication.translate("PythonConsole", "Options…"), self.parent.openSettings) runAction.setEnabled(False) clearAction.setEnabled(False) copyAction.setEnabled(False) selectAllAction.setEnabled(False) showEditorAction.setEnabled(True) if self.hasSelectedText(): runAction.setEnabled(True) copyAction.setEnabled(True) if not self.text(3) == '': selectAllAction.setEnabled(True) clearAction.setEnabled(True) if self.parent.tabEditorWidget.isVisible(): showEditorAction.setEnabled(False) menu.exec_(self.mapToGlobal(e.pos())) def hideToolBar(self): tB = self.parent.toolBar tB.hide() if tB.isVisible() else tB.show() self.shell.setFocus() def showEditor(self): Ed = self.parent.splitterObj if not Ed.isVisible(): Ed.show() self.parent.showEditorButton.setChecked(True) self.shell.setFocus() def copy(self): """Copy text to clipboard... or keyboard interrupt""" if self.hasSelectedText(): text = self.selectedText() text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts QApplication.clipboard().setText(text) else: raise KeyboardInterrupt def enteredSelected(self): cmd = self.selectedText() self.shell.insertFromDropPaste(cmd) self.shell.entered() def keyPressEvent(self, e): # empty text indicates possible shortcut key sequence so stay in output txt = e.text() if len(txt) and txt >= " ": self.shell.append(txt) self.shell.move_cursor_to_end() self.shell.setFocus() e.ignore() else: # possible shortcut key sequence, accept it e.accept() def widgetMessageBar(self, iface, text): timeout = iface.messageTimeout() self.infoBar.pushMessage(text, Qgis.Info, timeout)
class SqlEdit(QsciScintilla): LEXER_PYTHON = 0 LEXER_R = 1 def __init__(self, parent=None): QsciScintilla.__init__(self, parent) self.mylexer = None self.api = None self.setCommonOptions() self.initShortcuts() def setCommonOptions(self): # Enable non-ASCII characters self.setUtf8(True) # Default font font = QFont() font.setFamily('Courier') font.setFixedPitch(True) font.setPointSize(10) self.setFont(font) self.setMarginsFont(font) self.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.setWrapMode(QsciScintilla.WrapWord) self.setWrapVisualFlags(QsciScintilla.WrapFlagByText, QsciScintilla.WrapFlagNone, 4) self.setSelectionForegroundColor(QColor('#2e3436')) self.setSelectionBackgroundColor(QColor('#babdb6')) # Show line numbers self.setMarginWidth(1, '000') self.setMarginLineNumbers(1, True) self.setMarginsForegroundColor(QColor('#2e3436')) self.setMarginsBackgroundColor(QColor('#babdb6')) # Highlight current line self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor('#d3d7cf')) # Folding self.setFolding(QsciScintilla.BoxedTreeFoldStyle) self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf')) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(QColor('#eeeeec')) # Indentation self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setTabWidth(4) # Autocomletion self.setAutoCompletionThreshold(2) self.setAutoCompletionSource(QsciScintilla.AcsAPIs) self.setAutoCompletionCaseSensitivity(False) # Load font from Python console settings settings = QgsSettings() fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') fontSize = int(settings.value('pythonConsole/fontsize', 10)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) self.defaultFont.setPointSize(fontSize) self.defaultFont.setStyleHint(QFont.TypeWriter) self.defaultFont.setStretch(QFont.SemiCondensed) self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0) self.defaultFont.setBold(False) self.boldFont = QFont(self.defaultFont) self.boldFont.setBold(True) self.italicFont = QFont(self.defaultFont) self.italicFont.setItalic(True) self.setFont(self.defaultFont) self.setMarginsFont(self.defaultFont) self.initLexer() def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion self.shortcutAutocomplete = QShortcut( QKeySequence(Qt.CTRL + Qt.Key_Space), self) self.shortcutAutocomplete.setContext(Qt.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) def autoComplete(self): self.autoCompleteFromAll() def initLexer(self): self.mylexer = QsciLexerSQL() colorDefault = QColor('#2e3436') colorComment = QColor('#c00') colorCommentBlock = QColor('#3465a4') colorNumber = QColor('#4e9a06') colorType = QColor('#4e9a06') colorKeyword = QColor('#204a87') colorString = QColor('#ce5c00') self.mylexer.setDefaultFont(self.defaultFont) self.mylexer.setDefaultColor(colorDefault) self.mylexer.setColor(colorComment, 1) self.mylexer.setColor(colorNumber, 2) self.mylexer.setColor(colorString, 3) self.mylexer.setColor(colorString, 4) self.mylexer.setColor(colorKeyword, 5) self.mylexer.setColor(colorString, 6) self.mylexer.setColor(colorString, 7) self.mylexer.setColor(colorType, 8) self.mylexer.setColor(colorCommentBlock, 12) self.mylexer.setColor(colorString, 15) self.mylexer.setFont(self.italicFont, 1) self.mylexer.setFont(self.boldFont, 5) self.mylexer.setFont(self.boldFont, 8) self.mylexer.setFont(self.italicFont, 12) self.setLexer(self.mylexer) def lexer(self): return self.mylexer def setMarginVisible(self, visible): pass
class ShellOutputScintilla(QsciScintilla): def __init__(self, parent=None): super(ShellOutputScintilla, self).__init__(parent) self.parent = parent self.shell = self.parent.shell self.settings = QSettings() # Creates layout for message bar self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.layout.addItem(spacerItem, 1, 0, 1, 1) # messageBar instance self.infoBar = QgsMessageBar() sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.infoBar.setSizePolicy(sizePolicy) self.layout.addWidget(self.infoBar, 0, 0, 1, 1) # Enable non-ascii chars for editor self.setUtf8(True) sys.stdout = writeOut(self, sys.stdout) sys.stderr = writeOut(self, sys.stderr, "_traceback") self.insertInitText() self.refreshSettingsOutput() 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 self.setMarginWidth(0, 0) self.setMarginWidth(1, 0) self.setMarginWidth(2, 0) #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.setCaretWidth(0) self.setMinimumHeight(120) self.setWrapMode(QsciScintilla.WrapCharacter) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) self.runScut.setContext(Qt.WidgetShortcut) self.runScut.activated.connect(self.enteredSelected) # Reimplemeted copy action to prevent paste prompt (>>>,...) in command view self.copyShortcut = QShortcut(QKeySequence.Copy, self) self.copyShortcut.activated.connect(self.copy) self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self) self.selectAllShortcut.activated.connect(self.selectAll) def insertInitText(self): txtInit = QCoreApplication.translate("PythonConsole", "Python Console \n" "Use iface to access QGIS API interface or Type help(iface) for more info") ## some translation string for the console header ends without '\n' ## and the first command in console will be appended at the header text. ## The following code add a '\n' at the end of the string if not present. if txtInit.endswith('\n'): self.setText(txtInit) else: self.setText(txtInit + '\n') def refreshSettingsOutput(self): # Set Python lexer self.setLexers() caretLineColor = self.settings.value("pythonConsole/caretLineColor", QColor("#fcf3ed")) cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(Qt.black)) self.setCaretLineBackgroundColor(caretLineColor) self.setCaretForegroundColor(cursorColor) def setLexers(self): self.lexer = QsciLexerPython() loadFont = self.settings.value("pythonConsole/fontfamilytext", "Monospace") fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int) font = QFont(loadFont) font.setFixedPitch(True) font.setPointSize(fontSize) font.setStyleHint(QFont.TypeWriter) font.setStretch(QFont.SemiCondensed) font.setLetterSpacing(QFont.PercentageSpacing, 87.0) font.setBold(False) self.lexer.setDefaultFont(font) self.lexer.setDefaultColor(QColor(self.settings.value("pythonConsole/defaultFontColor", QColor(Qt.black)))) self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentFontColor", QColor(Qt.gray))), 1) self.lexer.setColor(QColor(self.settings.value("pythonConsole/keywordFontColor", QColor(Qt.darkGreen))), 5) self.lexer.setColor(QColor(self.settings.value("pythonConsole/classFontColor", QColor(Qt.blue))), 8) self.lexer.setColor(QColor(self.settings.value("pythonConsole/methodFontColor", QColor(Qt.darkGray))), 9) self.lexer.setColor(QColor(self.settings.value("pythonConsole/decorFontColor", QColor(Qt.darkBlue))), 15) self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentBlockFontColor", QColor(Qt.gray))), 12) self.lexer.setColor(QColor(self.settings.value("pythonConsole/singleQuoteFontColor", QColor(Qt.blue))), 4) self.lexer.setColor(QColor(self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(Qt.blue))), 3) self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(Qt.blue))), 6) self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(Qt.blue))), 7) self.lexer.setColor(QColor(Qt.red), 14) self.lexer.setFont(font, 1) self.lexer.setFont(font, 2) self.lexer.setFont(font, 3) self.lexer.setFont(font, 4) for style in range(0, 33): paperColor = QColor(self.settings.value("pythonConsole/paperBackgroundColor", QColor(Qt.white))) self.lexer.setPaper(paperColor, style) self.setLexer(self.lexer) def clearConsole(self): self.setText('') self.insertInitText() self.shell.setFocus() def contextMenuEvent(self, e): menu = QMenu(self) iconRun = QgsApplication.getThemeIcon("console/iconRunConsole.png") iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.png") iconHideTool = QgsApplication.getThemeIcon("console/iconHideToolConsole.png") iconSettings = QgsApplication.getThemeIcon("console/iconSettingsConsole.png") menu.addAction(iconHideTool, QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), self.hideToolBar) menu.addSeparator() showEditorAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Show Editor"), self.showEditor) menu.addSeparator() runAction = menu.addAction(iconRun, QCoreApplication.translate("PythonConsole", "Enter Selected"), self.enteredSelected, QKeySequence(Qt.CTRL + Qt.Key_E)) clearAction = menu.addAction(iconClear, QCoreApplication.translate("PythonConsole", "Clear Console"), self.clearConsole) menu.addSeparator() copyAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Copy"), self.copy, QKeySequence.Copy) selectAllAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Select All"), self.selectAll, QKeySequence.SelectAll) menu.addSeparator() menu.addAction(iconSettings, QCoreApplication.translate("PythonConsole", "Options..."), self.parent.openSettings) runAction.setEnabled(False) clearAction.setEnabled(False) copyAction.setEnabled(False) selectAllAction.setEnabled(False) showEditorAction.setEnabled(True) if self.hasSelectedText(): runAction.setEnabled(True) copyAction.setEnabled(True) if not self.text(3) == '': selectAllAction.setEnabled(True) clearAction.setEnabled(True) if self.parent.tabEditorWidget.isVisible(): showEditorAction.setEnabled(False) menu.exec_(self.mapToGlobal(e.pos())) def hideToolBar(self): tB = self.parent.toolBar tB.hide() if tB.isVisible() else tB.show() self.shell.setFocus() def showEditor(self): Ed = self.parent.splitterObj if not Ed.isVisible(): Ed.show() self.parent.showEditorButton.setChecked(True) self.shell.setFocus() def copy(self): """Copy text to clipboard... or keyboard interrupt""" if self.hasSelectedText(): text = self.selectedText() text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts QApplication.clipboard().setText(text) else: raise KeyboardInterrupt def enteredSelected(self): cmd = self.selectedText() self.shell.insertFromDropPaste(cmd) self.shell.entered() def keyPressEvent(self, e): # empty text indicates possible shortcut key sequence so stay in output txt = e.text() if len(txt) and txt >= " ": self.shell.append(txt) self.shell.move_cursor_to_end() self.shell.setFocus() e.ignore() else: # possible shortcut key sequence, accept it e.accept() def widgetMessageBar(self, iface, text): timeout = iface.messageTimeout() self.infoBar.pushMessage(text, QgsMessageBar.INFO, timeout)