def fixUpLine(self, line: int, newText: str, data: int): """ The receiver of the 'fixupText' signal should invoke this method to replace the line with the cleaned text and the model's matching row """ block = self.document().findBlockByLineNumber(line) if block.isValid(): if block.userData() is None: block.setUserData(self._UserData(data)) else: block.userData().row = data text = newText.strip() if not text: block.setUserState(self._State.Blank) elif data < 0: block.setUserState(self._State.Error) else: block.setUserState(self._State.Fixup) cursor = QTextCursor(block) cursor.beginEditBlock() cursor.movePosition(QTextCursor.StartOfLine) cursor.select(QTextCursor.LineUnderCursor) cursor.removeSelectedText() cursor.insertText(text) cursor.endEditBlock()
def _update_text(self, changes): """Apply the changes to our QTextDocument.""" c = QTextCursor(self.document()) c.beginEditBlock() for start, end, text in reversed(changes): c.setPosition(end) if start != end: c.setPosition(start, QTextCursor.KeepAnchor) c.insertText(text) c.endEditBlock()
def keywordHighlight(self, doc): cursor = QTextCursor(doc) cursor.beginEditBlock() fmt = QTextCharFormat() fmt.setBackground(Qt.darkYellow) highlightCursor = QTextCursor(doc) while not highlightCursor.isNull() and not highlightCursor.atEnd(): highlightCursor = doc.find(self.keyword, highlightCursor) if not highlightCursor.isNull(): highlightCursor.mergeCharFormat(fmt) cursor.endEditBlock()
async def __readAndPrintStream(self, sr: asyncio.StreamReader, text_cursor: QTextCursor): leftover_data = bytearray() while not sr.at_eof() or len(leftover_data) > 0: separator_encountered = False meaningful_data = None cr_found = False lf_found = False while not separator_encountered: leftover_data += await sr.read(64) separator_index = -1 for index, b in enumerate(leftover_data): if b == ord(b'\r'): separator_index = index cr_found = True break elif b == ord(b'\n'): separator_index = index lf_found = True break if separator_index != -1: separator_encountered = True meaningful_data = leftover_data[0:separator_index] leftover_data = leftover_data[separator_index + 1:] else: leftover_data += leftover_data[separator_index + 1:] text = meaningful_data.decode( ) if meaningful_data is not None else '' text_cursor.beginEditBlock() if cr_found: text_cursor.movePosition(QTextCursor.StartOfLine) text_cursor.insertText(text) i = 1 count = len(text) while i <= count: text_cursor.deleteChar() i += 1 elif lf_found: text_cursor.insertText(text + '\n') else: text_cursor.insertText(text) text_cursor.endEditBlock() self.__ui.terminalLogWindow.ensureCursorVisible()
def set_bytes(self, bs): self.pretty_mode = False self.data = bs chunks = HextEditor._split_by_printables(bs) self.clear() cursor = QTextCursor(self.textedit.document()) cursor.beginEditBlock() cursor.select(QTextCursor.Document) cursor.setCharFormat(QTextCharFormat()) cursor.clearSelection() for chunk in chunks: if chr(chunk[0]) in qtprintable: cursor.insertText(chunk.decode()) else: for b in chunk: self._insert_byte(cursor, b) cursor.endEditBlock()
def on_findButton_clicked(self): search_string = self.ui_line_edit.text() document = self.ui_text_edit.document() self.found = False document.undo() if not search_string: QMessageBox.information(self, "Empty Search Field", 'Please enter a word') else: highlight_cursor = QTextCursor(document) cursor = QTextCursor(document) cursor.beginEditBlock() plain_format = QTextCharFormat(highlight_cursor.charFormat()) color_format = plain_format color_format.setForeground(Qt.red) while not highlight_cursor.isNull() and not highlight_cursor.atEnd(): highlight_cursor = document.find( search_string, highlight_cursor, QTextDocument.FindWholeWords ) if not highlight_cursor.isNull(): self.found = True highlight_cursor.movePosition(QTextCursor.WordRight, QTextCursor.KeepAnchor) highlight_cursor.mergeCharFormat(color_format) cursor.endEditBlock() if not self.found: QMessageBox.information(self, "Word not found", "Sorry, the word coannot be found")
def apply_changes(self): """Apply the changes and update the tokens.""" c = QTextCursor(self._d) # record a sensible position for undo c.setPosition(self._changes_list[-1][0]) c.joinPreviousEditBlock() if self.combine_undo else c.beginEditBlock() try: for start, end, text in self._changes_list: c.movePosition(QTextCursor.End) if end is None else c.setPosition(end) c.setPosition(start, QTextCursor.KeepAnchor) c.insertText(text) finally: c.endEditBlock() if self.combine_undo is None: self.combine_undo = True
def apply_changes(self): """Apply the changes and update the tokens.""" c = QTextCursor(self._d) # record a sensible position for undo c.setPosition(self._changes_list[-1][0]) c.joinPreviousEditBlock() if self.combine_undo else c.beginEditBlock() try: for start, end, text in self._changes_list: c.movePosition( QTextCursor.End) if end is None else c.setPosition(end) c.setPosition(start, QTextCursor.KeepAnchor) c.insertText(text) finally: c.endEditBlock() if self.combine_undo is None: self.combine_undo = True
class TextSectionEditor(QTextDocument): def __init__(self, sectionId: str, content="", pos=0, selectionStart=0, selectionEnd=0): super().__init__() self.dtb = DTB() self.sectionId = sectionId self.setDefaultStyleSheet(CSS) self.setHtml(content) self.s_start = selectionStart self.s_end = selectionEnd self.cur = QTextCursor(self) self.cur.setPosition(pos) self.result = { "text": "", "cursorPosition": self.pos, "eventAccepted": False } self.pending = False @property def len(self): return self.characterCount() @property def s_len(self): return abs(self.s_end - self.s_start) @property def pos(self): return self.cur.position() def onChange(self): self._update_ddb() self.setResponse(True) return self.result def onLoad(self): item = self.dtb.getDB("Section", self.sectionId) self.setHtml(item["text"]) self.setResponse(True, cur=self.len) return self.result def onMenu(self, style={}, **kwargs): backup = [self.pos, self.s_start, self.s_end] for k, v in style.items(): # un peut répétition mais uniquement sur des if alors ... if k == "fgColor": self._set_fg_color(v) elif k == "underline": # pragma: no branch self._set_underline(style["underline"]) self.cur.setPosition(backup[0]) self.s_start = backup[1] self.s_end = backup[2] if self.pending: # else: self._update_ddb() else: self.setResponse(False) return self.result def onKey(self, event): # on met en premier ceux à qui il faut passer l'event if event["key"] == Qt.Key_Return: self.do_key_return(event) elif event["modifiers"] == Qt.ControlModifier: self.do_control_modifier(event) else: self.setResponse(False) if self.pending: self._update_ddb() return self.result def do_control_modifier(self, event): if event == KeyW.KEY_1: self.do_key_1() elif event == KeyW.KEY_2: self.do_key_2() elif event == KeyW.KEY_3: self.do_key_3() elif event == KeyW.KEY_4: self.do_key_4() elif event["key"] == Qt.Key_U: # pragma: no branch self.do_key_u() def do_key_1(self): self._set_fg_color(BLACK) def do_key_2(self): self._set_fg_color(BLUE) def do_key_3(self): self._set_fg_color(GREEN) def do_key_4(self): self._set_fg_color(RED) def do_key_return(self, event): block = self.findBlock(self.pos) if event["modifiers"] == Qt.ControlModifier: self._appendEmptyBlock() elif event["modifiers"] == Qt.ShiftModifier: self._insertEmptyBlock() elif block.blockFormat().headingLevel(): self._appendEmptyBlock() else: if self._headerAutoFormat(): return else: self.setResponse(False) def do_key_u(self): self._set_underline("toggle") def setResponse(self, accepted, text=None, cur=None): self.result["text"] = text or self.toHtml() self.result["cursorPosition"] = cur or self.cur.position() self.result["eventAccepted"] = accepted def _appendEmptyBlock(self, section="p", pre_move=QTextCursor.EndOfBlock, set_response=True): self.cur.movePosition(pre_move) self.cur.insertBlock(blockFormat[section], blockCharFormat[section]) self.cur.insertFragment(QTextDocumentFragment.fromPlainText("")) self.pending = True if set_response: self.setResponse(True) def _insertEmptyBlock(self, section="p", pre_move=QTextCursor.StartOfBlock, set_response=True): old = self.cur.blockFormat().headingLevel() self._appendEmptyBlock(pre_move=pre_move, set_response=False) self._set_block_style(old) self.cur.movePosition(QTextCursor.PreviousBlock) self._set_block_style(section) self.pending = True if set_response: # pragma: no branch self.setResponse(True) def _headerAutoFormat(self): # on check les expressions régulières suivantes: # #, ##, ###, ####, ##### line = self.cur.block().text() matched = RE_AUTOPARAGRAPH_DEBUT.search(line) matched_at_start = False if not matched: matched = RE_AUTOPARAGRAPH_FIN.search(line) if not matched: return False else: matched_at_start = True # strip les # et applique les styles par défault level = len(matched.groups()[0]) if matched_at_start: text = self.cur.block().text()[level + 1:] else: text = self.cur.block().text()[:-(level + 1)] self.cur.beginEditBlock() self.cur.select(QTextCursor.LineUnderCursor) self.cur.setCharFormat(blockCharFormat[level]) self.cur.insertText(text) self.cur.setBlockFormat(blockFormat[level]) self.cur.endEditBlock() self._appendEmptyBlock() self.pending = True self.setResponse(True) return True @contextmanager def _merge_char_format(self): self._select_word_or_selection() f: QTextCharFormat = QTextCharFormat() yield f self.cur.mergeCharFormat(f) self.pending = True self.setResponse(True, cur=max(self.pos, self.s_start, self.s_end)) def _select_word_or_selection(self): if self.s_start < self.pos: self.cur.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, self.s_len) elif self.s_end > self.pos: self.cur.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, self.s_len) else: self.cur.select(QTextCursor.WordUnderCursor) def _set_block_style(self, level): self.cur.setBlockFormat(blockFormat[level]) self.cur.setBlockCharFormat(blockCharFormat[level]) def _set_fg_color(self, color): with self._merge_char_format() as f: f.setForeground(QBrush(QColor(color))) def _set_underline(self, value): with self._merge_char_format() as f: if value == "toggle": value = not self.cur.charFormat().fontUnderline() f.setFontUnderline(value) def _update_ddb(self): new_body = TextSectionFormatter(self.toHtml()).build_body() self.dtb.setDB("Section", self.sectionId, {"text": new_body}) return new_body