Esempio n. 1
0
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, command):
        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()
        if command == "processing":
            # import Processing class
            self.append('import processing')
        elif command == "qtCore":
            # import QtCore class
            self.append('from PyQt4.QtCore import *')
        elif command == "qtGui":
            # import QtGui class
            self.append('from PyQt4.QtGui import *')
        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(unicode(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')
        N = 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 \
            not 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:
            rH = codecs.open(_historyFile, 'r', encoding='utf-8')
            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 to copy and select
            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 = unicode(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)
        showHistoryAction = subMenu.addAction(
                            QCoreApplication.translate("PythonConsole", "Show"),
                            self.showHistory, 'Ctrl+Shift+SPACE')
        subMenu.addSeparator()
        saveHistoryAction = subMenu.addAction(
                            QCoreApplication.translate("PythonConsole", "Save"),
                            self.writeHistoryFile)
        subMenu.addSeparator()
        clearHistoryAction = subMenu.addAction(
                             QCoreApplication.translate("PythonConsole", "Clear File"),
                             self.clearHistory)
        clearSessHistoryAction = 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)
        action = 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 = unicode(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 = unicode(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:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = unicode(textDP).splitlines()
        if pasteList:
            for line in pasteList[:-1]:
                cleanLine = line.replace(">>> ", "").replace("... ", "")
                self.insert(unicode(cleanLine))
                self.move_cursor_to_end()
                self.runCommand(unicode(self.currentCommand()))
            if pasteList[-1] != "":
                line = pasteList[-1]
                cleanLine = line.replace(">>> ", "").replace("... ", "")
                self.insert(unicode(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(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def entered(self):
        self.move_cursor_to_end()
        self.runCommand( unicode(self.currentCommand()) )
        self.setFocus()
        self.move_cursor_to_end()

    def currentCommand(self):
        linenr, index = self.getCursorPosition()
        txtLength = len(self.text(linenr))
        string = self.text()
        cmdLine = string[4:]
        cmd = unicode(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, "<input>")
            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')
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.setLexers()
        self.setReadOnly(True)

        # Set the default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        # Margin 0 is used for line numbers
        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.setCaretLineBackgroundColor(QColor("#fcf3ed"))

        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 %1 on %2\n"
                                             "## Type help(iface) for more info and list of methods.\n").arg(sys.version,  socket.gethostname())
        initText = self.setText(txtInit)

    def refreshLexerProperties(self):
        self.setLexers()

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

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

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

        self.setLexer(self.lexer)

    def 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")
        hideToolBar = menu.addAction(iconHideTool,
                                     "Hide/Show Toolbar",
                                     self.hideToolBar)
        menu.addSeparator()
        showEditorAction = menu.addAction("Show Editor",
                                     self.showEditor)
        menu.addSeparator()
        runAction = menu.addAction(iconRun,
                                   "Enter Selected",
                                   self.enteredSelected,
                                   QKeySequence(Qt.CTRL + Qt.Key_E))
        clearAction = menu.addAction(iconClear,
                                     "Clear console",
                                     self.clearConsole)
        menu.addSeparator()
        copyAction = menu.addAction("Copy",
                                    self.copy,
                                    QKeySequence.Copy)
        menu.addSeparator()
        selectAllAction = menu.addAction("Select All",
                                         self.selectAll,
                                         QKeySequence.SelectAll)
        menu.addSeparator()
        settingsDialog = menu.addAction(iconSettings,
                                        "Settings",
                                        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)
        action = 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 = unicode(self.selectedText())
            text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    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 txt.length() 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)
Esempio n. 3
0
class PythonEdit(QsciScintilla, code.InteractiveInterpreter):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(PythonEdit, self).__init__(parent)
        code.InteractiveInterpreter.__init__(self, locals=None)

        self.parent = parent

        # 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 = QStringList()
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()

        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        #self.moveToMatchingBrace()
        #self.selectToMatchingBrace()

        # Current line visible with special background color
        #self.setCaretLineVisible(True)
        #self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
        self.setCaretWidth(2)

        # Set Python lexer
        self.setLexers()

        # Indentation
        #self.setAutoIndent(True)
        #self.setIndentationsUseTabs(False)
        #self.setIndentationWidth(4)
        #self.setTabIndents(True)
        #self.setBackspaceUnindents(True)
        #self.setTabWidth(4)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(self.AcsAPIs)

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        # not too small
        #self.setMinimumSize(500, 300)
        self.setMinimumHeight(20)

        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.newShortcutCS = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space),
                                       self)
        self.newShortcutCAS = QShortcut(
            QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self)
        self.newShortcutCS.activated.connect(self.autoComplete)
        self.newShortcutCAS.activated.connect(self.showHistory)
        self.connect(self, SIGNAL('userListActivated(int, const QString)'),
                     self.completion_list_selected)

    def showHistory(self):
        self.showUserList(1, QStringList(self.history))

    def autoComplete(self):
        self.autoCompleteFromAll()

    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCursorPosition()
        selCmdLenght = self.text(line).length()
        self.setSelection(line, 4, line, selCmdLenght)
        self.removeSelectedText()
        if command == "sextante":
            # import Sextante class
            self.append('import sextante')
        elif command == "qtCore":
            # import QtCore class
            self.append('from PyQt4.QtCore import *')
        elif command == "qtGui":
            # import QtGui class
            self.append('from PyQt4.QtGui import *')
        self.entered()
        self.move_cursor_to_end()
        self.setFocus()

    def setLexers(self):
        self.lexer = QsciLexerPython()
        settings = QSettings()
        loadFont = settings.value("pythonConsole/fontfamilytext",
                                  "Monospace").toString()
        fontSize = settings.value("pythonConsole/fontsize", 10).toInt()[0]

        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.setColor(Qt.red, 1)
        self.lexer.setColor(Qt.darkGreen, 5)
        self.lexer.setColor(Qt.darkBlue, 15)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        self.api = QsciAPIs(self.lexer)
        chekBoxAPI = settings.value("pythonConsole/preloadAPI", True).toBool()
        if chekBoxAPI:
            self.api.loadPrepared(QgsApplication.pkgDataPath() +
                                  "/python/qsci_apis/pyqgis_master.pap")
        else:
            apiPath = settings.value("pythonConsole/userAPI").toStringList()
            for i in range(0, len(apiPath)):
                self.api.load(QString(unicode(apiPath[i])))
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)

    ## TODO: show completion list for file and directory

    def completion_list_selected(self, id, txt):
        if id == 1:
            txt = unicode(txt)
            # get current cursor position
            line, pos = self.getCursorPosition()
            selCmdLength = self.text(line).length()
            # select typed text
            self.setSelection(line, 4, line, selCmdLength)
            self.removeSelectedText()
            self.insert(txt)

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode('utf-8')
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH) + 1
        bb = QByteArray(len, '0')
        N = self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

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

    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()

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

#    def on_new_line(self):
#        """On new input line"""
#        self.move_cursor_to_end()
#        self.new_input_line = False

    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1

    def 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 refreshLexerProperties(self):
        self.setLexers()

#    def check_selection(self):
#        """
#        Check if selected text is r/w,
#        otherwise remove read-only parts of selection
#        """
#        #if self.current_prompt_pos is None:
#            #self.move_cursor_to_end()
#            #return
#        line_from, index_from, line_to, index_to = self.getSelection()
#        pline, pindex = self.getCursorPosition()
#        if line_from < pline or \
#           (line_from == pline and index_from < pindex):
#            self.setSelection(pline, pindex, line_to, index_to)

    def displayPrompt(self, more=False):
        self.append("... ") if more else self.append(">>> ")
        self.move_cursor_to_end()

    def updateHistory(self, command):
        if isinstance(command, QStringList):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or \
            not command == self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)

    def writeHistoryFile(self):
        wH = open(_historyFile, 'w')
        for s in self.history:
            wH.write(s + '\n')
        wH.close()

    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = open(_historyFile, 'r')
            for line in rH:
                if line != "\n":
                    l = line.rstrip('\n')
                    self.updateHistory(l)
        else:
            return

    def clearHistoryFile(self):
        cH = open(_historyFile, 'w')
        cH.close()

    def showPrevious(self):
        if self.historyIndex < len(
                self.history) and not self.history.isEmpty():
            line, pos = self.getCursorPosition()
            selCmdLenght = self.text(line).length()
            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 not self.history.isEmpty():
            line, pos = self.getCursorPosition()
            selCmdLenght = self.text(line).length()
            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, _, endLine, _ = self.getSelection()

        # handle invalid cursor position and multiline selections
        if not self.is_cursor_on_edition_zone() or startLine < endLine:
            # allow to copy and select
            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:
            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:
            QsciScintilla.keyPressEvent(self, e)

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        copyAction = menu.addAction("Copy", self.copy, QKeySequence.Copy)
        pasteAction = menu.addAction("Paste", self.paste, QKeySequence.Paste)
        copyAction.setEnabled(False)
        pasteAction.setEnabled(False)
        if self.hasSelectedText():
            copyAction.setEnabled(True)
        if QApplication.clipboard().text() != "":
            pasteAction.setEnabled(True)
        action = 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 = unicode(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 = unicode(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.MoveAction)
            e.accept()
        else:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = textDP.split("\n")
        for line in pasteList[:-1]:
            line.replace(">>> ", "").replace("... ", "")
            self.insert(line)
            self.move_cursor_to_end()
            self.runCommand(unicode(self.currentCommand()))
        if pasteList[-1] != "":
            line = pasteList[-1]
            line.replace(">>> ", "").replace("... ", "")
            self.insert(unicode(line))
            self.move_cursor_to_end()

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

    def insertTextFromFile(self, listOpenFile):
        for line in listOpenFile[:-1]:
            self.append(line)
            self.move_cursor_to_end()
            self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def entered(self):
        self.move_cursor_to_end()
        self.runCommand(unicode(self.currentCommand()))
        self.setFocus()
        self.move_cursor_to_end()
        #self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)

    def currentCommand(self):
        linenr, index = self.getCursorPosition()
        #for i in range(0, linenr):
        txtLength = self.text(linenr).length()
        string = self.text()
        cmdLine = string.right(txtLength - 4)
        cmd = unicode(cmdLine)
        return cmd

    def runCommand(self, cmd):
        self.write_stdout(cmd)
        import webbrowser
        self.updateHistory(cmd)
        line, pos = self.getCursorPosition()
        selCmdLenght = self.text(line).length()
        self.setSelection(line, 0, line, selCmdLenght)
        self.removeSelectedText()
        if cmd in ('_save', '_clear', '_clearAll', '_pyqgis', '_api'):
            if cmd == '_save':
                self.writeHistoryFile()
                msgText = QCoreApplication.translate(
                    'PythonConsole', 'History saved successfully.')
            elif cmd == '_clear':
                self.clearHistoryFile()
                msgText = QCoreApplication.translate(
                    'PythonConsole', 'History cleared successfully.')
            elif cmd == '_clearAll':
                self.history = QStringList()
                self.clearHistoryFile()
                msgText = QCoreApplication.translate(
                    'PythonConsole',
                    'Session and file history cleared successfully.')
            elif cmd == '_pyqgis':
                webbrowser.open("http://www.qgis.org/pyqgis-cookbook/")
            elif cmd == '_api':
                webbrowser.open("http://www.qgis.org/api/")
            if msgText:
                self.parent.callWidgetMessageBar(msgText)

            self.displayPrompt(False)
        else:
            self.buffer.append(cmd)
            src = u"\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            if not more:
                self.buffer = []
            self.move_cursor_to_end()
            self.displayPrompt(more)

    def write(self, txt):
        sys.stderr.write(txt)

    def write_stdout(self, txt):
        if len(txt) > 0:
            getCmdString = self.text()
            prompt = getCmdString[0:4]
            sys.stdout.write(prompt + txt + '\n')
Esempio n. 4
0
class EditorOutput(QsciScintilla):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(EditorOutput,self).__init__(parent)
        self.parent = parent
        self.edit = self.parent.edit

        # 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.setLexers()
        self.setReadOnly(True)

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

        self.setMinimumHeight(120)

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

        ## Edge Mode
        #self.setEdgeMode(QsciScintilla.EdgeLine)
        #self.setEdgeColumn(80)
        #self.setEdgeColor(QColor("#FF0000"))

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        self.runShortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self)
        self.runShortcut.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",
                                             "## To access Quantum GIS environment from this console\n"
                                             "## use qgis.utils.iface object (instance of QgisInterface class). Read help for more info.\n\n")
        initText = self.setText(txtInit)

    def refreshLexerProperties(self):
        self.setLexers()

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

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

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

        self.setLexer(self.lexer)

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

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

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        iconRun = QIcon(":/images/console/iconRunConsole.png")
        iconPastebin = QIcon(":/images/console/iconCodepadConsole.png")
        iconClear = QIcon(":/images/console/iconClearConsole.png")
        iconHideTool = QIcon(":/images/console/iconHideToolConsole.png")
        hideToolBar = menu.addAction(iconHideTool,
                                     "Hide/Show Toolbar",
                                     self.hideToolBar)
        menu.addSeparator()
        runAction = menu.addAction(iconRun,
                                   "Enter Selected",
                                   self.enteredSelected,
                                   QKeySequence(Qt.CTRL + Qt.Key_E))
        clearAction = menu.addAction(iconClear,
                                     "Clear console",
                                     self.clearConsole)
        menu.addSeparator()
        copyAction = menu.addAction("Copy",
                                    self.copy,
                                    QKeySequence.Copy)
        pastebinAction = menu.addAction(iconPastebin,
                                        "Share on codepad",
                                        self.pastebin)
        menu.addSeparator()
        selectAllAction = menu.addAction("Select All",
                                         self.selectAll,
                                         QKeySequence.SelectAll)
        runAction.setEnabled(False)
        clearAction.setEnabled(False)
        copyAction.setEnabled(False)
        pastebinAction.setEnabled(False)
        selectAllAction.setEnabled(False)
        if self.hasSelectedText():
            runAction.setEnabled(True)
            copyAction.setEnabled(True)
            pastebinAction.setEnabled(True)
        if not self.text(3) == '':
            selectAllAction.setEnabled(True)
            clearAction.setEnabled(True)
        action = menu.exec_(self.mapToGlobal(e.pos()))

    def hideToolBar(self):
        tB = self.parent.toolBar
        tB.hide() if tB.isVisible() else tB.show()
        self.edit.setFocus()

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

    def enteredSelected(self):
        cmd = self.selectedText()
        self.edit.insertFromDropPaste(cmd)
        self.edit.entered()

    def keyPressEvent(self, e):
        # empty text indicates possible shortcut key sequence so stay in output
        txt = e.text()
        if txt.length() and txt >= " ":
            self.edit.append(txt)
            self.edit.move_cursor_to_end()
            self.edit.setFocus()
            e.ignore()
        else:
            # possible shortcut key sequence, accept it
            e.accept()

    def pastebin(self):
        import urllib2, urllib
        listText = self.selectedText().split('\n')
        getCmd = []
        for strLine in listText:
            if strLine != "":
            #if s[0:3] in (">>>", "..."):
                # filter for special command (_save,_clear) and comment
                if strLine[4] != "_" and strLine[:2] != "##":
                    strLine.replace(">>> ", "").replace("... ", "")
                    getCmd.append(unicode(strLine))
        pasteText= u"\n".join(getCmd)
        url = 'http://codepad.org'
        values = {'lang' : 'Python',
                  'code' : pasteText,
                  'submit':'Submit'}
        try:
            response = urllib2.urlopen(url, urllib.urlencode(values))
            url = response.read()
            for href in url.split("</a>"):
                if "Link:" in href:
                    ind=href.index('Link:')
                    found = href[ind+5:]
                    for i in found.split('">'):
                        if '<a href=' in i:
                             link = i.replace('<a href="',"").strip()
            if link:
                QApplication.clipboard().setText(link)
                print "## URL copied to clipboard ##"
        except urllib2.URLError, e:
            print "## Connection error ##"
            print "## " + str(e.args) + " ##"
Esempio n. 5
0
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)
        menu.addSeparator()
        selectAllAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Select All"),
            self.selectAll, QKeySequence.SelectAll)
        menu.addSeparator()
        menu.addAction(iconSettings,
                       QCoreApplication.translate("PythonConsole", "Settings"),
                       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 = unicode(self.selectedText())
            text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    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)
Esempio n. 6
0
class Editor(QsciScintilla):
    def __init__(self, parent=None):
        super(Editor,self).__init__(parent)
        self.parent = parent

        self.settings = QSettings()

        # Enable non-ascii chars for editor
        self.setUtf8(True)

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

        # Clickable margin 1 for showing markers
#        self.setMarginSensitivity(1, True)
#        self.connect(self,
#            SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'),
#            self.on_margin_clicked)
#        self.markerDefine(QsciScintilla.RightArrow,
#            self.ARROW_MARKER_NUM)
#        self.setMarkerBackgroundColor(QColor("#ee1111"),
#            self.ARROW_MARKER_NUM)

        self.setMinimumHeight(120)
        #self.setMinimumWidth(300)

        # Folding
        self.setFolding(QsciScintilla.PlainFoldStyle)
        self.setFoldMarginColors(QColor("#f4f4f4"),QColor("#f4f4f4"))
        #self.setWrapMode(QsciScintilla.WrapCharacter)

        ## Edge Mode
        self.setEdgeMode(QsciScintilla.EdgeLine)
        self.setEdgeColumn(80)
        self.setEdgeColor(QColor("#FF0000"))

        #self.setWrapMode(QsciScintilla.WrapCharacter)
        self.setWhitespaceVisibility(QsciScintilla.WsVisibleAfterIndent)
        #self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
        
        self.settingsEditor()
        
        # Annotations
        #self.setAnnotationDisplay(QsciScintilla.ANNOTATION_BOXED)
        
        # Indentation
        self.setAutoIndent(True)
        self.setIndentationsUseTabs(False)
        self.setIndentationWidth(4)
        self.setTabIndents(True)
        self.setBackspaceUnindents(True)
        self.setTabWidth(4)
        self.setIndentationGuides(True)

        ## 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.newShortcutCS = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self)
        self.newShortcutCS.setContext(Qt.WidgetShortcut)
        self.newShortcutCS.activated.connect(self.autoCompleteKeyBinding)
        self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self)
        self.runScut.setContext(Qt.WidgetShortcut)
        self.runScut.activated.connect(self.runSelectedCode)
        self.runScriptScut = QShortcut(QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_E), self)
        self.runScriptScut.setContext(Qt.WidgetShortcut)
        self.runScriptScut.activated.connect(self.runScriptCode)
        
        self.commentScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_3), self)
        self.commentScut.setContext(Qt.WidgetShortcut)
        self.commentScut.activated.connect(self.parent.pc.commentCode)
        self.uncommentScut = QShortcut(QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_3), self)
        self.uncommentScut.setContext(Qt.WidgetShortcut)
        self.uncommentScut.activated.connect(self.parent.pc.uncommentCode)
        
    def settingsEditor(self):
        # Set Python lexer
        self.setLexers()
        threshold = self.settings.value("pythonConsole/autoCompThresholdEditor", 2).toInt()[0]
        radioButtonSource = self.settings.value("pythonConsole/autoCompleteSourceEditor", 'fromAPI').toString()
        autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabledEditor", True).toBool()
        self.setAutoCompletionThreshold(threshold)
        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)

    def autoCompleteKeyBinding(self):
        radioButtonSource = self.settings.value("pythonConsole/autoCompleteSourceEditor").toString()
        autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabledEditor").toBool()
        if autoCompEnabled:
            if radioButtonSource == 'fromDoc':
                self.autoCompleteFromDocument()
            elif radioButtonSource == 'fromAPI':
                self.autoCompleteFromAPIs()
            elif radioButtonSource == 'fromDocAPI':
                self.autoCompleteFromAll()

    def on_margin_clicked(self, nmargin, nline, modifiers):
        # Toggle marker for the line the margin was clicked on
        if self.markersAtLine(nline) != 0:
            self.markerDelete(nline, self.ARROW_MARKER_NUM)
        else:
            self.markerAdd(nline, self.ARROW_MARKER_NUM)

    def setLexers(self):
        from qgis.core import QgsApplication

        self.lexer = QsciLexerPython()
        self.lexer.setIndentationWarning(QsciLexerPython.Inconsistent)
        self.lexer.setFoldComments(True)
        self.lexer.setFoldQuotes(True)

        loadFont = self.settings.value("pythonConsole/fontfamilytextEditor", "Monospace").toString()
        fontSize = self.settings.value("pythonConsole/fontsizeEditor", 10).toInt()[0]

        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.setColor(Qt.red, 1)
        self.lexer.setColor(Qt.darkGreen, 5)
        self.lexer.setColor(Qt.darkBlue, 15)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        self.api = QsciAPIs(self.lexer)
        chekBoxAPI = self.settings.value("pythonConsole/preloadAPI", True).toBool()
        if chekBoxAPI:
            self.api.loadPrepared( QgsApplication.pkgDataPath() + "/python/qsci_apis/pyqgis_master.pap" )
        else:
            apiPath = self.settings.value("pythonConsole/userAPI").toStringList()
            for i in range(0, len(apiPath)):
                self.api.load(QString(unicode(apiPath[i])))
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)

    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 get_end_pos(self):
        """Return (line, index) position of the last character"""
        line = self.lines() - 1
        return (line, self.text(line).length())

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        iconRun = QgsApplication.getThemeIcon("console/iconRunConsole.png")
        iconCodePad = QgsApplication.getThemeIcon("console/iconCodepadConsole.png")
        iconNewEditor = QgsApplication.getThemeIcon("console/iconTabEditorConsole.png")
        iconCommentEditor = QgsApplication.getThemeIcon("console/iconCommentEditorConsole.png")
        iconUncommentEditor = QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.png")
        iconSettings = QgsApplication.getThemeIcon("console/iconSettingsConsole.png")
        hideEditorAction = menu.addAction("Hide Editor",
                                     self.hideEditor)
        menu.addSeparator()
        newTabAction = menu.addAction(iconNewEditor,
                                    "New Tab",
                                    self.parent.newTab, 'Ctrl+T')
        closeTabAction = menu.addAction("Close Tab",
                                    self.parent.close, 'Ctrl+W')
        menu.addSeparator()
        runSelected = menu.addAction(iconRun,
                                   "Enter selected",
                                   self.runSelectedCode, 'Ctrl+E')
        runScript = menu.addAction(iconRun,
                                   "Run Script",
                                   self.runScriptCode, 'Shift+Ctrl+E')
        menu.addSeparator()
        undoAction = menu.addAction("Undo", self.undo, QKeySequence.Undo)
        redoAction = menu.addAction("Redo", self.redo, QKeySequence.Redo)
        menu.addSeparator()
        cutAction = menu.addAction("Cut",
                                    self.cut,
                                    QKeySequence.Cut)
        copyAction = menu.addAction("Copy",
                                    self.copy,
                                    QKeySequence.Copy)
        pasteAction = menu.addAction("Paste", self.paste, QKeySequence.Paste)
        menu.addSeparator()
        commentCodeAction = menu.addAction(iconCommentEditor, "Comment",
                                           self.parent.pc.commentCode, 'Ctrl+3')
        uncommentCodeAction = menu.addAction(iconUncommentEditor, "Uncomment", 
                                             self.parent.pc.uncommentCode, 
                                             'Shift+Ctrl+3')
        menu.addSeparator()
        codePadAction = menu.addAction(iconCodePad,
                                        "Share on codepad",
                                        self.codepad)
        menu.addSeparator()
        showCodeInspection = menu.addAction("Hide/Show Object list",
                                     self.objectListEditor)
        menu.addSeparator()
        selectAllAction = menu.addAction("Select All",
                                         self.selectAll,
                                         QKeySequence.SelectAll)
        menu.addSeparator()
        settingsDialog = menu.addAction(iconSettings,
                                        "Settings",
                                        self.parent.pc.openSettings)
        pasteAction.setEnabled(False)
        codePadAction.setEnabled(False)
        cutAction.setEnabled(False)
        runSelected.setEnabled(False)
        copyAction.setEnabled(False)
        selectAllAction.setEnabled(False)
        closeTabAction.setEnabled(False)
        undoAction.setEnabled(False)
        redoAction.setEnabled(False)
        if self.parent.mw.count() > 1:
            closeTabAction.setEnabled(True)
        if self.hasSelectedText():
            runSelected.setEnabled(True)
            copyAction.setEnabled(True)
            cutAction.setEnabled(True)
            codePadAction.setEnabled(True)
        if not self.text() == '':
            selectAllAction.setEnabled(True)
        if self.isUndoAvailable():
            undoAction.setEnabled(True)
        if self.isRedoAvailable():
            redoAction.setEnabled(True)
        if QApplication.clipboard().text() != "":
            pasteAction.setEnabled(True)
        action = menu.exec_(self.mapToGlobal(e.pos()))

    def objectListEditor(self):
        listObj = self.parent.pc.listClassMethod
        if listObj.isVisible():
             listObj.hide()
             self.parent.pc.objectListButton.setChecked(False)
        else:
            listObj.show()
            self.parent.pc.objectListButton.setChecked(True)
    
    def codepad(self):
        import urllib2, urllib
        listText = self.selectedText().split('\n')
        getCmd = []
        for strLine in listText:
            if strLine != "":
            #if s[0:3] in (">>>", "..."):
                # filter for special command (_save,_clear) and comment
                if strLine[4] != "_" and strLine[:2] != "##":
                    strLine.replace(">>> ", "").replace("... ", "")
                    getCmd.append(unicode(strLine))
        pasteText= u"\n".join(getCmd)
        url = 'http://codepad.org'
        values = {'lang' : 'Python',
                  'code' : pasteText,
                  'submit':'Submit'}
        try:
            response = urllib2.urlopen(url, urllib.urlencode(values))
            url = response.read()
            for href in url.split("</a>"):
                if "Link:" in href:
                    ind=href.index('Link:')
                    found = href[ind+5:]
                    for i in found.split('">'):
                        if '<a href=' in i:
                             link = i.replace('<a href="',"").strip()
            if link:
                QApplication.clipboard().setText(link)
                msgText = QCoreApplication.translate('PythonConsole', 'URL copied to clipboard.')
                self.parent.pc.callWidgetMessageBarEditor(msgText)
        except urllib2.URLError, e:
            msgText = QCoreApplication.translate('PythonConsole', 'Connection error: ')
            self.parent.pc.callWidgetMessageBarEditor(msgText + str(e.args))
Esempio n. 7
0
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.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 = QStringList()
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()

        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        # Current line visible with special background color
        self.setCaretWidth(2)

        self.settingsShell()

        # 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.setMinimumHeight(20)

        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)
        self.connect(self, SIGNAL("userListActivated(int, const QString)"), self.completion_list_selected)

    def settingsShell(self):
        # Set Python lexer
        self.setLexers()
        threshold = self.settings.value("pythonConsole/autoCompThreshold", 2).toInt()[0]
        self.setAutoCompletionThreshold(threshold)
        radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", "fromAPI").toString()
        autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True).toBool()
        self.setAutoCompletionThreshold(threshold)
        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)

    def showHistory(self):
        self.showUserList(1, QStringList(self.history))

    def autoCompleteKeyBinding(self):
        radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource").toString()
        autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled").toBool()
        if autoCompEnabled:
            if radioButtonSource == "fromDoc":
                self.autoCompleteFromDocument()
            elif radioButtonSource == "fromAPI":
                self.autoCompleteFromAPIs()
            elif radioButtonSource == "fromDocAPI":
                self.autoCompleteFromAll()

    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCursorPosition()
        selCmdLenght = self.text(line).length()
        self.setSelection(line, 4, line, selCmdLenght)
        self.removeSelectedText()
        if command == "sextante":
            # import Sextante class
            self.append("import sextante")
        elif command == "qtCore":
            # import QtCore class
            self.append("from PyQt4.QtCore import *")
        elif command == "qtGui":
            # import QtGui class
            self.append("from PyQt4.QtGui import *")
        self.entered()
        self.move_cursor_to_end()
        self.setFocus()

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

        loadFont = self.settings.value("pythonConsole/fontfamilytext", "Monospace").toString()
        fontSize = self.settings.value("pythonConsole/fontsize", 10).toInt()[0]

        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.setColor(Qt.red, 1)
        self.lexer.setColor(Qt.darkGreen, 5)
        self.lexer.setColor(Qt.darkBlue, 15)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        self.api = QsciAPIs(self.lexer)
        chekBoxAPI = self.settings.value("pythonConsole/preloadAPI", True).toBool()
        if chekBoxAPI:
            self.api.loadPrepared(QgsApplication.pkgDataPath() + "/python/qsci_apis/pyqgis_master.pap")
        else:
            apiPath = self.settings.value("pythonConsole/userAPI").toStringList()
            for i in range(0, len(apiPath)):
                self.api.load(QString(unicode(apiPath[i])))
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)

    ## TODO: show completion list for file and directory

    def completion_list_selected(self, id, txt):
        if id == 1:
            txt = unicode(txt)
            # get current cursor position
            line, pos = self.getCursorPosition()
            selCmdLength = self.text(line).length()
            # select typed text
            self.setSelection(line, 4, line, selCmdLength)
            self.removeSelectedText()
            self.insert(txt)

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode("utf-8")
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH) + 1
        bb = QByteArray(len, "0")
        N = self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

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

    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()

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

    # def on_new_line(self):
    # """On new input line"""
    # self.move_cursor_to_end()
    # self.new_input_line = False

    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1

    def 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, QStringList):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or not command == self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)

    def writeHistoryFile(self):
        wH = open(_historyFile, "w")
        for s in self.history:
            wH.write(s + "\n")
        wH.close()

    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = open(_historyFile, "r")
            for line in rH:
                if line != "\n":
                    l = line.rstrip("\n")
                    self.updateHistory(l)
        else:
            return

    def clearHistoryFile(self):
        cH = open(_historyFile, "w")
        cH.close()

    def showPrevious(self):
        if self.historyIndex < len(self.history) and not self.history.isEmpty():
            line, pos = self.getCursorPosition()
            selCmdLenght = self.text(line).length()
            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 not self.history.isEmpty():
            line, pos = self.getCursorPosition()
            selCmdLenght = self.text(line).length()
            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, _, endLine, _ = self.getSelection()

        # handle invalid cursor position and multiline selections
        if not self.is_cursor_on_edition_zone() or startLine < endLine:
            # allow to copy and select
            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:
            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:
            QsciScintilla.keyPressEvent(self, e)

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        copyAction = menu.addAction("Copy", self.copy, QKeySequence.Copy)
        pasteAction = menu.addAction("Paste", self.paste, QKeySequence.Paste)
        copyAction.setEnabled(False)
        pasteAction.setEnabled(False)
        if self.hasSelectedText():
            copyAction.setEnabled(True)
        if QApplication.clipboard().text() != "":
            pasteAction.setEnabled(True)
        action = 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 = unicode(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 = unicode(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:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = str(textDP).splitlines()
        for line in pasteList[:-1]:
            line.replace(">>> ", "").replace("... ", "")
            self.insert(unicode(line))
            self.move_cursor_to_end()
            self.runCommand(unicode(self.currentCommand()))
        if pasteList[-1] != "":
            line = pasteList[-1]
            line.replace(">>> ", "").replace("... ", "")
            self.insert(unicode(line))
            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(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def entered(self):
        self.move_cursor_to_end()
        self.runCommand(unicode(self.currentCommand()))
        self.setFocus()
        self.move_cursor_to_end()
        # self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)

    def currentCommand(self):
        linenr, index = self.getCursorPosition()
        # for i in range(0, linenr):
        txtLength = self.text(linenr).length()
        string = self.text()
        cmdLine = string.right(txtLength - 4)
        cmd = unicode(cmdLine)
        return cmd

    def runCommand(self, cmd):
        self.writeCMD(cmd)
        import webbrowser

        self.updateHistory(cmd)
        line, pos = self.getCursorPosition()
        selCmdLenght = self.text(line).length()
        self.setSelection(line, 0, line, selCmdLenght)
        self.removeSelectedText()
        if cmd in ("_save", "_clear", "_clearAll", "_pyqgis", "_api"):
            if cmd == "_save":
                self.writeHistoryFile()
                msgText = QCoreApplication.translate("PythonConsole", "History saved successfully.")
            elif cmd == "_clear":
                self.clearHistoryFile()
                msgText = QCoreApplication.translate("PythonConsole", "History cleared successfully.")
            elif cmd == "_clearAll":
                self.history = QStringList()
                self.clearHistoryFile()
                msgText = QCoreApplication.translate("PythonConsole", "Session and file history cleared successfully.")
            elif cmd == "_pyqgis":
                webbrowser.open("http://www.qgis.org/pyqgis-cookbook/")
            elif cmd == "_api":
                webbrowser.open("http://www.qgis.org/api/")
            if msgText:
                self.parent.callWidgetMessageBar(msgText)

            self.displayPrompt(False)
        else:
            self.buffer.append(cmd)
            src = u"\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            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")
Esempio n. 8
0
class PythonEdit(QsciScintilla, code.InteractiveInterpreter):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(PythonEdit,self).__init__(parent)
        code.InteractiveInterpreter.__init__(self, locals=None)
        
        # 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.insertInitText()
        self.displayPrompt(False)
        
        for line in _init_commands:
            self.runsource(line)
            
        self.history = QStringList()
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()
          
        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        #self.moveToMatchingBrace()
        #self.selectToMatchingBrace()
        
        # Current line visible with special background color
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
        self.setCaretWidth(2)
    
        # Set Python lexer
        # Set style for Python comments (style number 1) to a fixed-width
        # courier.
        self.setLexers()
               
        # Indentation
        #self.setAutoIndent(True)
        #self.setIndentationsUseTabs(False)
        #self.setIndentationWidth(4)
        #self.setTabIndents(True)
        #self.setBackspaceUnindents(True)
        #self.setTabWidth(4)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(self.AcsAPIs)

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
    
        # not too small
        #self.setMinimumSize(500, 300)
        self.setMinimumHeight(125)
        
        self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 1)
        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.newShortcutCS = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self)
        self.newShortcutCAS = QShortcut(QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self)
        self.newShortcutCS.activated.connect(self.autoComplete)
        self.newShortcutCAS.activated.connect(self.showHistory)
        self.connect(self, SIGNAL('userListActivated(int, const QString)'),
                     self.completion_list_selected)
    
    def showHistory(self):
        self.showUserList(1, QStringList(self.history))
    
    def autoComplete(self):
        self.autoCompleteFromAll()
       
    def clearConsole(self):
        """Clear the contents of the console."""
        self.SendScintilla(QsciScintilla.SCI_CLEARALL)
        #self.setText('')
        self.insertInitText()
        self.displayPrompt(False)
        self.setFocus()
        
    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCursorPosition()
        selCmdLenght = self.text(line).length()
        self.setSelection(line, 4, line, selCmdLenght)
        self.removeSelectedText()
        if command == "iface":
            """Import QgisInterface class"""
            self.append('from qgis.utils import iface')
            self.move_cursor_to_end()
        elif command == "sextante":
            """Import Sextante class"""
            self.append('from sextante.core.Sextante import Sextante')
            self.move_cursor_to_end()
        elif command == "cLayer":
            """Retrieve current Layer from map camvas"""
            self.append('cLayer = iface.mapCanvas().currentLayer()')
            self.move_cursor_to_end()
        elif command == "qtCore":
            """Import QtCore class"""
            self.append('from PyQt4.QtCore import *')
            self.move_cursor_to_end()
        elif command == "qtGui":
            """Import QtGui class"""
            self.append('from PyQt4.QtGui import *')
            self.move_cursor_to_end()
        self.setFocus()

    def setLexers(self):
        from qgis.core import QgsApplication
        
        self.lexer = QsciLexerPython()
        settings = QSettings()
        loadFont = settings.value("pythonConsole/fontfamilytext", "Monospace").toString()
        fontSize = settings.value("pythonConsole/fontsize", 10).toInt()[0]
        
        font = QFont(loadFont)
        font.setFixedPitch(True)
        font.setPointSize(fontSize)
        
        self.lexer.setDefaultFont(font)
        self.lexer.setColor(Qt.red, 1)
        self.lexer.setColor(Qt.darkGreen, 5)
        self.lexer.setColor(Qt.darkBlue, 15)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)
        
        self.api = QsciAPIs(self.lexer)
        chekBoxAPI = settings.value( "pythonConsole/preloadAPI" ).toBool()
        if chekBoxAPI:
            self.api.loadPrepared( QgsApplication.pkgDataPath() + "/python/qsci_apis/pyqgis_master.pap" )
        else:
            apiPath = settings.value("pythonConsole/userAPI").toStringList()
            for i in range(0, len(apiPath)):
                self.api.load(QString(unicode(apiPath[i])))        
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)
            
    ## TODO: show completion list for file and directory
    
    def completion_list_selected(self, id, txt):
        if id == 1:
            txt = unicode(txt)
            # get current cursor position 
            line, pos = self.getCursorPosition()
            selCmdLength = self.text(line).length()
            # select typed text
            self.setSelection(line, 4, line, selCmdLength)
            self.removeSelectedText()
            self.insert(txt)

    def insertInitText(self):
        #self.setLexers(False)
        txtInit = QCoreApplication.translate("PythonConsole",
                                             "## To access Quantum GIS environment from this console\n"
                                             "## use qgis.utils.iface object (instance of QgisInterface class). Read help for more info.\n\n")
        initText = self.setText(txtInit)

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode('utf-8')
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH)+1
        bb = QByteArray(len,'0')
        N = self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

    def get_end_pos(self):
        """Return (line, index) position of the last character"""
        line = self.lines() - 1
        return (line, self.text(line).length())
    
    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()
    
    def move_cursor_to_end(self):
        """Move cursor to end of text"""
        line, index = self.get_end_pos()
        self.setCursorPosition(line, index)
        self.ensureCursorVisible()
        self.ensureLineVisible(line)
        
#    def on_new_line(self):
#        """On new input line"""
#        self.move_cursor_to_end()
#        self.new_input_line = False
        
    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1

    def 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 refreshLexerProperties(self):
        self.setLexers()
        
#    def check_selection(self):
#        """
#        Check if selected text is r/w,
#        otherwise remove read-only parts of selection
#        """
#        #if self.current_prompt_pos is None:
#            #self.move_cursor_to_end()
#            #return
#        line_from, index_from, line_to, index_to = self.getSelection()
#        pline, pindex = self.getCursorPosition()
#        if line_from < pline or \
#           (line_from == pline and index_from < pindex):
#            self.setSelection(pline, pindex, line_to, index_to)

    def displayPrompt(self, more=False):
        self.append("... ") if more else self.append(">>> ")
        self.move_cursor_to_end()
        
    def updateHistory(self, command):
        if isinstance(command, QStringList):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or \
            not command == self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)
        
    def writeHistoryFile(self):
        wH = open(_historyFile, 'w')
        for s in self.history:
            wH.write(s + '\n')
        wH.close()
        
    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = open(_historyFile, 'r')
            for line in rH:
                if line != "\n":
                    l = line.rstrip('\n')
                    self.updateHistory(l)
        else:
            return
        
    def clearHistoryFile(self):
        cH = open(_historyFile, 'w')
        cH.close()
        
    def showPrevious(self):
        if self.historyIndex < len(self.history) and not self.history.isEmpty():
            line, pos = self.getCursorPosition()
            selCmdLenght = self.text(line).length()
            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 not self.history.isEmpty():
            line, pos = self.getCursorPosition()
            selCmdLenght = self.text(line).length()
            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, _, endLine, _ = self.getSelection()

        # handle invalid cursor position and multiline selections
        if not self.is_cursor_on_edition_zone() or startLine < endLine:
            # allow to copy and select
            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)

        elif e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and \
                e.key() == Qt.Key_V:
            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:
            QsciScintilla.keyPressEvent(self, e)
                
    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 = unicode(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 = unicode(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.MoveAction)
            e.accept()
        else:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP): 
        pasteList = textDP.split("\n")
        for line in pasteList[:-1]:
            self.insert(line)
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        if pasteList[-1] != "":
            self.insert(unicode(pasteList[-1]))
            self.move_cursor_to_end()

    def getTextFromEditor(self):
        text = self.text()
        textList = text.split("\n")
        return textList
    
    def insertTextFromFile(self, listOpenFile):
        for line in listOpenFile[:-1]:
            self.append(line)
            self.move_cursor_to_end()
            self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            
    def entered(self):
        self.move_cursor_to_end()
        self.runCommand( unicode(self.currentCommand()) )
        self.setFocus()
        self.move_cursor_to_end()
        #self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)
        
    def currentCommand(self):
        linenr, index = self.getCursorPosition()
        #for i in range(0, linenr):
        txtLength = self.text(linenr).length()
        string = self.text()
        cmdLine = string.right(txtLength - 4)
        cmd = unicode(cmdLine)
        return cmd

    def runCommand(self, cmd):
        import webbrowser
        self.updateHistory(cmd)
        self.SendScintilla(QsciScintilla.SCI_NEWLINE)
        if cmd in ('_save', '_clear', '_clearAll', '_pyqgis', '_api'):
            if cmd == '_save':
                self.writeHistoryFile()
                print QCoreApplication.translate("PythonConsole", 
                                                 "## History saved successfully ##")
            elif cmd == '_clear':
                self.clearHistoryFile()
                print QCoreApplication.translate("PythonConsole", 
                                                 "## History cleared successfully ##")
            elif cmd == '_clearAll':
                res = QMessageBox.question(self, "Python Console", 
                                           QCoreApplication.translate("PythonConsole", 
                                                                      "Are you sure you want to completely\n"
                                                                      "delete the command history ?"),
                                                                      QMessageBox.Yes | QMessageBox.No)
                if res == QMessageBox.No:
                    self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
                    return
                self.history = QStringList()
                self.clearHistoryFile()
                print QCoreApplication.translate("PythonConsole", 
                                                 "## History cleared successfully ##")
            elif cmd == '_pyqgis':
                webbrowser.open( "http://www.qgis.org/pyqgis-cookbook/" )
            elif cmd == '_api':
                webbrowser.open( "http://www.qgis.org/api/" )
                
            output = sys.stdout.get_and_clean_data()
            if output:
                self.append(output)
            self.displayPrompt(False)
        else:
            self.buffer.append(cmd)
            src = u"\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            if not more:
                self.buffer = []
            output = sys.stdout.get_and_clean_data()
            if output:
                self.append(output)
            self.move_cursor_to_end()
            self.displayPrompt(more)

    def write(self, txt):
        self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
        self.append(txt)
        self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
Esempio n. 9
0
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 = unicode(self.selectedText())
            text = text.replace('>>> ',
                                '').replace('... ',
                                            '').strip()  # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    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)
Esempio n. 10
0
class PythonEdit(QsciScintilla, code.InteractiveInterpreter):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(PythonEdit,self).__init__(parent)
        code.InteractiveInterpreter.__init__(self, locals=None)
        
        self.current_prompt_pos = None
        self.new_input_line = True 
        
        self.setMarginWidth(0, 0)
        self.setMarginWidth(1, 0)
        self.setMarginWidth(2, 0)
        
        self.buffer = []
        
        self.insertInitText()
        
        self.setCursorPosition(4,4)
        
        self.displayPrompt(False)
        
        for line in _init_commands:
            self.runsource(line)
            
        self.history = QStringList()
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()
          
        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        #self.moveToMatchingBrace()
        #self.selectToMatchingBrace()
        
        # Current line visible with special background color
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
        self.setCaretWidth(2)
    
        # Set Python lexer
        # Set style for Python comments (style number 1) to a fixed-width
        # courier.
        self.setLexers(True)
               
        # Indentation
        #self.setAutoIndent(True)
        #self.setIndentationsUseTabs(False)
        #self.setIndentationWidth(4)
        #self.setTabIndents(True)
        #self.setBackspaceUnindents(True)
        #self.setTabWidth(4)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(self.AcsAPIs)

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
    
        # not too small
        #self.setMinimumSize(500, 300)
        self.setMinimumHeight(125)
        
        self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 1)
        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.newShortcutCS = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space), self)
        self.newShortcutCAS = QShortcut(QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self)
        self.newShortcutCS.activated.connect(self.autoComplete)
        self.newShortcutCAS.activated.connect(self.showHistory)
        self.connect(self, SIGNAL('userListActivated(int, const QString)'),
                     self.completion_list_selected)
    
    def showHistory(self):
        self.showUserList(1, QStringList(self.history))
    
    def autoComplete(self):
        self.autoCompleteFromAll()
        
    def clearConsole(self):
        """Clear the contents of the console."""
        self.setText('')
        self.insertInitText()
        self.displayPrompt(False)
        self.setFocus()
        
    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCurLine()
        selCmd= self.text(line).length()
        self.setSelection(line, 4, line, selCmd)
        self.removeSelectedText()
        if command == "iface":
            """Import QgisInterface class"""
            self.append('from qgis.utils import iface')
            self.move_cursor_to_end()
        elif command == "sextante":
            """Import Sextante class"""
            self.append('from sextante.core.Sextante import Sextante')
            self.move_cursor_to_end()
        elif command == "cLayer":
            """Retrive current Layer from map camvas"""
            self.append('cLayer = iface.mapCanvas().currentLayer()')
            self.move_cursor_to_end()
        self.setFocus()
        
    def setLexers(self, lexer):
        if lexer:
            font = QFont()
            font.setFamily('Mono') ## Courier New
            font.setFixedPitch(True)
            ## check platform for font size
            if sys.platform.startswith('darwin'):
                font.setPointSize(13)
            else:
                font.setPointSize(10)
            self.setFont(font)
            self.setMarginsFont(font)
            self.lexer = QsciLexerPython()
            self.lexer.setDefaultFont(font)
            self.lexer.setColor(Qt.red, 1)
            self.lexer.setColor(Qt.darkGreen, 5)
            self.lexer.setColor(Qt.darkBlue, 15)
            self.lexer.setFont(font, 1)
            self.lexer.setFont(font, 3)
            self.lexer.setFont(font, 4)
            self.api = QsciAPIs(self.lexer)
            self.api.loadPrepared(QString(os.path.dirname(__file__) + "/api/pyqgis_master.pap"))
            self.setLexer(self.lexer)
            
    ## TODO: show completion list for file and directory
    
    def completion_list_selected(self, id, txt):
        if id == 1:
            txt = unicode(txt)
            # get current cursor position 
            line, pos = self.getCurLine()
            selCmd= self.text(line).length()
            # select typed text
            self.setSelection(line, 4, line, selCmd)
            self.removeSelectedText()
            self.insert(txt)

    def insertInitText(self):
        #self.setLexers(False)
        txtInit = QCoreApplication.translate("PythonConsole",
                                             "## To access Quantum GIS environment from this console\n"
                                             "## use qgis.utils.iface object (instance of QgisInterface class). Read help for more info.\n\n")
        initText = self.setText(txtInit)

    def getCurrentPos(self):
        """ Get the position (as an int) of the cursor. 
        getCursorPosition() returns a (linenr, index) tuple.
        """        
        return self.SendScintilla(self.SCI_GETCURRENTPOS)

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode('utf-8')
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH)+1
        bb = QByteArray(len,'0')
        N = self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

    def getLine(self, linenr):
        """ Get the bytes on the given line number. """
        len = self.SendScintilla(QsciScintilla.SCI_LINELENGTH)+1
        bb = QByteArray(len,'0')
        N = self.SendScintilla(QsciScintilla.SCI_GETLINE, len, bb)
        return bytes(bb)[:-1]
    
    def getCurLine(self):
        """ Get the current line (as a string) and the 
        position of the cursor in it. """
        linenr, index = self.getCursorPosition()
        #line = self.getLine(linenr) #.decode('utf-8')
        return linenr, index
    
    def get_end_pos(self):
        """Return (line, index) position of the last character"""
        line = self.lines() - 1
        return (line, self.text(line).length())
    
    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()
    
    def move_cursor_to_end(self):
        """Move cursor to end of text"""
        line, index = self.get_end_pos()
        self.setCursorPosition(line, index)
        self.ensureCursorVisible()
        
    def on_new_line(self):
        """On new input line"""
        self.move_cursor_to_end()
        self.current_prompt_pos = self.getCursorPosition()
        self.new_input_line = False
        
    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1
    
    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        self.current_prompt_pos = self.getCursorPosition()
        self.ensureCursorVisible()
        
    def check_selection(self):
        """
        Check if selected text is r/w,
        otherwise remove read-only parts of selection
        """
        #if self.current_prompt_pos is None:
            #self.move_cursor_to_end()
            #return
        line_from, index_from, line_to, index_to = self.getSelection()
        pline, pindex = self.getCursorPosition()
        if line_from < pline or \
           (line_from == pline and index_from < pindex):
            self.setSelection(pline, pindex, line_to, index_to)

    def displayPrompt(self, more=False):
        self.append("... ") if more else self.append(">>> ")
        self.move_cursor_to_end()
        
    def updateHistory(self, command):
        if isinstance(command, QStringList):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or \
            not command == self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)
        
    def writeHistoryFile(self):
        wH = open(_historyFile, 'w')
        for s in self.history:
            wH.write(s + '\n')
        wH.close()
        
    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = open(_historyFile, 'r')
            for line in rH:
                if line != "\n":
                    l = line.rstrip('\n')
                    self.updateHistory(l)
        else:
            return
        
    def clearHistoryFile(self):
        cH = open(_historyFile, 'w')
        cH.close()
        
    def showPrevious(self):
        if self.historyIndex < len(self.history) and not self.history.isEmpty():
            line, pos = self.getCurLine()
            selCmd= self.text(line).length()
            self.setSelection(line, 4, line, selCmd)
            self.removeSelectedText()
            self.historyIndex += 1
            if self.historyIndex == len(self.history):
                self.insert("")
                pass
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            
    def showNext(self):
        if  self.historyIndex > 0 and not self.history.isEmpty():
            line, pos = self.getCurLine()
            selCmd = self.text(line).length()
            self.setSelection(line, 4, line, selCmd)
            self.removeSelectedText()
            self.historyIndex -= 1
            if self.historyIndex == len(self.history):
                self.insert("")
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def keyPressEvent(self, e):  
        linenr, index = self.getCurLine()
        if not self.is_cursor_on_last_line() or index < 4:
            if e.modifiers() & Qt.ControlModifier or e.modifiers() & Qt.MetaModifier:
                if e.key() == Qt.Key_C or e.key() == Qt.Key_A:
                    QsciScintilla.keyPressEvent(self, e)
            else:
                # all other keystrokes get sent to the input line
                self.move_cursor_to_end()
                #pass
        else:
            if (e.key() == Qt.Key_Return or e.key() == Qt.Key_Enter) and not self.isListActive():
                    self.entered()
            elif e.modifiers() & Qt.ControlModifier:
                if e.key() == Qt.Key_V:
                    self.paste()
                elif e.key() == Qt.Key_C:
                    self.copy()
                elif e.key() == Qt.Key_X:
                    self.cut()  
                elif e.key() == Qt.Key_Left:
                    e.accept()
                    if e.modifiers() & Qt.ShiftModifier:
                        if index > 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(QsciScintilla.SCI_WORDLEFTEXTEND)
                            else:
                                self.SendScintilla(QsciScintilla.SCI_CHARLEFTEXTEND)
                    else:
                        if index > 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(QsciScintilla.SCI_WORDLEFT)
                            else:
                                self.SendScintilla(QsciScintilla.SCI_CHARLEFT)
                elif e.key() == Qt.Key_Right:
                    e.accept()
                    if e.modifiers() & Qt.ShiftModifier:
                        if index >= 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(QsciScintilla.SCI_WORDRIGHTEXTEND)
                            else:
                                self.SendScintilla(QsciScintilla.SCI_CHARRIGHTEXTEND)
                    else:
                        if index >= 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(QsciScintilla.SCI_WORDRIGHT)
                            else:
                                self.SendScintilla(QsciScintilla.SCI_CHARRIGHT)
            elif e.key() == Qt.Key_Backspace:
                curPos, pos = self.getCursorPosition()
                line = self.lines() -1
                if curPos < line -1 or pos < 5:
                    return
                #else:
                    #self.move_cursor_to_end()
                QsciScintilla.keyPressEvent(self, e)
            elif e.key() == Qt.Key_Delete:
                if self.hasSelectedText():
                    self.removeSelectedText()
                elif self.is_cursor_on_last_line():
                    self.SendScintilla(QsciScintilla.SCI_CLEAR)
                e.accept()
            elif e.key() == Qt.Key_Home:
                self.setCursorPosition(linenr,4)
                self.ensureCursorVisible()
            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:
                QsciScintilla.keyPressEvent(self, e)
                
    def paste(self):
        """Reimplement QScintilla method"""
        stringPaste = unicode(QApplication.clipboard().text())
        if self.hasSelectedText():
            self.removeSelectedText()
        self.insertFromDropPaste(stringPaste)
        
    ## Drag and drop
    def dropEvent(self, e):
        if e.mimeData().hasText():
            stringDrag = e.mimeData().text()
            self.insertFromDropPaste(stringDrag)
            e.setDropAction(Qt.MoveAction)
            e.accept()
        else:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = QStringList()
        pasteList = textDP.split("\n")
        for line in pasteList[:-1]:
            self.insert(line)
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.insert(unicode(pasteList[-1]))
        self.move_cursor_to_end()

    def getTextFromEditor(self):
        text = self.text()
        textList = QStringList()
        textList = text.split("\n")
        return textList
    
    def insertTextFromFile(self, listOpenFile):
        for line in listOpenFile[:-1]:
            self.append(line)
            self.move_cursor_to_end()
            self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            
    def entered(self):
        self.move_cursor_to_end()
        self.runCommand( unicode(self.currentCommand()) )
        self.setFocus()
        #self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)
        
    def currentCommand(self):
        linenr, index = self.getCurLine()
        #for i in range(0, linenr):
        txtLength = self.text(linenr).length()
        string = self.text()
        cmdLine = string.right(txtLength - 4)
        cmd = str(cmdLine)
        return cmd

    def runCommand(self, cmd):
        self.updateHistory(cmd)
        self.SendScintilla(QsciScintilla.SCI_NEWLINE)
        if cmd in ('_save', '_clear', '_clearAll'):
            if cmd == '_save':
                self.writeHistoryFile()
                print QCoreApplication.translate("PythonConsole", 
                                                 "## History saved successfully ##")
            elif cmd == '_clear':
                self.clearHistoryFile()
                print QCoreApplication.translate("PythonConsole", 
                                                 "## History cleared successfully ##")
            elif cmd == '_clearAll':
                res = QMessageBox.question(self, "Python Console", 
                                           QCoreApplication.translate("PythonConsole", 
                                                                      "Are you sure you want to completely\n"
                                                                      "delete the command history ?"),
                                                                      QMessageBox.Yes | QMessageBox.No)
                if res == QMessageBox.No:
                    self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
                    return
                self.history = QStringList()
                self.clearHistoryFile()
                print QCoreApplication.translate("PythonConsole", 
                                                 "## History cleared successfully ##")
            output = sys.stdout.get_and_clean_data()
            if output:
                self.append(output)
            self.displayPrompt(False)
        else:
            self.buffer.append(cmd)
            src = "\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            if not more:
                self.buffer = []
            output = sys.stdout.get_and_clean_data()
            if output:
                self.append(output)
            self.move_cursor_to_end()
            self.displayPrompt(more)

    def write(self, txt):
        self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
        self.append(txt)
        self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
Esempio n. 11
0
class PythonEdit(QsciScintilla, code.InteractiveInterpreter):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(PythonEdit, self).__init__(parent)
        code.InteractiveInterpreter.__init__(self, locals=None)

        self.current_prompt_pos = None
        self.new_input_line = True

        self.setMarginWidth(0, 0)
        self.setMarginWidth(1, 0)
        self.setMarginWidth(2, 0)

        self.buffer = []

        self.insertInitText()

        self.setCursorPosition(4, 4)

        self.displayPrompt(False)

        for line in _init_commands:
            self.runsource(line)

        self.history = QStringList()
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()

        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        #self.moveToMatchingBrace()
        #self.selectToMatchingBrace()

        # Current line visible with special background color
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
        self.setCaretWidth(2)

        # Set Python lexer
        # Set style for Python comments (style number 1) to a fixed-width
        # courier.
        self.setLexers(True)

        # Indentation
        #self.setAutoIndent(True)
        #self.setIndentationsUseTabs(False)
        #self.setIndentationWidth(4)
        #self.setTabIndents(True)
        #self.setBackspaceUnindents(True)
        #self.setTabWidth(4)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(self.AcsAPIs)

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        # not too small
        #self.setMinimumSize(500, 300)
        self.setMinimumHeight(125)

        self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 1)
        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.newShortcutCS = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Space),
                                       self)
        self.newShortcutCAS = QShortcut(
            QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self)
        self.newShortcutCS.activated.connect(self.autoComplete)
        self.newShortcutCAS.activated.connect(self.showHistory)
        self.connect(self, SIGNAL('userListActivated(int, const QString)'),
                     self.completion_list_selected)

    def showHistory(self):
        self.showUserList(1, QStringList(self.history))

    def autoComplete(self):
        self.autoCompleteFromAll()

    def clearConsole(self):
        """Clear the contents of the console."""
        self.setText('')
        self.insertInitText()
        self.displayPrompt(False)
        self.setFocus()

    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCurLine()
        selCmd = self.text(line).length()
        self.setSelection(line, 4, line, selCmd)
        self.removeSelectedText()
        if command == "iface":
            """Import QgisInterface class"""
            self.append('from qgis.utils import iface')
            self.move_cursor_to_end()
        elif command == "sextante":
            """Import Sextante class"""
            self.append('from sextante.core.Sextante import Sextante')
            self.move_cursor_to_end()
        elif command == "cLayer":
            """Retrive current Layer from map camvas"""
            self.append('cLayer = iface.mapCanvas().currentLayer()')
            self.move_cursor_to_end()
        self.setFocus()

    def setLexers(self, lexer):
        if lexer:
            font = QFont()
            font.setFamily('Mono')  ## Courier New
            font.setFixedPitch(True)
            ## check platform for font size
            if sys.platform.startswith('darwin'):
                font.setPointSize(13)
            else:
                font.setPointSize(10)
            self.setFont(font)
            self.setMarginsFont(font)
            self.lexer = QsciLexerPython()
            self.lexer.setDefaultFont(font)
            self.lexer.setColor(Qt.red, 1)
            self.lexer.setColor(Qt.darkGreen, 5)
            self.lexer.setColor(Qt.darkBlue, 15)
            self.lexer.setFont(font, 1)
            self.lexer.setFont(font, 3)
            self.lexer.setFont(font, 4)
            self.api = QsciAPIs(self.lexer)
            self.api.loadPrepared(
                QString(os.path.dirname(__file__) + "/api/pyqgis_master.pap"))
            self.setLexer(self.lexer)

    ## TODO: show completion list for file and directory

    def completion_list_selected(self, id, txt):
        if id == 1:
            txt = unicode(txt)
            # get current cursor position
            line, pos = self.getCurLine()
            selCmd = self.text(line).length()
            # select typed text
            self.setSelection(line, 4, line, selCmd)
            self.removeSelectedText()
            self.insert(txt)

    def insertInitText(self):
        #self.setLexers(False)
        txtInit = QCoreApplication.translate(
            "PythonConsole",
            "## To access Quantum GIS environment from this console\n"
            "## use qgis.utils.iface object (instance of QgisInterface class). Read help for more info.\n\n"
        )
        initText = self.setText(txtInit)

    def getCurrentPos(self):
        """ Get the position (as an int) of the cursor. 
        getCursorPosition() returns a (linenr, index) tuple.
        """
        return self.SendScintilla(self.SCI_GETCURRENTPOS)

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode('utf-8')
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH) + 1
        bb = QByteArray(len, '0')
        N = self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

    def getLine(self, linenr):
        """ Get the bytes on the given line number. """
        len = self.SendScintilla(QsciScintilla.SCI_LINELENGTH) + 1
        bb = QByteArray(len, '0')
        N = self.SendScintilla(QsciScintilla.SCI_GETLINE, len, bb)
        return bytes(bb)[:-1]

    def getCurLine(self):
        """ Get the current line (as a string) and the 
        position of the cursor in it. """
        linenr, index = self.getCursorPosition()
        #line = self.getLine(linenr) #.decode('utf-8')
        return linenr, index

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

    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()

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

    def on_new_line(self):
        """On new input line"""
        self.move_cursor_to_end()
        self.current_prompt_pos = self.getCursorPosition()
        self.new_input_line = False

    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1

    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        self.current_prompt_pos = self.getCursorPosition()
        self.ensureCursorVisible()

    def check_selection(self):
        """
        Check if selected text is r/w,
        otherwise remove read-only parts of selection
        """
        #if self.current_prompt_pos is None:
        #self.move_cursor_to_end()
        #return
        line_from, index_from, line_to, index_to = self.getSelection()
        pline, pindex = self.getCursorPosition()
        if line_from < pline or \
           (line_from == pline and index_from < pindex):
            self.setSelection(pline, pindex, line_to, index_to)

    def displayPrompt(self, more=False):
        self.append("... ") if more else self.append(">>> ")
        self.move_cursor_to_end()

    def updateHistory(self, command):
        if isinstance(command, QStringList):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or \
            not command == self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)

    def writeHistoryFile(self):
        wH = open(_historyFile, 'w')
        for s in self.history:
            wH.write(s + '\n')
        wH.close()

    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = open(_historyFile, 'r')
            for line in rH:
                if line != "\n":
                    l = line.rstrip('\n')
                    self.updateHistory(l)
        else:
            return

    def clearHistoryFile(self):
        cH = open(_historyFile, 'w')
        cH.close()

    def showPrevious(self):
        if self.historyIndex < len(
                self.history) and not self.history.isEmpty():
            line, pos = self.getCurLine()
            selCmd = self.text(line).length()
            self.setSelection(line, 4, line, selCmd)
            self.removeSelectedText()
            self.historyIndex += 1
            if self.historyIndex == len(self.history):
                self.insert("")
                pass
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def showNext(self):
        if self.historyIndex > 0 and not self.history.isEmpty():
            line, pos = self.getCurLine()
            selCmd = self.text(line).length()
            self.setSelection(line, 4, line, selCmd)
            self.removeSelectedText()
            self.historyIndex -= 1
            if self.historyIndex == len(self.history):
                self.insert("")
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def keyPressEvent(self, e):
        linenr, index = self.getCurLine()
        if not self.is_cursor_on_last_line() or index < 4:
            if e.modifiers() & Qt.ControlModifier or e.modifiers(
            ) & Qt.MetaModifier:
                if e.key() == Qt.Key_C or e.key() == Qt.Key_A:
                    QsciScintilla.keyPressEvent(self, e)
            else:
                # all other keystrokes get sent to the input line
                self.move_cursor_to_end()
                #pass
        else:
            if (e.key() == Qt.Key_Return
                    or e.key() == Qt.Key_Enter) and not self.isListActive():
                self.entered()
            elif e.modifiers() & Qt.ControlModifier:
                if e.key() == Qt.Key_V:
                    self.paste()
                elif e.key() == Qt.Key_C:
                    self.copy()
                elif e.key() == Qt.Key_X:
                    self.cut()
                elif e.key() == Qt.Key_Left:
                    e.accept()
                    if e.modifiers() & Qt.ShiftModifier:
                        if index > 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(
                                    QsciScintilla.SCI_WORDLEFTEXTEND)
                            else:
                                self.SendScintilla(
                                    QsciScintilla.SCI_CHARLEFTEXTEND)
                    else:
                        if index > 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(QsciScintilla.SCI_WORDLEFT)
                            else:
                                self.SendScintilla(QsciScintilla.SCI_CHARLEFT)
                elif e.key() == Qt.Key_Right:
                    e.accept()
                    if e.modifiers() & Qt.ShiftModifier:
                        if index >= 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(
                                    QsciScintilla.SCI_WORDRIGHTEXTEND)
                            else:
                                self.SendScintilla(
                                    QsciScintilla.SCI_CHARRIGHTEXTEND)
                    else:
                        if index >= 4:
                            if e.modifiers() & Qt.ControlModifier:
                                self.SendScintilla(QsciScintilla.SCI_WORDRIGHT)
                            else:
                                self.SendScintilla(QsciScintilla.SCI_CHARRIGHT)
            elif e.key() == Qt.Key_Backspace:
                curPos, pos = self.getCursorPosition()
                line = self.lines() - 1
                if curPos < line - 1 or pos < 5:
                    return
                #else:
                #self.move_cursor_to_end()
                QsciScintilla.keyPressEvent(self, e)
            elif e.key() == Qt.Key_Delete:
                if self.hasSelectedText():
                    self.removeSelectedText()
                elif self.is_cursor_on_last_line():
                    self.SendScintilla(QsciScintilla.SCI_CLEAR)
                e.accept()
            elif e.key() == Qt.Key_Home:
                self.setCursorPosition(linenr, 4)
                self.ensureCursorVisible()
            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:
                QsciScintilla.keyPressEvent(self, e)

    def paste(self):
        """Reimplement QScintilla method"""
        stringPaste = unicode(QApplication.clipboard().text())
        if self.hasSelectedText():
            self.removeSelectedText()
        self.insertFromDropPaste(stringPaste)

    ## Drag and drop
    def dropEvent(self, e):
        if e.mimeData().hasText():
            stringDrag = e.mimeData().text()
            self.insertFromDropPaste(stringDrag)
            e.setDropAction(Qt.MoveAction)
            e.accept()
        else:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = QStringList()
        pasteList = textDP.split("\n")
        for line in pasteList[:-1]:
            self.insert(line)
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.insert(unicode(pasteList[-1]))
        self.move_cursor_to_end()

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

    def insertTextFromFile(self, listOpenFile):
        for line in listOpenFile[:-1]:
            self.append(line)
            self.move_cursor_to_end()
            self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def entered(self):
        self.move_cursor_to_end()
        self.runCommand(unicode(self.currentCommand()))
        self.setFocus()
        #self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)

    def currentCommand(self):
        linenr, index = self.getCurLine()
        #for i in range(0, linenr):
        txtLength = self.text(linenr).length()
        string = self.text()
        cmdLine = string.right(txtLength - 4)
        cmd = str(cmdLine)
        return cmd

    def runCommand(self, cmd):
        self.updateHistory(cmd)
        self.SendScintilla(QsciScintilla.SCI_NEWLINE)
        if cmd in ('_save', '_clear', '_clearAll'):
            if cmd == '_save':
                self.writeHistoryFile()
                print QCoreApplication.translate(
                    "PythonConsole", "## History saved successfully ##")
            elif cmd == '_clear':
                self.clearHistoryFile()
                print QCoreApplication.translate(
                    "PythonConsole", "## History cleared successfully ##")
            elif cmd == '_clearAll':
                res = QMessageBox.question(
                    self, "Python Console",
                    QCoreApplication.translate(
                        "PythonConsole",
                        "Are you sure you want to completely\n"
                        "delete the command history ?"),
                    QMessageBox.Yes | QMessageBox.No)
                if res == QMessageBox.No:
                    self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
                    return
                self.history = QStringList()
                self.clearHistoryFile()
                print QCoreApplication.translate(
                    "PythonConsole", "## History cleared successfully ##")
            output = sys.stdout.get_and_clean_data()
            if output:
                self.append(output)
            self.displayPrompt(False)
        else:
            self.buffer.append(cmd)
            src = "\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            if not more:
                self.buffer = []
            output = sys.stdout.get_and_clean_data()
            if output:
                self.append(output)
            self.move_cursor_to_end()
            self.displayPrompt(more)

    def write(self, txt):
        self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
        self.append(txt)
        self.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(txt), 1)
Esempio n. 12
0
class EditorOutput(QsciScintilla):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(EditorOutput, self).__init__(parent)
        self.parent = parent
        self.edit = self.parent.edit

        # 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.setLexers()
        self.setReadOnly(True)

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

        self.setMinimumHeight(120)

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

        ## Edge Mode
        #self.setEdgeMode(QsciScintilla.EdgeLine)
        #self.setEdgeColumn(80)
        #self.setEdgeColor(QColor("#FF0000"))

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        self.runShortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self)
        self.runShortcut.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",
            "## To access Quantum GIS environment from this console\n"
            "## use qgis.utils.iface object (instance of QgisInterface class). Read help for more info.\n\n"
        )
        initText = self.setText(txtInit)

    def refreshLexerProperties(self):
        self.setLexers()

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

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

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

        self.setLexer(self.lexer)

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

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

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        iconRun = QIcon(":/images/console/iconRunConsole.png")
        iconPastebin = QIcon(":/images/console/iconCodepadConsole.png")
        iconClear = QIcon(":/images/console/iconClearConsole.png")
        iconHideTool = QIcon(":/images/console/iconHideToolConsole.png")
        hideToolBar = menu.addAction(iconHideTool, "Hide/Show Toolbar",
                                     self.hideToolBar)
        menu.addSeparator()
        runAction = menu.addAction(iconRun, "Enter Selected",
                                   self.enteredSelected,
                                   QKeySequence(Qt.CTRL + Qt.Key_E))
        clearAction = menu.addAction(iconClear, "Clear console",
                                     self.clearConsole)
        menu.addSeparator()
        copyAction = menu.addAction("Copy", self.copy, QKeySequence.Copy)
        pastebinAction = menu.addAction(iconPastebin, "Share on codepad",
                                        self.pastebin)
        menu.addSeparator()
        selectAllAction = menu.addAction("Select All", self.selectAll,
                                         QKeySequence.SelectAll)
        runAction.setEnabled(False)
        clearAction.setEnabled(False)
        copyAction.setEnabled(False)
        pastebinAction.setEnabled(False)
        selectAllAction.setEnabled(False)
        if self.hasSelectedText():
            runAction.setEnabled(True)
            copyAction.setEnabled(True)
            pastebinAction.setEnabled(True)
        if not self.text(3) == '':
            selectAllAction.setEnabled(True)
            clearAction.setEnabled(True)
        action = menu.exec_(self.mapToGlobal(e.pos()))

    def hideToolBar(self):
        tB = self.parent.toolBar
        tB.hide() if tB.isVisible() else tB.show()
        self.edit.setFocus()

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

    def enteredSelected(self):
        cmd = self.selectedText()
        self.edit.insertFromDropPaste(cmd)
        self.edit.entered()

    def keyPressEvent(self, e):
        # empty text indicates possible shortcut key sequence so stay in output
        txt = e.text()
        if txt.length() and txt >= " ":
            self.edit.append(txt)
            self.edit.move_cursor_to_end()
            self.edit.setFocus()
            e.ignore()
        else:
            # possible shortcut key sequence, accept it
            e.accept()

    def pastebin(self):
        import urllib2, urllib
        listText = self.selectedText().split('\n')
        getCmd = []
        for strLine in listText:
            if strLine != "":
                #if s[0:3] in (">>>", "..."):
                # filter for special command (_save,_clear) and comment
                if strLine[4] != "_" and strLine[:2] != "##":
                    strLine.replace(">>> ", "").replace("... ", "")
                    getCmd.append(unicode(strLine))
        pasteText = u"\n".join(getCmd)
        url = 'http://codepad.org'
        values = {'lang': 'Python', 'code': pasteText, 'submit': 'Submit'}
        try:
            response = urllib2.urlopen(url, urllib.urlencode(values))
            url = response.read()
            for href in url.split("</a>"):
                if "Link:" in href:
                    ind = href.index('Link:')
                    found = href[ind + 5:]
                    for i in found.split('">'):
                        if '<a href=' in i:
                            link = i.replace('<a href="', "").strip()
            if link:
                QApplication.clipboard().setText(link)
                print "## URL copied to clipboard ##"
        except urllib2.URLError, e:
            print "## Connection error ##"
            print "## " + str(e.args) + " ##"
Esempio n. 13
0
class EditorOutput(QsciScintilla):
    def __init__(self, parent=None):
        #QsciScintilla.__init__(self, parent)
        super(EditorOutput,self).__init__(parent)
        # Enable non-ascii chars for editor
        self.setUtf8(True)
        
        sys.stdout = writeOut(self, sys.stdout)
        sys.stderr = writeOut(self, sys.stderr, "traceback")
        
        self.edit = PythonEdit() 
        self.setLexers()
        self.setReadOnly(True)
        
        # Set the default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        # Margin 0 is used for line numbers
        #fm = QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(1, "00000")
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor("#3E3EE3"))
        self.setMarginsBackgroundColor(QColor("#f9f9f9"))
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#fcf3ed"))


        # Folding
        #self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
        #self.setFoldMarginColors(QColor("#99CC66"),QColor("#333300"))
        #self.setWrapMode(QsciScintilla.WrapCharacter)
        
         ## Edge Mode : does not seems to work
        #self.setEdgeMode(QsciScintilla.EdgeLine)
        #self.setEdgeColumn(80)
        #self.setEdgeColor(QColor("#FF0000")) 
        
        self.SendScintilla(QsciScintilla.SCI_SETWRAPMODE, 2)  
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
        
    def refreshLexerProperties(self):
        self.setLexers()
        
    def setLexers(self):
        self.lexer = QsciLexerPython()
        
        settings = QSettings()
        loadFont = settings.value("pythonConsole/fontfamilytext").toString()
        fontSize = settings.value("pythonConsole/fontsize").toInt()[0]
        font = QFont(loadFont)
        font.setFixedPitch(True)
        font.setPointSize(fontSize)
        
        self.lexer.setDefaultFont(font)
        self.lexer.setColor(Qt.red, 1)
        self.lexer.setColor(Qt.darkGreen, 5)
        self.lexer.setColor(Qt.darkBlue, 15)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 2)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        self.setLexer(self.lexer)

    def getTextFromEditor(self):
        text = self.text()
        textList = text.split("\n")
        return textList
    
    def clearConsole(self):
        #self.SendScintilla(QsciScintilla.SCI_CLEARALL)
        self.setText('')
        
    def contextMenuEvent(self, e):   
        menu = QMenu(self)
        runAction = menu.addAction("Enter Selected")
        copyAction = menu.addAction("Copy  CTRL+C")
        runAction.setEnabled(False)
        if self.hasSelectedText():
            runAction.setEnabled(True)
        action = menu.exec_(self.mapToGlobal(e.pos()))
        if action == runAction:
            cmd = self.selectedText()
            self.edit.insertFromDropPaste(cmd)
            self.edit.entered()
        if action == copyAction:
            self.copy()
            
    def copy(self):
        """Copy text to clipboard... or keyboard interrupt"""
        if self.hasSelectedText():
            text = unicode(self.selectedText())
            text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))
Esempio n. 14
0
class ScintillaPythonEditBox(QsciScintilla, BasePythonEditBox):
    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
        # Load font from Python console settings
        settings = QSettings()
        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.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

        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'))

        # 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.AcsAll)

    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):
        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)

        self.setLexer(self.lexer)

    #impliment base editor
    def insertPlainText(self, text):
        self.insert(text)
        pos = self.getCursorPosition()
        self.setCursorPosition(pos[0], pos[1] + len(text))

    def toPlainText(self):
        return self.text()

    def get_font_size(self):
        return self.font().pointSize()

    def set_font_size(self, new_point_size):
        font = self.font()
        self.setFont(QFont(font.family(), new_point_size))

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ControlModifier:
            self.emit(SIGNAL("wheelEvent(QWheelEvent)"), event)
        else:
            super(ScintillaPythonEditBox, self).wheelEvent(event)
class ScintillaPythonEditBox(QsciScintilla, BasePythonEditBox):

    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
        # Load font from Python console settings
        settings = QSettings()
        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.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

        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'))

        # 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.AcsAll)


    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):
        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)

        self.setLexer(self.lexer)

    #impliment base editor
    def insertPlainText(self, text):
        self.insert(text)
        pos = self.getCursorPosition()
        self.setCursorPosition(pos[0], pos[1]+len(text))

    def toPlainText(self):
        return self.text()

    def get_font_size(self):
        return self.font().pointSize()

    def set_font_size(self, new_point_size):
        font = self.font()
        self.setFont(QFont(font.family(), new_point_size))

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ControlModifier:
            self.emit(SIGNAL("wheelEvent(QWheelEvent)"), event)
        else:
            super(ScintillaPythonEditBox, self).wheelEvent(event)
Esempio n. 16
0
class ShellOutputScintilla(QsciScintilla):
    def __init__(self, parent=None):
        super(ShellOutputScintilla, self).__init__(parent)
        self.parent = parent
        self.shell = self.parent.shell

        # 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.setLexers()
        self.setReadOnly(True)

        # Set the default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        # Margin 0 is used for line numbers
        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.setCaretLineBackgroundColor(QColor("#fcf3ed"))

        self.setMinimumHeight(120)

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        # 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 %1 on %2\n"
            "## Type help(iface) for more info and list of methods.\n").arg(
                sys.version, socket.gethostname())
        initText = self.setText(txtInit)

    def refreshLexerProperties(self):
        self.setLexers()

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

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

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

        self.setLexer(self.lexer)

    def 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")
        hideToolBar = menu.addAction(iconHideTool, "Hide/Show Toolbar",
                                     self.hideToolBar)
        menu.addSeparator()
        showEditorAction = menu.addAction("Show Editor", self.showEditor)
        menu.addSeparator()
        runAction = menu.addAction(iconRun, "Enter Selected",
                                   self.enteredSelected,
                                   QKeySequence(Qt.CTRL + Qt.Key_E))
        clearAction = menu.addAction(iconClear, "Clear console",
                                     self.clearConsole)
        menu.addSeparator()
        copyAction = menu.addAction("Copy", self.copy, QKeySequence.Copy)
        menu.addSeparator()
        selectAllAction = menu.addAction("Select All", self.selectAll,
                                         QKeySequence.SelectAll)
        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)
        action = 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.widgetEditor
        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 = unicode(self.selectedText())
            text = text.replace('>>> ',
                                '').replace('... ',
                                            '').strip()  # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    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 txt.length() 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('Console', text, QgsMessageBar.INFO, timeout)