📄 qtextedit.cpp
字号:
}void QTextEditPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document){ Q_Q(QTextEdit); // for use when called from setPlainText. we may want to re-use the currently // set char format then. const QTextCharFormat charFormatForInsertion = cursor.charFormat(); bool clearDocument = true; if (!doc) { if (document) { doc = document; clearDocument = false; } else { doc = new QTextDocument(q); } QObject::connect(doc->documentLayout(), SIGNAL(update(QRectF)), q, SLOT(_q_repaintContents(QRectF))); QObject::connect(doc->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars())); cursor = QTextCursor(doc); doc->setDefaultFont(q->font()); doc->documentLayout()->setPaintDevice(viewport); QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection())); QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor))); // convenience signal forwards QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged())); QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool))); QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool))); } doc->setUndoRedoEnabled(false); q->setAttribute(Qt::WA_InputMethodEnabled); // avoid multiple textChanged() signals being emitted QObject::disconnect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged())); if (clearDocument) { doc->clear(); cursor.movePosition(QTextCursor::Start); QTextBlockFormat blockFmt; blockFmt.setLayoutDirection(q->layoutDirection()); cursor.setBlockFormat(blockFmt); } if (!text.isEmpty()) { // clear 'our' cursor for insertion to prevent // the emission of the cursorPositionChanged() signal. // instead we emit it only once at the end instead of // at the end of the document after loading and when // positioning the cursor again to the start of the // document. cursor = QTextCursor(); if (format == Qt::PlainText) { QTextCursor insertionCursor(doc); insertionCursor.setCharFormat(charFormatForInsertion); insertionCursor.insertText(text); } else { doc->setHtml(text); } cursor = QTextCursor(doc); } else { // preserve the char format across clear() cursor.movePosition(QTextCursor::Start); cursor.setCharFormat(charFormatForInsertion); } QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged())); emit q->textChanged(); doc->setUndoRedoEnabled(!q->isReadOnly()); _q_updateCurrentCharFormatAndSelection(); doc->setModified(false); anchorToScrollToWhenVisible.clear(); emit q->cursorPositionChanged();}#ifndef QT_NO_DRAGANDDROPvoid QTextEditPrivate::startDrag(){ Q_Q(QTextEdit); mousePressed = false; QMimeData *data = q->createMimeDataFromSelection(); QDrag *drag = new QDrag(q); drag->setMimeData(data); Qt::DropActions actions = Qt::CopyAction; if (!readOnly) actions |= Qt::MoveAction; Qt::DropAction action = drag->start(actions); if (action == Qt::MoveAction && drag->target() != q) cursor.removeSelectedText();}#endif // QT_NO_DRAGANDDROPvoid QTextEditPrivate::setCursorPosition(const QPoint &pos){ const int cursorPos = doc->documentLayout()->hitTest(mapToContents(pos), Qt::FuzzyHit); if (cursorPos == -1) return; cursor.setPosition(cursorPos);}void QTextEditPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode){ cursor.setPosition(pos, mode); if (mode != QTextCursor::KeepAnchor) { selectedWordOnDoubleClick = QTextCursor(); selectedLineOnDoubleClick = QTextCursor(); }}void QTextEditPrivate::_q_repaintContents(const QRectF &contentsRect){ const int xOffset = horizontalOffset(); const int yOffset = verticalOffset(); const QRect visibleRect(xOffset, yOffset, viewport->width(), viewport->height()); QRect r = contentsRect.toRect().intersect(visibleRect); if (r.isEmpty()) return; r.translate(-xOffset, -yOffset); viewport->update(r);}void QTextEditPrivate::repaintCursor(){ Q_Q(const QTextEdit); viewport->update(q->cursorRect());}void QTextEditPrivate::selectionChanged(){ Q_Q(QTextEdit); bool current = cursor.hasSelection(); if (current == lastSelectionState) return; lastSelectionState = current; emit q->copyAvailable(current); emit q->selectionChanged(); q->updateMicroFocus();}void QTextEditPrivate::pageUp(QTextCursor::MoveMode moveMode){ Q_Q(QTextEdit); int targetY = verticalOffset() - viewport->height(); bool moved = false; qreal y; // move to the targetY using movePosition to keep the cursor's x do { const QRect r = q->cursorRect(); y = verticalOffset() + r.y() - r.height(); moved = cursor.movePosition(QTextCursor::Up, moveMode); } while (moved && y > targetY); if (moved) { q->ensureCursorVisible(); emit q->cursorPositionChanged(); q->updateMicroFocus(); }}void QTextEditPrivate::pageDown(QTextCursor::MoveMode moveMode){ Q_Q(QTextEdit); int targetY = verticalOffset() + 2 * viewport->height(); bool moved = false; qreal y; // move to the targetY using movePosition to keep the cursor's x do { y = verticalOffset() + q->cursorRect().bottom(); moved = cursor.movePosition(QTextCursor::Down, moveMode); } while (moved && y < targetY); if (moved) { q->ensureCursorVisible(); emit q->cursorPositionChanged(); q->updateMicroFocus(); }}void QTextEditPrivate::_q_updateCurrentCharFormatAndSelection(){ updateCurrentCharFormat(); selectionChanged();}#ifndef QT_NO_SCROLLBARvoid QTextEditPrivate::_q_adjustScrollbars(){ if (ignoreAutomaticScrollbarAdjustement) return; QAbstractTextDocumentLayout *layout = doc->documentLayout(); const QSize viewportSize = viewport->size(); QSize docSize; if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) { docSize = tlayout->dynamicDocumentSize().toSize(); int percentageDone = tlayout->layoutStatus(); // extrapolate height if (percentageDone > 0) docSize.setHeight(docSize.height() * 100 / percentageDone); } else { docSize = layout->documentSize().toSize(); } hbar->setRange(0, docSize.width() - viewportSize.width()); hbar->setPageStep(viewportSize.width()); vbar->setRange(0, docSize.height() - viewportSize.height()); vbar->setPageStep(viewportSize.height()); // if we are in left-to-right mode widening the document due to // lazy layouting does not require a repaint. If in right-to-left // the scrollbar has the value zero and it visually has the maximum // value (it is visually at the right), then widening the document // keeps it at value zero but visually adjusts it to the new maximum // on the right, hence we need an update. if (q_func()->isRightToLeft()) viewport->update();}#endif#ifndef QT_NO_CLIPBOARDvoid QTextEditPrivate::setClipboardSelection(){ QClipboard *clipboard = QApplication::clipboard(); if (!cursor.hasSelection() || !clipboard->supportsSelection()) return; Q_Q(QTextEdit); QMimeData *data = q->createMimeDataFromSelection(); clipboard->setMimeData(data, QClipboard::Selection);}#endifvoid QTextEditPrivate::ensureVisible(int documentPosition){ // don't check for the visibility of the vertical scrollbar here, // always scroll to the position. we might have a layoutChildren // in QAbstractScrollArea pending, which will make things visible later on // then, for example when initially showing the widget and right // after that calling scrollToAnchor, which calls us. the vbar // isn't visible then, but that's okay. QTextBlock block = doc->findBlock(documentPosition); QTextLayout *layout = block.layout(); const qreal blockY = doc->documentLayout()->blockBoundingRect(block).top(); const int relativePos = documentPosition - block.position(); QTextLine line = layout->lineForTextPosition(relativePos); if (!line.isValid()) return; const int y = qRound(blockY + line.y()); vbar->setValue(y);}// rect is in content coordinatesvoid QTextEditPrivate::ensureVisible(const QRect &rect){ const int visibleWidth = viewport->width(); const int visibleHeight = viewport->height(); if (rect.x() < horizontalOffset()) hbar->setValue(rect.x() - rect.width()); else if (rect.x() + rect.width() > horizontalOffset() + visibleWidth) hbar->setValue(rect.x() + rect.width() - visibleWidth); if (rect.y() < verticalOffset()) vbar->setValue(rect.y() - rect.height()); else if (rect.y() + rect.height() > verticalOffset() + visibleHeight) vbar->setValue(rect.y() + rect.height() - visibleHeight);}void QTextEditPrivate::ensureViewportLayouted(){ QAbstractTextDocumentLayout *layout = doc->documentLayout(); if (!layout) return; if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) tlayout->ensureLayouted(verticalOffset() + viewport->height());}void QTextEditPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor){ Q_Q(QTextEdit); if (someCursor.isCopyOf(cursor)) { emit q->cursorPositionChanged(); q->updateMicroFocus(); }}void QTextEditPrivate::setBlinkingCursorEnabled(bool enable){ Q_Q(QTextEdit); if (enable && QApplication::cursorFlashTime() > 0) cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q); else cursorBlinkTimer.stop(); repaintCursor();}void QTextEditPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition){ Q_Q(QTextEdit); // if inside the initial selected word keep that if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart() && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) { q->setTextCursor(selectedWordOnDoubleClick); return; } QTextCursor curs = selectedWordOnDoubleClick; curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor); if (!curs.movePosition(QTextCursor::StartOfWord)) return; const int wordStartPos = curs.position(); const int blockPos = curs.block().position(); const QPointF blockCoordinates = doc->documentLayout()->blockBoundingRect(curs.block()).topLeft(); QTextLine line = currentTextLine(curs); if (!line.isValid()) return; const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x(); if (!curs.movePosition(QTextCursor::EndOfWord)) return; const int wordEndPos = curs.position(); const QTextLine otherLine = currentTextLine(curs); if (otherLine.textStart() != line.textStart() || wordEndPos == wordStartPos) return; const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x(); if (mouseXPosition < wordStartX || mouseXPosition > wordEndX) return; // keep the already selected word even when moving to the left // (#39164) if (suggestedNewPosition < selectedWordOnDoubleClick.position()) cursor.setPosition(selectedWordOnDoubleClick.selectionEnd()); else cursor.setPosition(selectedWordOnDoubleClick.selectionStart()); const qreal differenceToStart = mouseXPosition - wordStartX; const qreal differenceToEnd = wordEndX - mouseXPosition; if (differenceToStart < differenceToEnd) setCursorPosition(wordStartPos, QTextCursor::KeepAnchor); else setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);}void QTextEditPrivate::extendLinewiseSelection(int suggestedNewPosition){ Q_Q(QTextEdit); // if inside the initial selected line keep that if (suggestedNewPosition >= selectedLineOnDoubleClick.selectionStart() && suggestedNewPosition <= selectedLineOnDoubleClick.selectionEnd()) { q->setTextCursor(selectedLineOnDoubleClick); return; } if (suggestedNewPosition < selectedLineOnDoubleClick.position()) { cursor.setPosition(selectedLineOnDoubleClick.selectionEnd()); cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); } else { cursor.setPosition(selectedLineOnDoubleClick.selectionStart()); cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); }}void QTextEditPrivate::_q_deleteSelected(){ if (readOnly || !cursor.hasSelection()) return; cursor.removeSelectedText();}void QTextEditPrivate::undo(){ Q_Q(QTextEdit); QObject::connect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_setCursorAfterUndoRedo(int, int, int))); doc->undo(); QObject::disconnect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_setCursorAfterUndoRedo(int, int, int))); q->ensureCursorVisible();}void QTextEditPrivate::redo(){ Q_Q(QTextEdit); QObject::connect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_setCursorAfterUndoRedo(int, int, int))); doc->redo(); QObject::disconnect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_setCursorAfterUndoRedo(int, int, int))); q->ensureCursorVisible();}void QTextEditPrivate::_q_setCursorAfterUndoRedo(int undoPosition, int /*charsRemoved*/, int charsAdded)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -