Ejemplo n.º 1
0
    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.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, type=bool)
        if chekBoxAPI:
            self.api.loadPrepared( QgsApplication.pkgDataPath() + "/python/qsci_apis/pyqgis_master.pap" )
        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)
Ejemplo n.º 2
0
 def active_code_completion(self, enabled=True):
     if self.api is not None and enabled:
         return
     if enabled:
         self.api = QsciAPIs(self._lexer)
         if settings.get_setting('editor/completion-keywords'):
             for keyword in keywords.keywords:
                 self.api.add(keyword)
             self.api.prepare()
             source = QsciScintilla.AcsAPIs
             if settings.get_setting('editor/completion-document'):
                 source = QsciScintilla.AcsAll
         elif settings.get_setting('editor/completion-document'):
             source = QsciScintilla.AcsDocument
         else:
             source = QsciScintilla.AcsNone
         threshold = settings.get_setting('editor/completion-threshold')
         self.setAutoCompletionThreshold(threshold)
         self.setAutoCompletionSource(source)
         cs = settings.get_setting('editor/completion-cs')
         self.setAutoCompletionCaseSensitivity(cs)
         repl_word = settings.get_setting('editor/completion-replace-word')
         self.setAutoCompletionReplaceWord(repl_word)
         show_single = settings.get_setting('editor/completion-single')
         use_single = 2 if show_single else 0
         self.setAutoCompletionUseSingle(use_single)
     else:
         self.api = None
         self.setAutoCompletionSource(0)
Ejemplo n.º 3
0
    def __init__(self, parent=None):
        super(RevsetEntry, self).__init__(parent)
        self.setMarginWidth(1, 0)
        self.setReadOnly(False)
        self.setUtf8(True)
        self.setCaretWidth(10)
        self.setCaretLineBackgroundColor(QColor("#e6fff0"))
        self.setCaretLineVisible(True)
        self.setAutoIndent(True)
        self.setMatchedBraceBackgroundColor(Qt.yellow)
        self.setIndentationsUseTabs(False)
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        sp = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        sp.setHorizontalStretch(1)
        sp.setVerticalStretch(0)
        self.setSizePolicy(sp)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setAutoCompletionFillupsEnabled(True)
        self.setLexer(QsciLexerPython(self))
        self.lexer().setFont(qtlib.getfont('fontcomment').font())
        self.apis = QsciAPIs(self.lexer())
Ejemplo n.º 4
0
class PrepareAPIDialog(QDialog):
    def __init__(self, api_lexer, api_files, pap_file, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_APIsDialogPythonConsole()
        self.ui.setupUi(self)
        self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Compile APIs"))
        self.ui.plainTextEdit.setVisible(False)
        self.ui.textEdit_Qsci.setVisible(False)
        self.adjustSize()
        self._api = None
        self.ui.buttonBox.rejected.connect(self._stopPreparation)
        self._api_files = api_files
        self._api_lexer = api_lexer
        self._pap_file = pap_file

    def _clearLexer(self):
        # self.ui.textEdit_Qsci.setLexer(0)
        self.qlexer = None

    def _stopPreparation(self):
        if self._api is not None:
            self._api.cancelPreparation()
        self._api = None
        self._clearLexer()
        self.close()

    def _preparationFinished(self):
        self._clearLexer()
        if os.path.exists(self._pap_file):
            os.remove(self._pap_file)
        self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Saving prepared file..."))
        prepd = self._api.savePrepared(unicode(self._pap_file))
        rslt = self.trUtf8("Error")
        if prepd:
            rslt = QCoreApplication.translate("PythonConsole", "Saved")
        self.ui.label.setText(u"{0} {1}".format(self.ui.label.text(), rslt))
        self._api = None
        self.ui.progressBar.setVisible(False)
        self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(QCoreApplication.translate("PythonConsole", "Done"))
        self.adjustSize()

    def prepareAPI(self):
        # self.ui.textEdit_Qsci.setLexer(0)
        exec(u"self.qlexer = {0}(self.ui.textEdit_Qsci)".format(self._api_lexer))
        # self.ui.textEdit_Qsci.setLexer(self.qlexer)
        self._api = QsciAPIs(self.qlexer)
        self._api.apiPreparationFinished.connect(self._preparationFinished)
        for api_file in self._api_files:
            self._api.load(unicode(api_file))
        try:
            self._api.prepare()
        except Exception as err:
            self._api = None
            self._clearLexer()
            self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Error preparing file..."))
            self.ui.progressBar.setVisible(False)
            self.ui.plainTextEdit.setVisible(True)
            self.ui.plainTextEdit.insertPlainText(err)
            self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(self.trUtf8("Done"))
            self.adjustSize()
Ejemplo n.º 5
0
    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.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,
                                         type=bool)
        chekBoxPreparedAPI = self.settings.value(
            "pythonConsole/usePreparedAPIFile", False, type=bool)
        if chekBoxAPI:
            apisdir = os.path.join(QgsApplication.pkgDataPath(), "python",
                                   "qsci_apis")
            pap = os.path.join(apisdir, "pyqgis.pap")
            mpap = os.path.join(apisdir, "pyqgis-master.pap")
            if os.path.exists(
                    mpap):  # override installed with master .pap build
                pap = mpap
            if QgsApplication.isRunningFromBuildDir():
                bdir = os.path.dirname(QgsApplication.buildOutputPath())
                bpap = os.path.join(bdir, "python", "qsci_apis",
                                    "pyqgis-master.pap")
                if os.path.exists(bpap):
                    # if not generated .pap exists, else fall back to preprepared one
                    pap = bpap
            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)
Ejemplo n.º 6
0
    def __init__(self, nombre_archivo, ext=''):
        super(Editor, self).__init__()
        self.__nombre = ""
        self.texto_modificado = False
        self.es_nuevo = True
        self.guardado_actualmente = False
        # Actualiza flags (espacios en blanco, cursor, sidebar, etc)
        self.actualizar()
        # Lexer
        self._lexer = None
        self.cargar_lexer(ext)
        # Autocompletado
        #FIXME:
        api = QsciAPIs(self._lexer)
        for palabra in keywords.keywords:
            api.add(palabra)
        api.prepare()
        self.setAutoCompletionThreshold(1)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        # Indentación
        self._indentacion = ESettings.get('editor/indentacionAncho')
        self.send("sci_settabwidth", self._indentacion)
        # Minimapa
        self.minimapa = MiniMapa(self)
        self.connect(self, SIGNAL("selectionChanged()"), self.minimapa.area)
        self.connect(self, SIGNAL("textChanged()"),
                     self.minimapa.actualizar_codigo)
        # Thread ocurrencias
        self.hilo_ocurrencias = ThreadBusqueda()
        self.connect(self.hilo_ocurrencias,
                     SIGNAL("ocurrenciasThread(PyQt_PyObject)"),
                     self.marcar_palabras)
        # Analizador de estilo de código
        self.checker = checker.Checker(self)
        self.connect(self.checker, SIGNAL("finished()"), self._show_violations)
        #self.checker.errores.connect(self._marcar_errores)
        # Fuente
        fuente = ESettings.get('editor/fuente')
        tam_fuente = ESettings.get('editor/fuenteTam')
        self.cargar_fuente(fuente, tam_fuente)
        self.setMarginsBackgroundColor(QColor(self._tema['sidebar-fondo']))
        self.setMarginsForegroundColor(QColor(self._tema['sidebar-fore']))

        # Línea actual, cursor
        self.caret_line(self._tema['caret-background'],
                        self._tema['caret-line'], self._tema['caret-opacidad'])
        # Márgen
        if ESettings.get('editor/margen'):
            self.actualizar_margen()

        # Brace matching
        self.match_braces(Base.SloppyBraceMatch)
        self.match_braces_color(self._tema['brace-background'],
                                self._tema['brace-foreground'])
        self.unmatch_braces_color(self._tema['brace-unbackground'],
                                  self._tema['brace-unforeground'])
Ejemplo n.º 7
0
 def prepareAPI(self):
     try:
         self._api = QsciAPIs(self._api_lexer)
         self._api.apiPreparationFinished.connect(self._preparationFinished)
         for api_file in self._api_files:
             self._api.load(unicode(api_file))
         self._api.prepare()
     except Exception as err:
         self._api = None
         sys.exit(1)
Ejemplo n.º 8
0
    def initLexer(self):
        if self.lexerType == self.LEXER_PYTHON:
            self.lexer = QsciLexerPython()

            colorDefault = QColor('#2e3436')
            colorComment = QColor('#c00')
            colorCommentBlock = QColor('#3465a4')
            colorNumber = QColor('#4e9a06')
            colorType = QColor('#4e9a06')
            colorKeyword = QColor('#204a87')
            colorString = QColor('#ce5c00')

            self.lexer.setDefaultFont(self.defaultFont)
            self.lexer.setDefaultColor(colorDefault)

            self.lexer.setColor(colorComment, 1)
            self.lexer.setColor(colorNumber, 2)
            self.lexer.setColor(colorString, 3)
            self.lexer.setColor(colorString, 4)
            self.lexer.setColor(colorKeyword, 5)
            self.lexer.setColor(colorString, 6)
            self.lexer.setColor(colorString, 7)
            self.lexer.setColor(colorType, 8)
            self.lexer.setColor(colorCommentBlock, 12)
            self.lexer.setColor(colorString, 15)

            self.lexer.setFont(self.italicFont, 1)
            self.lexer.setFont(self.boldFont, 5)
            self.lexer.setFont(self.boldFont, 8)
            self.lexer.setFont(self.italicFont, 12)

            self.api = QsciAPIs(self.lexer)

            settings = QSettings()
            useDefaultAPI = bool(
                settings.value('pythonConsole/preloadAPI', True))
            if useDefaultAPI:
                # Load QGIS API shipped with Python console
                self.api.loadPrepared(
                    os.path.join(QgsApplication.pkgDataPath(), 'python',
                                 'qsci_apis', 'pyqgis.pap'))
            else:
                # Load user-defined API files
                apiPaths = settings.value('pythonConsole/userAPI', [])
                for path in apiPaths:
                    self.api.load(path)
                self.api.prepare()
                self.lexer.setAPIs(self.api)
        elif self.lexerType == self.LEXER_R:
            # R lexer
            self.lexer = LexerR()

        self.setLexer(self.lexer)
Ejemplo n.º 9
0
class RevsetEntry(QsciScintilla):

    returnPressed = pyqtSignal()

    def __init__(self, parent=None):
        super(RevsetEntry, self).__init__(parent)
        self.setMarginWidth(1, 0)
        self.setReadOnly(False)
        self.setUtf8(True)
        self.setCaretWidth(10)
        self.setCaretLineBackgroundColor(QColor("#e6fff0"))
        self.setCaretLineVisible(True)
        self.setAutoIndent(True)
        self.setMatchedBraceBackgroundColor(Qt.yellow)
        self.setIndentationsUseTabs(False)
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        sp = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        sp.setHorizontalStretch(1)
        sp.setVerticalStretch(0)
        self.setSizePolicy(sp)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setAutoCompletionFillupsEnabled(True)
        self.setLexer(QsciLexerPython(self))
        self.lexer().setFont(qtlib.getfont('fontcomment').font())
        self.apis = QsciAPIs(self.lexer())

    def addCompletions(self, *lists):
        for list in lists:
            for x, y in list:
                self.apis.add(x)
        self.apis.prepare()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            event.ignore()
            return
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            if not self.isListActive():
                event.ignore()
                self.returnPressed.emit()
                return
        super(RevsetEntry, self).keyPressEvent(event)

    def sizeHint(self):
        return QSize(10, self.fontMetrics().height())
Ejemplo n.º 10
0
class RevsetEntry(QsciScintilla):

    returnPressed = pyqtSignal()

    def __init__(self, parent=None):
        super(RevsetEntry, self).__init__(parent)
        self.setMarginWidth(1, 0)
        self.setReadOnly(False)
        self.setUtf8(True)
        self.setCaretWidth(10)
        self.setCaretLineBackgroundColor(QColor("#e6fff0"))
        self.setCaretLineVisible(True)
        self.setAutoIndent(True)
        self.setMatchedBraceBackgroundColor(Qt.yellow)
        self.setIndentationsUseTabs(False)
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        sp = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        sp.setHorizontalStretch(1)
        sp.setVerticalStretch(0)
        self.setSizePolicy(sp)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setAutoCompletionFillupsEnabled(True)
        self.setLexer(QsciLexerPython(self))
        self.lexer().setFont(qtlib.getfont('fontcomment').font())
        self.apis = QsciAPIs(self.lexer())

    def addCompletions(self, *lists):
        for list in lists:
            for x, y in list:
                self.apis.add(x)
        self.apis.prepare()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            event.ignore()
            return
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            if not self.isListActive():
                event.ignore()
                self.returnPressed.emit()
                return
        super(RevsetEntry, self).keyPressEvent(event)

    def sizeHint(self):
        return QSize(10, self.fontMetrics().height())
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
    def __init__(self, parent=None):
        super(RevsetEntry, self).__init__(parent)
        self.setMarginWidth(1, 0)
        self.setReadOnly(False)
        self.setUtf8(True)
        self.setCaretWidth(10)
        self.setCaretLineBackgroundColor(QColor("#e6fff0"))
        self.setCaretLineVisible(True)
        self.setAutoIndent(True)
        self.setMatchedBraceBackgroundColor(Qt.yellow)
        self.setIndentationsUseTabs(False)
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        sp = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        sp.setHorizontalStretch(1)
        sp.setVerticalStretch(0)
        self.setSizePolicy(sp)

        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setAutoCompletionFillupsEnabled(True)
        self.setLexer(QsciLexerPython(self))
        self.lexer().setFont(qtlib.getfont('fontcomment').font())
        self.apis = QsciAPIs(self.lexer())
Ejemplo n.º 13
0
Archivo: editor.py Proyecto: Garjy/edis
 def active_code_completion(self, enabled=True):
     if self.api is not None and enabled:
         return
     if enabled:
         self.api = QsciAPIs(self._lexer)
         if settings.get_setting('editor/completion-keywords'):
             for keyword in keywords.keywords:
                 self.api.add(keyword)
             self.api.prepare()
             source = QsciScintilla.AcsAPIs
             if settings.get_setting('editor/completion-document'):
                 source = QsciScintilla.AcsAll
         elif settings.get_setting('editor/completion-document'):
             source = QsciScintilla.AcsDocument
         else:
             source = QsciScintilla.AcsNone
         threshold = settings.get_setting('editor/completion-threshold')
         self.setAutoCompletionThreshold(threshold)
         self.setAutoCompletionSource(source)
         cs = settings.get_setting('editor/completion-cs')
         self.setAutoCompletionCaseSensitivity(cs)
         repl_word = settings.get_setting('editor/completion-replace-word')
         self.setAutoCompletionReplaceWord(repl_word)
         show_single = settings.get_setting('editor/completion-single')
         use_single = 2 if show_single else 0
         self.setAutoCompletionUseSingle(use_single)
     else:
         self.api = None
         self.setAutoCompletionSource(0)
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    def __init__(self, parent=None, line_num_margin=3, autocomplete_list=None):
        super(PythonEditor, self).__init__(parent, line_num_margin, autocomplete_list)

        # Set Python lexer
        self.lexer = QsciLexerPython(self)
        self.lexer.setDefaultFont(self.editor_font)
        self.lexer.setFont(self.editor_font, QsciLexerPython.Comment)
        # Indentation warning ("The indentation is inconsistent when compared to the previous line")
        self.lexer.setIndentationWarning(QsciLexerPython.Inconsistent)
        # Set auto-completion
        self.api = QsciAPIs(self.lexer)
        if autocomplete_list is not None:
            # Add additional completion strings
            for i in autocomplete_list:
                self.api.add(i)
        self.api.prepare()
        self.setAutoCompletionThreshold(3)
        self.setAutoCompletionSource(QsciScintilla.AcsAll)
        self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit)
        self.setLexer(self.lexer)

        # PEP8 tabs
        self.setIndentationsUseTabs(False)
        self.setAutoIndent(True)
        self.setIndentationGuides(True)
        
        # PEP8 edge column line
        self.edgecol = 80

        # Linters
        self.linter = 'internal'
Ejemplo n.º 16
0
 def __init__(self, language, forPreparation = False, parent = None):
     """
     Constructor
     
     @param language language of the APIs object (string)
     @param forPreparation flag indicating this object is just needed
         for a preparation process (boolean)
     @param parent reference to the parent object (QObject)
     """
     QObject.__init__(self, parent)
     self.setObjectName("APIs_%s" % language)
     
     self.__inPreparation = False
     self.__language = language
     self.__forPreparation = forPreparation
     self.__lexer = Lexers.getLexer(self.__language)
     self.__apifiles = Preferences.getEditorAPI(self.__language)
     self.__apifiles.sort()
     if self.__lexer is None:
         self.__apis = None
     else:
         self.__apis = QsciAPIs(self.__lexer)
         self.connect(self.__apis, SIGNAL("apiPreparationFinished()"),
                      self.__apiPreparationFinished)
         self.connect(self.__apis, SIGNAL("apiPreparationCancelled()"),
                      self.__apiPreparationCancelled)
         self.connect(self.__apis, SIGNAL("apiPreparationStarted()"),
                      self.__apiPreparationStarted)
         self.__loadAPIs()
Ejemplo n.º 17
0
    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.setDefaultFont(QFont('Mono', 10, 0, False))
            # self.lexer.setDefaultColor(Qt.darkGray)
            self.lexer.setColor(Qt.red, 1)
            self.lexer.setColor(Qt.darkGreen, 5)
            self.lexer.setColor(Qt.darkBlue, 15)
            self.lexer.setFont(font, 1)
            self.lexer.setFont(font, 3)
            self.lexer.setFont(font, 4)
            self.api = QsciAPIs(self.lexer)
            self.api.loadPrepared(QString(os.path.dirname(__file__) + "/api/pyqgis_master.pap"))
            #            self.api.load(os.path.dirname(__file__) + "/api/PyQGIS_1.8.api")
            #            self.api.load(os.path.dirname(__file__) + "/api/osgeo_gdal-ogr_1.9.1-1.api")
            #            self.api.load("qgis.networkanalysis.api")
            #            self.api.load("qgis.gui.api")
            #            self.api.load("qgis.core.api")
            #            self.api.load("qgis.analysis.api")

            #            self.api.prepare()
            #            self.lexer.setAPIs(self.api)
            self.setLexer(self.lexer)
Ejemplo n.º 18
0
    def setLexers(self, lexer):
        from qgis.core import QgsApplication
        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( QgsApplication.pkgDataPath() + "/python/qsci_apis/pyqgis_master.pap" )

            self.setLexer(self.lexer)
Ejemplo n.º 19
0
 def init(self):
     self.setCaretLineBackgroundColor(self.colorStyle.caret)
     self.setMarginsBackgroundColor(self.colorStyle.margin)
     self.setMarkerBackgroundColor(self.colorStyle.marker,self.ARROW_MARKER_NUM)
     self.font = QFont()
     self.font.setFamily(fontName)
     #self.font.setFixedPitch(True)
     self.font.setPointSize(self.fontSize)
     self.setFont(self.font)
     self.fontmetrics = QFontMetrics(self.font)
     self.setMarginsFont(self.font)
     # Margin 0 is used for line numbers
     #self.setMarginLineNumbers(0, True)
     #self.setMarginWidth(0, self.fontmetrics.width("0000") + 6)
     self.setMarginLineNumbers(1, True)
     self.setMarginWidth(1, QString("-------"))
     self.setCaretLineVisible(True)
     if self.lang == 0:
         self.lexer = QsciLexerPython()
     elif self.lang == 1:
         self.lexer = QsciLexerCPP()
     elif self.lang == 2:
         self.lexer = LexerSquirrel(self.colorStyle,self)
     self.lexer.setDefaultFont(self.font)
     self.api = QsciAPIs(self.lexer)
     self.api.load(ospathjoin(apiDir,"emo.api"))
     self.api.prepare()
     self.lexer.setAPIs(self.api) #Very important do not change line otherwise gg
     self.setLexer(self.lexer) #Very important do not change line otherwise gg
Ejemplo n.º 20
0
 def setup_api(self):
     """Load and prepare Python API"""
     if self.lexer() is None:
         return
     self.api = QsciAPIs(self.lexer())
     is_api_ready = False
     api_path = CONF.get('editor', 'api')
     if not osp.isfile(api_path):
         from spyderlib.config import DATA_PATH
         api_path = osp.join(DATA_PATH, 'python.api')
         if osp.isfile(api_path):
             CONF.set('editor', 'api', api_path)
         else:
             return False
     api_size = CONF.get('editor', 'api_size', None)
     current_api_size = os.stat(api_path).st_size
     if api_size is not None and api_size == current_api_size:
         if self.api.isPrepared():
             is_api_ready = self.api.loadPrepared()
     else:
         CONF.set('editor', 'api_size', current_api_size)
     if not is_api_ready:
         if self.api.load(api_path):
             self.api.prepare()
             self.connect(self.api, SIGNAL("apiPreparationFinished()"),
                          self.api.savePrepared)
     return is_api_ready
Ejemplo n.º 21
0
class CSSEditor(BaseEditor):
    def __init__(self, parent=None, line_num_margin=3, autocomplete_list=None):
        super(CSSEditor, self).__init__(parent, line_num_margin, autocomplete_list)

        # Set HTML lexer
        self.lexer = QsciLexerCSS(self)
        self.lexer.setDefaultFont(self.editor_font)
        # Set auto-completion
        self.api = QsciAPIs(self.lexer)
        if autocomplete_list is not None:
            # Add additional completion strings
            for i in autocomplete_list:
                self.api.add(i)
        self.api.prepare()
        self.setAutoCompletionThreshold(3)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setLexer(self.lexer)
Ejemplo n.º 22
0
 def setApi(self, text):
     self.api = QsciAPIs(self.lexer)
     self.api.load(ospathjoin(apiDir,text+".api"))
     self.api.prepare()
     self.lexer.setAPIs(self.api) #Very important do not change line otherwise gg
     self.setLexer(self.lexer) #Very important do not change line otherwise gg
     editStyle = config.readStyle()
     self.setMarginsBackgroundColor(QColor(editStyle["margin"]))
     '''This is done cause the margin color is set only when lexer is set 
Ejemplo n.º 23
0
 def prepareAPI(self):
     try:
         self._api = QsciAPIs(self._api_lexer)
         self._api.apiPreparationFinished.connect(self._preparationFinished)
         for api_file in self._api_files:
             self._api.load(unicode(api_file))
         self._api.prepare()
     except Exception as err:
         self._api = None
         sys.exit(1)
Ejemplo n.º 24
0
class HTMLEditor(BaseEditor):
    def __init__(self, parent=None, line_num_margin=3, autocomplete_list=None):
        super(HTMLEditor, self).__init__(parent, line_num_margin, autocomplete_list)

        # Set HTML lexer
        self.lexer = QsciLexerHTML(self)
        self.lexer.setDefaultFont(self.editor_font)
        self.lexer.setFont(self.editor_font, QsciLexerHTML.Default)  # Text between tags
        self.lexer.setFont(self.editor_font, QsciLexerHTML.JavaScriptWord)  # Text between script tags
        # Set auto-completion
        self.api = QsciAPIs(self.lexer)
        if autocomplete_list is not None:
            # Add additional completion strings
            for i in autocomplete_list:
                self.api.add(i)
        self.api.prepare()
        self.setAutoCompletionThreshold(3)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit)
        self.setLexer(self.lexer)
Ejemplo n.º 25
0
    def __init__(self, parent=None):
        QsciScintilla.__init__(self, parent)
        self.setTabWidth(4)
        self.setTabIndents(True)
        self.setIndentationsUseTabs(False)

        self._lexer = QsciLexerPython()
        self._lexer.setFont(QFont('DejaVu Sans Mono'))
        self._lexer.setIndentationWarning(QsciLexerPython.Tabs)

        # load current preview to lexer
        api = QsciAPIs(self._lexer)
        api.load('/tmp/preview.py')
        api.prepare()

        self.setLexer(self._lexer)
        self.setAutoCompletionSource(QsciScintilla.AcsAll)
        self.setAutoCompletionThreshold(2)
        self.setAutoIndent(True)
        self.setCaretForegroundColor(g.cursor_color)
        self.zoomTo(5)
Ejemplo n.º 26
0
    def initLexer(self):
        if self.lexerType == self.LEXER_PYTHON:
            self.lexer = QsciLexerPython()

            colorDefault = QColor('#2e3436')
            colorComment = QColor('#c00')
            colorCommentBlock = QColor('#3465a4')
            colorNumber = QColor('#4e9a06')
            colorType = QColor('#4e9a06')
            colorKeyword = QColor('#204a87')
            colorString = QColor('#ce5c00')

            self.lexer.setDefaultFont(self.defaultFont)
            self.lexer.setDefaultColor(colorDefault)

            self.lexer.setColor(colorComment, 1)
            self.lexer.setColor(colorNumber, 2)
            self.lexer.setColor(colorString, 3)
            self.lexer.setColor(colorString, 4)
            self.lexer.setColor(colorKeyword, 5)
            self.lexer.setColor(colorString, 6)
            self.lexer.setColor(colorString, 7)
            self.lexer.setColor(colorType, 8)
            self.lexer.setColor(colorCommentBlock, 12)
            self.lexer.setColor(colorString, 15)

            self.lexer.setFont(self.italicFont, 1)
            self.lexer.setFont(self.boldFont, 5)
            self.lexer.setFont(self.boldFont, 8)
            self.lexer.setFont(self.italicFont, 12)

            self.api = QsciAPIs(self.lexer)

            settings = QSettings()
            useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI',
                                                True))
            if useDefaultAPI:
                # Load QGIS API shipped with Python console
                self.api.loadPrepared(
                    os.path.join(QgsApplication.pkgDataPath(),
                                 'python', 'qsci_apis', 'pyqgis.pap'))
            else:
                # Load user-defined API files
                apiPaths = settings.value('pythonConsole/userAPI', [])
                for path in apiPaths:
                    self.api.load(path)
                self.api.prepare()
                self.lexer.setAPIs(self.api)
        elif self.lexerType == self.LEXER_R:
            # R lexer
            self.lexer = LexerR()

        self.setLexer(self.lexer)
Ejemplo n.º 27
0
class PrepareAPIs(QObject):

    def __init__(self, api_lexer, api_files, pap_file):
        QObject.__init__(self)
        self._api = None
        self._api_files = api_files
        self._api_lexer = api_lexer
        self._pap_file = pap_file

    def _clearLexer(self):
        self.qlexer = None

    def _stopPreparation(self):
        if self._api is not None:
            self._api.cancelPreparation()
        self._api = None
        sys.exit(1)

    def _preparationFinished(self):
        self._clearLexer()
        try:
            if os.path.exists(self._pap_file):
                os.remove(self._pap_file)
            prepd = self._api.savePrepared(unicode(self._pap_file))
            self._api = None
            sys.exit(0 if prepd else 1)
        except Exception as err:
            self._api = None
            sys.exit(1)

    def prepareAPI(self):
        try:
            self._api = QsciAPIs(self._api_lexer)
            self._api.apiPreparationFinished.connect(self._preparationFinished)
            for api_file in self._api_files:
                self._api.load(unicode(api_file))
            self._api.prepare()
        except Exception as err:
            self._api = None
            sys.exit(1)
Ejemplo n.º 28
0
class PrepareAPIs(QObject):
    def __init__(self, api_lexer, api_files, pap_file):
        QObject.__init__(self)
        self._api = None
        self._api_files = api_files
        self._api_lexer = api_lexer
        self._pap_file = pap_file

    def _clearLexer(self):
        self.qlexer = None

    def _stopPreparation(self):
        if self._api is not None:
            self._api.cancelPreparation()
        self._api = None
        sys.exit(1)

    def _preparationFinished(self):
        self._clearLexer()
        try:
            if os.path.exists(self._pap_file):
                os.remove(self._pap_file)
            prepd = self._api.savePrepared(unicode(self._pap_file))
            self._api = None
            sys.exit(0 if prepd else 1)
        except Exception as err:
            self._api = None
            sys.exit(1)

    def prepareAPI(self):
        try:
            self._api = QsciAPIs(self._api_lexer)
            self._api.apiPreparationFinished.connect(self._preparationFinished)
            for api_file in self._api_files:
                self._api.load(unicode(api_file))
            self._api.prepare()
        except Exception as err:
            self._api = None
            sys.exit(1)
Ejemplo n.º 29
0
 def setup_api(self):
     """Load and prepare API"""
     if self.lexer() is None:
         return
     self.api = QsciAPIs(self.lexer())
     is_api_ready = False
     api_path = CONF.get('editor', 'api')
     if not os.path.isfile(api_path):
         return False
     api_stat = CONF.get('editor', 'api_stat', None)
     current_api_stat = os.stat(api_path)
     if (api_stat is not None) and (api_stat == current_api_stat):
         if self.api.isPrepared():
             is_api_ready = self.api.loadPrepared()
     else:
         CONF.set('editor', 'api_stat', current_api_stat)
     if not is_api_ready:
         if self.api.load(api_path):
             self.api.prepare()
             self.connect(self.api, SIGNAL("apiPreparationFinished()"),
                          self.api.savePrepared)
     return is_api_ready
 def prepareAPI(self):
     # self.ui.textEdit_Qsci.setLexer(0)
     exec u'self.qlexer = {0}(self.ui.textEdit_Qsci)'.format(
         self._api_lexer)
     # self.ui.textEdit_Qsci.setLexer(self.qlexer)
     self._api = QsciAPIs(self.qlexer)
     self._api.apiPreparationFinished.connect(self._preparationFinished)
     for api_file in self._api_files:
         self._api.load(unicode(api_file))
     try:
         self._api.prepare()
     except Exception, err:
         self._api = None
         self._clearLexer()
         self.ui.label.setText(
             QCoreApplication.translate("PythonConsole",
                                        "Error preparing file..."))
         self.ui.progressBar.setVisible(False)
         self.ui.plainTextEdit.setVisible(True)
         self.ui.plainTextEdit.insertPlainText(err)
         self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(
             self.trUtf8("Done"))
         self.adjustSize()
Ejemplo n.º 31
0
 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)
Ejemplo n.º 32
0
    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.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, type=bool)
        chekBoxPreparedAPI = self.settings.value("pythonConsole/usePreparedAPIFile", False, type=bool)
        if chekBoxAPI:
            apisdir = os.path.join(QgsApplication.pkgDataPath(), "python", "qsci_apis")
            pap = os.path.join(apisdir, "pyqgis.pap")
            mpap = os.path.join(apisdir, "pyqgis-master.pap")
            if os.path.exists(mpap):  # override installed with master .pap build
                pap = mpap
            if QgsApplication.isRunningFromBuildDir():
                bdir = os.path.dirname(QgsApplication.buildOutputPath())
                bpap = os.path.join(bdir, "python", "qsci_apis", "pyqgis-master.pap")
                if os.path.exists(bpap):
                    # if not generated .pap exists, else fall back to preprepared one
                    pap = bpap
            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)
Ejemplo n.º 33
0
 def prepareAPI(self):
     # self.ui.textEdit_Qsci.setLexer(0)
     exec(u"self.qlexer = {0}(self.ui.textEdit_Qsci)".format(self._api_lexer))
     # self.ui.textEdit_Qsci.setLexer(self.qlexer)
     self._api = QsciAPIs(self.qlexer)
     self._api.apiPreparationFinished.connect(self._preparationFinished)
     for api_file in self._api_files:
         self._api.load(unicode(api_file))
     try:
         self._api.prepare()
     except Exception as err:
         self._api = None
         self._clearLexer()
         self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Error preparing file..."))
         self.ui.progressBar.setVisible(False)
         self.ui.plainTextEdit.setVisible(True)
         self.ui.plainTextEdit.insertPlainText(err)
         self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(self.trUtf8("Done"))
         self.adjustSize()
Ejemplo n.º 34
0
 def __init__(self, parent=None):
     super(CommandShell, self).__init__(parent)
     self.setMinimumHeight(50)
     self.setMaximumHeight(50)
     self.settings = QSettings()
     self.lex = QsciLexerPython(self)
     self.apis = QsciAPIs(self.lex)
     self.lex.setAPIs(self.apis)
     self.setLexers()
     self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
     self.SendScintilla(QsciScintilla.SCI_SETVSCROLLBAR, 0)
     self.setFolding(0)
     self._start_prompt = _start_prompt
     self.prompt = self._start_prompt
     self.currentfunction = None
     self.setAutoCompletionSource(self.AcsAPIs)
     self.setAutoCompletionThreshold(1)
     self.setAutoCompletionReplaceWord(True)
     self.setCallTipsStyle(QsciScintilla.CallTipsNoContext)
     self.parent().installEventFilter(self)
     self.textChanged.connect(self.text_changed)
     self._lastcompletions = None
Ejemplo n.º 35
0
    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.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, 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)
Ejemplo n.º 36
0
 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)
  def initCompleter(self):
    dictionary = None
    if self.db:
        dictionary = self.db.connector.getSqlDictionary()
    if not dictionary:
        # use the generic sql dictionary
        from .sql_dictionary import getSqlDictionary
        dictionary = getSqlDictionary()

    wordlist = []
    for name, value in dictionary.iteritems():
        wordlist += value   # concat lists
    wordlist = list(set(wordlist))  # remove duplicates

    api = QsciAPIs(self.editSql.lexer())
    for word in wordlist:
        api.add(word)

    api.prepare()
    self.editSql.lexer().setAPIs(api)
Ejemplo n.º 38
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')
Ejemplo n.º 39
0
class QsciEditor(TextEditBaseWidget):
    """
    QScintilla Base Editor Widget
    """
    LEXERS = {
              ('py', 'pyw', 'python'): (QsciLexerPython, '#'),
              ('f', 'for'): (QsciLexerFortran77, 'c'),
              ('f90', 'f95', 'f2k'): (QsciLexerFortran, '!'),
              ('diff', 'patch', 'rej'): (QsciLexerDiff, ''),
              'css': (QsciLexerCSS, '#'),
              ('htm', 'html'): (QsciLexerHTML, ''),
              ('c', 'cpp', 'h'): (QsciLexerCPP, '//'),
              ('bat', 'cmd', 'nt'): (QsciLexerBatch, 'rem '),
              ('properties', 'session', 'ini', 'inf', 'reg', 'url',
               'cfg', 'cnf', 'aut', 'iss'): (QsciLexerProperties, '#'),
              }
    TAB_ALWAYS_INDENTS = ('py', 'pyw', 'python', 'c', 'cpp', 'h')
    OCCURENCE_INDICATOR = QsciScintilla.INDIC_CONTAINER
    EOL_MODES = {"\r\n": QsciScintilla.EolWindows,
                 "\n":   QsciScintilla.EolUnix,
                 "\r":   QsciScintilla.EolMac}
    
    def __init__(self, parent=None):
        TextEditBaseWidget.__init__(self, parent)
                    
        # Indicate occurences of the selected word
        self.connect(self, SIGNAL('cursorPositionChanged(int, int)'),
                     self.__cursor_position_changed)
        self.__find_start = None
        self.__find_end = None
        self.__find_flags = None
        self.SendScintilla(QsciScintilla.SCI_INDICSETSTYLE,
                           self.OCCURENCE_INDICATOR,
                           QsciScintilla.INDIC_BOX)
        self.SendScintilla(QsciScintilla.SCI_INDICSETFORE,
                           self.OCCURENCE_INDICATOR,
                           0x4400FF)

        self.supported_language = None
        self.comment_string = None

        # Mark errors, warnings, ...
        self.markers = []
        self.marker_lines = {}
        self.error = self.markerDefine(QPixmap(get_image_path('error.png'),
                                               'png'))
        self.warning = self.markerDefine(QPixmap(get_image_path('warning.png'),
                                                 'png'))
            
        # Scintilla Python API
        self.api = None
        
        # Mark occurences timer
        self.occurences_timer = QTimer(self)
        self.occurences_timer.setSingleShot(True)
        self.occurences_timer.setInterval(750)
        self.connect(self.occurences_timer, SIGNAL("timeout()"), 
                     self.__mark_occurences)
        
        # Context menu
        self.setup_context_menu()
        
        # Tab key behavior
        self.tab_indents = None
        self.tab_mode = True # see QsciEditor.set_tab_mode
        
    def setup_editor(self, linenumbers=True, language=None,
                     code_analysis=False, code_folding=False,
                     show_eol_chars=False, show_whitespace=False,
                     font=None, wrap=True, tab_mode=True):
        # Lexer
        self.set_language(language)
                
        # Tab always indents (even when cursor is not at the begin of line)
        self.tab_indents = language in self.TAB_ALWAYS_INDENTS
        self.tab_mode = tab_mode
        
        if linenumbers:
            self.connect( self, SIGNAL('linesChanged()'), self.__lines_changed )
        self.setup_margins(linenumbers, code_analysis, code_folding)

        if font is not None:
            self.set_font(font)
             
        # Re-enable brace matching (already enabled in TextEditBaseWidget.setup
        # but for an unknown reason, changing the 'set_font' call above reset
        # this setting to default, which is no brace matching):
        # XXX: find out why
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        self.setMatchedBraceBackgroundColor(Qt.yellow)
        
        self.set_eol_chars_visible(show_eol_chars)
        self.set_whitespace_visible(show_whitespace)
        
        self.toggle_wrap_mode(wrap)
        self.setup_api()
        self.setModified(False)
        
    def set_tab_mode(self, enable):
        """
        enabled = tab always indent
        (otherwise tab indents only when cursor is at the beginning of a line)
        """
        self.tab_mode = enable
        
    def set_language(self, language):
        self.supported_language = False
        self.comment_string = ''
        if language is not None:
            for key in self.LEXERS:
                if language.lower() in key:
                    self.supported_language = True
                    lexer_class, comment_string = self.LEXERS[key]
                    self.comment_string = comment_string
                    if lexer_class is not None:
                        # Fortran lexers are sometimes unavailable:
                        # the corresponding class is then replaced by None
                        # (see the import lines at the beginning of the script)
                        self.setLexer( lexer_class(self) )
                    break
                
    def is_python(self):
        return isinstance(self.lexer(), QsciLexerPython)
        
        
#===============================================================================
#    QScintilla
#===============================================================================
    def setup(self):
        """Reimplement TextEditBaseWidget method"""
        TextEditBaseWidget.setup(self)
        
        # Wrapping
        if CONF.get('editor', 'wrapflag'):
            self.setWrapVisualFlags(QsciScintilla.WrapFlagByBorder)
        
        # Indentation
        self.setIndentationGuides(True)
        self.setIndentationGuidesForegroundColor(Qt.lightGray)
        
        # 80-columns edge
        self.setEdgeColumn(80)
        self.setEdgeMode(QsciScintilla.EdgeLine)
        
        # Auto-completion
        self.setAutoCompletionSource(QsciScintilla.AcsAll)

    def setup_margins(self, linenumbers=True,
                      code_analysis=False, code_folding=False):
        """
        Setup margin settings
        (except font, now set in self.set_font)
        """
        for i_margin in range(5):
            # Reset margin settings
            self.setMarginWidth(i_margin, 0)
            self.setMarginLineNumbers(i_margin, False)
            self.setMarginMarkerMask(i_margin, 0)
            self.setMarginSensitivity(i_margin, False)
        if linenumbers:
            # 1: Line numbers margin
            self.setMarginLineNumbers(1, True)
            self.update_line_numbers_margin()
            if code_analysis:
                # 2: Errors/warnings margin
                mask = (1 << self.error) | (1 << self.warning)
                self.setMarginSensitivity(0, True)
                self.setMarginMarkerMask(0, mask)
                self.setMarginWidth(0, 14)
                self.connect(self,
                     SIGNAL('marginClicked(int,int,Qt::KeyboardModifiers)'),
                     self.__margin_clicked)
        if code_folding:
            # 0: Folding margin
            self.setMarginWidth(2, 14)
            self.setFolding(QsciScintilla.BoxedFoldStyle)                
        # Colors
        fcol = CONF.get('scintilla', 'margins/foregroundcolor')
        bcol = CONF.get('scintilla', 'margins/backgroundcolor')
        if fcol:
            self.setMarginsForegroundColor(QColor(fcol))
        if bcol:
            self.setMarginsBackgroundColor(QColor(bcol))
        fcol = CONF.get('scintilla', 'foldmarginpattern/foregroundcolor')
        bcol = CONF.get('scintilla', 'foldmarginpattern/backgroundcolor')
        if fcol and bcol:
            self.setFoldMarginColors(QColor(fcol), QColor(bcol))
        
    def setup_api(self):
        """Load and prepare API"""
        if self.lexer() is None:
            return
        self.api = QsciAPIs(self.lexer())
        is_api_ready = False
        api_path = CONF.get('editor', 'api')
        if not os.path.isfile(api_path):
            return False
        api_stat = CONF.get('editor', 'api_stat', None)
        current_api_stat = os.stat(api_path)
        if (api_stat is not None) and (api_stat == current_api_stat):
            if self.api.isPrepared():
                is_api_ready = self.api.loadPrepared()
        else:
            CONF.set('editor', 'api_stat', current_api_stat)
        if not is_api_ready:
            if self.api.load(api_path):
                self.api.prepare()
                self.connect(self.api, SIGNAL("apiPreparationFinished()"),
                             self.api.savePrepared)
        return is_api_ready
    
    def set_whitespace_visible(self, state):
        """Show/hide whitespace"""
        if state:
            self.setWhitespaceVisibility(QsciScintilla.WsVisible)
        else:
            self.setWhitespaceVisibility(QsciScintilla.WsInvisible)
    
    def set_eol_chars_visible(self, state):
        """Show/hide EOL characters"""
        self.setEolVisibility(state)
    
    def convert_eol_chars(self):
        """Convert EOL characters to current mode"""
        self.convertEols(self.eolMode())
        
    def remove_trailing_spaces(self):
        """Remove trailing spaces"""
        text_before = unicode(self.text())
        text_after = sourcecode.remove_trailing_spaces(text_before)
        if text_before != text_after:
            self.setText(text_after)
            
    def fix_indentation(self):
        """Replace tabs by spaces"""
        text_before = unicode(self.text())
        text_after = sourcecode.fix_indentation(text_before)
        if text_before != text_after:
            self.setText(text_after)
    
    def set_eol_mode(self, text):
        """
        Set QScintilla widget EOL mode based on *text* EOL characters
        """
        if isinstance(text, QString):
            text = unicode(text)
        eol_chars = sourcecode.get_eol_chars(text)
        if eol_chars is not None:
            self.setEolMode(self.EOL_MODES[eol_chars])
        
    def get_line_separator(self):
        """Return line separator based on current EOL mode"""
        current_mode = self.eolMode()
        for eol_chars, mode in self.EOL_MODES.iteritems():
            if current_mode == mode:
                return eol_chars
        else:
            return ''
    
    def __find_first(self, text):
        """Find first occurence"""
        self.__find_flags = QsciScintilla.SCFIND_MATCHCASE | \
                            QsciScintilla.SCFIND_WHOLEWORD
        self.__find_start = 0
        line = self.lines()-1
        self.__find_end = self.position_from_lineindex(line,
                                                       self.text(line).length())
        return self.__find_next(text)
    
    def __find_next(self, text):
        """Find next occurence"""
        if self.__find_start == self.__find_end:
            return False
        
        self.SendScintilla(QsciScintilla.SCI_SETTARGETSTART,
                           self.__find_start)
        self.SendScintilla(QsciScintilla.SCI_SETTARGETEND,
                           self.__find_end)
        self.SendScintilla(QsciScintilla.SCI_SETSEARCHFLAGS,
                           self.__find_flags)
        pos = self.SendScintilla(QsciScintilla.SCI_SEARCHINTARGET, 
                                 len(text), text)
        
        if pos == -1:
            return False
        self.__find_start = self.SendScintilla(QsciScintilla.SCI_GETTARGETEND)
        return True
        
    def __get_found_occurence(self):
        """Return found occurence"""
        spos = self.SendScintilla(QsciScintilla.SCI_GETTARGETSTART)
        epos = self.SendScintilla(QsciScintilla.SCI_GETTARGETEND)
        return (spos, epos - spos)
        
    def __cursor_position_changed(self):
        """Cursor position has changed"""
        #TODO: Add attribute for occurences marking enable/disable:
        # if self.occurences_marking:
        self.occurences_timer.stop()
        self.occurences_timer.start()
        
    def __mark_occurences(self):
        """Marking occurences of the currently selected word"""
        self.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT,
                           self.OCCURENCE_INDICATOR)
        self.SendScintilla(QsciScintilla.SCI_INDICATORCLEARRANGE,
                           0, self.length())

        if not self.supported_language:
            return
            
        text = self.get_current_word()
        if text.isEmpty():
            return

        # Highlighting all occurences of word *text*
        ok = self.__find_first(text)
        while ok:
            spos = self.SendScintilla(QsciScintilla.SCI_GETTARGETSTART)
            epos = self.SendScintilla(QsciScintilla.SCI_GETTARGETEND)
            self.SendScintilla(QsciScintilla.SCI_INDICATORFILLRANGE,
                               spos, epos-spos)
            ok = self.__find_next(text)
        
    def __lines_changed(self):
        """Update margin"""
        self.update_line_numbers_margin()
        
    def update_line_numbers_margin(self):
        """Update margin width"""
        width = log(self.lines(), 10) + 2
        self.setMarginWidth(1, QString('0'*int(width)))

    def delete(self):
        """Remove selected text"""
        # Used by global callbacks in Spyder -> delete_action
        QsciScintilla.removeSelectedText(self)

    def set_font(self, font):
        """Set shell font"""
        if self.lexer() is None:
            self.setFont(font)
        else:
            self.lexer().setFont(font)
            self.setLexer(self.lexer())
        self.setMarginsFont(font)
        
    def set_text(self, text):
        """Set the text of the editor"""
        self.setText(text)
        self.set_eol_mode(text)

    def get_text(self):
        """Return editor text"""
        return self.text()
    
    def paste(self):
        """
        Reimplement QsciScintilla's method to fix the following issue:
        on Windows, pasted text has only 'LF' EOL chars even if the original
        text has 'CRLF' EOL chars
        """
        clipboard = QApplication.clipboard()
        text = unicode(clipboard.text())
        if len(text.splitlines()) > 1:
            eol_chars = self.get_line_separator()
            clipboard.setText( eol_chars.join((text+eol_chars).splitlines()) )
        # Standard paste
        TextEditBaseWidget.paste(self)
        
    def fold_header(self, line):
        """Is it a fold header line?"""
        lvl = self.SendScintilla(QsciScintilla.SCI_GETFOLDLEVEL, line)
        return lvl & QsciScintilla.SC_FOLDLEVELHEADERFLAG
    
    def fold_expanded(self, line):
        """Is fold expanded?"""
        return self.SendScintilla(QsciScintilla.SCI_GETFOLDEXPANDED, line)
        
    def get_folded_lines(self):
        """Return the list of folded line numbers"""
        return [line for line in xrange(self.lines()) \
                if self.fold_header(line) and not self.fold_expanded(line) ]
        
    def unfold_all(self):
        """Unfold all folded lines"""
        for line in self.get_folded_lines():
            self.foldLine(line)
        
        
#===============================================================================
#    High-level editor features
#===============================================================================
    def highlight_line(self, line):
        """Highlight line number *line*"""
        text = unicode(self.text(line-1)).rstrip()
        self.setSelection(line-1, len(text), line-1, 0)
        self.ensureLineVisible(line-1)

    def cleanup_code_analysis(self):
        """Remove all code analysis markers"""
        for marker in self.markers:
            self.markerDeleteHandle(marker)
        self.markers = []
        self.marker_lines = {}
        
    def process_code_analysis(self, check_results):
        """Analyze filename code with pyflakes"""
        self.cleanup_code_analysis()
        if check_results is None:
            # Not able to compile module
            return
        for message, line0, error in check_results:
            line1 = line0 - 1
            marker = self.markerAdd(line1, 0 if error else 1)
            self.markers.append(marker)
            if line1 not in self.marker_lines:
                self.marker_lines[line1] = []
            self.marker_lines[line1].append( (message, error) )

    def __highlight_warning(self, line):
        self.highlight_line(line+1)
        self.__show_code_analysis_results(line)

    def go_to_next_warning(self):
        """Go to next code analysis warning message"""
        cline, _ = self.getCursorPosition()
        lines = sorted(self.marker_lines.keys())
        for line in lines:
            if line > cline:
                self.__highlight_warning(line)
                return
        else:
            self.__highlight_warning(lines[0])

    def go_to_previous_warning(self):
        """Go to previous code analysis warning message"""
        cline, _ = self.getCursorPosition()
        lines = sorted(self.marker_lines.keys(), reverse=True)
        for line in lines:
            if line < cline:
                self.__highlight_warning(line)
                return
        else:
            self.__highlight_warning(lines[0])

    def __show_code_analysis_results(self, line):
        """Show warning/error messages"""
        if line in self.marker_lines:
            msglist = [ msg for msg, _error in self.marker_lines[line] ]
            self.show_calltip(self.tr("Code analysis"), msglist,
                              color='#129625', at_line=line)
    
    def __margin_clicked(self, margin, line, modifier):
        """Margin was clicked, that's for sure!"""
        if margin == 0:
            self.__show_code_analysis_results(line)

    def mouseMoveEvent(self, event):
        line = self.get_line_number_at(event.pos())
        self.__show_code_analysis_results(line)
        QsciScintilla.mouseMoveEvent(self, event)
        
    def add_prefix(self, prefix):
        """Add prefix to current line or selected line(s)"""        
        if self.hasSelectedText():
            # Add prefix to selected line(s)
            line_from, index_from, line_to, index_to = self.getSelection()
            if index_to == 0:
                line_to -= 1
            self.beginUndoAction()
            for line in range(line_from, line_to+1):
                self.insertAt(prefix, line, 0)
            self.endUndoAction()
            if index_to == 0:
                line_to += 1
            else:
                index_to += len(prefix)
            self.setSelection(line_from, index_from+len(prefix),
                              line_to, index_to)
        else:
            # Add prefix to current line
            line, index = self.getCursorPosition()
            self.beginUndoAction()
            self.insertAt(prefix, line, 0)
            self.endUndoAction()
            self.setCursorPosition(line, index+len(prefix))
    
    def remove_prefix(self, prefix):
        """Remove prefix from current line or selected line(s)"""        
        if self.hasSelectedText():
            # Remove prefix from selected line(s)
            line_from, index_from, line_to, index_to = self.getSelection()
            if index_to == 0:
                line_to -= 1
            self.beginUndoAction()
            for line in range(line_from, line_to+1):
                if not self.text(line).startsWith(prefix):
                    continue
                self.setSelection(line, 0, line, len(prefix))
                self.removeSelectedText()
                if line == line_from:
                    index_from = max([0, index_from-len(prefix)])
                if line == line_to and index_to != 0:
                    index_to = max([0, index_to-len(prefix)])
            if index_to == 0:
                line_to += 1
            self.setSelection(line_from, index_from, line_to, index_to)
            self.endUndoAction()
        else:
            # Remove prefix from current line
            line, index = self.getCursorPosition()
            if not self.text(line).startsWith(prefix):
                return
            self.beginUndoAction()
            self.setSelection(line, 0, line, len(prefix))
            self.removeSelectedText()
            self.setCursorPosition(line, index-len(prefix))
            self.endUndoAction()
            self.setCursorPosition(line, max([0, index-len(prefix)]))
    
    def fix_indent(self, forward=True):
        """
        Fix indentation (Python only, no text selection)
        forward=True: fix indent only if text is not enough indented
                      (otherwise force indent)
        forward=False: fix indent only if text is too much indented
                       (otherwise force unindent)
        """
        if not self.is_python():
            return        
        line, index = self.getCursorPosition()
        prevtext = unicode(self.text(line-1)).rstrip()
        indent = self.indentation(line)
        correct_indent = self.indentation(line-1)
        if prevtext.endswith(':'):
            # Indent            
            correct_indent += 4
        elif prevtext.endswith('continue') or prevtext.endswith('break'):
            # Unindent
            correct_indent -= 4
        elif prevtext.endswith(','):
            rlmap = {")":"(", "]":"[", "}":"{"}
            for par in rlmap:
                i_right = prevtext.rfind(par)
                if i_right != -1:
                    prevtext = prevtext[:i_right]
                    i_left = prevtext.rfind(rlmap[par])
                    if i_left != -1:
                        prevtext = prevtext[:i_left]
                    else:
                        break
            else:
                prevexpr = re.split(r'\(|\{|\[', prevtext)[-1]
                correct_indent = len(prevtext)-len(prevexpr)
        if forward:
            if indent == correct_indent or indent > correct_indent:
                # Force indent
                correct_indent = indent + 4
        elif indent == correct_indent or indent < correct_indent:
            # Force unindent
            correct_indent = indent - 4
            
        if correct_indent >= 0:
            self.beginUndoAction()
            self.setSelection(line, 0, line, indent)
            self.removeSelectedText()
            if index > indent:
                index -= indent-correct_indent
            else:
                index = correct_indent
            self.insertAt(" "*correct_indent, line, 0)
            self.setCursorPosition(line, index)
            self.endUndoAction()
    
    def __no_char_before_cursor(self):
        line, index = self.getCursorPosition()
        self.setSelection(line, 0, line, index)
        selected_text = unicode(self.selectedText())
        self.clear_selection()
        return len(selected_text.strip()) == 0
    
    def indent(self):
        """Indent current line or selection"""
        if self.hasSelectedText():
            self.add_prefix( " "*4 )
        elif self.__no_char_before_cursor() or \
             (self.tab_indents and self.tab_mode):
            if self.is_python():
                self.fix_indent(forward=True)
            else:
                self.add_prefix( " "*4 )
        else:
            self.SendScintilla(QsciScintilla.SCI_TAB)
    
    def unindent(self):
        """Unindent current line or selection"""
        if self.hasSelectedText():
            self.remove_prefix( " "*4 )
        elif self.__no_char_before_cursor() or \
             (self.tab_indents and self.tab_mode):
            if self.is_python():
                self.fix_indent(forward=False)
            else:
                self.remove_prefix( " "*4 )
            
    def comment(self):
        """Comment current line or selection"""
        self.add_prefix(self.comment_string)

    def uncomment(self):
        """Uncomment current line or selection"""
        self.remove_prefix(self.comment_string)
    
    def blockcomment(self):
        """Block comment current line or selection"""
        comline = self.comment_string + '='*(80-len(self.comment_string)) \
                  + self.get_line_separator()
        if self.hasSelectedText():
            line_from, _index_from, line_to, _index_to = self.getSelection()
            lines = range(line_from, line_to+1)
        else:
            line, _index = self.getCursorPosition()
            lines = [line]
        self.beginUndoAction()
        self.insertAt( comline, lines[-1]+1, 0 )
        self.insertAt( comline, lines[0], 0 )
        for l in lines:
            self.insertAt( '# ', l+1, 0 )
        self.endUndoAction()
        self.setCursorPosition(lines[-1]+2, 80)

    def __is_comment_bar(self, line):
        comline = '#' + '='*79 + self.get_line_separator()
        self.setSelection(line, 0, line+1, 0)
        return unicode(self.selectedText()) == comline            
    
    def unblockcomment(self):
        """Un-block comment current line or selection"""
        line, index = self.getCursorPosition()
        self.setSelection(line, 0, line, 1)
        if unicode(self.selectedText()) != '#':
            self.setCursorPosition(line, index)
            return
        # Finding first comment bar
        line1 = line-1
        while line1 >= 0 and not self.__is_comment_bar(line1):
            line1 -= 1
        if not self.__is_comment_bar(line1):
            self.setCursorPosition(line, index)
            return
        # Finding second comment bar
        line2 = line+1
        while line2 < self.lines() and not self.__is_comment_bar(line2):
            line2 += 1
        if not self.__is_comment_bar(line2) or line2 > self.lines()-2:
            self.setCursorPosition(line, index)
            return
        lines = range(line1+1, line2)
        self.beginUndoAction()
        self.setSelection(line2, 0, line2+1, 0)
        self.removeSelectedText()
        for l in lines:
            self.setSelection(l, 0, l, 2)
            self.removeSelectedText()
        self.setSelection(line1, 0, line1+1, 0)
        self.removeSelectedText()
        self.endUndoAction()
    
#===============================================================================
#    Qt Event handlers
#===============================================================================
    def setup_context_menu(self):
        """Setup context menu"""
        self.undo_action = create_action(self,
                           translate("SimpleEditor", "Undo"),
                           shortcut=keybinding('Undo'),
                           icon=get_icon('undo.png'), triggered=self.undo)
        self.redo_action = create_action(self,
                           translate("SimpleEditor", "Redo"),
                           shortcut=keybinding('Redo'),
                           icon=get_icon('redo.png'), triggered=self.redo)
        self.cut_action = create_action(self,
                           translate("SimpleEditor", "Cut"),
                           shortcut=keybinding('Cut'),
                           icon=get_icon('editcut.png'), triggered=self.cut)
        self.copy_action = create_action(self,
                           translate("SimpleEditor", "Copy"),
                           shortcut=keybinding('Copy'),
                           icon=get_icon('editcopy.png'), triggered=self.copy)
        paste_action = create_action(self,
                           translate("SimpleEditor", "Paste"),
                           shortcut=keybinding('Paste'),
                           icon=get_icon('editpaste.png'), triggered=self.paste)
        self.delete_action = create_action(self,
                           translate("SimpleEditor", "Delete"),
                           shortcut=keybinding('Delete'),
                           icon=get_icon('editdelete.png'),
                           triggered=self.removeSelectedText)
        selectall_action = create_action(self,
                           translate("SimpleEditor", "Select all"),
                           shortcut=keybinding('SelectAll'),
                           icon=get_icon('selectall.png'),
                           triggered=self.selectAll)
        self.menu = QMenu(self)
        add_actions(self.menu, (self.undo_action, self.redo_action, None,
                                self.cut_action, self.copy_action,
                                paste_action, self.delete_action,
                                None, selectall_action))        
        # Read-only context-menu
        self.readonly_menu = QMenu(self)
        add_actions(self.readonly_menu,
                    (self.copy_action, None, selectall_action))        
            
    def keyPressEvent(self, event):
        """Reimplement Qt method"""
        key = event.key()
        ctrl = event.modifiers() & Qt.ControlModifier
        shift = event.modifiers() & Qt.ShiftModifier
        # Zoom in/out
        if ((key == Qt.Key_Plus) and ctrl) \
             or ((key==Qt.Key_Equal) and shift and ctrl):
            self.zoomIn()
            event.accept()
        elif (key == Qt.Key_Minus) and ctrl:
            self.zoomOut()
            event.accept()
        # Indent/unindent
        elif key == Qt.Key_Backtab:
            self.unindent()
            event.accept()
        elif (key == Qt.Key_Tab):
            if self.is_completion_widget_visible():
                self.SendScintilla(QsciScintilla.SCI_TAB)
            else:
                self.indent()
            event.accept()
        elif (key == Qt.Key_V) and ctrl:
            self.paste()
            event.accept()
#TODO: find other shortcuts...
#        elif (key == Qt.Key_3) and ctrl:
#            self.comment()
#            event.accept()
#        elif (key == Qt.Key_2) and ctrl:
#            self.uncomment()
#            event.accept()
#        elif (key == Qt.Key_4) and ctrl:
#            self.blockcomment()
#            event.accept()
#        elif (key == Qt.Key_5) and ctrl:
#            self.unblockcomment()
#            event.accept()
        else:
            QsciScintilla.keyPressEvent(self, event)
            
    def mousePressEvent(self, event):
        """Reimplement Qt method"""
        if event.button() == Qt.MidButton:
            self.setFocus()
            event = QMouseEvent(QEvent.MouseButtonPress, event.pos(),
                                Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
            QsciScintilla.mousePressEvent(self, event)
            QsciScintilla.mouseReleaseEvent(self, event)
            self.paste()
        else:
            QsciScintilla.mousePressEvent(self, event)
            
    def contextMenuEvent(self, event):
        """Reimplement Qt method"""
        state = self.hasSelectedText()
        self.copy_action.setEnabled(state)
        self.cut_action.setEnabled(state)
        self.delete_action.setEnabled(state)
        self.undo_action.setEnabled( self.isUndoAvailable() )
        self.redo_action.setEnabled( self.isRedoAvailable() )
        menu = self.menu
        if self.isReadOnly():
            menu = self.readonly_menu
        menu.popup(event.globalPos())
        event.accept()
Ejemplo n.º 40
0
    def __init__(self, parent=None):
        #CONSTRUCTOR DE LA CLASE HEREDADA
        super(editor, self).__init__(parent)

        #DEFINICION DE LA FUENTE Y SUS PROPIEDADES
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        self.lineas_marcadas = []

        #PROFIEDADES AVANZADAS DE LA FUENTE DEL EDITOR
        fontmetrics = QFontMetrics(font)
        self.setMarginsFont(font)
        #SE CAMBIA EL MARGEN ANCHO DE LA FUNETE
        self.setMarginWidth(0, fontmetrics.width("00000") - 15)
        #MARGEN DE LOS NUMEROS DE LINEA
        self.setMarginLineNumbers(0, True)
        #COLOR DE FONDO DE LOS NUMEROS DE LINEA
        self.setMarginsBackgroundColor(QColor("#E0E0E0"))

        self.setMarginSensitivity(1, True)

        #CREAMOS LA SEÑA PARA AGREGAR LINEA MARCADA
        self.connect(self,
                     SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'),
                     self.on_margin_clicked)
        #SE DEFINE EL ICONO A MOSTRAR EN LA LINEA MARCADA
        self.markerDefine(QsciScintilla.Circle, self.ARROW_MARKER_NUM)
        self.setMarkerBackgroundColor(QColor("#FF6C3B"), self.ARROW_MARKER_NUM)

        #RESALTADO DE PARENTECIS,CORCHETES Y OTROS
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        #RESALTADO DE LA LINEA DONDE SE ENCUENTRA EL CURSOR
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#32f24c"))

        #AUTOIDENTACION
        self.setAutoIndent(True)
        self.setIndentationGuides(True)
        self.setIndentationsUseTabs(True)
        self.setIndentationWidth(4)

        #DEFINIMOS EL RESALTADO O LEXER
        self.lexer = QsciLexerPascal()
        self.lexer.setDefaultFont(font)  #FUENTE DEL LEXER

        #API PARA EL AUTOCOMPETADO
        api = QsciAPIs(self.lexer)
        self.palabraAutocompletar(api)
        api.prepare()

        self.cambiarColores()
        self.setLexer(self.lexer)
        self.setAutoCompletionThreshold(1)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)

        #ESCONDER SCROLLBAR HORIZONTAL
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
        #TAMAÑO MINIMO DEL EDITOR
        self.setMinimumSize(600, 360)
Ejemplo n.º 41
0
class PythonEditor(BaseEditor):
    def __init__(self, parent=None, line_num_margin=3, autocomplete_list=None):
        super(PythonEditor, self).__init__(parent, line_num_margin, autocomplete_list)

        # Set Python lexer
        self.lexer = QsciLexerPython(self)
        self.lexer.setDefaultFont(self.editor_font)
        self.lexer.setFont(self.editor_font, QsciLexerPython.Comment)
        # Indentation warning ("The indentation is inconsistent when compared to the previous line")
        self.lexer.setIndentationWarning(QsciLexerPython.Inconsistent)
        # Set auto-completion
        self.api = QsciAPIs(self.lexer)
        if autocomplete_list is not None:
            # Add additional completion strings
            for i in autocomplete_list:
                self.api.add(i)
        self.api.prepare()
        self.setAutoCompletionThreshold(3)
        self.setAutoCompletionSource(QsciScintilla.AcsAll)
        self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit)
        self.setLexer(self.lexer)

        # PEP8 tabs
        self.setIndentationsUseTabs(False)
        self.setAutoIndent(True)
        self.setIndentationGuides(True)
        
        # PEP8 edge column line
        self.edgecol = 80

        # Linters
        self.linter = 'internal'

    def clean_code(self):
        self.setText(autopep8.fix_code(self.text(), options={'aggressive': 2}))

    def check_code(self, path):
        self._clear_all_margin_markers()
        self.lint_data = {}
        try:
            warnings = linter.check(self.text(), os.path.basename(path))
            for w in warnings:
                w.type = 'warning'
                key = w.lineno - 1
                if key in self.lint_data.keys():
                    self.lint_data[key].append(w)
                else:
                    self.lint_data[key] = [w]
                self._add_warn_margin_marker(w.lineno - 1)
        except linter.LinterSyntaxError as e:
            e.type = 'error'
            self.lint_data[e.lineno - 1] = e
            self._add_error_margin_marker(e.lineno - 1)
        except linter.LinterUnexpectedError as e:
            print(e)

    def margin_clicked(self, marnum, linenum, modifiers):
        if self._margin_popup.isVisible():
            self._hide_margin_popup()
        else:
            try:
                warnings = self.lint_data[linenum]
                desc = ''
                if isinstance(warnings, linter.LinterError):
                    desc = warnings.message
                    self._show_margin_popup(desc.strip(), bg_color=self.colorErrorBackground)
                else:
                    for warning in warnings:
                        desc += warning.message % warning.message_args + '\n'
                    self._show_margin_popup(desc.strip(), bg_color=self.colorWarnBackground)
            except KeyError:
                pass
        return True
Ejemplo n.º 42
0
    editor.setCaretLineVisible(True)
    editor.setCaretLineBackgroundColor(QtGui.QColor("#CDA869"))

    ## Margins colors
    # line numbers margin
    editor.setMarginsBackgroundColor(QtGui.QColor("#333333"))
    editor.setMarginsForegroundColor(QtGui.QColor("#CCCCCC"))

    # folding margin colors (foreground,background)
    editor.setFoldMarginColors(QtGui.QColor("#99CC66"),
                               QtGui.QColor("#333300"))

    ## Choose a lexer
    lexer = QsciLexerPython1()

    lexer.setDefaultFont(font)
    editor.setLexer(lexer)
    myApis = QsciAPIs(lexer)
    myApis.add(QtCore.QString("SDR"))
    myApis.add(QtCore.QString("sdr"))
    myApis.prepare()
    editor.setAutoCompletionSource(QsciScintilla.AcsAll)
    editor.setAutoCompletionCaseSensitivity(False)
    editor.setAutoCompletionThreshold(1)

    ## Render on screen
    editor.show()

    ## Show this file in the editor
    editor.setText(open("chardet.txt").read())
    sys.exit(app.exec_())
Ejemplo n.º 43
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")
Ejemplo n.º 44
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)
class PrepareAPIDialog(QDialog):
    def __init__(self, api_lexer, api_files, pap_file, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_APIsDialogPythonConsole()
        self.ui.setupUi(self)
        self.setWindowTitle(
            QCoreApplication.translate("PythonConsole", "Compile APIs"))
        self.ui.plainTextEdit.setVisible(False)
        self.ui.textEdit_Qsci.setVisible(False)
        self.adjustSize()
        self._api = None
        self.ui.buttonBox.rejected.connect(self._stopPreparation)
        self._api_files = api_files
        self._api_lexer = api_lexer
        self._pap_file = pap_file

    def _clearLexer(self):
        # self.ui.textEdit_Qsci.setLexer(0)
        self.qlexer = None

    def _stopPreparation(self):
        if self._api is not None:
            self._api.cancelPreparation()
        self._api = None
        self._clearLexer()
        self.close()

    def _preparationFinished(self):
        self._clearLexer()
        if os.path.exists(self._pap_file):
            os.remove(self._pap_file)
        self.ui.label.setText(
            QCoreApplication.translate("PythonConsole",
                                       "Saving prepared file..."))
        prepd = self._api.savePrepared(unicode(self._pap_file))
        rslt = self.trUtf8("Error")
        if prepd:
            rslt = QCoreApplication.translate("PythonConsole", "Saved")
        self.ui.label.setText(u'{0} {1}'.format(self.ui.label.text(), rslt))
        self._api = None
        self.ui.progressBar.setVisible(False)
        self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(
            QCoreApplication.translate("PythonConsole", "Done"))
        self.adjustSize()

    def prepareAPI(self):
        # self.ui.textEdit_Qsci.setLexer(0)
        exec u'self.qlexer = {0}(self.ui.textEdit_Qsci)'.format(
            self._api_lexer)
        # self.ui.textEdit_Qsci.setLexer(self.qlexer)
        self._api = QsciAPIs(self.qlexer)
        self._api.apiPreparationFinished.connect(self._preparationFinished)
        for api_file in self._api_files:
            self._api.load(unicode(api_file))
        try:
            self._api.prepare()
        except Exception, err:
            self._api = None
            self._clearLexer()
            self.ui.label.setText(
                QCoreApplication.translate("PythonConsole",
                                           "Error preparing file..."))
            self.ui.progressBar.setVisible(False)
            self.ui.plainTextEdit.setVisible(True)
            self.ui.plainTextEdit.insertPlainText(err)
            self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(
                self.trUtf8("Done"))
            self.adjustSize()
Ejemplo n.º 46
0
    def __init__(self, parent=None, fileName=None, readOnlyFiles=[]):
        '''
        Constructor
        '''
        super(CppEditor, self).__init__(parent)
        self.parent = parent
        self.roFiles = readOnlyFiles

        self.setAcceptDrops(False)  # drag&drop is on its parent

        # Set the default font
        font = QtGui.QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)

        # C/C++ lexer
        self.lexer = QsciLexerCPP(self, True)
        self.lexer.setDefaultFont(font)
        self.libraryAPIs = QsciAPIs(QsciLexerCPP(self, True))
        self.setLexer(self.lexer)
        self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, 'Courier')

        # Auto-indent
        self.setTabWidth(4)
        #self.setIndentationsUseTabs(False)
        self.setAutoIndent(True)

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

        # Enable brace matching
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        # Enable folding visual- use boxes
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)

        # show line numbers
        fontmetrics = QtGui.QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(0, fontmetrics.width("00000") + 4)
        self.setMarginLineNumbers(0, True)
        self.setMarginsBackgroundColor(QtGui.QColor("#ccccee"))

        # not too small
        self.setMinimumSize(400, 200)

        # set the length of the string before the editor tries to auto-complete
        self.setAutoCompletionThreshold(3)
        # tell the editor we are using a QsciAPI for the auto-completion
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        # removed remaining right side characters from the current cursor
        self.setAutoCompletionReplaceWord(True)

        # "CTRL+Space" autocomplete
        self.shortcut_ctrl_space = QtGui.QShortcut(
            QtGui.QKeySequence("Ctrl+Space"), self)
        self.connect(self.shortcut_ctrl_space, QtCore.SIGNAL('activated()'),
                     self.autoCompleteFromAll)

        if fileName:
            self.curFile = fileName
            self.loadFile(fileName)
            self.isUntitled = False
        else:
            self.curFile = PROJECT_NONAME + USER_CODE_EXT
            self.setText(__default_content__)
            self.isUntitled = True

        self.updateApiKeywords()
        self.isModified = False
        self.connect(self, QtCore.SIGNAL('textChanged()'), self.onTextChanged)
Ejemplo n.º 47
0
class CppEditor(QsciScintilla):
    '''
    classdocs
    '''
    def __init__(self, parent=None, fileName=None, readOnlyFiles=[]):
        '''
        Constructor
        '''
        super(CppEditor, self).__init__(parent)
        self.parent = parent
        self.roFiles = readOnlyFiles

        self.setAcceptDrops(False)  # drag&drop is on its parent

        # Set the default font
        font = QtGui.QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)

        # C/C++ lexer
        self.lexer = QsciLexerCPP(self, True)
        self.lexer.setDefaultFont(font)
        self.libraryAPIs = QsciAPIs(QsciLexerCPP(self, True))
        self.setLexer(self.lexer)
        self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, 'Courier')

        # Auto-indent
        self.setTabWidth(4)
        #self.setIndentationsUseTabs(False)
        self.setAutoIndent(True)

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

        # Enable brace matching
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        # Enable folding visual- use boxes
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)

        # show line numbers
        fontmetrics = QtGui.QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(0, fontmetrics.width("00000") + 4)
        self.setMarginLineNumbers(0, True)
        self.setMarginsBackgroundColor(QtGui.QColor("#ccccee"))

        # not too small
        self.setMinimumSize(400, 200)

        # set the length of the string before the editor tries to auto-complete
        self.setAutoCompletionThreshold(3)
        # tell the editor we are using a QsciAPI for the auto-completion
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        # removed remaining right side characters from the current cursor
        self.setAutoCompletionReplaceWord(True)

        # "CTRL+Space" autocomplete
        self.shortcut_ctrl_space = QtGui.QShortcut(
            QtGui.QKeySequence("Ctrl+Space"), self)
        self.connect(self.shortcut_ctrl_space, QtCore.SIGNAL('activated()'),
                     self.autoCompleteFromAll)

        if fileName:
            self.curFile = fileName
            self.loadFile(fileName)
            self.isUntitled = False
        else:
            self.curFile = PROJECT_NONAME + USER_CODE_EXT
            self.setText(__default_content__)
            self.isUntitled = True

        self.updateApiKeywords()
        self.isModified = False
        self.connect(self, QtCore.SIGNAL('textChanged()'), self.onTextChanged)

    def onTextChanged(self):
        self.isModified = True
        self.parent.onChildContentChanged()

    def loadFile(self, fileName):
        qfile = QtCore.QFile(fileName)
        if not qfile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(
                self, PROJECT_ALIAS,
                "Cannot read file %s:\n%s." % (fileName, qfile.errorString()))
            return False

        ret = True
        try:
            # workaround for OS X QFile.readAll()
            f = open(qfile.fileName(), 'r')
            self.clear()
            for line in f.readlines():
                self.append(line)
        except:
            QtGui.QMessageBox.warning(self, PROJECT_ALIAS,
                                      "failed to read %s." % fileName)
            ret = False
        finally:
            f.close()

        qfile.close()
        return ret

    def saveFile(self, fileName):
        if str(fileName).find(' ') >= 0:
            QtGui.QMessageBox.warning(
                self, PROJECT_ALIAS,
                'File path "%s" contains space(s). Please save to a valid location.'
                % fileName)
            return None
        qfile = QtCore.QFile(fileName)
        if not qfile.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(
                self, PROJECT_ALIAS,
                "Cannot write file %s:\n%s." % (fileName, qfile.errorString()))
            return None

        try:
            qfile.writeData(self.text())
        except:
            QtGui.QMessageBox.warning(self, PROJECT_ALIAS,
                                      "Failed to save %s." % fileName)
            qfile.close()
            return None

        qfile.close()
        self.curFile = fileName
        self.isUntitled = False
        self.isModified = False
        return fileName

    def saveAs(self):
        fileName = QtGui.QFileDialog.getSaveFileName(
            self, "Save As", self.curFile,
            PROJECT_ALIAS + " (*" + USER_CODE_EXT + ");;" +
            "C source (*.c);;C++ source (*.cpp);;Text File (*.txt);;All files (*.*)"
        )
        if not fileName:
            return None
        return self.saveFile(fileName)

    def save(self):
        f1 = os.path.abspath(self.curFile)
        for fname in self.roFiles:
            if f1 == os.path.abspath(fname):  # same file
                if QtGui.QMessageBox.question(self.parent, "Project is read-only",
                        "This project is marked as \"read-only\".\n" + \
                        "Please click \"Cancel\" and save this to another location.\n\n" + \
                        "Continue saving the current project anyway?", "OK", "Cancel"):
                    return None
                #return self.saveAs()
                return self.saveFile(self.curFile)
        if self.isUntitled:
            return self.saveAs()
        else:
            return self.saveFile(self.curFile)

    def currentFile(self):
        return self.curFile

    def modified(self):
        return self.isModified

    def updateApiKeywords(self):
        self.libraryAPIs.clear()
        self.apiKeywords = self.parent.getDefaultKeywords()
        headerfiles = []
        for line in range(self.lines()):
            txt = str(self.text(line)).strip()
            if txt.find('int') == 0:  # e.g. reached "int main()"
                break
            elif txt.find('#include') == 0:
                txt = ''.join(txt.split())
                temp = txt[len('#includes') - 1:]
                header = temp[1:-1]  # get the header file
                hfile = os.path.join('libraries', header[:-2], header)
                if os.path.isfile(hfile):
                    if not (hfile in headerfiles): headerfiles.append(hfile)
        if len(headerfiles):
            #print 'parsing: ', headerfiles
            self.apiKeywords += getLibraryKeywords(headerfiles)
        #self.apiKeywords = list(set(self.apiKeywords)) # remove duplicates
        for keyword in self.apiKeywords:
            self.libraryAPIs.add(keyword)
        self.libraryAPIs.prepare()
        self.lexer.setAPIs(self.libraryAPIs)

    def insertIncludeDirective(self, library=''):
        directive = '#include <' + library + '.h>\r\n'
        insert_pos = 0
        found_inc = False
        for line in range(self.lines()):
            txt = str(self.text(line)).strip()
            if txt.find('int') == 0:  # e.g. reached "int main()"
                insert_pos = line - 1
                break
            elif txt.find('#include') == 0:
                found_inc = True
            elif found_inc:
                insert_pos = line
                break
        if insert_pos < 0 or insert_pos >= self.lines():
            insert_pos = 0
        self.insertAt(directive, insert_pos, 0)
        self.updateApiKeywords()
Ejemplo n.º 48
0
class ScriptEdit(QsciScintilla):

    LEXER_PYTHON = 0
    LEXER_R = 1

    def __init__(self, parent=None):
        QsciScintilla.__init__(self, parent)

        self.lexer = None
        self.api = None
        self.lexerType = -1

        self.setCommonOptions()
        self.initShortcuts()

    def setCommonOptions(self):
        # Enable non-ASCII characters
        self.setUtf8(True)

        # Default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(20)
        self.setFont(font)
        self.setMarginsFont(font)

        self.initLexer()

        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setWrapVisualFlags(QsciScintilla.WrapFlagByText,
                                QsciScintilla.WrapFlagNone, 4)

        self.setSelectionForegroundColor(QColor('#2e3436'))
        self.setSelectionBackgroundColor(QColor('#babdb6'))

        # Show line numbers
        self.setMarginWidth(1, '000')
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor('#2e3436'))
        self.setMarginsBackgroundColor(QColor('#babdb6'))

        # Highlight current line
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor('#d3d7cf'))

        # Folding
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
        self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf'))

        # Mark column 80 with vertical line
        self.setEdgeMode(QsciScintilla.EdgeLine)
        self.setEdgeColumn(80)
        self.setEdgeColor(QColor('#eeeeec'))

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

        # Autocomletion
        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)

        self.setFonts(10)

    def setFonts(self, size):

        # Load font from Python console settings
        settings = QSettings()
        fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace')
        fontSize = int(settings.value('pythonConsole/fontsize', size))

        self.defaultFont = QFont(fontName)
        self.defaultFont.setFixedPitch(True)
        self.defaultFont.setPointSize(fontSize)
        self.defaultFont.setStyleHint(QFont.TypeWriter)
        self.defaultFont.setStretch(QFont.SemiCondensed)
        self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        self.defaultFont.setBold(False)

        self.boldFont = QFont(self.defaultFont)
        self.boldFont.setBold(True)

        self.italicFont = QFont(self.defaultFont)
        self.italicFont.setItalic(True)

        self.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

    def initShortcuts(self):
        (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)

        # Disable some shortcuts
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY,
                           ord('L') + ctrl + shift)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)

        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)

        # Use Ctrl+Space for autocompletion
        self.shortcutAutocomplete = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Space), self)
        self.shortcutAutocomplete.setContext(Qt.WidgetShortcut)
        self.shortcutAutocomplete.activated.connect(self.autoComplete)

    def autoComplete(self):
        self.autoCompleteFromAll()

    def setLexerType(self, lexerType):
        self.lexerType = lexerType
        self.initLexer()

    def initLexer(self):
        if self.lexerType == self.LEXER_PYTHON:
            self.lexer = QsciLexerPython()

            colorDefault = QColor('#2e3436')
            colorComment = QColor('#c00')
            colorCommentBlock = QColor('#3465a4')
            colorNumber = QColor('#4e9a06')
            colorType = QColor('#4e9a06')
            colorKeyword = QColor('#204a87')
            colorString = QColor('#ce5c00')

            self.lexer.setDefaultFont(self.defaultFont)
            self.lexer.setDefaultColor(colorDefault)

            self.lexer.setColor(colorComment, 1)
            self.lexer.setColor(colorNumber, 2)
            self.lexer.setColor(colorString, 3)
            self.lexer.setColor(colorString, 4)
            self.lexer.setColor(colorKeyword, 5)
            self.lexer.setColor(colorString, 6)
            self.lexer.setColor(colorString, 7)
            self.lexer.setColor(colorType, 8)
            self.lexer.setColor(colorCommentBlock, 12)
            self.lexer.setColor(colorString, 15)

            self.lexer.setFont(self.italicFont, 1)
            self.lexer.setFont(self.boldFont, 5)
            self.lexer.setFont(self.boldFont, 8)
            self.lexer.setFont(self.italicFont, 12)

            self.api = QsciAPIs(self.lexer)

            settings = QSettings()
            useDefaultAPI = bool(
                settings.value('pythonConsole/preloadAPI', True))
            if useDefaultAPI:
                # Load QGIS API shipped with Python console
                self.api.loadPrepared(
                    os.path.join(QgsApplication.pkgDataPath(), 'python',
                                 'qsci_apis', 'pyqgis.pap'))
            else:
                # Load user-defined API files
                apiPaths = settings.value('pythonConsole/userAPI', [])
                for path in apiPaths:
                    self.api.load(path)
                self.api.prepare()
                self.lexer.setAPIs(self.api)
        elif self.lexerType == self.LEXER_R:
            # R lexer
            self.lexer = LexerR()

        self.setLexer(self.lexer)
Ejemplo n.º 49
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')
Ejemplo n.º 50
0
class Editor(base.Base):

    # Braces
    BRACE = {'(': ')', '[': ']'}

    # Quotes
    QUOTE = {"'": "'", '"': '"'}

    # Marcadores
    MARKER_MODIFIED = 3
    MARKER_SAVED = 4

    # Indicadores
    WORD_INDICATOR = 0
    WARNING_INDICATOR = 1

    def __init__(self, obj_file):
        super(Editor, self).__init__()
        self.obj_file = obj_file  # Asociación con el objeto EdisFile
        self._font = None
        # Configuración
        use_tabs = settings.get_setting('editor/usetabs')
        self.setIndentationsUseTabs(use_tabs)
        self.setAutoIndent(settings.get_setting('editor/indent'))
        self.setBackspaceUnindents(True)
        # Quita el scrollbar
        self.send("sci_sethscrollbar", 0)
        # Configuración de indicadores
        self.send("sci_indicsetstyle", Editor.WORD_INDICATOR, "indic_box")
        self.send("sci_indicsetfore", Editor.WORD_INDICATOR, QColor("#FF0000"))
        self.send("sci_indicsetstyle", Editor.WARNING_INDICATOR,
                  "indic_squiggle")
        self.send("sci_indicsetfore", Editor.WARNING_INDICATOR,
                  QColor("#0000FF"))
        # Scheme
        self.scheme = editor_scheme.get_scheme(
            settings.get_setting('editor/scheme'))
        # Folding
        self.setFolding(QsciScintilla.PlainFoldStyle)  # en márgen 2
        self.setMarginWidth(3, 5)  # 5px de espacios en márgen 3
        self.send("sci_markersetfore", QsciScintilla.SC_MARKNUM_FOLDER,
                  QColor(self.scheme['FoldMarkerFore']))
        self.send("sci_markersetback", QsciScintilla.SC_MARKNUM_FOLDER,
                  QColor(self.scheme['FoldMarkerBack']))
        self.setFoldMarginColors(QColor(self.scheme['FoldMarginBack']),
                                 QColor(self.scheme['FoldMarginFore']))
        # Marcadores
        self.markerDefine(QsciScintilla.SC_MARK_LEFTRECT,
                          Editor.MARKER_MODIFIED)
        self.setMarkerBackgroundColor(QColor(226, 255, 141),
                                      Editor.MARKER_MODIFIED)
        self.markerDefine(QsciScintilla.SC_MARK_LEFTRECT, Editor.MARKER_SAVED)
        self.setMarkerBackgroundColor(QColor(55, 142, 103),
                                      Editor.MARKER_SAVED)

        # Actualiza flags (espacios en blanco, cursor, sidebar, etc)
        self.update_options()
        # Lexer
        self._lexer = lexer.Lexer()
        self.setLexer(self._lexer)
        # Autocompletado
        self.api = None
        if settings.get_setting('editor/completion'):
            self.active_code_completion()
        # Indentación
        self._indentation = settings.get_setting('editor/width-indent')
        self.send("sci_settabwidth", self._indentation)
        # Minimapa
        self.minimap = None
        if settings.get_setting('editor/minimap'):
            self.minimap = minimap.Minimap(self)
            self.connect(self, SIGNAL("textChanged()"),
                         self.minimap.update_code)
        # Thread que busca palabras
        self.search_thread = editor_helpers.SearchThread()
        self.connect(self.search_thread, SIGNAL("foundWords(PyQt_PyObject)"),
                     self.mark_words)
        # Analizador de estilo de código
        self.checker = None
        if settings.get_setting('editor/style-checker'):
            self.load_checker()
        # Fuente
        font = settings.get_setting('editor/font')
        font_size = settings.get_setting('editor/size-font')
        self.load_font(font, font_size)
        self.setMarginsBackgroundColor(QColor(self.scheme['SidebarBack']))
        self.setMarginsForegroundColor(QColor(self.scheme['SidebarFore']))
        # Línea actual
        self.send("sci_setcaretlinevisible",
                  settings.get_setting('editor/show-caret-line'))
        self.send("sci_setcaretlineback", QColor(self.scheme['CaretLineBack']))
        self.send("sci_setcaretfore", QColor(self.scheme['CaretLineFore']))
        self.send("sci_setcaretlinebackalpha", self.scheme['CaretLineAlpha'])
        # Cursor
        caret_period = settings.get_setting('editor/cursor-period')
        self.send("sci_setcaretperiod", caret_period)
        # Márgen
        if settings.get_setting('editor/show-margin'):
            self.update_margin()
        # Brace matching
        self.setBraceMatching(int(settings.get_setting('editor/match-brace')))
        self.setMatchedBraceBackgroundColor(
            QColor(self.scheme['MatchedBraceBack']))
        self.setMatchedBraceForegroundColor(
            QColor(self.scheme['MatchedBraceFore']))
        self.setUnmatchedBraceBackgroundColor(
            QColor(self.scheme['UnmatchedBraceBack']))
        self.setUnmatchedBraceForegroundColor(
            QColor(self.scheme['UnmatchedBraceFore']))
        # Selecciones Múltiples
        self.send("sci_setadditionalcaretfore", QColor(157, 64, 40))
        self.send("sci_setadditionalcaretsblink", 1)
        self.send("sci_setadditionalselalpha", 100)
        self.send("sci_setmultipleselection", 1)
        self.send("sci_setadditionalselectiontyping", 1)
        # Conexiones
        self.connect(self, SIGNAL("linesChanged()"), self.update_sidebar)
        self.connect(self, SIGNAL("textChanged()"), self._add_marker_modified)

    @property
    def filename(self):
        return self.obj_file.filename

    @property
    def is_modified(self):
        return self.isModified()

    def load_font(self, fuente, tam):
        self._font = QFont(fuente, tam)
        if self._lexer is None:
            self.setFont(self._font)
        else:
            self._lexer.setFont(self._font)
        self.setMarginsFont(self._font)

    def load_checker(self, activated=True):
        if activated and self.checker is not None:
            return
        if not activated:
            self.checker = None
            self.clear_indicators(Editor.WARNING_INDICATOR)
        else:
            self.checker = checker.Checker(self)
            self.connect(self.checker, SIGNAL("finished()"),
                         self._show_violations)

    def set_brace_matching(self):
        match_brace = int(settings.get_setting('editor/match-brace'))
        self.setBraceMatching(match_brace)

    def update_options(self):
        """ Actualiza las opciones del editor """

        if settings.get_setting('editor/show-tabs-spaces'):
            self.setWhitespaceVisibility(self.WsVisible)
        else:
            self.setWhitespaceVisibility(self.WsInvisible)
        self.setIndentationGuides(settings.get_setting('editor/show-guides'))
        if settings.get_setting('editor/wrap-mode'):
            self.setWrapMode(self.WrapWord)
        else:
            self.setWrapMode(self.WrapNone)
        self.send("sci_setcaretstyle", settings.get_setting('editor/cursor'))
        self.setCaretWidth(settings.get_setting('editor/caret-width'))
        self.setAutoIndent(settings.get_setting('editor/indent'))
        self.send("sci_setcaretperiod",
                  settings.get_setting('editor/cursor-period'))
        current_line = settings.get_setting('editor/show-caret-line')
        self.send("sci_setcaretlinevisible", current_line)
        self.setEolVisibility(settings.get_setting('editor/eof'))

    def update_sidebar(self):
        """ Ajusta el ancho del sidebar """

        fmetrics = QFontMetrics(self._font)
        lines = str(self.lines()) + '0'
        line_number = settings.get_setting('editor/show-line-number')
        width = fmetrics.width(lines) if line_number else 0
        self.setMarginWidth(0, width)

    def show_line_numbers(self):
        line_number = settings.get_setting('editor/show-line-number')
        self.setMarginLineNumbers(0, line_number)
        self.update_sidebar()

    def update_margin(self):
        """ Actualiza el ancho del márgen de línea """

        if settings.get_setting('editor/show-margin'):
            self.setEdgeMode(QsciScintilla.EdgeLine)
            ancho = settings.get_setting('editor/width-margin')
            self.setEdgeColumn(ancho)
            self.setEdgeColor(QColor(self.scheme['Margin']))
        else:
            self.setEdgeMode(QsciScintilla.EdgeNone)

    def update_indentation(self):
        ancho = settings.get_setting('editor/width-indent')
        self.send("sci_settabwidth", ancho)
        self._indentation = ancho

    def mark_words(self, palabras):
        self.clear_indicators(Editor.WORD_INDICATOR)
        for p in palabras:
            self.fillIndicatorRange(p[0], p[1], p[0], p[2],
                                    Editor.WORD_INDICATOR)

    def active_code_completion(self, enabled=True):
        if self.api is not None and enabled:
            return
        if enabled:
            self.api = QsciAPIs(self._lexer)
            if settings.get_setting('editor/completion-keywords'):
                for keyword in keywords.keywords:
                    self.api.add(keyword)
                self.api.prepare()
                source = QsciScintilla.AcsAPIs
                if settings.get_setting('editor/completion-document'):
                    source = QsciScintilla.AcsAll
            elif settings.get_setting('editor/completion-document'):
                source = QsciScintilla.AcsDocument
            else:
                source = QsciScintilla.AcsNone
            threshold = settings.get_setting('editor/completion-threshold')
            self.setAutoCompletionThreshold(threshold)
            self.setAutoCompletionSource(source)
            cs = settings.get_setting('editor/completion-cs')
            self.setAutoCompletionCaseSensitivity(cs)
            repl_word = settings.get_setting('editor/completion-replace-word')
            self.setAutoCompletionReplaceWord(repl_word)
            show_single = settings.get_setting('editor/completion-single')
            use_single = 2 if show_single else 0
            self.setAutoCompletionUseSingle(use_single)
        else:
            self.api = None
            self.setAutoCompletionSource(0)

    def _add_marker_modified(self):
        """ Agrega el marcador cuando el texto cambia """

        if not settings.get_setting('editor/mark-change'):
            return
        nline, _ = self.getCursorPosition()
        if self.markersAtLine(nline):
            self.markerDelete(nline)
        self.markerAdd(nline, Editor.MARKER_MODIFIED)

    def _show_violations(self):
        data = self.checker.data
        self.clear_indicators(Editor.WARNING_INDICATOR)
        for line, message in list(data.items()):
            line = int(line) - 1
            self.fillIndicatorRange(line, 0, line, self.lineLength(line),
                                    Editor.WARNING_INDICATOR)

    def _text_under_cursor(self):
        """ Texto seleccionado con el cursor """

        line, index = self.getCursorPosition()  # Posición del cursor
        word = self.wordAtLineIndex(line, index)  # Palabra en esa pos
        return word

    def mouseReleaseEvent(self, e):
        super(Editor, self).mouseReleaseEvent(e)
        if e.button() == Qt.LeftButton:
            word = self._text_under_cursor()
            if not word:
                self.clear_indicators(Editor.WORD_INDICATOR)
                return
            self.search_thread.find(word, self.text())

    def mouseMoveEvent(self, event):
        super(Editor, self).mouseMoveEvent(event)
        if self.checker is None:
            return
        position = event.pos()
        line = str(self.lineAt(position) + 1)
        message = self.checker.data.get(line, None)
        if message is not None:
            QToolTip.showText(self.mapToGlobal(position), message)

    def keyReleaseEvent(self, event):
        super(Editor, self).keyReleaseEvent(event)
        line, _ = self.getCursorPosition()
        self.emit(SIGNAL("linesChanged(int)"), line)

    def keyPressEvent(self, event):
        super(Editor, self).keyPressEvent(event)
        key = event.key()
        # Borra indicador de palabra
        if key == Qt.Key_Escape:
            self.clear_indicators(Editor.WORD_INDICATOR)
            return
        # Completado de comillas
        if key == Qt.Key_Apostrophe:
            if settings.get_setting('editor/complete-single-quote'):
                self._complete_quote(event)
            return
        if key == Qt.Key_QuoteDbl:
            if settings.get_setting('editor/complete-double-quote'):
                self._complete_quote(event)
            return
        # Completado de llaves
        if key == Qt.Key_BraceLeft:
            if settings.get_setting('editor/complete-brace'):
                self._complete_key(event)
        if key in (Qt.Key_BracketLeft, Qt.Key_ParenLeft, Qt.Key_BracketRight,
                   Qt.Key_ParenRight):
            self._complete_brace(event)

    def _complete_quote(self, event):
        """ Autocompleta comillas simples y dobles, si existe el complementario
            el cursor se mueve un espacio.
        """

        complementary = Editor.QUOTE.get(event.text())
        line, index = self.getCursorPosition()
        text_line = self.text(line)
        portion = text_line[index - 1:index + 1]
        if portion in settings.QUOTES:
            self.setSelection(line, index, line, index + 1)
            self.replaceSelectedText('')
        else:
            self.insertAt(complementary, line, index)

    def _complete_brace(self, event):
        """ Autocompleta un brace cuando es abierto '(, ['.
            Si existe el complementario '), ]' el índice del cursor se
            mueve un espacio.
        """

        brace_close = settings.BRACES.get(event.text(), None)
        braces_open = list(Editor.BRACE.keys())
        line, index = self.getCursorPosition()
        if event.text() in settings.BRACES.values():
            text_line = self.text(line)
            found = 0
            # Busco un brace cerrado en el texto
            for token in text_line:
                if token in settings.BRACES.values():
                    found += 1
            try:
                # Brace abierto
                brace_open = text_line[index]
            except:
                brace_open = ''
            if found > 1 and brace_open not in braces_open:
                # Reemplazo el brace sobrante por un string vacío
                self.setSelection(line, index, line, index + 1)
                self.replaceSelectedText('')
            return
        elif event.text() in settings.BRACES.keys(
        ) and brace_close is not None:
            # Inserto el brace complementario
            self.insertAt(brace_close, line, index)

    def _complete_key(self, event):
        """ Autocompleta llaves en funciones y estructuras.
            Si se usa typedef en la definición de la estructura se completa
            la variable.
         """

        line, index = self.getCursorPosition()
        text_line = self.text(line)
        # Estructura
        if REGEX_STRUCT.match(text_line):
            if text_line.split()[0] == 'typedef':
                # Obtengo la variable
                split_line = text_line.split()
                if split_line[-1] == '{':
                    typedef = split_line[-2]
                else:
                    typedef = split_line[-1][:-1]
                text = "}%s;" % typedef.title()
            else:
                text = "};"
            self.insert("\n")
            self.insertAt(text, line + 1, 0)
            return
        # Función
        portion = text_line[index - 3:index]
        if ')' in portion:
            self.insert("\n")
            current_indentation = self.indentation(line)
            self.setIndentation(line + 1, current_indentation)
            self.insertAt('}', line + 1, current_indentation)

    def resizeEvent(self, e):
        super(Editor, self).resizeEvent(e)
        if self.minimap is not None:
            self.minimap.update_geometry()

    def comment(self):
        # FIXME: tener en cuenta /* */
        # FIXME: no funciona si el comentario no inicia en el índice 0
        if self.hasSelectedText():
            line_from, _, line_to, _ = self.getSelection()

            # Iterar todas las líneas seleccionadas
            self.send("sci_beginundoaction")
            for line in range(line_from, line_to + 1):
                self.insertAt('//', line, 0)
            self.send("sci_endundoaction")
        else:
            line, _ = self.getCursorPosition()
            self.insertAt('//', line, 0)

    def uncomment(self):
        if self.hasSelectedText():
            line_from, _, line_to, _ = self.getSelection()
            self.send("sci_beginundoaction")
            for line in range(line_from, line_to + 1):
                self.setSelection(line, 0, line, 2)
                if not self.text(line).startswith('//'):
                    continue
                self.removeSelectedText()
            self.send("sci_endundoaction")
        else:
            line, _ = self.getCursorPosition()
            if not self.text(line).startswith('//'):
                return
            self.setSelection(line, 0, line, 2)
            self.removeSelectedText()

    def to_lowercase(self):
        if self.hasSelectedText():
            text = self.selectedText().lower()
        else:
            line, _ = self.getCursorPosition()
            text = self.text(line).lower()
            self.setSelection(line, 0, line, len(text))
        self.replaceSelectedText(text)

    def to_uppercase(self):
        if self.hasSelectedText():
            text = self.selectedText().upper()
        else:
            line, _ = self.getCursorPosition()
            text = self.text(line).upper()
            self.setSelection(line, 0, line, len(text))
        self.replaceSelectedText(text)

    def to_title(self):
        if self.hasSelectedText():
            text = self.selectedText().title()
        else:
            line, _ = self.getCursorPosition()
            text = self.text(line).title()
            self.setSelection(line, 0, line, len(text))
        self.replaceSelectedText(text)

    def duplicate_line(self):
        self.send("sci_lineduplicate")

    def delete_line(self):
        if self.hasSelectedText():
            self.send("sci_beginundoaction")
            desde, desde_indice, hasta, _ = self.getSelection()
            self.setCursorPosition(desde, desde_indice)
            while desde != hasta:
                self.send("sci_linedelete")
                desde += 1
            self.send("sci_endundoaction")
        else:
            self.send("sci_linedelete")

    def indent_more(self):
        if self.hasSelectedText():
            self.send("sci_beginundoaction")
            desde, _, hasta, _ = self.getSelection()
            for linea in range(desde, hasta + 1):
                self.indent(linea)
            self.send("sci_endundoaction")
        else:
            linea, _ = self.getCursorPosition()
            self.indent(linea)

    def indent_less(self):
        if self.hasSelectedText():
            self.send("sci_beginundoaction")
            desde, _, hasta, _ = self.getSelection()
            for linea in range(desde, hasta + 1):
                self.unindent(linea)
            self.send("sci_endundoaction")
        else:
            linea, _ = self.getCursorPosition()
            self.unindent(linea)

    def move_down(self):
        self.send("sci_moveselectedlinesdown")

    def move_up(self):
        self.send("sci_moveselectedlinesup")

    def reemplazar_tabs_por_espacios(self):
        codigo = self.text()
        codigo_sin_tabs = codigo.replace('\t', ' ' * self._indentation)
        self.setText(codigo_sin_tabs)

    def saved(self):
        # Esta señal sirve para actualizar el árbol de símbolos
        self.emit(SIGNAL("fileSaved(QString)"), self.obj_file.filename)
        self.setModified(False)
        # Itera todas las líneas y si existe un _marker_modified agrega
        # un _marker_save
        for nline in range(self.lines()):
            if self.markersAtLine(nline):
                self.markerAdd(nline, Editor.MARKER_SAVED)

    def dropEvent(self, event):
        self.emit(SIGNAL("dropEvent(PyQt_PyObject)"), event)