Ejemplo n.º 1
0
class AbstractReferenceSelector(ABC, QWidget, metaclass=SelectorMeta):
    changed = Signal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.completer = None
        self.p_selected_id = 0

        self.layout = QHBoxLayout()
        self.layout.setMargin(0)
        self.name = QLineEdit()
        self.name.setText("")
        self.layout.addWidget(self.name)
        self.details = QLabel()
        self.details.setText("")
        self.details.setVisible(False)
        self.layout.addWidget(self.details)
        self.button = QPushButton("...")
        self.button.setFixedWidth(self.button.fontMetrics().width("XXXX"))
        self.layout.addWidget(self.button)
        self.setLayout(self.layout)

        self.setFocusProxy(self.name)

        self.button.clicked.connect(self.on_button_clicked)

        if self.details_field:
            self.name.setFixedWidth(self.name.fontMetrics().width("X") * 15)
            self.details.setVisible(True)
        self.completer = QCompleter(self.dialog.model.completion_model)
        self.completer.setCompletionColumn(
            self.dialog.model.completion_model.fieldIndex(self.selector_field))
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.name.setCompleter(self.completer)
        self.completer.activated[QModelIndex].connect(self.on_completion)

    def getId(self):
        return self.p_selected_id

    def setId(self, selected_id):
        if self.p_selected_id == selected_id:
            return
        self.p_selected_id = selected_id
        self.name.setText(
            self.dialog.model.getFieldValue(selected_id, self.selector_field))
        if self.details_field:
            self.details.setText(
                self.dialog.model.getFieldValue(selected_id,
                                                self.details_field))

    selected_id = Property(int, getId, setId, notify=changed, user=True)

    def on_button_clicked(self):
        ref_point = self.mapToGlobal(self.name.geometry().bottomLeft())
        self.dialog.setGeometry(ref_point.x(), ref_point.y(),
                                self.dialog.width(), self.dialog.height())
        res = self.dialog.exec_(enable_selection=True,
                                selected=self.selected_id)
        if res:
            self.selected_id = self.dialog.selected_id
            self.changed.emit()

    @Slot(QModelIndex)
    def on_completion(self, index):
        model = index.model()
        self.selected_id = model.data(model.index(index.row(), 0),
                                      Qt.DisplayRole)
        self.changed.emit()

    def isCustom(self):
        return True
Ejemplo n.º 2
0
class Editor(QPlainTextEdit):

    keyPressed = Signal(QEvent)

    class _NumberArea(QWidget):
        def __init__(self, editor):
            super().__init__(editor)
            self.codeEditor = editor

        def sizeHint(self):
            return QSize(self.editor.lineNumberAreaWidth(), 0)

        def paintEvent(self, event):
            self.codeEditor.lineNumberAreaPaintEvent(event)

    def __init__(self, **kwargs):
        parent = kwargs["parent"] if "parent" in kwargs else None
        super().__init__(parent)
        self._addSaveAction = kwargs[
            "saveAction"] if "saveAction" in kwargs else False
        self._addSaveAction = kwargs[
            "saveAction"] if "saveAction" in kwargs else False
        if self._addSaveAction:
            self.saveACT = QAction("Save")
            self.saveACT.setShortcut(QKeySequence("Ctrl+S"))
            self.saveACT.triggered.connect(
                lambda: self._save_file(self.toPlainText()))
            self.addAction(self.saveACT)
        self._saveCB = kwargs[
            "saveFunction"] if "saveFunction" in kwargs else None
        self.setFont(QFont("Courier New", 11))
        self.lineNumberArea = Editor._NumberArea(self)
        self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
        self.updateRequest.connect(self.updateLineNumberArea)
        self.cursorPositionChanged.connect(self.highlightCurrentLine)
        self.updateLineNumberAreaWidth(0)
        self.findHighlightFormat = QTextCharFormat()
        self.findHighlightFormat.setBackground(QBrush(QColor("red")))
        self.searchTxtBx = None

    def lineNumberAreaWidth(self):
        digits = 5
        max_value = max(1, self.blockCount())
        while max_value >= 10:
            max_value /= 10
            digits += 1
        space = 3 + self.fontMetrics().width('9') * digits
        return space

    def updateLineNumberAreaWidth(self, _):
        self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)

    def updateLineNumberArea(self, rect, dy):
        if dy:
            self.lineNumberArea.scroll(0, dy)
        else:
            self.lineNumberArea.update(0, rect.y(),
                                       self.lineNumberArea.width(),
                                       rect.height())
        if rect.contains(self.viewport().rect()):
            self.updateLineNumberAreaWidth(0)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        cr = self.contentsRect()
        self.lineNumberArea.setGeometry(
            QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(),
                  cr.height()))

    def highlightCurrentLine(self):
        extraSelections = []
        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()
            lineColor = QColor(229, 248, 255, 255)
            selection.format.setBackground(lineColor)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            extraSelections.append(selection)
        self.setExtraSelections(extraSelections)

    def lineNumberAreaPaintEvent(self, event):
        painter = QPainter(self.lineNumberArea)

        painter.fillRect(event.rect(), QColor(233, 233, 233, 255))

        block = self.firstVisibleBlock()
        blockNumber = block.blockNumber()
        top = self.blockBoundingGeometry(block).translated(
            self.contentOffset()).top()
        bottom = top + self.blockBoundingRect(block).height()

        # Just to make sure I use the right font
        height = self.fontMetrics().height()
        while block.isValid() and (top <= event.rect().bottom()):
            if block.isVisible() and (bottom >= event.rect().top()):
                number = str(blockNumber + 1)
                fFont = QFont("Courier New", 10)
                painter.setPen(QColor(130, 130, 130, 255))
                painter.setFont(fFont)
                painter.drawText(0, top, self.lineNumberArea.width(), height,
                                 Qt.AlignCenter, number)

            block = block.next()
            top = bottom
            bottom = top + self.blockBoundingRect(block).height()
            blockNumber += 1

    def contextMenuEvent(self, event):
        menu = self.createStandardContextMenu()
        if self._addSaveAction:
            index = 0
            if len(menu.actions()) > 6: index = 5
            act_beforeACT = menu.actions()[index]
            menu.insertAction(act_beforeACT, self.saveACT)
        action = menu.addAction("Find" + "\t" + "Ctrl+F")
        action.triggered.connect(self.find_key)
        menu.popup(event.globalPos())

    def keyPressEvent(self, event: QKeyEvent):
        if event.key() == Qt.Key_F and (event.modifiers()
                                        & Qt.ControlModifier):
            self.find_key()
        if event.key() == Qt.Key_Escape:
            if self.searchTxtBx is not None:
                self.searchTxtBx.hide()
                self.searchTxtBx = None
                self.clear_format()
        super(Editor, self).keyPressEvent(event)

    def find_key(self):
        if self.searchTxtBx is None:
            self.searchTxtBx = QLineEdit(self)
            p = self.geometry().topRight() - self.searchTxtBx.geometry(
            ).topRight() - QPoint(50, 0)
            self.searchTxtBx.move(p)
            self.searchTxtBx.show()
            self.searchTxtBx.textChanged.connect(self.find_with_pattern)
        self.searchTxtBx.setFocus()

    def find_with_pattern(self, pattern):
        self.setUndoRedoEnabled(False)
        self.clear_format()
        if pattern == "":
            return
        cursor = self.textCursor()
        regex = QRegExp(pattern)
        pos = 0
        index = regex.indexIn(self.toPlainText(), pos)
        while index != -1:
            cursor.setPosition(index)
            cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor,
                                1)
            cursor.mergeCharFormat(self.findHighlightFormat)
            pos = index + regex.matchedLength()
            index = regex.indexIn(self.toPlainText(), pos)
        self.setUndoRedoEnabled(True)

    def clear_format(self):
        cursor = self.textCursor()
        cursor.select(QTextCursor.Document)
        cursor.setCharFormat(QTextCharFormat())
        cursor.clearSelection()
        self.setTextCursor(cursor)

    def setSaveCB(self, cb):
        self._saveCB = cb

    def _save_file(self, text):
        if self._saveCB is not None:
            self._saveCB(text)