def paint(self, painter, option, index): option = QStyleOptionViewItem(option) # copy option self.initStyleOption(option, index) style = option.widget.style() if option.widget else QApplication.style() doc = QTextDocument() doc.setHtml(option.text) # painting item without text option.text = "" style.drawControl(QStyle.CE_ItemViewItem, option, painter) ctx = QAbstractTextDocumentLayout.PaintContext() # Hilight text if item is selected if option.state & QStyle.State_Selected: ctx.palette.setColor(QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText)) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, option) painter.save() painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
class HTMLDelegate(QStyledItemDelegate): def __init__(self, parent=None): super(HTMLDelegate, self).__init__(parent) self.doc = QTextDocument(self) def paint(self, painter, option, index): painter.save() options = QStyleOptionViewItem(option) self.initStyleOption(options, index) self.doc.setHtml(options.text) options.text = "" style = QApplication.style() if options.widget is None \ else options.widget.style() style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() if option.state & QStyle.State_Selected: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText)) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.translate(textRect.topLeft()) self.doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): self.initStyleOption(option, index) style = QApplication.style() doc = QTextDocument() if index.column() in (NetworkTableModel.columns_types.index('address'), NetworkTableModel.columns_types.index('port'), NetworkTableModel.columns_types.index('api')): doc.setHtml(option.text) else: doc.setPlainText(option.text) option.text = "" style.drawControl(QStyle.CE_ItemViewItem, option, painter) ctx = QAbstractTextDocumentLayout.PaintContext() text_rect = style.subElementRect(QStyle.SE_ItemViewItemText, option) painter.save() painter.translate(text_rect.topLeft()) painter.setClipRect(text_rect.translated(-text_rect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): self.initStyleOption(option, index) foreground = index.data(Qt.ForegroundRole) font = index.data(Qt.FontRole) style = QApplication.style() doc = QTextDocument() if index.column() == HistoryTableModel.columns_types.index('pubkey'): doc.setHtml(option.text) else: doc.setPlainText(option.text) option.text = "" style.drawControl(QStyle.CE_ItemViewItem, option, painter) ctx = QAbstractTextDocumentLayout.PaintContext() if foreground: if foreground.isValid(): ctx.palette.setColor(QPalette.Text, foreground) if font: doc.setDefaultFont(font) text_rect = style.subElementRect(QStyle.SE_ItemViewItemText, option) painter.save() painter.translate(text_rect.topLeft()) painter.setClipRect(text_rect.translated(-text_rect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): options = QStyleOptionViewItem(option) item = index.data(Qt.UserRole) if isinstance(item, (CommentItem, ChangeItem)): options.decorationAlignment = Qt.AlignHCenter self.initStyleOption(options,index) if options.widget is None: style = QApplication.style() else: style = options.widget.style() doc = QTextDocument() doc.setHtml(options.text) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected #if (optionV4.state & QStyle::State_Selected) #ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText)) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): text = index.data() if isinstance(text, str): painter.save() doc = QTextDocument() doc.setHtml(text) doc.setPageSize(QSizeF(option.rect.size())) painter.setClipRect(option.rect) painter.translate(option.rect.x(), option.rect.y()) doc.documentLayout().draw( painter, QAbstractTextDocumentLayout.PaintContext()) painter.restore() else: QStyledItemDelegate.paint(self, painter, option, index)
def sizeHint(self, styleOption, modelIndex): """Return the size of Data Edit Cells with rich text. Other cells return the base class size. Arguments: styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be painted """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): doc = cell.doc doc.setTextWidth(styleOption.rect.width()) size = doc.documentLayout().documentSize().toSize() maxHeight = self.parent().height() * 9 // 10 # 90% of view height if (size.height() > maxHeight and globalref.genOptions['EditorLimitHeight']): size.setHeight(maxHeight) if cell.field.numLines > 1: minDoc = QTextDocument('\n' * (cell.field.numLines - 1)) minDoc.setDefaultFont(cell.doc.defaultFont()) minHeight = ( minDoc.documentLayout().documentSize().toSize().height()) if minHeight > size.height(): size.setHeight(minHeight) return size + QSize(0, 4) return super().sizeHint(styleOption, modelIndex)
def paint(self, painter: QPainter, option, index): # reference following link # https://stackoverflow.com/questions/53353450/how-to-highlight-a-words-in-qtablewidget-from-a-searchlist # https://stackoverflow.com/questions/34623036/implementing-a-delegate-for-wordwrap-in-a-qtreeview-qt-pyside-pyqt painter.save() doc = QTextDocument(self) # option.palette.setColor(QPalette.HighlightedText, QColor.fromRgb(30, 136, 200)) # remove dotted border in table if option.state & QStyle.State_HasFocus: option.state = option.state ^ QStyle.State_HasFocus options = QStyleOptionViewItem(option) self.initStyleOption(options, index) doc.setPlainText(options.text) # keyword = index.data(Qt.UserRole) # if self.keywords: self.keywordHighlight(doc) options.text = "" # print(dir(options.palette)) # print(options.palette.Highlight) style = QApplication.style() if options.widget is None \ else options.widget.style() style.drawControl(QStyle.CE_ItemViewItem, options, painter, options.widget) # for selection highlight ctx = QAbstractTextDocumentLayout.PaintContext() if index.data(Qt.UserRole) == 'reserved': ctx.palette.setColor(QPalette.Text, QColor.fromRgb(100, 100, 100)) doc.setDefaultFont( QFont(option.font.family(), option.font.pointSize() * 2 // 3)) else: ctx.palette.setColor(QPalette.Text, QColor.fromRgb(217, 217, 217)) doc.setDefaultFont(option.font) textRect = option.rect # margin = 4 # textRect.setTop(textRect.top() + margin) textRect.setTop(textRect.top()) painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.setTextWidth(option.rect.width()) doc.documentLayout().draw(painter, ctx) painter.restore()
class TableDelegate(QStyledItemDelegate): """Table 富文本""" def __init__(self, parent=None): super(TableDelegate, self).__init__(parent) self.doc = QTextDocument(self) def paint(self, painter, option, index): painter.save() options = QStyleOptionViewItem(option) self.initStyleOption(options, index) self.doc.setHtml(options.text) options.text = "" # 原字符 style = QApplication.style( ) if options.widget is None else options.widget.style() style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() if option.state & QStyle.State_Selected: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText)) else: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.Text)) text_rect = style.subElementRect(QStyle.SE_ItemViewItemText, options) the_fuck_your_shit_up_constant = 3 #  ̄へ ̄ # margin = (option.rect.height() - options.fontMetrics.height()) // 2 margin = margin - the_fuck_your_shit_up_constant text_rect.setTop(text_rect.top() + margin) painter.translate(text_rect.topLeft()) painter.setClipRect(text_rect.translated(-text_rect.topLeft())) self.doc.documentLayout().draw(painter, ctx) painter.restore() def sizeHint(self, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) self.doc.setHtml(options.text) self.doc.setTextWidth(options.rect.width()) return QSize(self.doc.idealWidth(), self.doc.size().height())
def paint(self, painter, option, index): self.initStyleOption(option, index) style = option.widget.style() if option.widget else QApplication.style() palette = QApplication.palette() color = palette.highlight().color() \ if option.state & QStyle.State_Selected \ else palette.base() ctx = QAbstractTextDocumentLayout.PaintContext() textRect = style.subElementRect(QStyle.SE_ItemViewItemText, option) painter.save() painter.fillRect(option.rect, color) painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc = QTextDocument() doc.setHtml(option.text) doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): """QStyledItemDelegate.paint implementation """ option.state &= ~QStyle.State_HasFocus # never draw focus rect options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = QApplication.style( ) if options.widget is None else options.widget.style() doc = QTextDocument() doc.setDocumentMargin(1) doc.setHtml(options.text) if options.widget is not None: doc.setDefaultFont(options.widget.font()) # bad long (multiline) strings processing doc.setTextWidth(options.rect.width()) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected if option.state & QStyle.State_Selected: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText)) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() painter.translate(textRect.topLeft()) """Original example contained line painter.setClipRect(textRect.translated(-textRect.topLeft())) but text is drawn clipped with it on kubuntu 12.04 """ doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): """QStyledItemDelegate.paint implementation """ option.state &= ~QStyle.State_HasFocus # never draw focus rect options = QStyleOptionViewItem(option) self.initStyleOption(options,index) style = QApplication.style() if options.widget is None else options.widget.style() doc = QTextDocument() doc.setDocumentMargin(1) doc.setHtml(options.text) if options.widget is not None: doc.setDefaultFont(options.widget.font()) # bad long (multiline) strings processing doc.setTextWidth(options.rect.width()) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter); ctx = QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected if option.state & QStyle.State_Selected: ctx.palette.setColor(QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText)) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() painter.translate(textRect.topLeft()) """Original example contained line painter.setClipRect(textRect.translated(-textRect.topLeft())) but text is drawn clipped with it on kubuntu 12.04 """ doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): """QStyledItemDelegate.paint implementation """ option.state &= ~QStyle.State_HasFocus # never draw focus rect option.state |= QStyle.State_Active # draw fuzzy-open completion as focused, even if focus is on the line edit options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = QApplication.style() if options.widget is None else options.widget.style() doc = QTextDocument() if self._font is not None: doc.setDefaultFont(self._font) doc.setDocumentMargin(1) doc.setHtml(options.text) # bad long (multiline) strings processing doc.setTextWidth(options.rect.width()) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected if option.state & QStyle.State_Selected: ctx.palette.setColor(QPalette.Text, option.palette.color(QPalette.Active, QPalette.Text)) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
class HyperlinkItemDelegate(QStyledItemDelegate): linkActivated = QtCore.pyqtSignal(str) def __init__(self, parentView: QTableView, link_color: str = ''): QStyledItemDelegate.__init__(self, parentView) parentView.setMouseTracking(True) self.doc_hovered_item = QTextDocument(self) self.doc_hovered_item.setDocumentMargin(0) self.doc_not_hovered = QTextDocument(self) self.doc_not_hovered.setDocumentMargin(0) self.last_hovered_pos = QPoint(0, 0) self.ctx_mnu = QMenu() self.last_link = None self.last_text = None if not link_color: self.link_color = parentView.palette().color( QPalette.Normal, parentView.palette().Link).name() else: self.link_color = link_color self.action_copy_link = self.ctx_mnu.addAction("Copy Link Location") self.action_copy_link.triggered.connect( self.on_action_copy_link_triggered) self.action_copy_text = self.ctx_mnu.addAction("Copy text") self.action_copy_text.triggered.connect( self.on_action_copy_text_triggered) def paint(self, painter, option: QStyleOptionViewItem, index: QModelIndex): self.initStyleOption(option, index) has_focus = self.parent().hasFocus() mouse_over = option.state & QStyle.State_MouseOver painter.save() if option.state & QStyle.State_Selected: if has_focus: painter.fillRect( option.rect, QBrush( option.palette.color(QPalette.Active, option.palette.Highlight))) color = option.palette.color( QPalette.Normal, option.palette.HighlightedText).name() else: painter.fillRect( option.rect, QBrush( option.palette.color(QPalette.Inactive, option.palette.Highlight))) color = option.palette.color( QPalette.Inactive, option.palette.HighlightedText).name() else: painter.setBrush( QBrush( option.palette.color(QPalette.Normal, option.palette.Base))) color = self.link_color if mouse_over: doc = self.doc_hovered_item self.last_hovered_pos = option.rect.topLeft() doc.setDefaultStyleSheet(f"a {{color: {color}}}") else: doc = self.doc_not_hovered self.parent().unsetCursor() doc.setDefaultStyleSheet( f"a {{text-decoration: none;color: {color};}}") doc.setDefaultFont(option.font) doc.setHtml(option.text) painter.translate(option.rect.topLeft() + QPoint(HTML_LINK_HORZ_MARGIN, 0)) ctx = QAbstractTextDocumentLayout.PaintContext() ctx.palette = option.palette clip = QRect(0, 0, option.rect.width() - HTML_LINK_HORZ_MARGIN * 2, option.rect.height()) painter.setClipRect(clip) doc.documentLayout().draw(painter, ctx) painter.restore() def editorEvent(self, event, model, option, index): if event.type() not in [QEvent.MouseMove, QEvent.MouseButtonRelease] \ or not (option.state & QStyle.State_Enabled): return False pos = QPointF(event.pos() - option.rect.topLeft()) anchor = self.doc_hovered_item.documentLayout().anchorAt(pos) if not anchor: self.parent().unsetCursor() else: self.parent().setCursor(Qt.PointingHandCursor) if event.type() == QEvent.MouseButtonRelease: if event.button() == Qt.LeftButton: self.linkActivated.emit(anchor) return True elif event.button() == Qt.RightButton: self.last_text = self.doc_hovered_item.toRawText() self.last_link = anchor p = QPoint( event.pos().x(), event.pos().y() + min(32, self.ctx_mnu.height())) p = option.widget.mapToGlobal(p) self.ctx_mnu.exec(p) return False def on_action_copy_link_triggered(self): clipboard = QApplication.clipboard() clipboard.setText(self.last_link) def on_action_copy_text_triggered(self): clipboard = QApplication.clipboard() clipboard.setText(self.last_text)
class SyntaxHighlightDelegate(QStyledItemDelegate): def __init__(self, parent=None, arch: str = "x86", dark_theme: bool = False): super(SyntaxHighlightDelegate, self).__init__(parent) self.doc = QTextDocument(self) self.highlighted_columns = [3] self.syntax_colors = [] self.custom_hl = [] self.register_hl = {} if dark_theme: self.load_syntax_file("gui/syntax_hl/syntax_x86_dark.txt") self.reg_hl_color = QColor("#000000") self.reg_hl_bg_color = QColor("#ffffff") else: self.load_syntax_file("gui/syntax_hl/syntax_x86_light.txt") self.reg_hl_color = QColor("#ffffff") self.reg_hl_bg_color = QColor("#333333") def set_reg_highlight(self, reg: str, enabled: bool): regs_hl = prefs.HL_REGS_X86 words = regs_hl.get(reg, [reg]) if enabled: self.register_hl[reg] = words elif reg in self.register_hl: del self.register_hl[reg] def load_syntax_file(self, filename: str): with open(filename) as f: self.syntax_colors = json.load(f) def paint(self, painter, option, index): painter.save() options = QStyleOptionViewItem(option) self.initStyleOption(options, index) self.doc.setPlainText(options.text) if index.column() in self.highlighted_columns: options.font.setWeight(QFont.Bold) self.highlight() self.doc.setDefaultFont(options.font) options.text = "" style = ( QApplication.style() if options.widget is None else options.widget.style() ) style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() if option.state & QStyle.State_Selected: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText), ) else: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.Text), ) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) if index.column() != 0: textRect.adjust(5, 0, 0, 0) the_constant = 4 margin = (option.rect.height() - options.fontMetrics.height()) // 2 margin = margin - the_constant textRect.setTop(textRect.top() + margin) painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) self.doc.documentLayout().draw(painter, ctx) painter.restore() def highlight(self): char_format = QTextCharFormat() cursor = QTextCursor(self.doc) while not cursor.isNull() and not cursor.atEnd(): cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) color = self.get_register_hl_color(cursor.selectedText()) if color is not None: char_format.setBackground(self.reg_hl_bg_color) else: color = self.get_color(cursor.selectedText()) if color is not None: char_format.setForeground(color) cursor.mergeCharFormat(char_format) char_format.clearBackground() self.move_to_next_word(self.doc, cursor) def move_to_next_word(self, doc, cursor): while not cursor.isNull() and not cursor.atEnd(): if doc.characterAt(cursor.position()) not in (" ", ",", "+", "[", "]"): return cursor.movePosition(QTextCursor.NextCharacter) def get_register_hl_color(self, word_to_check: str): for words in self.register_hl.values(): if word_to_check in words: return QColor(self.reg_hl_color) return None def get_color(self, word_to_check: str): for syntax in self.syntax_colors: if "words" in syntax: for word in syntax["words"]: if word == word_to_check: return QColor(syntax["color"]) if "startswith" in syntax: for sw in syntax["startswith"]: if word_to_check.startswith(sw): return QColor(syntax["color"]) if "has" in syntax: for has in syntax["has"]: if has in word_to_check: return QColor(syntax["color"]) return None
class SyntaxHighlightDelegate(QStyledItemDelegate): def __init__(self, parent=None): super(SyntaxHighlightDelegate, self).__init__(parent) self.doc = QTextDocument(self) self.disasm_columns = [] self.value_columns = [] self.highlighted_regs = {} self.reg_hl_color = prefs.REG_HL_COLOR self.reg_hl_bg_colors = prefs.REG_HL_BG_COLORS self.ignored_chars = (" ", ",", "+", "[", "]") self.disasm_rules = self.load_rules_file(prefs.DISASM_RULES_FILE) self.value_rules = self.load_rules_file(prefs.VALUE_RULES_FILE) def load_rules_file(self, filename: str) -> list: """Loads syntax highlighting rules from json file""" with open(filename) as f: return json.load(f) def reset(self): """Resets highlighter""" self.highlighted_regs = {} def paint(self, painter, option, index): painter.save() options = QStyleOptionViewItem(option) self.initStyleOption(options, index) self.doc.setPlainText(options.text) column = index.column() if column in self.disasm_columns: options.font.setWeight(QFont.Bold) self.highlight(self.doc, self.disasm_rules) elif column in self.value_columns: options.font.setWeight(QFont.Bold) self.highlight(self.doc, self.value_rules) self.doc.setDefaultFont(options.font) options.text = "" style = (QApplication.style() if options.widget is None else options.widget.style()) style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() if option.state & QStyle.State_Selected: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText), ) else: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.Text), ) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) if index.column() != 0: textRect.adjust(5, 0, 0, 0) the_constant = 4 margin = (option.rect.height() - options.fontMetrics.height()) // 2 margin = margin - the_constant textRect.setTop(textRect.top() + margin) painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) self.doc.documentLayout().draw(painter, ctx) painter.restore() def set_reg_highlight(self, reg: str, enabled: bool): """Enables or disables register highlight""" regs_hl = prefs.HL_REGS_X86 words = regs_hl.get(reg, [reg]) if enabled: self.highlighted_regs[reg] = words elif reg in self.highlighted_regs: del self.highlighted_regs[reg] def highlight(self, document: QTextDocument, rules: list): """Highlights document""" char_format = QTextCharFormat() cursor = QTextCursor(document) while not cursor.isNull() and not cursor.atEnd(): cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) text = cursor.selectedText() color, bgcolor = self.get_register_hl_color( text, self.highlighted_regs) if not color: color, bgcolor = self.get_color(text, rules) if color: char_format.setForeground(QColor(color)) if bgcolor: char_format.setBackground(QColor(bgcolor)) if color or bgcolor: cursor.mergeCharFormat(char_format) char_format.clearBackground() self.move_to_next_word(document, cursor) def move_to_next_word(self, doc: QTextDocument, cursor: QTextCursor): """Moves cursor to next word""" while not cursor.isNull() and not cursor.atEnd(): if doc.characterAt(cursor.position()) not in self.ignored_chars: return cursor.movePosition(QTextCursor.NextCharacter) def get_register_hl_color(self, word_to_check: str, regs_hl: dict) -> tuple: """Gets color and bgcolor if given word is found in regs_hl""" color_index = 0 for words in regs_hl.values(): if word_to_check in words: if color_index < len(self.reg_hl_bg_colors): bg_color = self.reg_hl_bg_colors[color_index] else: bg_color = self.reg_hl_bg_colors[-1] return (self.reg_hl_color, bg_color) color_index += 1 return ("", "") def get_color(self, word_to_check: str, rules: dict) -> tuple: """Gets color and bgcolor if given word is found in rules""" for rule in rules: if "words" in rule: for word in rule["words"]: if word == word_to_check: return (rule["color"], rule.get("bgcolor", "")) if "startswith" in rule: for sw in rule["startswith"]: if word_to_check.startswith(sw): return (rule["color"], rule.get("bgcolor", "")) if "has" in rule: for has in rule["has"]: if has in word_to_check: return (rule["color"], rule.get("bgcolor", "")) return ("", "")
class SyntaxHighlightDelegate(QStyledItemDelegate): def __init__(self, parent=None, arch="x86", use_darker_text_color=False): super(SyntaxHighlightDelegate, self).__init__(parent) self.doc = QTextDocument(self) self.syntax_colors = SYNTAX_COLORS_X86 self.highlighted_columns = [3] self.use_darker_text_color = use_darker_text_color def paint(self, painter, option, index): painter.save() options = QStyleOptionViewItem(option) self.initStyleOption(options, index) self.doc.setPlainText(options.text) if index.column() in self.highlighted_columns: self.highlight() options.text = "" style = (QApplication.style() if options.widget is None else options.widget.style()) style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() if option.state & QStyle.State_Selected: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.HighlightedText), ) else: ctx.palette.setColor( QPalette.Text, option.palette.color(QPalette.Active, QPalette.Text), ) textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) if index.column() != 0: textRect.adjust(5, 0, 0, 0) the_constant = 4 margin = (option.rect.height() - options.fontMetrics.height()) // 2 margin = margin - the_constant textRect.setTop(textRect.top() + margin) painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) self.doc.documentLayout().draw(painter, ctx) painter.restore() def highlight(self): char_format = QTextCharFormat() cursor = QTextCursor(self.doc) while not cursor.isNull() and not cursor.atEnd(): cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) color = self.get_color(cursor.selectedText()) if color is not None: if self.use_darker_text_color: color = color.darker() char_format.setForeground(color) cursor.mergeCharFormat(char_format) self.move_to_next_word(self.doc, cursor) def move_to_next_word(self, doc, cursor): while not cursor.isNull() and not cursor.atEnd(): if doc.characterAt(cursor.position()) not in (" ", ",", "+", "[", "]"): return cursor.movePosition(QTextCursor.NextCharacter) def get_color(self, word_to_check: str): for syntax in self.syntax_colors: if "words" in syntax: for word in syntax["words"]: if word == word_to_check: return syntax["color"] if "startswith" in syntax: for sw in syntax["startswith"]: if word_to_check.startswith(sw): return syntax["color"] if "has" in syntax: for has in syntax["has"]: if has in word_to_check: return syntax["color"] return None
class OutputItem: """Class to store output for a single node. Stores text lines and original indent level. """ def __init__(self, spot, level): """Convert the spot's node into an output item. Create a blank item if spot is None. Arguments: spot -- the tree spot to convert level -- the node's original indent level """ if spot: node = spot.nodeRef nodeFormat = node.formatRef if not nodeFormat.useTables: self.textLines = [ line + '<br />' for line in node.output(spotRef=spot) ] else: self.textLines = node.output(keepBlanks=True, spotRef=spot) if not self.textLines: self.textLines = [''] self.addSpace = nodeFormat.spaceBetween self.siblingPrefix = nodeFormat.siblingPrefix self.siblingSuffix = nodeFormat.siblingSuffix if nodeFormat.useBullets and self.textLines: # remove <br /> extra space for bullets self.textLines[-1] = self.textLines[-1][:-6] self.uId = node.uId else: self.textLines = [''] self.addSpace = False self.siblingPrefix = '' self.siblingSuffix = '' self.uId = None self.level = level # following variables used by printdata only: self.height = 0 self.pageNum = 0 self.columnNum = 0 self.pagePos = 0 self.doc = None self.parentItem = None self.lastChildItem = None def duplicate(self): """Return an independent copy of this OutputItem. """ item = OutputItem(None, 0) item.textLines = self.textLines[:] item.addSpace = self.addSpace item.siblingPrefix = self.siblingPrefix item.siblingSuffix = self.siblingSuffix item.uId = self.uId item.level = self.level item.height = self.height item.pageNum = self.pageNum item.columnNum = self.columnNum item.pagePos = self.pagePos item.doc = None item.parentItem = self.parentItem item.lastChildItem = self.lastChildItem return item def addIndent(self, prevLevel, nextLevel): """Add <div> tags to define indent levels in the output. Arguments: prevLevel -- the level of the previous item in the list nextLevel -- the level of the next item in the list """ for num in range(self.level - prevLevel): self.textLines[0] = '<div>' + self.textLines[0] for num in range(self.level - nextLevel): self.textLines[-1] += '</div>' def addAbsoluteIndent(self, pixels): """Add tags for an individual indentation. Removes the <br /> tag from the last line to avoid excess space, since <div> starts a new line. The Qt output view does not fully support nested <div> tags. Arguments: pixels -- the amount to indent """ self.textLines[0] = ('<div style="margin-left: {0}">{1}'.format( pixels * self.level, self.textLines[0])) if not self.siblingPrefix and self.textLines[-1].endswith('<br />'): self.textLines[-1] = self.textLines[-1][:-6] self.textLines[-1] += '</div>' def addSiblingPrefix(self): """Add the sibling prefix before this output. """ if self.siblingPrefix: self.textLines[0] = self.siblingPrefix + self.textLines[0] def addSiblingSuffix(self): """Add the sibling suffix after this output. """ if self.siblingSuffix: self.textLines[-1] += self.siblingSuffix def addAnchor(self): """Add a link anchor to this item. """ self.textLines[0] = '<a id="{0}" />{1}'.format(self.uId, self.textLines[0]) def intLinkIds(self): """Return a set of uIDs from any internal links in this item. """ linkIds = set() for line in self.textLines: startPos = 0 while True: match = _linkRe.search(line, startPos) if not match: break uId = match.group(1) if uId: linkIds.add(uId) startPos = match.start(1) return linkIds def numLines(self): """Return the number of text lines in the item. """ return len(self.textLines) def equalPrefix(self, otherItem): """Return True if sibling prefixes and suffixes are equal. Arguments: otherItem -- the item to compare """ return (self.siblingPrefix == otherItem.siblingPrefix and self.siblingSuffix == otherItem.siblingSuffix) def setDocHeight(self, paintDevice, width, printFont, replaceDoc=False): """Set the height of this item for use in printer output. Creates an output document if not already created. Arguments: paintDevice -- the printer or other device for settings width -- the width available for the output text printFont -- the default font for the document replaceDoc -- if true, re-create the text document """ if not self.doc or replaceDoc: self.doc = QTextDocument() lines = '\n'.join(self.textLines) if lines.endswith('<br />'): # remove trailing <br /> tag to avoid excess space lines = lines[:-6] self.doc.setHtml(lines) self.doc.setDefaultFont(printFont) frameFormat = self.doc.rootFrame().frameFormat() frameFormat.setBorder(0) frameFormat.setMargin(0) frameFormat.setPadding(0) self.doc.rootFrame().setFrameFormat(frameFormat) layout = self.doc.documentLayout() layout.setPaintDevice(paintDevice) self.doc.setTextWidth(width) self.height = layout.documentSize().height() def splitDocHeight(self, initHeight, maxHeight, paintDevice, width, printFont): """Split this item into two items and return them. The first item will fit into initHeight if practical. Splits at line endings if posible. Arguments: initHeight -- the preferred height of the first page maxheight -- the max height of any pages paintDevice -- the printer or other device for settings width -- the width available for the output text printFont -- the default font for the document """ newItem = self.duplicate() fullHeight = self.height lines = '\n'.join(self.textLines) allLines = [line + '<br />' for line in lines.split('<br />')] self.textLines = [] prevHeight = 0 for line in allLines: self.textLines.append(line) self.setDocHeight(paintDevice, width, printFont, True) if ((prevHeight and self.height > initHeight and fullHeight - prevHeight > maxHeight) or (prevHeight and self.height > maxHeight)): self.textLines = self.textLines[:-1] self.setDocHeight(paintDevice, width, printFont, True) newItem.textLines = allLines[len(self.textLines):] newItem.setDocHeight(paintDevice, width, printFont, True) return (self, newItem) if self.height > maxHeight: break prevHeight = self.height # no line ending breaks found text = ' \n'.join(allLines) allWords = [word + ' ' for word in text.split(' ')] newWords = [] prevHeight = 0 for word in allWords: if word.strip() == '<img': break newWords.append(word) self.textLines = [''.join(newWords)] self.setDocHeight(paintDevice, width, printFont, True) if ((prevHeight and self.height > initHeight and fullHeight - prevHeight < maxHeight) or (prevHeight and self.height > maxHeight)): self.textLines = [''.join(newWords[:-1])] self.setDocHeight(paintDevice, width, printFont, True) newItem.textLines = [''.join(allWords[len(newWords):])] newItem.setDocHeight(paintDevice, width, printFont, True) return (self, newItem) if self.height > maxHeight: break prevHeight = self.height newItem.setDocHeight(paintDevice, width, printFont, True) return (newItem, None) # fail to split