def edit(self, cursor): """Edit the block at the specified QTextCursor.""" if self._document: self._document.closed.disconnect(self.reject) self._document = cursor.document() self._document.closed.connect(self.reject) # don't change the cursor c = self._range = QTextCursor(cursor) cursorpos = c.position() - c.block().position() cursortools.strip_indent(c) indentpos = c.position() - c.block().position() c.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) self.view.setPlainText(c.selection().toPlainText()) self.highlighter.setInitialState( tokeniter.state(cursortools.block(cursor))) self.highlighter.setHighlighting( metainfo.info(cursor.document()).highlighting) self.highlighter.rehighlight() # let autocomplete query the real document as if we're at the start # of the current block self.completer.document_cursor = QTextCursor(cursor.block()) self.completer.autoComplete = QSettings().value("autocomplete", True) not in ('false', False) cursor = self.view.textCursor() cursor.setPosition(max(0, cursorpos - indentpos)) self.view.setTextCursor(cursor) self.updateMessage()
def insert_snippet(text, cursor, variables): """Inserts a normal text snippet. After the insert, the cursor points to the end of the inserted snippet. If this function returns a cursor it must be set as the cursor for the view after the snippet has been inserted. """ exp_base = expand.Expander(cursor) evs = [] # make a list of events, either text or a constant for text, key in snippets.expand(text): if text: evs.append(text) if key == '$': evs.append('$') elif key: # basic variables func = getattr(exp_base, key, None) if func: evs.append(func()) selectionUsed = expand.SELECTION in evs # do the padding if 'selection: strip;' is used if selectionUsed and 'strip' in variables.get('selection', ''): space = '\n' if '\n' in cursor.selection().toPlainText() else ' ' # change whitespace in previous and next piece of text i = evs.index(expand.SELECTION) for j in range(i-1, -i, -1): if evs[j] not in expand.constants: evs[j] = evs[j].rstrip() + space break for j in range(i+1, len(evs)): if evs[j] not in expand.constants: evs[j] = space + evs[j].lstrip() break # now insert the text ins = QTextCursor(cursor) selectionUsed and ins.setPosition(cursor.selectionStart()) a, c = -1, -1 for e in evs: if e == expand.ANCHOR: a = ins.position() elif e == expand.CURSOR: c = ins.position() elif e == expand.SELECTION: ins.setPosition(cursor.selectionEnd()) else: ins.insertText(e) cursor.setPosition(ins.position()) # return a new cursor if requested if (a, c) != (-1, -1): new = QTextCursor(cursor) if a != -1: new.setPosition(a) if c != -1: new.setPosition(c, QTextCursor.KeepAnchor if a != -1 else QTextCursor.MoveAnchor) return new
def put_some_text_in(self): c = QTextCursor(self.text.document()) c.insertText("sat") c.insertBlock() c.insertImage(self.load_an_image(), 'image') c.insertBlock() c.insertText("unsat") # Move back to head of document self.text.setTextCursor(QTextCursor(self.text.document()))
def insert_python(text, cursor, name, view): """Regards the text as Python code, and exec it. name and view are given in case an exception occurs. The following variables are available: - text: contains selection or '', set it to insert new text - state: contains simplestate for the cursor position - cursor: the QTextCursor After the insert, the cursor points to the end of the inserted snippet. """ namespace = { 'cursor': QTextCursor(cursor), 'state': state(cursor), 'text': cursor.selection().toPlainText(), 'view': view, 'ANCHOR': 1, 'CURSOR': 2, } try: code = compile(text, "<snippet>", "exec") if sys.version_info < (3, 0): exec("exec code in namespace") else: exec(code, namespace) if 'main' in namespace: return namespace['main']() except Exception: handle_exception(name, view) else: text = namespace.get('text', '') if isinstance(text, (tuple, list)): ANCHOR = namespace.get('ANCHOR', 1) CURSOR = namespace.get('CURSOR', 2) a, c = -1, -1 for t in text: if t == ANCHOR: a = cursor.selectionStart() elif t == CURSOR: c = cursor.selectionStart() else: cursor.insertText(t) if (a, c) != (-1, -1): new = QTextCursor(cursor) if a != -1: new.setPosition(a) if c != -1: new.setPosition( c, QTextCursor.KeepAnchor if a != -1 else QTextCursor.MoveAnchor) return new else: cursor.insertText(namespace['text'])
def selectedPosition(self, pos): anchorPos, cursorPos = pos anchorLine, anchorCol = anchorPos cursorLine, cursorCol = cursorPos anchorCursor = QTextCursor( self.document().findBlockByNumber(anchorLine)) setPositionInBlock(anchorCursor, anchorCol) # just get absolute position cursor = QTextCursor(self.document().findBlockByNumber(cursorLine)) setPositionInBlock(cursor, cursorCol) anchorCursor.setPosition(cursor.position(), QTextCursor.KeepAnchor) self.setTextCursor(anchorCursor)
def append(self, text): """Append line to the end """ cursor = QTextCursor(self._doc) cursor.movePosition(QTextCursor.End) cursor.insertBlock() cursor.insertText(text)
def onMatchNumberChange(self, matchNumber): # Set default format on the whole text before highlighting the selected # match. document = self.matchText.document() cursor = QTextCursor(document) cursor.movePosition(QTextCursor.End, QTextCursor.KeepAnchor) cursor.setCharFormat(QTextCharFormat()) search = self.getSearchText() for i, match in enumerate(self.regex.finditer(search)): if i + 1 == matchNumber: break else: assert False, ("We didn't find a match?! (RE=%r, text=%r" % (self.regex.pattern, search)) self.formatMatchedText(document, match) model = self.groupsView.model() model.clear() # Create a reversed self.regex.groupindex dictionnary groupsIndexes = dict( (v, k) for (k, v) in self.regex.groupindex.iteritems()) for i in range(1, self.regex.groups + 1): groupName = groupsIndexes.get(i, "") groupValue = match.group(i) model.append((groupName, groupValue))
def cursors(self): """Cursors for rectangular selection. 1 cursor for every line """ cursors = [] if self._start is not None: startLine, startVisibleCol = self._start currentLine, currentCol = self._qpart.cursorPosition if abs(startLine - currentLine) > self._MAX_SIZE or \ abs(startVisibleCol - currentCol) > self._MAX_SIZE: # Too big rectangular selection freezes the GUI self._qpart.userWarning.emit('Rectangular selection area is too big') self._start = None return [] currentBlockText = self._qpart.textCursor().block().text() currentVisibleCol = self._realToVisibleColumn(currentBlockText, currentCol) for lineNumber in range(min(startLine, currentLine), max(startLine, currentLine) + 1): block = self._qpart.document().findBlockByNumber(lineNumber) cursor = QTextCursor(block) realStartCol = self._visibleToRealColumn(block.text(), startVisibleCol) realCurrentCol = self._visibleToRealColumn(block.text(), currentVisibleCol) if realStartCol is None: realStartCol = block.length() # out of range value if realCurrentCol is None: realCurrentCol = block.length() # out of range value cursor.setPosition(cursor.block().position() + min(realStartCol, block.length() - 1)) cursor.setPosition(cursor.block().position() + min(realCurrentCol, block.length() - 1), QTextCursor.KeepAnchor) cursors.append(cursor) return cursors
def setLine(self, line): cursor = QTextCursor(self.document()) cursor.movePosition(QTextCursor.End) cursor.setPosition(self.newPromptPos, QTextCursor.KeepAnchor) cursor.removeSelectedText() cursor.insertText(line) self.setTextCursor(cursor)
def load(self, keepUndo=False): """Loads the current url. Returns True if loading succeeded, False if an error occurred, and None when the current url is empty or non-local. Currently only local files are supported. If keepUndo is True, the loading can be undone (with Ctrl-Z). """ fileName = self.url().toLocalFile() if fileName: try: with open(fileName) as f: data = f.read() except (IOError, OSError): return False # errors are caught in MainWindow.openUrl() text = util.decode(data) if keepUndo: c = QTextCursor(self) c.select(QTextCursor.Document) c.insertText(text) else: self.setPlainText(text) self.setModified(False) self.loaded() app.documentLoaded(self) return True
def load(self, url=None, encoding=None, keepUndo=False): """Load the specified or current url (if None was specified). Currently only local files are supported. An IOError is raised when trying to load a nonlocal URL. If loading succeeds and an url was specified, the url is make the current url (by calling setUrl() internally). If keepUndo is True, the loading can be undone (with Ctrl-Z). """ if url is None: url = QUrl() u = url if not url.isEmpty() else self.url() text = self.load_data(u, encoding or self._encoding) if keepUndo: c = QTextCursor(self) c.select(QTextCursor.Document) c.insertText(text) else: self.setPlainText(text) self.setModified(False) if not url.isEmpty(): self.setUrl(url) self.loaded() app.documentLoaded(self)
def articulation_positions(cursor): """Returns a list of positions where an articulation can be added. Every position is given as a QTextCursor instance. If the cursor has a selection, all positions in the selection are returned. """ c = lydocument.cursor(cursor) if not cursor.hasSelection(): # just select until the end of the current line c.select_end_of_block() rests = True partial = ly.document.OUTSIDE else: rests = False partial = ly.document.INSIDE positions = [] for item in ly.rhythm.music_items(c, partial): if not rests and item.tokens and isinstance(item.tokens[0], ly.lex.lilypond.Rest): continue csr = QTextCursor(cursor.document()) csr.setPosition(item.end) positions.append(csr) if not cursor.hasSelection(): break # leave if first found, that's enough return positions
def cursor(self): """Return a QTextCursor with the same selection.""" c = QTextCursor(self.document.document) c.movePosition(QTextCursor.End) if self.end is None else c.setPosition( self.end) c.setPosition(self.start, QTextCursor.KeepAnchor) return c
def postImport(self, settings, doc): """Adaptations of the source after running musicxml2ly Present settings: Reformat source Remove superfluous durations Remove duration scaling Engrave directly """ cursor = QTextCursor(doc) if settings[0]: import reformat reformat.reformat(cursor) if settings[1]: cursor.select(QTextCursor.Document) from rhythm import rhythm rhythm.rhythm_implicit_per_line(cursor) if settings[2]: cursor.select(QTextCursor.Document) from rhythm import rhythm rhythm.rhythm_remove_fraction_scaling(cursor) if settings[3]: import engrave engrave.engraver(self.mainwindow()).engrave('preview', doc, False)
def _find(self, textEdit=None, backward=False): if textEdit is None: textEdit = self.textEdit found = False if textEdit is not None: cursor = textEdit.textCursor() text, flags = self._textAndFindFlags(backward=backward) position = cursor.position() cursor = textEdit.document().find(text, cursor, flags) if not cursor.isNull(): textEdit.setTextCursor(cursor) found = True elif self.wrapAroundCheckBox.isChecked(): cursor = QTextCursor(textEdit.textCursor()) cursor.movePosition(backward and QTextCursor.End or QTextCursor.Start) cursor = textEdit.document().find(text, cursor, flags) if not cursor.isNull(): if position == cursor.position(): pass #todo textEdit.setTextCursor(cursor) found = True self.writeSettings() if not found: QApplication.beep() self.feedbackLabel.setText(self.tr("Not found")) else: self.clearFeedback()
def drawContents(self, painter): """ Reimplementation of drawContents to limit the drawing inside `textRext`. """ painter.setPen(self.__color) painter.setFont(self.font()) if self.__textRect: rect = self.__textRect else: rect = self.rect().adjusted(5, 5, -5, -5) if Qt.mightBeRichText(self.__message): doc = QTextDocument() doc.setHtml(self.__message) doc.setTextWidth(rect.width()) cursor = QTextCursor(doc) cursor.select(QTextCursor.Document) fmt = QTextBlockFormat() fmt.setAlignment(self.__alignment) cursor.mergeBlockFormat(fmt) painter.save() painter.translate(rect.topLeft()) doc.drawContents(painter) painter.restore() else: painter.drawText(rect, self.__alignment, self.__message)
def actionTriggered(self, name): # convert arpeggio_normal to arpeggioNormal, etc. name = _arpeggioTypes[name] cursor = self.mainwindow().textCursor() # which arpeggio type is last used? lastused = '\\arpeggioNormal' types = set(_arpeggioTypes.values()) block = cursor.block() while block.isValid(): s = types.intersection(tokeniter.tokens(block)) if s: lastused = s.pop() break block = block.previous() # where to insert c = lydocument.cursor(cursor) c.select_end_of_block() with cursortools.compress_undo(cursor): for item in ly.rhythm.music_items(c, partial=ly.document.OUTSIDE): c = QTextCursor(cursor.document()) c.setPosition(item.end) c.insertText('\\arpeggio') if name != lastused: cursortools.strip_indent(c) indent = c.block().text()[:c.position() - c.block().position()] c.insertText(name + '\n' + indent) # just pick the first place return
def selected_comment_changed(self, curr, prev): #called whenever another comment is selected self.ui.plainTextEditComment.blockSignals(True) #otherwise it would cause a textChanged() event which would overwrite the data if not curr is None: self.current_comment = self.comments[curr] comment_text = self.current_comment.get_text() self.ui.plainTextEditComment.setPlainText(comment_text) self.ui.plainTextEditComment.setReadOnly(False) self.ui.spinBoxStartLine.setEnabled(True) self.ui.spinBoxEndLine.setEnabled(True) self.ui.spinBoxStartLine.blockSignals(True) self.ui.spinBoxStartLine.setValue(self.current_comment.start_line) self.ui.spinBoxStartLine.blockSignals(False) self.ui.spinBoxEndLine.blockSignals(True) self.ui.spinBoxEndLine.setValue(self.current_comment.end_line) self.ui.spinBoxEndLine.blockSignals(False) #jump to first marker if len(self.current_comment.markers) > 0: first_marker = self.current_comment.markers[0] line = first_marker.line_index cursor = QTextCursor(self.ui.plainTextEditCode.document().findBlockByNumber(line)) #only works without word wrap self.ui.plainTextEditCode.setTextCursor(cursor) else: self.ui.plainTextEditComment.clear() self.ui.plainTextEditComment.setReadOnly(True) self.ui.actionRemove_Comment.setEnabled(False) self.ui.spinBoxStartLine.setEnabled(False) self.ui.spinBoxEndLine.setEnabled(False) self.current_comment = None self.ui.plainTextEditComment.blockSignals(False)
def spanner_positions(cursor): """Return a list with 0 to 2 QTextCursor instances. At the first cursor a starting spanner item can be inserted, at the second an ending item. """ c = lydocument.cursor(cursor) if cursor.hasSelection(): partial = ly.document.INSIDE else: # just select until the end of the current line c.select_end_of_block() partial = ly.document.OUTSIDE items = list(ly.rhythm.music_items(c, partial=partial)) if cursor.hasSelection(): del items[1:-1] else: del items[2:] positions = [] for i in items: c = QTextCursor(cursor.document()) c.setPosition(i.end) positions.append(c) return positions
def html_copy(cursor, scheme='editor', number_lines=False): """Return a new QTextDocument with highlighting set as HTML textcharformats. The cursor is a cursor of a document.Document instance. If the cursor has a selection, only the selection is put in the new document. If number_lines is True, line numbers are added. """ data = textformats.formatData(scheme) doc = QTextDocument() doc.setDefaultFont(data.font) doc.setPlainText(cursor.document().toPlainText()) if metainfo.info(cursor.document()).highlighting: highlight(doc, mapping(data), ly.lex.state(documentinfo.mode(cursor.document()))) if cursor.hasSelection(): # cut out not selected text start, end = cursor.selectionStart(), cursor.selectionEnd() cur1 = QTextCursor(doc) cur1.setPosition(start, QTextCursor.KeepAnchor) cur2 = QTextCursor(doc) cur2.setPosition(end) cur2.movePosition(QTextCursor.End, QTextCursor.KeepAnchor) cur2.removeSelectedText() cur1.removeSelectedText() if number_lines: c = QTextCursor(doc) f = QTextCharFormat() f.setBackground(QColor('#eeeeee')) if cursor.hasSelection(): num = cursor.document().findBlock( cursor.selectionStart()).blockNumber() + 1 last = cursor.document().findBlock(cursor.selectionEnd()) else: num = 1 last = cursor.document().lastBlock() lastnum = last.blockNumber() + 1 padding = len(format(lastnum)) block = doc.firstBlock() while block.isValid(): c.setPosition(block.position()) c.setCharFormat(f) c.insertText('{0:>{1}d} '.format(num, padding)) block = block.next() num += 1 return doc
def goto_target(mainwindow, target): """Switch to the document and location where the node target is.""" filename = target.document.filename doc = app.openUrl(QUrl.fromLocalFile(filename)) cursor = QTextCursor(doc) cursor.setPosition(target.position) browseriface.get(mainwindow).setTextCursor(cursor) mainwindow.currentView().centerCursor()
def insert(self, index, text): """Insert line to the document """ if index < 0 or index > self._doc.blockCount(): raise IndexError('Invalid block index', index) if index == 0: # first cursor = QTextCursor(self._doc.firstBlock()) cursor.insertText(text) cursor.insertBlock() elif index != self._doc.blockCount(): # not the last cursor = QTextCursor(self._doc.findBlockByNumber(index).previous()) cursor.movePosition(QTextCursor.EndOfBlock) cursor.insertBlock() cursor.insertText(text) else: # last append to the end self.append(text)
def formatMatchedText(self, document, match): """Format the matched text in a document""" cursor = QTextCursor(document) cursor.setPosition(match.start()) cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor, match.end() - match.start()) cursor.setCharFormat(self.matchFormat)
def _makeQtExtraSelection(startAbsolutePosition, length): selection = QTextEdit.ExtraSelection() cursor = QTextCursor(self.document()) cursor.setPosition(startAbsolutePosition) cursor.setPosition(startAbsolutePosition + length, QTextCursor.KeepAnchor) selection.cursor = cursor selection.format = self._userExtraSelectionFormat return selection
def show_msg(self, message): """Show message in textBrowser """ self.textEdit.append(message) # Scroll to end of the last message cursor = QTextCursor(self.textEdit.textCursor()) cursor.movePosition(QTextCursor.End) self.textEdit.setTextCursor(cursor) QApplication.processEvents()
def _removeBlock(blockIndex): block = self._doc.findBlockByNumber(blockIndex) if block.next().isValid(): # not the last cursor = QTextCursor(block) cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor) elif block.previous().isValid(): # the last, not the first cursor = QTextCursor(block.previous()) cursor.movePosition(QTextCursor.EndOfBlock) cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor) cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) else: # only one block cursor = QTextCursor(block) cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) cursor.removeSelectedText()
def _onNextBookmark(self): """Previous Bookmark action triggered. Move cursor """ for block in qutepart.iterateBlocksFrom( self._qpart.textCursor().block().next()): if self.isBlockMarked(block) or \ block.blockNumber() in self._qpart.lintMarks: self._qpart.setTextCursor(QTextCursor(block)) return
def _selectLines(self, startBlockNumber, endBlockNumber): """Select whole lines """ startBlock = self.document().findBlockByNumber(startBlockNumber) endBlock = self.document().findBlockByNumber(endBlockNumber) cursor = QTextCursor(startBlock) cursor.setPosition(endBlock.position(), QTextCursor.KeepAnchor) cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) self.setTextCursor(cursor)
def save(self): """Called to perform the edits in the document.""" cursor = QTextCursor(self._range) start = cursor.selectionStart() # use cursordiff; don't destroy point and click positions cursordiff.insert_text(cursor, self.view.toPlainText()) cursor.setPosition(start, QTextCursor.KeepAnchor) with cursortools.compress_undo(cursor, True): # re-indent the inserted line(s) indent.re_indent(cursor)
def is_cell_separator(self, cursor=None, block=None): """Return True if cursor (or text block) is on a block separator""" assert cursor is not None or block is not None if cursor is not None: cursor0 = QTextCursor(cursor) cursor0.select(QTextCursor.BlockUnderCursor) text = to_text_string(cursor0.selectedText()) else: text = to_text_string(block.text()) return text.lstrip().startswith(self.CELL_SEPARATORS)