133 Q_Q(QWidgetTextControl);
137 const QTextCursor oldSelection = cursor;
138 const int oldCursorPos = cursor.position();
140 QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
141 QTextCursor::MoveOperation op = QTextCursor::NoMove;
145#ifndef QT_NO_SHORTCUT
146 if (e == QKeySequence::MoveToNextChar) {
147 op = QTextCursor::Right;
149 else if (e == QKeySequence::MoveToPreviousChar) {
150 op = QTextCursor::Left;
152 else if (e == QKeySequence::SelectNextChar) {
153 op = QTextCursor::Right;
154 mode = QTextCursor::KeepAnchor;
156 else if (e == QKeySequence::SelectPreviousChar) {
157 op = QTextCursor::Left;
158 mode = QTextCursor::KeepAnchor;
160 else if (e == QKeySequence::SelectNextWord) {
161 op = QTextCursor::WordRight;
162 mode = QTextCursor::KeepAnchor;
164 else if (e == QKeySequence::SelectPreviousWord) {
165 op = QTextCursor::WordLeft;
166 mode = QTextCursor::KeepAnchor;
168 else if (e == QKeySequence::SelectStartOfLine) {
169 op = QTextCursor::StartOfLine;
170 mode = QTextCursor::KeepAnchor;
172 else if (e == QKeySequence::SelectEndOfLine) {
173 op = QTextCursor::EndOfLine;
174 mode = QTextCursor::KeepAnchor;
176 else if (e == QKeySequence::SelectStartOfBlock) {
177 op = QTextCursor::StartOfBlock;
178 mode = QTextCursor::KeepAnchor;
180 else if (e == QKeySequence::SelectEndOfBlock) {
181 op = QTextCursor::EndOfBlock;
182 mode = QTextCursor::KeepAnchor;
184 else if (e == QKeySequence::SelectStartOfDocument) {
185 op = QTextCursor::Start;
186 mode = QTextCursor::KeepAnchor;
188 else if (e == QKeySequence::SelectEndOfDocument) {
189 op = QTextCursor::End;
190 mode = QTextCursor::KeepAnchor;
192 else if (e == QKeySequence::SelectPreviousLine) {
193 op = QTextCursor::Up;
194 mode = QTextCursor::KeepAnchor;
196 QTextBlock block = cursor.block();
197 QTextLine line = currentTextLine(cursor);
198 if (!block.previous().isValid()
200 && line.lineNumber() == 0)
201 op = QTextCursor::Start;
204 else if (e == QKeySequence::SelectNextLine) {
205 op = QTextCursor::Down;
206 mode = QTextCursor::KeepAnchor;
208 QTextBlock block = cursor.block();
209 QTextLine line = currentTextLine(cursor);
210 if (!block.next().isValid()
212 && line.lineNumber() == block.layout()->lineCount() - 1)
213 op = QTextCursor::End;
216 else if (e == QKeySequence::MoveToNextWord) {
217 op = QTextCursor::WordRight;
219 else if (e == QKeySequence::MoveToPreviousWord) {
220 op = QTextCursor::WordLeft;
222 else if (e == QKeySequence::MoveToEndOfBlock) {
223 op = QTextCursor::EndOfBlock;
225 else if (e == QKeySequence::MoveToStartOfBlock) {
226 op = QTextCursor::StartOfBlock;
228 else if (e == QKeySequence::MoveToNextLine) {
229 op = QTextCursor::Down;
231 else if (e == QKeySequence::MoveToPreviousLine) {
232 op = QTextCursor::Up;
234 else if (e == QKeySequence::MoveToStartOfLine) {
235 op = QTextCursor::StartOfLine;
237 else if (e == QKeySequence::MoveToEndOfLine) {
238 op = QTextCursor::EndOfLine;
240 else if (e == QKeySequence::MoveToStartOfDocument) {
241 op = QTextCursor::Start;
243 else if (e == QKeySequence::MoveToEndOfDocument) {
244 op = QTextCursor::End;
261 bool visualNavigation = cursor.visualNavigation();
262 cursor.setVisualNavigation(
true);
263 const bool moved = cursor.movePosition(op, mode);
264 cursor.setVisualNavigation(visualNavigation);
265 q->ensureCursorVisible();
267 bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
268 bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
270#ifdef QT_KEYPAD_NAVIGATION
271 ignoreNavigationEvents = ignoreNavigationEvents || QApplicationPrivate::keypadNavigationEnabled();
272 isNavigationEvent = isNavigationEvent ||
273 (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
274 && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
276 isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
280 if (cursor.position() != oldCursorPos)
281 emit q->cursorPositionChanged();
282 emit q->microFocusChanged();
283 }
else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
287 selectionChanged((mode == QTextCursor::KeepAnchor));
289 repaintOldAndNewSelection(oldSelection);
411 Q_Q(QWidgetTextControl);
415 const QTextCharFormat charFormatForInsertion = cursor.charFormat();
417 bool clearDocument =
true;
422 palette = QApplication::palette(
"QWidgetTextControl");
423 doc =
new QTextDocument(q);
425 clearDocument =
false;
427 cursor = QTextCursor(doc);
431 QObjectPrivate::connect(doc, &QTextDocument::contentsChanged,
this,
432 &QWidgetTextControlPrivate::_q_updateCurrentCharFormatAndSelection);
433 QObjectPrivate::connect(doc, &QTextDocument::cursorPositionChanged,
this,
434 &QWidgetTextControlPrivate::_q_emitCursorPosChanged);
435 QObjectPrivate::connect(doc, &QTextDocument::documentLayoutChanged,
this,
436 &QWidgetTextControlPrivate::_q_documentLayoutChanged);
439 QObject::connect(doc, &QTextDocument::undoAvailable, q, &QWidgetTextControl::undoAvailable);
440 QObject::connect(doc, &QTextDocument::redoAvailable, q, &QWidgetTextControl::redoAvailable);
441 QObject::connect(doc, &QTextDocument::modificationChanged, q,
442 &QWidgetTextControl::modificationChanged);
443 QObject::connect(doc, &QTextDocument::blockCountChanged, q,
444 &QWidgetTextControl::blockCountChanged);
447 bool previousUndoRedoState =
doc->isUndoRedoEnabled();
449 doc->setUndoRedoEnabled(
false);
452 static int contentsChangedIndex = QMetaMethod::fromSignal(&QTextDocument::contentsChanged).methodIndex();
453 static int textChangedIndex = QMetaMethod::fromSignal(&QWidgetTextControl::textChanged).methodIndex();
455 QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
457 if (!text.isEmpty()) {
464 cursor = QTextCursor();
465 if (format == Qt::PlainText) {
466 QTextCursor formatCursor(doc);
470 formatCursor.beginEditBlock();
471 doc->setPlainText(text);
472 doc->setUndoRedoEnabled(
false);
473 formatCursor.select(QTextCursor::Document);
474 formatCursor.setCharFormat(charFormatForInsertion);
475 formatCursor.endEditBlock();
476#if QT_CONFIG(textmarkdownreader)
477 }
else if (format == Qt::MarkdownText) {
478 doc->setMarkdown(text);
479 doc->setUndoRedoEnabled(
false);
482#ifndef QT_NO_TEXTHTMLPARSER
485 doc->setPlainText(text);
487 doc->setUndoRedoEnabled(
false);
489 cursor = QTextCursor(doc);
490 }
else if (clearDocument) {
493 cursor.setCharFormat(charFormatForInsertion);
495 QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
496 emit q->textChanged();
498 doc->setUndoRedoEnabled(previousUndoRedoState);
501 doc->setModified(
false);
503 q->ensureCursorVisible();
504 emit q->cursorPositionChanged();
506 QObjectPrivate::connect(doc, &QTextDocument::contentsChange,
this,
507 &QWidgetTextControlPrivate::_q_contentsChanged, Qt::UniqueConnection);
591 Q_Q(QWidgetTextControl);
592 if (forceEmitSelectionChanged) {
593 emit q->selectionChanged();
594#if QT_CONFIG(accessibility)
595 if (q->parent() && q->parent()->isWidgetType()) {
596 QAccessibleTextSelectionEvent ev(q->parent(), cursor.anchor(), cursor.position());
597 QAccessible::updateAccessibility(&ev);
602 if (cursor.position() == lastSelectionPosition
603 && cursor.anchor() == lastSelectionAnchor)
606 bool selectionStateChange = (cursor.hasSelection()
607 != (lastSelectionPosition != lastSelectionAnchor));
608 if (selectionStateChange)
609 emit q->copyAvailable(cursor.hasSelection());
611 if (!forceEmitSelectionChanged
612 && (selectionStateChange
613 || (cursor.hasSelection()
614 && (cursor.position() != lastSelectionPosition
615 || cursor.anchor() != lastSelectionAnchor)))) {
616 emit q->selectionChanged();
617#if QT_CONFIG(accessibility)
618 if (q->parent() && q->parent()->isWidgetType()) {
619 QAccessibleTextSelectionEvent ev(q->parent(), cursor.anchor(), cursor.position());
620 QAccessible::updateAccessibility(&ev);
624 emit q->microFocusChanged();
625 lastSelectionPosition = cursor.position();
626 lastSelectionAnchor = cursor.anchor();
731 Q_Q(QWidgetTextControl);
734 if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
735 && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
736 q->setTextCursor(selectedWordOnDoubleClick);
740 QTextCursor curs = selectedWordOnDoubleClick;
741 curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
743 if (!curs.movePosition(QTextCursor::StartOfWord))
745 const int wordStartPos = curs.position();
747 const int blockPos = curs.block().position();
748 const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
750 QTextLine line = currentTextLine(curs);
754 const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
756 if (!curs.movePosition(QTextCursor::EndOfWord))
758 const int wordEndPos = curs.position();
760 const QTextLine otherLine = currentTextLine(curs);
761 if (otherLine.textStart() != line.textStart()
762 || wordEndPos == wordStartPos)
765 const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
771 if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
772 cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
773 setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
775 cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
776 setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
781 if (suggestedNewPosition < selectedWordOnDoubleClick.position())
782 cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
784 cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
786 const qreal differenceToStart = mouseXPosition - wordStartX;
787 const qreal differenceToEnd = wordEndX - mouseXPosition;
789 if (differenceToStart < differenceToEnd)
790 setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
792 setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
795 if (interactionFlags & Qt::TextSelectableByMouse) {
796#ifndef QT_NO_CLIPBOARD
998void QWidgetTextControl::processEvent(QEvent *e,
const QTransform &transform, QWidget *contextWidget)
1000 Q_D(QWidgetTextControl);
1001 if (d->interactionFlags == Qt::NoTextInteraction) {
1006 d->contextWidget = contextWidget;
1008 if (!d->contextWidget) {
1009 switch (e->type()) {
1010#if QT_CONFIG(graphicsview)
1011 case QEvent::GraphicsSceneMouseMove:
1012 case QEvent::GraphicsSceneMousePress:
1013 case QEvent::GraphicsSceneMouseRelease:
1014 case QEvent::GraphicsSceneMouseDoubleClick:
1015 case QEvent::GraphicsSceneContextMenu:
1016 case QEvent::GraphicsSceneHoverEnter:
1017 case QEvent::GraphicsSceneHoverMove:
1018 case QEvent::GraphicsSceneHoverLeave:
1019 case QEvent::GraphicsSceneHelp:
1020 case QEvent::GraphicsSceneDragEnter:
1021 case QEvent::GraphicsSceneDragMove:
1022 case QEvent::GraphicsSceneDragLeave:
1023 case QEvent::GraphicsSceneDrop: {
1024 QGraphicsSceneEvent *ev =
static_cast<QGraphicsSceneEvent *>(e);
1025 d->contextWidget = ev->widget();
1033 switch (e->type()) {
1034 case QEvent::KeyPress:
1035 d->keyPressEvent(
static_cast<QKeyEvent *>(e));
1037 case QEvent::MouseButtonPress: {
1038 QMouseEvent *ev =
static_cast<QMouseEvent *>(e);
1039 d->mousePressEvent(ev, ev->button(), transform.map(ev->position()), ev->modifiers(),
1040 ev->buttons(), ev->globalPosition());
1043 d->updateHighlightedAnchor(transform.map(
static_cast<QEnterEvent *>(e)->position()));
1046 d->resetHighlightedAnchor();
1048 case QEvent::MouseMove: {
1049 QMouseEvent *ev =
static_cast<QMouseEvent *>(e);
1050 d->mouseMoveEvent(ev, ev->button(), transform.map(ev->position()), ev->modifiers(),
1051 ev->buttons(), ev->globalPosition());
1053 case QEvent::MouseButtonRelease: {
1054 QMouseEvent *ev =
static_cast<QMouseEvent *>(e);
1055 d->mouseReleaseEvent(ev, ev->button(), transform.map(ev->position()), ev->modifiers(),
1056 ev->buttons(), ev->globalPosition());
1058 case QEvent::MouseButtonDblClick: {
1059 QMouseEvent *ev =
static_cast<QMouseEvent *>(e);
1060 d->mouseDoubleClickEvent(ev, ev->button(), transform.map(ev->position()), ev->modifiers(),
1061 ev->buttons(), ev->globalPosition());
1063 case QEvent::InputMethod:
1064 d->inputMethodEvent(
static_cast<QInputMethodEvent *>(e));
1066#ifndef QT_NO_CONTEXTMENU
1067 case QEvent::ContextMenu: {
1068 QContextMenuEvent *ev =
static_cast<QContextMenuEvent *>(e);
1069 d->contextMenuEvent(ev->globalPos(), transform.map(ev->pos()), contextWidget);
1072 case QEvent::FocusIn:
1073 case QEvent::FocusOut:
1074 d->focusEvent(
static_cast<QFocusEvent *>(e));
1077 case QEvent::EnabledChange:
1078 d->isEnabled = e->isAccepted();
1081#if QT_CONFIG(tooltip)
1082 case QEvent::ToolTip: {
1083 QHelpEvent *ev =
static_cast<QHelpEvent *>(e);
1084 d->showToolTip(ev->globalPos(), transform.map(ev->pos()), contextWidget);
1089#if QT_CONFIG(draganddrop)
1090 case QEvent::DragEnter: {
1091 QDragEnterEvent *ev =
static_cast<QDragEnterEvent *>(e);
1092 if (d->dragEnterEvent(e, ev->mimeData()))
1093 ev->acceptProposedAction();
1096 case QEvent::DragLeave:
1097 d->dragLeaveEvent();
1099 case QEvent::DragMove: {
1100 QDragMoveEvent *ev =
static_cast<QDragMoveEvent *>(e);
1101 if (d->dragMoveEvent(e, ev->mimeData(), transform.map(ev->position())))
1102 ev->acceptProposedAction();
1105 case QEvent::Drop: {
1106 QDropEvent *ev =
static_cast<QDropEvent *>(e);
1107 if (d->dropEvent(ev->mimeData(), transform.map(ev->position()), ev->dropAction(), ev->source()))
1108 ev->acceptProposedAction();
1113#if QT_CONFIG(graphicsview)
1114 case QEvent::GraphicsSceneMousePress: {
1115 QGraphicsSceneMouseEvent *ev =
static_cast<QGraphicsSceneMouseEvent *>(e);
1116 d->mousePressEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1119 case QEvent::GraphicsSceneMouseMove: {
1120 QGraphicsSceneMouseEvent *ev =
static_cast<QGraphicsSceneMouseEvent *>(e);
1121 d->mouseMoveEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1124 case QEvent::GraphicsSceneMouseRelease: {
1125 QGraphicsSceneMouseEvent *ev =
static_cast<QGraphicsSceneMouseEvent *>(e);
1126 d->mouseReleaseEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1129 case QEvent::GraphicsSceneMouseDoubleClick: {
1130 QGraphicsSceneMouseEvent *ev =
static_cast<QGraphicsSceneMouseEvent *>(e);
1131 d->mouseDoubleClickEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1134 case QEvent::GraphicsSceneContextMenu: {
1135 QGraphicsSceneContextMenuEvent *ev =
static_cast<QGraphicsSceneContextMenuEvent *>(e);
1136 d->contextMenuEvent(ev->screenPos(), transform.map(ev->pos()), contextWidget);
1139 case QEvent::GraphicsSceneHoverMove: {
1140 QGraphicsSceneHoverEvent *ev =
static_cast<QGraphicsSceneHoverEvent *>(e);
1141 d->mouseMoveEvent(ev, Qt::NoButton, transform.map(ev->pos()), ev->modifiers(),Qt::NoButton,
1145 case QEvent::GraphicsSceneDragEnter: {
1146 QGraphicsSceneDragDropEvent *ev =
static_cast<QGraphicsSceneDragDropEvent *>(e);
1147 if (d->dragEnterEvent(e, ev->mimeData()))
1148 ev->acceptProposedAction();
1150 case QEvent::GraphicsSceneDragLeave:
1151 d->dragLeaveEvent();
1153 case QEvent::GraphicsSceneDragMove: {
1154 QGraphicsSceneDragDropEvent *ev =
static_cast<QGraphicsSceneDragDropEvent *>(e);
1155 if (d->dragMoveEvent(e, ev->mimeData(), transform.map(ev->pos())))
1156 ev->acceptProposedAction();
1158 case QEvent::GraphicsSceneDrop: {
1159 QGraphicsSceneDragDropEvent *ev =
static_cast<QGraphicsSceneDragDropEvent *>(e);
1160 if (d->dropEvent(ev->mimeData(), transform.map(ev->pos()), ev->dropAction(), ev->source()))
1164#ifdef QT_KEYPAD_NAVIGATION
1165 case QEvent::EnterEditFocus:
1166 case QEvent::LeaveEditFocus:
1167 if (QApplicationPrivate::keypadNavigationEnabled())
1168 d->editFocusEvent(e);
1171 case QEvent::ShortcutOverride:
1172 if (d->interactionFlags & Qt::TextEditable) {
1173 QKeyEvent* ke =
static_cast<QKeyEvent *>(e);
1174 if (isCommonTextEditShortcut(ke))
1226 Q_Q(QWidgetTextControl);
1227#ifndef QT_NO_SHORTCUT
1228 if (e == QKeySequence::SelectAll) {
1231#ifndef QT_NO_CLIPBOARD
1232 setClipboardSelection();
1236#ifndef QT_NO_CLIPBOARD
1237 else if (e == QKeySequence::Copy) {
1245 if (interactionFlags & Qt::TextSelectableByKeyboard
1246 && cursorMoveKeyEvent(e))
1249 if (interactionFlags & Qt::LinksAccessibleByKeyboard) {
1250 if ((e->key() == Qt::Key_Return
1251 || e->key() == Qt::Key_Enter
1252#ifdef QT_KEYPAD_NAVIGATION
1253 || e->key() == Qt::Key_Select
1256 && cursor.hasSelection()) {
1259 activateLinkUnderCursor();
1264 if (!(interactionFlags & Qt::TextEditable)) {
1269 if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
1270 QTextBlockFormat fmt;
1271 fmt.setLayoutDirection((e->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1272 cursor.mergeBlockFormat(fmt);
1282 if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~(Qt::ShiftModifier | Qt::GroupSwitchModifier))) {
1283 QTextBlockFormat blockFmt = cursor.blockFormat();
1284 QTextList *list = cursor.currentList();
1285 if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
1286 list->remove(cursor.block());
1287 }
else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1288 blockFmt.setIndent(blockFmt.indent() - 1);
1289 cursor.setBlockFormat(blockFmt);
1291 QTextCursor localCursor = cursor;
1292 localCursor.deletePreviousChar();
1298#ifndef QT_NO_SHORTCUT
1299 else if (e == QKeySequence::InsertParagraphSeparator) {
1300 insertParagraphSeparator();
1303 }
else if (e == QKeySequence::InsertLineSeparator) {
1304 cursor.insertText(QString(QChar::LineSeparator));
1311#ifndef QT_NO_SHORTCUT
1312 else if (e == QKeySequence::Undo) {
1315 else if (e == QKeySequence::Redo) {
1318#ifndef QT_NO_CLIPBOARD
1319 else if (e == QKeySequence::Cut) {
1322 else if (e == QKeySequence::Paste) {
1323 QClipboard::Mode mode = QClipboard::Clipboard;
1324 if (QGuiApplication::clipboard()->supportsSelection()) {
1325 if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
1326 mode = QClipboard::Selection;
1331 else if (e == QKeySequence::Delete) {
1332 QTextCursor localCursor = cursor;
1333 localCursor.deleteChar();
1336 }
else if (e == QKeySequence::Backspace) {
1337 QTextCursor localCursor = cursor;
1338 localCursor.deletePreviousChar();
1341 }
else if (e == QKeySequence::DeleteEndOfWord) {
1342 if (!cursor.hasSelection())
1343 cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
1344 cursor.removeSelectedText();
1346 else if (e == QKeySequence::DeleteStartOfWord) {
1347 if (!cursor.hasSelection())
1348 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
1349 cursor.removeSelectedText();
1351 else if (e == QKeySequence::DeleteEndOfLine) {
1352 QTextBlock block = cursor.block();
1353 if (cursor.position() == block.position() + block.length() - 2)
1354 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
1356 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1357 cursor.removeSelectedText();
1367 if (q->isAcceptableInput(e)) {
1371 && !cursor.hasSelection()
1372 && !cursor.atBlockEnd())
1373 cursor.deleteChar();
1375 cursor.insertText(e->text());
1385#ifndef QT_NO_CLIPBOARD
1386 setClipboardSelection();
1392 q->ensureCursorVisible();
1394 updateCurrentCharFormat();
1483QRectF QWidgetTextControl::selectionRect(
const QTextCursor &cursor)
const
1485 Q_D(
const QWidgetTextControl);
1487 QRectF r = d->rectForPosition(cursor.selectionStart());
1489 if (cursor.hasComplexSelection() && cursor.currentTable()) {
1490 QTextTable *table = cursor.currentTable();
1492 r = d->doc->documentLayout()->frameBoundingRect(table);
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534 }
else if (cursor.hasSelection()) {
1535 const int position = cursor.selectionStart();
1536 const int anchor = cursor.selectionEnd();
1537 const QTextBlock posBlock = d->doc->findBlock(position);
1538 const QTextBlock anchorBlock = d->doc->findBlock(anchor);
1539 if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) {
1540 const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
1541 const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
1543 const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
1544 const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
1545 const QTextLayout *layout = posBlock.layout();
1547 for (
int i = firstLine; i <= lastLine; ++i) {
1548 r |= layout->lineAt(i).rect();
1549 r |= layout->lineAt(i).naturalTextRect();
1551 r.translate(blockBoundingRect(posBlock).topLeft());
1553 QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
1555 r |= boundingRectOfFloatsInSelection(cursor);
1556 QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
1557 r.setLeft(frameRect.left());
1558 r.setRight(frameRect.right());
1561 r.adjust(-1, -1, 1, 1);
1574 Qt::MouseButtons buttons,
const QPointF &globalPos)
1576 Q_Q(QWidgetTextControl);
1578 mousePressPos = pos;
1580#if QT_CONFIG(draganddrop)
1581 mightStartDrag =
false;
1584 if (sendMouseEventToInputContext(
1585 e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) {
1589 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1590 anchorOnMousePress = q->anchorAt(pos);
1595 cursor.clearSelection();
1598 if (!(button & Qt::LeftButton) ||
1599 !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
1603 bool wasValid = blockWithMarkerUnderMouse.isValid();
1604 blockWithMarkerUnderMouse = q->blockWithMarkerAt(pos);
1605 if (wasValid != blockWithMarkerUnderMouse.isValid())
1606 emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
1610 const QTextCursor oldSelection = cursor;
1611 const int oldCursorPos = cursor.position();
1613 mousePressed = (interactionFlags & Qt::TextSelectableByMouse);
1617 if (trippleClickTimer.isActive()
1618 && ((pos - trippleClickPoint).manhattanLength() < QApplication::startDragDistance())) {
1620 cursor.movePosition(QTextCursor::StartOfBlock);
1621 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1622 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1623 selectedBlockOnTrippleClick = cursor;
1625 anchorOnMousePress = QString();
1626 blockWithMarkerUnderMouse = QTextBlock();
1627 emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
1629 trippleClickTimer.stop();
1631 int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1632 if (cursorPos == -1) {
1637 if (modifiers == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) {
1638 if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1639 selectedWordOnDoubleClick = cursor;
1640 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1643 if (selectedBlockOnTrippleClick.hasSelection())
1645 else if (selectedWordOnDoubleClick.hasSelection())
1646 extendWordwiseSelection(cursorPos, pos.x());
1647 else if (!wordSelectionEnabled)
1648 setCursorPosition(cursorPos, QTextCursor::KeepAnchor);
1652 && cursor.hasSelection()
1653 && !cursorIsFocusIndicator
1654 && cursorPos >= cursor.selectionStart()
1655 && cursorPos <= cursor.selectionEnd()
1656 && q->hitTest(pos, Qt::ExactHit) != -1) {
1657#if QT_CONFIG(draganddrop)
1658 mightStartDrag =
true;
1663 setCursorPosition(cursorPos);
1667 if (interactionFlags & Qt::TextEditable) {
1668 q->ensureCursorVisible();
1669 if (cursor.position() != oldCursorPos)
1670 emit q->cursorPositionChanged();
1673 if (cursor.position() != oldCursorPos) {
1674 emit q->cursorPositionChanged();
1675 emit q->microFocusChanged();
1679 repaintOldAndNewSelection(oldSelection);
1680 hadSelectionOnMousePress = cursor.hasSelection();
1684 Qt::MouseButtons buttons,
const QPointF &globalPos)
1686 Q_Q(QWidgetTextControl);
1688 if (interactionFlags & Qt::LinksAccessibleByMouse)
1689 updateHighlightedAnchor(mousePos);
1691 if (buttons & Qt::LeftButton) {
1692 const bool editable = interactionFlags & Qt::TextEditable;
1697 || selectedWordOnDoubleClick.hasSelection()
1698 || selectedBlockOnTrippleClick.hasSelection()))
1701 const QTextCursor oldSelection = cursor;
1702 const int oldCursorPos = cursor.position();
1705 if ((mousePos - mousePressPos).manhattanLength() > QApplication::startDragDistance())
1710 const qreal mouseX = qreal(mousePos.x());
1712 int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1716 int selectionStartPos = q->hitTest(mousePressPos, Qt::FuzzyHit);
1718 if (newCursorPos != selectionStartPos) {
1721 newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1722 selectionStartPos = q->hitTest(mousePressPos, Qt::FuzzyHit);
1723 setCursorPosition(selectionStartPos);
1727 if (newCursorPos == -1)
1730 if (mousePressed && wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1731 selectedWordOnDoubleClick = cursor;
1732 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1735 if (selectedBlockOnTrippleClick.hasSelection())
1737 else if (selectedWordOnDoubleClick.hasSelection())
1738 extendWordwiseSelection(newCursorPos, mouseX);
1739 else if (mousePressed && !isPreediting())
1740 setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
1742 if (interactionFlags & Qt::TextEditable) {
1746 if (cursor.position() != oldCursorPos)
1747 emit q->cursorPositionChanged();
1751 QGuiApplication::inputMethod()->update(Qt::ImQueryInput);
1755 if (cursor.position() != oldCursorPos) {
1756 emit q->cursorPositionChanged();
1757 emit q->microFocusChanged();
1761 repaintOldAndNewSelection(oldSelection);
1763 bool wasValid = blockWithMarkerUnderMouse.isValid();
1764 blockWithMarkerUnderMouse = q->blockWithMarkerAt(mousePos);
1765 if (wasValid != blockWithMarkerUnderMouse.isValid())
1766 emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
1769 sendMouseEventToInputContext(e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos);
1773 Qt::MouseButtons buttons,
const QPointF &globalPos)
1775 Q_Q(QWidgetTextControl);
1777 const QTextCursor oldSelection = cursor;
1778 if (sendMouseEventToInputContext(
1779 e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
1780 repaintOldAndNewSelection(oldSelection);
1784 const int oldCursorPos = cursor.position();
1786#if QT_CONFIG(draganddrop)
1787 if (mightStartDrag && (button & Qt::LeftButton)) {
1788 mousePressed =
false;
1789 setCursorPosition(pos);
1790 cursor.clearSelection();
1796#ifndef QT_NO_CLIPBOARD
1799 }
else if (button == Qt::MiddleButton
1800 && (interactionFlags & Qt::TextEditable)
1801 && QGuiApplication::clipboard()->supportsSelection()) {
1802 setCursorPosition(pos);
1803 const QMimeData *md = QGuiApplication::clipboard()->mimeData(QClipboard::Selection);
1805 q->insertFromMimeData(md);
1809 repaintOldAndNewSelection(oldSelection);
1811 if (cursor.position() != oldCursorPos) {
1812 emit q->cursorPositionChanged();
1813 emit q->microFocusChanged();
1817 if ((interactionFlags & Qt::TextEditable) && (button & Qt::LeftButton) &&
1818 (blockWithMarkerUnderMouse.isValid()) && !cursor.hasSelection()) {
1819 QTextBlock markerBlock = q->blockWithMarkerAt(pos);
1820 if (markerBlock == blockWithMarkerUnderMouse) {
1821 auto fmt = blockWithMarkerUnderMouse.blockFormat();
1822 switch (fmt.marker()) {
1823 case QTextBlockFormat::MarkerType::Unchecked :
1824 fmt.setMarker(QTextBlockFormat::MarkerType::Checked);
1826 case QTextBlockFormat::MarkerType::Checked:
1827 fmt.setMarker(QTextBlockFormat::MarkerType::Unchecked);
1832 cursor.setBlockFormat(fmt);
1836 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1839 if (!(button & Qt::LeftButton)) {
1844 const QString anchor = q->anchorAt(pos);
1847 if (anchor.isEmpty()) {
1852 if (!cursor.hasSelection()
1853 || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
1855 const int anchorPos = q->hitTest(pos, Qt::ExactHit);
1858 if (anchorPos < 0) {
1863 cursor.setPosition(anchorPos);
1864 activateLinkUnderCursor(std::exchange(anchorOnMousePress, QString()));
2040 Q_Q(QWidgetTextControl);
2041 if (!(interactionFlags & (Qt::TextEditable | Qt::TextSelectableByMouse)) || cursor.isNull()) {
2045 bool isGettingInput = !e->commitString().isEmpty()
2046 || e->preeditString() != cursor.block().layout()->preeditAreaText()
2047 || e->replacementLength() > 0;
2049 if (!isGettingInput && e->attributes().isEmpty()) {
2054 int oldCursorPos = cursor.position();
2056 cursor.beginEditBlock();
2057 if (isGettingInput) {
2058 cursor.removeSelectedText();
2064 if (!e->commitString().isEmpty() || e->replacementLength()) {
2065 auto *mimeData = QInputControl::mimeDataForInputEvent(e);
2066 if (mimeData && q->canInsertFromMimeData(mimeData)) {
2067 q->insertFromMimeData(mimeData);
2069 if (e->commitString().endsWith(QChar::LineFeed))
2070 block = cursor.block();
2071 QTextCursor c = cursor;
2072 c.setPosition(c.position() + e->replacementStart());
2073 c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
2074 c.insertText(e->commitString());
2078 for (
int i = 0; i < e->attributes().size(); ++i) {
2079 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
2080 if (a.type == QInputMethodEvent::Selection) {
2081 QTextCursor oldCursor = cursor;
2082 int blockStart = a.start + cursor.block().position();
2083 cursor.setPosition(blockStart, QTextCursor::MoveAnchor);
2084 cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
2085 q->ensureCursorVisible();
2086 repaintOldAndNewSelection(oldCursor);
2090 if (!block.isValid())
2091 block = cursor.block();
2092 QTextLayout *layout = block.layout();
2094 layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
2095 QList<QTextLayout::FormatRange> overrides;
2096 overrides.reserve(e->attributes().size());
2097 const int oldPreeditCursor = preeditCursor;
2098 preeditCursor = e->preeditString().size();
2100 for (
int i = 0; i < e->attributes().size(); ++i) {
2101 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
2102 if (a.type == QInputMethodEvent::Cursor) {
2103 preeditCursor = a.start;
2104 hideCursor = !a.length;
2105 }
else if (a.type == QInputMethodEvent::TextFormat) {
2106 QTextCharFormat f = cursor.charFormat();
2107 f.merge(qvariant_cast<QTextFormat>(a.value).toCharFormat());
2109 QTextLayout::FormatRange o;
2110 o.start = a.start + cursor.position() - block.position();
2111 o.length = a.length;
2115 QList<QTextLayout::FormatRange>::iterator it = overrides.end();
2116 while (it != overrides.begin()) {
2117 QList<QTextLayout::FormatRange>::iterator previous = it - 1;
2118 if (o.start >= previous->start) {
2119 overrides.insert(it, o);
2125 if (it == overrides.begin())
2126 overrides.prepend(o);
2131 if (cursor.charFormat().isValid()) {
2132 int start = cursor.position() - block.position();
2133 int end = start + e->preeditString().size();
2135 QList<QTextLayout::FormatRange>::iterator it = overrides.begin();
2136 while (it != overrides.end()) {
2137 QTextLayout::FormatRange range = *it;
2138 int rangeStart = range.start;
2139 if (rangeStart > start) {
2140 QTextLayout::FormatRange o;
2142 o.length = rangeStart - start;
2143 o.format = cursor.charFormat();
2144 it = overrides.insert(it, o) + 1;
2148 start = range.start + range.length;
2152 QTextLayout::FormatRange o;
2154 o.length = end - start;
2155 o.format = cursor.charFormat();
2156 overrides.append(o);
2159 layout->setFormats(overrides);
2161 cursor.endEditBlock();
2165 if (oldCursorPos != cursor.position())
2166 emit q->cursorPositionChanged();
2167 if (oldPreeditCursor != preeditCursor)
2168 emit q->microFocusChanged();
2171QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument)
const
2173 Q_D(
const QWidgetTextControl);
2174 QTextBlock block = d->cursor.block();
2176 case Qt::ImCursorRectangle:
2177 return cursorRect();
2178 case Qt::ImAnchorRectangle:
2179 return d->rectForPosition(d->cursor.anchor());
2181 return QVariant(d->cursor.charFormat().font());
2182 case Qt::ImCursorPosition: {
2183 const QPointF pt = argument.toPointF();
2185 return QVariant(cursorForPosition(pt).position() - block.position());
2186 return QVariant(d->cursor.position() - block.position()); }
2187 case Qt::ImSurroundingText:
2188 return QVariant(block.text());
2189 case Qt::ImCurrentSelection: {
2190 QMimeData *mimeData = createMimeDataFromSelection();
2191 mimeData->deleteLater();
2192 return QInputControl::selectionWrapper(mimeData);
2194 case Qt::ImMaximumTextLength:
2196 case Qt::ImAnchorPosition:
2197 return QVariant(d->cursor.anchor() - block.position());
2198 case Qt::ImAbsolutePosition: {
2199 const QPointF pt = argument.toPointF();
2201 return QVariant(cursorForPosition(pt).position());
2202 return QVariant(d->cursor.position()); }
2203 case Qt::ImTextAfterCursor:
2205 int maxLength = argument.isValid() ? argument.toInt() : 1024;
2206 QTextCursor tmpCursor = d->cursor;
2207 int localPos = d->cursor.position() - block.position();
2208 QString result = block.text().mid(localPos);
2209 while (result.size() < maxLength) {
2210 int currentBlock = tmpCursor.blockNumber();
2211 tmpCursor.movePosition(QTextCursor::NextBlock);
2212 if (tmpCursor.blockNumber() == currentBlock)
2214 result += u'\n' + tmpCursor.block().text();
2216 return QVariant(result);
2218 case Qt::ImTextBeforeCursor:
2220 int maxLength = argument.isValid() ? argument.toInt() : 1024;
2221 QTextCursor tmpCursor = d->cursor;
2222 int localPos = d->cursor.position() - block.position();
2224 int resultLen = localPos;
2225 while (resultLen < maxLength) {
2226 int currentBlock = tmpCursor.blockNumber();
2227 tmpCursor.movePosition(QTextCursor::PreviousBlock);
2228 if (tmpCursor.blockNumber() == currentBlock)
2231 resultLen += tmpCursor.block().length();
2235 result += tmpCursor.block().text() + u'\n';
2236 tmpCursor.movePosition(QTextCursor::NextBlock);
2239 result += QStringView{block.text()}.mid(0, localPos);
2240 return QVariant(result);
2333QMenu *QWidgetTextControl::createStandardContextMenu(
const QPointF &pos, QWidget *parent)
2335 Q_D(QWidgetTextControl);
2337 const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
2339 d->linkToCopy = QString();
2341 d->linkToCopy = anchorAt(pos);
2343 if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
2346 QMenu *menu =
new QMenu(parent);
2349 if (d->interactionFlags & Qt::TextEditable) {
2350 a = menu->addAction(tr(
"&Undo") +
ACCEL_KEY(QKeySequence::Undo),
this, SLOT(undo()));
2351 a->setEnabled(d->doc->isUndoAvailable());
2352 a->setObjectName(QStringLiteral(
"edit-undo"));
2353 setActionIcon(a, QStringLiteral(
"edit-undo"));
2354 a = menu->addAction(tr(
"&Redo") +
ACCEL_KEY(QKeySequence::Redo),
this, SLOT(redo()));
2355 a->setEnabled(d->doc->isRedoAvailable());
2356 a->setObjectName(QStringLiteral(
"edit-redo"));
2357 setActionIcon(a, QStringLiteral(
"edit-redo"));
2358 menu->addSeparator();
2360#ifndef QT_NO_CLIPBOARD
2361 a = menu->addAction(tr(
"Cu&t") +
ACCEL_KEY(QKeySequence::Cut),
this, SLOT(cut()));
2362 a->setEnabled(d->cursor.hasSelection());
2363 a->setObjectName(QStringLiteral(
"edit-cut"));
2364 setActionIcon(a, QStringLiteral(
"edit-cut"));
2368#ifndef QT_NO_CLIPBOARD
2369 if (showTextSelectionActions) {
2370 a = menu->addAction(tr(
"&Copy") +
ACCEL_KEY(QKeySequence::Copy),
this, SLOT(copy()));
2371 a->setEnabled(d->cursor.hasSelection());
2372 a->setObjectName(QStringLiteral(
"edit-copy"));
2373 setActionIcon(a, QStringLiteral(
"edit-copy"));
2376 if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
2377 || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
2379 a = menu->addAction(tr(
"Copy &Link Location"),
this, SLOT(_q_copyLink()));
2380 a->setEnabled(!d->linkToCopy.isEmpty());
2381 a->setObjectName(QStringLiteral(
"link-copy"));
2385 if (d->interactionFlags & Qt::TextEditable) {
2386#ifndef QT_NO_CLIPBOARD
2387 a = menu->addAction(tr(
"&Paste") +
ACCEL_KEY(QKeySequence::Paste),
this, SLOT(paste()));
2388 a->setEnabled(canPaste());
2389 a->setObjectName(QStringLiteral(
"edit-paste"));
2390 setActionIcon(a, QStringLiteral(
"edit-paste"));
2392 a = menu->addAction(tr(
"Delete"),
this, SLOT(_q_deleteSelected()));
2393 a->setEnabled(d->cursor.hasSelection());
2394 a->setObjectName(QStringLiteral(
"edit-delete"));
2395 setActionIcon(a, QStringLiteral(
"edit-delete"));
2399 if (showTextSelectionActions) {
2400 menu->addSeparator();
2401 a = menu->addAction(tr(
"Select All") +
ACCEL_KEY(QKeySequence::SelectAll),
this, SLOT(selectAll()));
2402 a->setEnabled(!d->doc->isEmpty());
2403 a->setObjectName(QStringLiteral(
"select-all"));
2404 setActionIcon(a, QStringLiteral(
"edit-select-all"));
2407 if ((d->interactionFlags & Qt::TextEditable) && QGuiApplication::styleHints()->useRtlExtensions()) {
2408 menu->addSeparator();
2409 QUnicodeControlCharacterMenu *ctrlCharacterMenu =
new QUnicodeControlCharacterMenu(
this, menu);
2410 menu->addMenu(ctrlCharacterMenu);
2772bool QWidgetTextControl::findNextPrevAnchor(
const QTextCursor &startCursor,
bool next, QTextCursor &newAnchor)
2774 Q_D(QWidgetTextControl);
2776 int anchorStart = -1;
2781 const int startPos = startCursor.selectionEnd();
2783 QTextBlock block = d->doc->findBlock(startPos);
2784 QTextBlock::Iterator it = block.begin();
2786 while (!it.atEnd() && it.fragment().position() < startPos)
2789 while (block.isValid()) {
2793 for (; !it.atEnd(); ++it) {
2794 const QTextFragment fragment = it.fragment();
2795 const QTextCharFormat fmt = fragment.charFormat();
2797 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2798 anchorStart = fragment.position();
2799 anchorHref = fmt.anchorHref();
2804 if (anchorStart != -1) {
2808 for (; !it.atEnd(); ++it) {
2809 const QTextFragment fragment = it.fragment();
2810 const QTextCharFormat fmt = fragment.charFormat();
2812 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2813 anchorEnd = fragment.position();
2818 if (anchorEnd == -1)
2819 anchorEnd = block.position() + block.length() - 1;
2825 block = block.next();
2829 int startPos = startCursor.selectionStart();
2833 QTextBlock block = d->doc->findBlock(startPos);
2834 QTextBlock::Iterator blockStart = block.begin();
2835 QTextBlock::Iterator it = block.end();
2837 if (startPos == block.position()) {
2841 if (it == blockStart) {
2842 it = QTextBlock::Iterator();
2843 block = QTextBlock();
2847 }
while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
2850 while (block.isValid()) {
2855 const QTextFragment fragment = it.fragment();
2856 const QTextCharFormat fmt = fragment.charFormat();
2858 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2859 anchorStart = fragment.position() + fragment.length();
2860 anchorHref = fmt.anchorHref();
2864 if (it == blockStart)
2865 it = QTextBlock::Iterator();
2868 }
while (!it.atEnd());
2871 if (anchorStart != -1 && !it.atEnd()) {
2875 const QTextFragment fragment = it.fragment();
2876 const QTextCharFormat fmt = fragment.charFormat();
2878 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2879 anchorEnd = fragment.position() + fragment.length();
2883 if (it == blockStart)
2884 it = QTextBlock::Iterator();
2887 }
while (!it.atEnd());
2889 if (anchorEnd == -1)
2890 anchorEnd = qMax(0, block.position());
2895 block = block.previous();
2897 if (it != block.begin())
2899 blockStart = block.begin();
2904 if (anchorStart != -1 && anchorEnd != -1) {
2905 newAnchor = d->cursor;
2906 newAnchor.setPosition(anchorStart);
2907 newAnchor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
2916 QTextCursor oldCursor = cursor;
2918 if (href.isEmpty()) {
2919 QTextCursor tmp = cursor;
2920 if (tmp.selectionStart() != tmp.position())
2921 tmp.setPosition(tmp.selectionStart());
2922 tmp.movePosition(QTextCursor::NextCharacter);
2923 href = tmp.charFormat().anchorHref();
2928 if (!cursor.hasSelection()) {
2929 QTextBlock block = cursor.block();
2930 const int cursorPos = cursor.position();
2932 QTextBlock::Iterator it = block.begin();
2933 QTextBlock::Iterator linkFragment;
2935 for (; !it.atEnd(); ++it) {
2936 QTextFragment fragment = it.fragment();
2937 const int fragmentPos = fragment.position();
2938 if (fragmentPos <= cursorPos &&
2939 fragmentPos + fragment.length() > cursorPos) {
2945 if (!linkFragment.atEnd()) {
2947 cursor.setPosition(it.fragment().position());
2948 if (it != block.begin()) {
2951 QTextFragment fragment = it.fragment();
2952 if (fragment.charFormat().anchorHref() != href)
2954 cursor.setPosition(fragment.position());
2955 }
while (it != block.begin());
2958 for (it = linkFragment; !it.atEnd(); ++it) {
2959 QTextFragment fragment = it.fragment();
2960 if (fragment.charFormat().anchorHref() != href)
2962 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
2971 cursor.clearSelection();
2973 repaintOldAndNewSelection(oldCursor);
2975#ifndef QT_NO_DESKTOPSERVICES
2977 QDesktopServices::openUrl(QUrl{href});
2980 emit q_func()->linkActivated(href);
3239 auto blockFmt = cursor.blockFormat();
3240 auto charFmt = cursor.charFormat();
3241 blockFmt.clearProperty(QTextFormat::BlockTrailingHorizontalRulerWidth);
3242 if (blockFmt.hasProperty(QTextFormat::HeadingLevel)) {
3243 blockFmt.clearProperty(QTextFormat::HeadingLevel);
3244 charFmt = QTextCharFormat();
3246 if (cursor.currentList()) {
3247 auto existingFmt = cursor.blockFormat();
3248 existingFmt.clearProperty(QTextBlockFormat::BlockBottomMargin);
3249 cursor.setBlockFormat(existingFmt);
3250 if (blockFmt.marker() == QTextBlockFormat::MarkerType::Checked)
3251 blockFmt.setMarker(QTextBlockFormat::MarkerType::Unchecked);
3256 if (cursor.block().text().isEmpty() &&
3257 !cursor.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth) &&
3258 !cursor.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) {
3259 blockFmt = QTextBlockFormat();
3260 const bool blockFmtChanged = (cursor.blockFormat() != blockFmt);
3261 charFmt = QTextCharFormat();
3262 cursor.setBlockFormat(blockFmt);
3263 cursor.setCharFormat(charFmt);
3268 if (blockFmtChanged)
3272 cursor.insertBlock(blockFmt, charFmt);
3344QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QWidget *widget)
const
3346 Q_D(
const QWidgetTextControl);
3348 QAbstractTextDocumentLayout::PaintContext ctx;
3350 ctx.selections = d->extraSelections;
3351 ctx.palette = d->palette;
3352#if QT_CONFIG(style_stylesheet)
3354 if (
auto cssStyle = qt_styleSheet(widget->style())) {
3355 QStyleOption option;
3356 option.initFrom(widget);
3357 cssStyle->styleSheetPalette(widget, &option, &ctx.palette);
3361 if (d->cursorOn && d->isEnabled) {
3363 ctx.cursorPosition = -1;
3364 else if (d->preeditCursor != 0)
3365 ctx.cursorPosition = - (d->preeditCursor + 2);
3367 ctx.cursorPosition = d->cursor.position();
3370 if (!d->dndFeedbackCursor.isNull())
3371 ctx.cursorPosition = d->dndFeedbackCursor.position();
3372#ifdef QT_KEYPAD_NAVIGATION
3373 if (!QApplicationPrivate::keypadNavigationEnabled() || d->hasEditFocus)
3375 if (d->cursor.hasSelection()) {
3376 QAbstractTextDocumentLayout::Selection selection;
3377 selection.cursor = d->cursor;
3378 if (d->cursorIsFocusIndicator) {
3380 opt.palette = ctx.palette;
3381 QStyleHintReturnVariant ret;
3382 QStyle *style = QApplication::style();
3384 style = widget->style();
3385 style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret);
3386 selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
3388 QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive;
3389 selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
3390 selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
3392 QStyle *style = QApplication::style();
3394 opt.initFrom(widget);
3395 style = widget->style();
3397 if (style->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, widget))
3398 selection.format.setProperty(QTextFormat::FullWidthSelection,
true);
3400 ctx.selections.append(selection);