12#if QT_CONFIG(draganddrop)
15#include <qclipboard.h>
21#include "private/qapplication_p.h"
22#include "private/qtextdocumentlayout_p.h"
23#include "private/qabstracttextdocumentlayout_p.h"
25#include "private/qtextdocument_p.h"
29#include <qtextformat.h>
31#include <qapplication.h>
33#include <qtexttable.h>
40#if defined(Q_OS_ANDROID)
42 return !control->isReadOnly() || (control->textInteractionFlags() & Qt::TextSelectableByMouse);
44 return !control->isReadOnly();
50 Q_DECLARE_PUBLIC(QPlainTextDocumentLayout)
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
106
107
108QPlainTextDocumentLayout::QPlainTextDocumentLayout(QTextDocument *document)
109 :QAbstractTextDocumentLayout(*
new QPlainTextDocumentLayoutPrivate, document) {
112
113
114QPlainTextDocumentLayout::~QPlainTextDocumentLayout() {}
118
119
120void QPlainTextDocumentLayout::draw(QPainter *,
const PaintContext &)
125
126
127int QPlainTextDocumentLayout::hitTest(
const QPointF &, Qt::HitTestAccuracy )
const
138
139
140int QPlainTextDocumentLayout::pageCount()
const
144
145
146QSizeF QPlainTextDocumentLayout::documentSize()
const
148 Q_D(
const QPlainTextDocumentLayout);
149 return QSizeF(d->maximumWidth, document()->lineCount());
153
154
155QRectF QPlainTextDocumentLayout::frameBoundingRect(QTextFrame *)
const
157 Q_D(
const QPlainTextDocumentLayout);
158 return QRectF(0, 0, qMax(d->width, d->maximumWidth), qreal(INT_MAX));
162
163
164QRectF QPlainTextDocumentLayout::blockBoundingRect(
const QTextBlock &block)
const
166 if (!block.isValid()) {
return QRectF(); }
167 QTextLayout *tl = block.layout();
168 if (!tl->lineCount())
169 const_cast<QPlainTextDocumentLayout*>(
this)->layoutBlock(block);
171 if (block.isVisible()) {
172 br = QRectF(QPointF(0, 0), tl->boundingRect().bottomRight());
173 if (tl->lineCount() == 1)
174 br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth()));
175 qreal margin = document()->documentMargin();
176 br.adjust(0, 0, margin, 0);
177 if (!block.next().isValid())
178 br.adjust(0, 0, 0, margin);
185
186
187void QPlainTextDocumentLayout::ensureBlockLayout(
const QTextBlock &block)
const
189 if (!block.isValid())
191 QTextLayout *tl = block.layout();
192 if (!tl->lineCount())
193 const_cast<QPlainTextDocumentLayout*>(
this)->layoutBlock(block);
198
199
200
201void QPlainTextDocumentLayout::setCursorWidth(
int width)
203 Q_D(QPlainTextDocumentLayout);
204 d->cursorWidth = width;
207int QPlainTextDocumentLayout::cursorWidth()
const
209 Q_D(
const QPlainTextDocumentLayout);
210 return d->cursorWidth;
213QPlainTextDocumentLayoutPrivate *QPlainTextDocumentLayout::priv()
const
215 Q_D(
const QPlainTextDocumentLayout);
216 return const_cast<QPlainTextDocumentLayoutPrivate*>(d);
221
222
223
224void QPlainTextDocumentLayout::requestUpdate()
226 emit update(QRectF(0., -document()->documentMargin(), 1000000000., 1000000000.));
230void QPlainTextDocumentLayout::setTextWidth(qreal newWidth)
232 Q_D(QPlainTextDocumentLayout);
233 d->width = d->maximumWidth = newWidth;
237qreal QPlainTextDocumentLayout::textWidth()
const
239 Q_D(
const QPlainTextDocumentLayout);
245 Q_Q(QPlainTextDocumentLayout);
246 QTextBlock block = q->document()->firstBlock();
247 while (block.isValid()) {
248 block.layout()->clearLayout();
249 block.setLineCount(block.isVisible() ? 1 : 0);
250 block = block.next();
257
258void QPlainTextDocumentLayout::documentChanged(
int from,
int charsRemoved,
int charsAdded)
260 Q_D(QPlainTextDocumentLayout);
261 QTextDocument *doc = document();
262 int newBlockCount = doc->blockCount();
263 int charsChanged = charsRemoved + charsAdded;
265 QTextBlock changeStartBlock = doc->findBlock(from);
266 QTextBlock changeEndBlock = doc->findBlock(qMax(0, from + charsChanged - 1));
267 bool blockVisibilityChanged =
false;
269 if (changeStartBlock == changeEndBlock && newBlockCount == d->blockCount) {
270 QTextBlock block = changeStartBlock;
271 if (block.isValid() && block.length()) {
272 QRectF oldBr = blockBoundingRect(block);
274 QRectF newBr = blockBoundingRect(block);
275 if (newBr.height() == oldBr.height()) {
277 emit updateBlock(block);
282 QTextBlock block = changeStartBlock;
285 if (block.isVisible()
286 ? (block.lineCount() == 0)
287 : (block.lineCount() > 0)) {
288 blockVisibilityChanged =
true;
289 block.setLineCount(block.isVisible() ? 1 : 0);
291 if (block == changeEndBlock)
293 block = block.next();
294 }
while(block.isValid());
297 if (newBlockCount != d->blockCount || blockVisibilityChanged) {
298 int changeEnd = changeEndBlock.blockNumber();
299 int blockDiff = newBlockCount - d->blockCount;
300 int oldChangeEnd = changeEnd - blockDiff;
302 if (d->maximumWidthBlockNumber > oldChangeEnd)
303 d->maximumWidthBlockNumber += blockDiff;
305 d->blockCount = newBlockCount;
306 if (d->blockCount == 1)
307 d->maximumWidth = blockWidth(doc->firstBlock());
309 if (!d->blockDocumentSizeChanged)
310 emit documentSizeChanged(documentSize());
312 if (blockDiff == 1 && changeEnd == newBlockCount -1 ) {
313 if (!d->blockUpdate) {
314 QTextBlock b = changeStartBlock;
317 if (b == changeEndBlock)
327 emit update(QRectF(0., -doc->documentMargin(), 1000000000., 1000000000.));
331void QPlainTextDocumentLayout::layoutBlock(
const QTextBlock &block)
333 Q_D(QPlainTextDocumentLayout);
334 QTextDocument *doc = document();
335 qreal margin = doc->documentMargin();
336 qreal blockMaximumWidth = 0;
339 QTextLayout *tl = block.layout();
340 QTextOption option = doc->defaultTextOption();
341 tl->setTextOption(option);
344 if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {
345 QFontMetrics fm(block.charFormat().font());
346 extraMargin += fm.horizontalAdvance(QChar(0x21B5));
349 qreal availableWidth = d->width;
350 if (availableWidth <= 0) {
351 availableWidth = qreal(INT_MAX);
353 availableWidth -= 2*margin + extraMargin;
355 QTextLine line = tl->createLine();
358 line.setLeadingIncluded(
true);
359 line.setLineWidth(availableWidth);
360 line.setPosition(QPointF(margin, height));
361 height += line.height();
362 if (line.leading() < 0)
363 height += qCeil(line.leading());
364 blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin);
368 int previousLineCount = doc->lineCount();
369 const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0);
370 int lineCount = doc->lineCount();
372 bool emitDocumentSizeChanged = previousLineCount != lineCount;
373 if (blockMaximumWidth > d->maximumWidth) {
375 d->maximumWidth = blockMaximumWidth;
376 d->maximumWidthBlockNumber = block.blockNumber();
377 emitDocumentSizeChanged =
true;
378 }
else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) {
380 QTextBlock b = doc->firstBlock();
382 QTextBlock maximumBlock;
383 while (b.isValid()) {
384 qreal blockMaximumWidth = blockWidth(b);
385 if (blockMaximumWidth > d->maximumWidth) {
386 d->maximumWidth = blockMaximumWidth;
391 if (maximumBlock.isValid()) {
392 d->maximumWidthBlockNumber = maximumBlock.blockNumber();
393 emitDocumentSizeChanged =
true;
396 if (emitDocumentSizeChanged && !d->blockDocumentSizeChanged)
397 emit documentSizeChanged(documentSize());
400qreal QPlainTextDocumentLayout::blockWidth(
const QTextBlock &block)
402 QTextLayout *layout = block.layout();
403 if (!layout->lineCount())
405 qreal blockWidth = 0;
406 for (
int i = 0; i < layout->lineCount(); ++i) {
407 QTextLine line = layout->lineAt(i);
408 blockWidth = qMax(line.naturalTextWidth() + 8, blockWidth);
415 : QWidgetTextControl(parent),
textEdit(parent),
418 setAcceptRichText(
false);
423 pageUpDownLastCursorYIsValid =
false;
425#if QT_CONFIG(accessibility)
426 QAccessibleTextCursorEvent ev(q, q->textCursor().position());
427 QAccessible::updateAccessibility(&ev);
429 emit q->cursorPositionChanged();
434 const auto a =
static_cast<QAbstractSlider::SliderAction>(action);
436 case QAbstractSlider::SliderPageStepAdd:
437 pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor,
false);
439 case QAbstractSlider::SliderPageStepSub:
440 pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor,
false);
448 QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
450 return QWidgetTextControl::createMimeDataFromSelection();
451 return ed->createMimeDataFromSelection();
454 QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
456 return QWidgetTextControl::canInsertFromMimeData(source);
457 return ed->canInsertFromMimeData(source);
460 QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
462 QWidgetTextControl::insertFromMimeData(source);
464 ed->insertFromMimeData(source);
470 QTextDocument *doc =
control->document();
473 QTextBlock currentBlock = doc->findBlockByNumber(topBlock);
474 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
475 Q_ASSERT(documentLayout);
476 QRectF r = documentLayout->blockBoundingRect(currentBlock);
478 QTextLayout *layout = currentBlock.layout();
479 if (layout && topLine <= layout->lineCount()) {
480 QTextLine line = layout->lineAt(topLine - 1);
481 const QRectF lr = line.naturalTextRect();
482 offset = lr.bottom();
485 if (topBlock == 0 && topLine == 0)
486 offset -= doc->documentMargin();
492 return verticalOffset(control->topBlock, topLine) + topLineFracture;
498 return document()->findBlockByNumber(
topBlock);
505 QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);
506 if (!currentBlock.isValid())
509 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());
510 Q_ASSERT(documentLayout);
513 QRectF r = documentLayout->blockBoundingRect(currentBlock);
514 while (currentBlock.next().isValid() && r.bottom() + offset.y() <= point.y()) {
515 offset.ry() += r.height();
516 currentBlock = currentBlock.next();
517 ++currentBlockNumber;
518 r = documentLayout->blockBoundingRect(currentBlock);
520 while (currentBlock.previous().isValid() && r.top() + offset.y() > point.y()) {
521 offset.ry() -= r.height();
522 currentBlock = currentBlock.previous();
523 --currentBlockNumber;
524 r = documentLayout->blockBoundingRect(currentBlock);
528 if (!currentBlock.isValid())
530 QTextLayout *layout = currentBlock.layout();
533 for (
int i = 0; i < layout->lineCount(); ++i) {
534 QTextLine line = layout->lineAt(i);
535 const QRectF lr = line.naturalTextRect();
536 if (lr.top() > pos.y()) {
537 off = qMin(off, line.textStart());
538 }
else if (lr.bottom() <= pos.y()) {
539 off = qMax(off, line.textStart() + line.textLength());
541 off = line.xToCursor(pos.x(), overwriteMode() ?
542 QTextLine::CursorOnCharacter : QTextLine::CursorBetweenCharacters);
547 return currentBlock.position() + off;
552 int blockNumber = block.blockNumber();
553 QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);
554 if (!currentBlock.isValid())
556 Q_ASSERT(currentBlock.blockNumber() == currentBlockNumber);
557 QTextDocument *doc = document();
558 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
559 Q_ASSERT(documentLayout);
562 if (!block.isValid())
564 QRectF r = documentLayout->blockBoundingRect(currentBlock);
565 int maxVerticalOffset = r.height();
566 while (currentBlockNumber < blockNumber && offset.y() - maxVerticalOffset <= 2*
textEdit->viewport()->height()) {
567 offset.ry() += r.height();
568 currentBlock = currentBlock.next();
569 ++currentBlockNumber;
570 if (!currentBlock.isVisible()) {
571 currentBlock = doc->findBlockByLineNumber(currentBlock.firstLineNumber());
572 currentBlockNumber = currentBlock.blockNumber();
574 r = documentLayout->blockBoundingRect(currentBlock);
576 while (currentBlockNumber > blockNumber && offset.y() + maxVerticalOffset >= -
textEdit->viewport()->height()) {
577 currentBlock = currentBlock.previous();
578 --currentBlockNumber;
579 while (!currentBlock.isVisible()) {
580 currentBlock = currentBlock.previous();
581 --currentBlockNumber;
583 if (!currentBlock.isValid())
586 r = documentLayout->blockBoundingRect(currentBlock);
587 offset.ry() -= r.height();
590 if (currentBlockNumber != blockNumber) {
593 r = documentLayout->blockBoundingRect(block);
594 if (currentBlockNumber > blockNumber)
595 offset.ry() -= r.height();
603 return textEdit->anchorAt(pos.toPoint());
608 QTextDocument *doc =
control->document();
609 QTextBlock block = doc->findBlockByLineNumber(visualTopLine);
610 int blockNumber = block.blockNumber();
611 int lineNumber = visualTopLine - block.firstLineNumber();
618 blockNumber = qMax(0, blockNumber);
619 lineNumber = qMax(0, lineNumber);
620 QTextDocument *doc =
control->document();
621 QTextBlock block = doc->findBlockByNumber(blockNumber);
623 int newTopLine = block.firstLineNumber() + lineNumber;
624 int maxTopLine = vbar->maximum();
626 if (newTopLine > maxTopLine) {
627 block = doc->findBlockByLineNumber(maxTopLine);
628 blockNumber = block.blockNumber();
629 lineNumber = maxTopLine - block.firstLineNumber();
632 vbar->setValue(newTopLine);
637 if (
viewport->updatesEnabled() && viewport->isVisible()) {
640 qreal realdy = -q->blockBoundingGeometry(block).y()
641 + verticalOffset() - verticalOffset(blockNumber, lineNumber);
643 topLineFracture = realdy - dy;
648 vbar->setValue(block.firstLineNumber() + lineNumber);
651 viewport->scroll(q->isRightToLeft() ? -dx : dx, dy);
652 QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
657 emit q->updateRequest(viewport->rect(), dy);
670 QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
671 QTextBlock block = control->document()->findBlock(position);
672 if (!block.isValid())
674 QRectF br = control->blockBoundingRect(block);
677 QTextLine line = block.layout()->lineForTextPosition(position - block.position());
678 Q_ASSERT(line.isValid());
679 QRectF lr = line.naturalTextRect().translated(br.topLeft());
681 if (lr.bottom() >= visible.bottom() || (center && lr.top() < visible.top()) || forceCenter){
683 qreal height = visible.height();
687 qreal h = center ? line.naturalTextRect().center().y() : line.naturalTextRect().bottom();
689 QTextBlock previousVisibleBlock = block;
690 while (h < height && block.previous().isValid()) {
691 previousVisibleBlock = block;
693 block = block.previous();
694 }
while (!block.isVisible() && block.previous().isValid());
695 h += q->blockBoundingRect(block).height();
699 int lineCount = block.layout()->lineCount();
700 qreal voffset = verticalOffset(block.blockNumber(), 0);
701 while (l < lineCount) {
702 QRectF lineRect = block.layout()->lineAt(l).naturalTextRect();
703 if (h - voffset - lineRect.top() <= height)
708 if (l >= lineCount) {
709 block = previousVisibleBlock;
713 }
else if (lr.top() < visible.top()) {
724 emit q->updateRequest(viewport->rect(), 0);
728 : tabChangesFocus(
false)
729 , showCursorOnInitialShow(
false)
730 , backgroundVisible(
false)
731 , centerOnScroll(
false)
733 , clickCausedFocus(
false)
734 , pageUpDownLastCursorYIsValid(
false)
735 , placeholderTextShown(
false)
742 control =
new QPlainTextEditControl(q);
744 QTextDocument *doc =
new QTextDocument(control);
745 QAbstractTextDocumentLayout *layout =
new QPlainTextDocumentLayout(doc);
746 doc->setDocumentLayout(layout);
749 control->setPalette(q->palette());
751 QObjectPrivate::connect(vbar, &QAbstractSlider::actionTriggered,
752 this, &QPlainTextEditPrivate::verticalScrollbarActionTriggered);
753 QObject::connect(control, &QWidgetTextControl::microFocusChanged, q,
754 [q](){q->updateMicroFocus(); });
755 QObjectPrivate::connect(control, &QWidgetTextControl::documentSizeChanged,
756 this, &QPlainTextEditPrivate::adjustScrollbars);
757 QObject::connect(control, &QWidgetTextControl::blockCountChanged,
758 q, &QPlainTextEdit::blockCountChanged);
759 QObjectPrivate::connect(control, &QWidgetTextControl::updateRequest,
760 this, &QPlainTextEditPrivate::repaintContents);
761 QObject::connect(control, &QWidgetTextControl::modificationChanged,
762 q, &QPlainTextEdit::modificationChanged);
763 QObject::connect(control, &QWidgetTextControl::textChanged, q, &QPlainTextEdit::textChanged);
764 QObject::connect(control, &QWidgetTextControl::undoAvailable, q, &QPlainTextEdit::undoAvailable);
765 QObject::connect(control, &QWidgetTextControl::redoAvailable, q, &QPlainTextEdit::redoAvailable);
766 QObject::connect(control, &QWidgetTextControl::copyAvailable, q, &QPlainTextEdit::copyAvailable);
767 QObject::connect(control, &QWidgetTextControl::selectionChanged, q, &QPlainTextEdit::selectionChanged);
768 QObjectPrivate::connect(control, &QWidgetTextControl::cursorPositionChanged,
769 this, &QPlainTextEditPrivate::cursorPositionChanged);
770 QObjectPrivate::connect(control, &QWidgetTextControl::textChanged,
771 this, &QPlainTextEditPrivate::updatePlaceholderVisibility);
772 QObject::connect(control, &QWidgetTextControl::textChanged, q, [q](){q->updateMicroFocus(); });
777 doc->setTextWidth(-1);
778 doc->documentLayout()->setPaintDevice(viewport);
779 doc->setDefaultFont(q->font());
785 hbar->setSingleStep(defaultSingleStep());
786 vbar->setSingleStep(1);
788 viewport->setBackgroundRole(QPalette::Base);
789 q->setAcceptDrops(
true);
790 q->setFocusPolicy(Qt::StrongFocus);
791 q->setAttribute(Qt::WA_KeyCompression);
792 q->setAttribute(Qt::WA_InputMethodEnabled);
793 q->setInputMethodHints(Qt::ImhMultiLine);
796 viewport->setCursor(Qt::IBeamCursor);
806 if (placeholderTextShown != placeHolderTextToBeShown()) {
808 placeholderTextShown = placeHolderTextToBeShown();
815 if (!contentsRect.isValid()) {
820 const int yOffset = (
int)verticalOffset();
821 const QRect visibleRect(xOffset, yOffset, viewport->width(), viewport->height());
823 QRect r = contentsRect.adjusted(-1, -1, 1, 1).intersected(visibleRect).toAlignedRect();
827 r.translate(-xOffset, -yOffset);
829 emit q->updateRequest(r, 0);
837 QTextCursor cursor = control->textCursor();
840 if (!pageUpDownLastCursorYIsValid)
841 pageUpDownLastCursorY = control->cursorRect(cursor).top() - verticalOffset();
844 qreal lastY = pageUpDownLastCursorY;
847 if (op == QTextCursor::Down) {
848 QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
849 QTextBlock firstVisibleBlock = q->firstVisibleBlock();
850 QTextBlock block = firstVisibleBlock;
851 QRectF br = q->blockBoundingRect(block);
854 while (h + br.height() <= visible.bottom()) {
855 if (!block.next().isValid()) {
857 lastY = visible.bottom();
861 block = block.next();
862 br = q->blockBoundingRect(block);
867 qreal diff = visible.bottom() - h;
868 int lineCount = block.layout()->lineCount();
869 while (line < lineCount - 1) {
870 if (block.layout()->lineAt(line).naturalTextRect().bottom() > diff) {
881 lastY += verticalOffset();
884 moved = cursor.movePosition(op, moveMode);
885 }
while (moved &&
control->cursorRect(cursor).top() < lastY);
888 }
else if (op == QTextCursor::Up) {
890 QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
891 visible.translate(0, -visible.height());
892 QTextBlock block = q->firstVisibleBlock();
894 while (h >= visible.top()) {
895 if (!block.previous().isValid()) {
901 block = block.previous();
902 QRectF br = q->blockBoundingRect(block);
907 if (block.isValid()) {
908 qreal diff = visible.top() - h;
909 int lineCount = block.layout()->lineCount();
910 while (line < lineCount) {
911 if (block.layout()->lineAt(line).naturalTextRect().top() >= diff)
915 if (line == lineCount) {
916 if (block.next().isValid() && block.next() != q->firstVisibleBlock()) {
917 block = block.next();
927 cursor.setVisualNavigation(
true);
929 lastY += verticalOffset();
932 moved = cursor.movePosition(op, moveMode);
933 }
while (moved &&
control->cursorRect(cursor).top() > lastY);
938 control->setTextCursor(cursor, moveMode == QTextCursor::KeepAnchor);
939 pageUpDownLastCursorYIsValid =
true;
943#if QT_CONFIG(scrollbar)
945void QPlainTextEditPrivate::adjustScrollbars()
948 QTextDocument *doc = control->document();
949 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
950 Q_ASSERT(documentLayout);
951 bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;
952 documentLayout->priv()->blockDocumentSizeChanged =
true;
953 qreal margin = doc->documentMargin();
957 int vSliderLength = 0;
958 if (!centerOnScroll && q->isVisible()) {
959 QTextBlock block = doc->lastBlock();
960 const qreal visible = viewport->rect().height() - margin - 1;
962 int visibleFromBottom = 0;
964 while (block.isValid()) {
965 if (!block.isVisible()) {
966 block = block.previous();
969 y += documentLayout->blockBoundingRect(block).height();
971 QTextLayout *layout = block.layout();
972 int layoutLineCount = layout->lineCount();
975 while (lineNumber < layoutLineCount) {
976 QTextLine line = layout->lineAt(lineNumber);
977 const QRectF lr = line.naturalTextRect();
978 if (lr.top() >= y - visible)
982 if (lineNumber < layoutLineCount)
983 visibleFromBottom += (layoutLineCount - lineNumber);
987 visibleFromBottom += layoutLineCount;
988 block = block.previous();
990 vmax = qMax(0, doc->lineCount() - visibleFromBottom);
991 vSliderLength = visibleFromBottom;
994 vmax = qMax(0, doc->lineCount() - 1);
995 int lineSpacing = q->fontMetrics().lineSpacing();
996 vSliderLength = lineSpacing != 0 ? viewport->height() / lineSpacing : 0;
999 QSizeF documentSize = documentLayout->documentSize();
1000 vbar->setRange(0, qMax(0, vmax));
1001 vbar->setPageStep(vSliderLength);
1002 int visualTopLine = vmax;
1003 QTextBlock firstVisibleBlock = q->firstVisibleBlock();
1004 if (firstVisibleBlock.isValid())
1005 visualTopLine = firstVisibleBlock.firstLineNumber() + topLine;
1007 vbar->setValue(visualTopLine);
1009 hbar->setRange(0, (
int)documentSize.width() - viewport->width());
1010 hbar->setPageStep(viewport->width());
1011 documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
1012 setTopLine(vbar->value());
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1191
1192
1193
1194
1195
1196
1197
1198
1199
1202
1203
1204
1205
1206
1207
1208
1209
1212
1213
1214
1215
1216
1220
1221
1222
1223QPlainTextEdit::QPlainTextEdit(QWidget *parent)
1224 : QAbstractScrollArea(*
new QPlainTextEditPrivate, parent)
1226 Q_D(QPlainTextEdit);
1231
1232
1233QPlainTextEdit::QPlainTextEdit(QPlainTextEditPrivate &dd, QWidget *parent)
1234 : QAbstractScrollArea(dd, parent)
1236 Q_D(QPlainTextEdit);
1241
1242
1243
1244QPlainTextEdit::QPlainTextEdit(
const QString &text, QWidget *parent)
1245 : QAbstractScrollArea(*
new QPlainTextEditPrivate, parent)
1247 Q_D(QPlainTextEdit);
1253
1254
1255QPlainTextEdit::~QPlainTextEdit()
1257 Q_D(QPlainTextEdit);
1258 if (d->documentLayoutPtr) {
1259 if (d->documentLayoutPtr->priv()->mainViewPrivate == d)
1260 d->documentLayoutPtr->priv()->mainViewPrivate =
nullptr;
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276void QPlainTextEdit::setDocument(QTextDocument *document)
1278 Q_D(QPlainTextEdit);
1279 QPlainTextDocumentLayout *documentLayout =
nullptr;
1282 document =
new QTextDocument(d->control);
1283 documentLayout =
new QPlainTextDocumentLayout(document);
1284 document->setDocumentLayout(documentLayout);
1286 documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());
1287 if (Q_UNLIKELY(!documentLayout)) {
1288 qWarning(
"QPlainTextEdit::setDocument: Document set does not support QPlainTextDocumentLayout");
1292 d->control->setDocument(document);
1293 if (!documentLayout->priv()->mainViewPrivate)
1294 documentLayout->priv()->mainViewPrivate = d;
1295 d->documentLayoutPtr = documentLayout;
1296 d->updateDefaultTextOption();
1297 d->relayoutDocument();
1298 d->adjustScrollbars();
1302
1303
1304
1305
1306QTextDocument *QPlainTextEdit::document()
const
1308 Q_D(
const QPlainTextEdit);
1309 return d->control->document();
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325void QPlainTextEdit::setPlaceholderText(
const QString &placeholderText)
1327 Q_D(QPlainTextEdit);
1328 if (d->placeholderText != placeholderText) {
1329 d->placeholderText = placeholderText;
1330 d->updatePlaceholderVisibility();
1334QString QPlainTextEdit::placeholderText()
const
1336 Q_D(
const QPlainTextEdit);
1337 return d->placeholderText;
1341
1342
1343void QPlainTextEdit::setTextCursor(
const QTextCursor &cursor)
1345 doSetTextCursor(cursor);
1349
1350
1351
1352
1354void QPlainTextEdit::doSetTextCursor(
const QTextCursor &cursor)
1356 Q_D(QPlainTextEdit);
1357 d->control->setTextCursor(cursor);
1361
1362
1363
1364
1365QTextCursor QPlainTextEdit::textCursor()
const
1367 Q_D(
const QPlainTextEdit);
1368 return d->control->textCursor();
1372
1373
1374
1375
1376
1377QString QPlainTextEdit::anchorAt(
const QPoint &pos)
const
1379 Q_D(
const QPlainTextEdit);
1380 int cursorPos = d->control->hitTest(pos + QPointF(d->horizontalOffset(),
1381 d->verticalOffset()),
1386 QTextDocumentPrivate *pieceTable = QTextDocumentPrivate::get(document());
1387 QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos);
1388 QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format);
1389 return fmt.anchorHref();
1393
1394
1395
1396
1397
1398
1399
1400void QPlainTextEdit::undo()
1402 Q_D(QPlainTextEdit);
1406void QPlainTextEdit::redo()
1408 Q_D(QPlainTextEdit);
1413
1414
1415
1416
1417
1418
1419
1420
1421
1423#ifndef QT_NO_CLIPBOARD
1425
1426
1427
1428
1429
1430
1431
1433void QPlainTextEdit::cut()
1435 Q_D(QPlainTextEdit);
1440
1441
1442
1443
1445void QPlainTextEdit::copy()
1447 Q_D(QPlainTextEdit);
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1465void QPlainTextEdit::paste()
1467 Q_D(QPlainTextEdit);
1468 d->control->paste();
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484void QPlainTextEdit::clear()
1486 Q_D(QPlainTextEdit);
1488 d->control->topBlock = d->topLine = d->topLineFracture = 0;
1489 d->control->clear();
1494
1495
1496
1497
1498void QPlainTextEdit::selectAll()
1500 Q_D(QPlainTextEdit);
1501 d->control->selectAll();
1505
1506bool QPlainTextEdit::event(QEvent *e)
1508 Q_D(QPlainTextEdit);
1510 switch (e->type()) {
1511#ifndef QT_NO_CONTEXTMENU
1512 case QEvent::ContextMenu:
1513 if (
static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
1514 ensureCursorVisible();
1515 const QPoint cursorPos = cursorRect().center();
1516 QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
1517 ce.setAccepted(e->isAccepted());
1518 const bool result = QAbstractScrollArea::event(&ce);
1519 e->setAccepted(ce.isAccepted());
1524 case QEvent::ShortcutOverride:
1525 case QEvent::ToolTip:
1526 d->sendControlEvent(e);
1528#ifdef QT_KEYPAD_NAVIGATION
1529 case QEvent::EnterEditFocus:
1530 case QEvent::LeaveEditFocus:
1531 if (QApplicationPrivate::keypadNavigationEnabled())
1532 d->sendControlEvent(e);
1535#ifndef QT_NO_GESTURES
1536 case QEvent::Gesture:
1537 if (
auto *g =
static_cast<QGestureEvent *>(e)->gesture(Qt::PanGesture)) {
1538 QPanGesture *panGesture =
static_cast<QPanGesture *>(g);
1539 QScrollBar *hBar = horizontalScrollBar();
1540 QScrollBar *vBar = verticalScrollBar();
1541 if (panGesture->state() == Qt::GestureStarted)
1542 d->originalOffsetY = vBar->value();
1543 QPointF offset = panGesture->offset();
1544 if (!offset.isNull()) {
1545 if (QGuiApplication::isRightToLeft())
1548 QFontMetrics fm(document()->defaultFont());
1549 int lineHeight = fm.height();
1550 int newX = hBar->value() - panGesture->delta().x();
1551 int newY = d->originalOffsetY - offset.y()/lineHeight;
1552 hBar->setValue(newX);
1553 vBar->setValue(newY);
1558 case QEvent::WindowActivate:
1559 case QEvent::WindowDeactivate:
1560 d->control->setPalette(palette());
1565 return QAbstractScrollArea::event(e);
1569
1571void QPlainTextEdit::timerEvent(QTimerEvent *e)
1573 Q_D(QPlainTextEdit);
1574 if (e->timerId() == d->autoScrollTimer.timerId()) {
1575 QRect visible = d->viewport->rect();
1578 pos = d->autoScrollDragPos;
1579 visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
1580 -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
1582 const QPoint globalPos = QCursor::pos();
1583 pos = d->viewport->mapFromGlobal(globalPos);
1584 QMouseEvent ev(QEvent::MouseMove, pos, d->viewport->mapTo(d->viewport->topLevelWidget(), pos), globalPos,
1585 Qt::LeftButton, Qt::LeftButton, QGuiApplication::keyboardModifiers());
1586 mouseMoveEvent(&ev);
1588 int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
1589 int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
1590 int delta = qMax(deltaX, deltaY);
1594 int timeout = 4900 / (delta * delta);
1595 d->autoScrollTimer.start(timeout,
this);
1598 d->vbar->triggerAction(pos.y() < visible.center().y() ?
1599 QAbstractSlider::SliderSingleStepSub
1600 : QAbstractSlider::SliderSingleStepAdd);
1602 d->hbar->triggerAction(pos.x() < visible.center().x() ?
1603 QAbstractSlider::SliderSingleStepSub
1604 : QAbstractSlider::SliderSingleStepAdd);
1607#ifdef QT_KEYPAD_NAVIGATION
1608 else if (e->timerId() == d->deleteAllTimer.timerId()) {
1609 d->deleteAllTimer.stop();
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1631void QPlainTextEdit::setPlainText(
const QString &text)
1633 Q_D(QPlainTextEdit);
1634 d->control->setPlainText(text);
1638
1639
1640
1641
1642
1643
1646
1647void QPlainTextEdit::keyPressEvent(QKeyEvent *e)
1649 Q_D(QPlainTextEdit);
1651#ifdef QT_KEYPAD_NAVIGATION
1653 case Qt::Key_Select:
1654 if (QApplicationPrivate::keypadNavigationEnabled()) {
1655 if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard))
1656 setEditFocus(!hasEditFocus());
1658 if (!hasEditFocus())
1661 QTextCursor cursor = d->control->textCursor();
1662 QTextCharFormat charFmt = cursor.charFormat();
1663 if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
1664 setEditFocus(
false);
1672 if (!QApplicationPrivate::keypadNavigationEnabled() || !hasEditFocus()) {
1678 if (QApplicationPrivate::keypadNavigationEnabled()) {
1679 if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {
1680 if (e->text()[0].isPrint()) {
1693#ifndef QT_NO_SHORTCUT
1695 Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
1697 if (tif & Qt::TextSelectableByKeyboard){
1698 if (e == QKeySequence::SelectPreviousPage) {
1700 d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
1702 }
else if (e ==QKeySequence::SelectNextPage) {
1704 d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
1708 if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
1709 if (e == QKeySequence::MoveToPreviousPage) {
1711 d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
1713 }
else if (e == QKeySequence::MoveToNextPage) {
1715 d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
1720 if (!(tif & Qt::TextEditable)) {
1724 if (e->modifiers() & Qt::ShiftModifier)
1725 d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
1727 d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
1730 d->sendControlEvent(e);
1731 if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
1732 if (e->key() == Qt::Key_Home) {
1733 d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
1735 }
else if (e->key() == Qt::Key_End) {
1736 d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
1740 if (!e->isAccepted()) {
1741 QAbstractScrollArea::keyPressEvent(e);
1748 d->sendControlEvent(e);
1749#ifdef QT_KEYPAD_NAVIGATION
1750 if (!e->isAccepted()) {
1754 if (QApplicationPrivate::keypadNavigationEnabled()) {
1763 if (QApplicationPrivate::keypadNavigationEnabled()
1764 && QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
1771 if (!e->isAutoRepeat()) {
1772 if (QApplicationPrivate::keypadNavigationEnabled()) {
1773 if (document()->isEmpty()) {
1774 setEditFocus(
false);
1776 }
else if (!d->deleteAllTimer.isActive()) {
1778 d->deleteAllTimer.start(750,
this);
1793
1794void QPlainTextEdit::keyReleaseEvent(QKeyEvent *e)
1796 Q_D(QPlainTextEdit);
1798 d->handleSoftwareInputPanel();
1800#ifdef QT_KEYPAD_NAVIGATION
1801 if (QApplicationPrivate::keypadNavigationEnabled()) {
1802 if (!e->isAutoRepeat() && e->key() == Qt::Key_Back
1803 && d->deleteAllTimer.isActive()) {
1804 d->deleteAllTimer.stop();
1805 QTextCursor cursor = d->control->textCursor();
1806 QTextBlockFormat blockFmt = cursor.blockFormat();
1808 QTextList *list = cursor.currentList();
1809 if (list && cursor.atBlockStart()) {
1810 list->remove(cursor.block());
1811 }
else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1812 blockFmt.setIndent(blockFmt.indent() - 1);
1813 cursor.setBlockFormat(blockFmt);
1815 cursor.deletePreviousChar();
1817 setTextCursor(cursor);
1821 QWidget::keyReleaseEvent(e);
1826
1827
1828
1829
1830
1831
1832QVariant QPlainTextEdit::loadResource(
int type,
const QUrl &name)
1840
1841void QPlainTextEdit::resizeEvent(QResizeEvent *e)
1843 Q_D(QPlainTextEdit);
1844 if (e->oldSize().width() != e->size().width())
1845 d->relayoutDocument();
1846 d->adjustScrollbars();
1851 QTextDocument *doc =
control->document();
1852 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
1853 Q_ASSERT(documentLayout);
1854 documentLayoutPtr = documentLayout;
1856 int width = viewport->width();
1858 if (documentLayout->priv()->mainViewPrivate ==
nullptr
1859 || documentLayout->priv()->mainViewPrivate ==
this
1860 || width > documentLayout->textWidth()) {
1861 documentLayout->priv()->mainViewPrivate =
this;
1862 documentLayout->setTextWidth(width);
1869 if (brush.style() >= Qt::LinearGradientPattern && brush.style() <= Qt::ConicalGradientPattern) {
1870 if (!gradientRect.isNull()) {
1871 QTransform m = QTransform::fromTranslate(gradientRect.left(), gradientRect.top());
1872 m.scale(gradientRect.width(), gradientRect.height());
1873 brush.setTransform(m);
1874 const_cast<QGradient *>(brush.gradient())->setCoordinateMode(QGradient::LogicalMode);
1877 p->setBrushOrigin(rect.topLeft());
1879 p->fillRect(rect, brush);
1886
1887void QPlainTextEdit::paintEvent(QPaintEvent *e)
1889 Q_D(QPlainTextEdit);
1890 QPainter painter(viewport());
1891 Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()));
1893 QPointF offset(contentOffset());
1895 QRect er = e->rect();
1896 QRect viewportRect = viewport()->rect();
1898 bool editable = !isReadOnly();
1900 QTextBlock block = firstVisibleBlock();
1901 qreal maximumWidth = document()->documentLayout()->documentSize().width();
1904 painter.setBrushOrigin(offset);
1907 int maxX = offset.x() + qMax((qreal)viewportRect.width(), maximumWidth)
1908 - document()->documentMargin() + cursorWidth();
1909 er.setRight(qMin(er.right(), maxX));
1910 painter.setClipRect(er);
1912 if (d->placeHolderTextToBeShown()) {
1913 const QColor col = d->control->palette().placeholderText().color();
1914 painter.setPen(col);
1915 painter.setClipRect(e->rect());
1916 const int margin =
int(document()->documentMargin());
1917 QRectF textRect = viewportRect.adjusted(margin, margin, 0, 0);
1918 painter.drawText(textRect, Qt::AlignTop | Qt::TextWordWrap, placeholderText());
1921 QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
1922 painter.setPen(context.palette.text().color());
1924 while (block.isValid()) {
1926 QRectF r = blockBoundingRect(block).translated(offset);
1927 QTextLayout *layout = block.layout();
1929 if (!block.isVisible()) {
1930 offset.ry() += r.height();
1931 block = block.next();
1935 if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
1937 QTextBlockFormat blockFormat = block.blockFormat();
1939 QBrush bg = blockFormat.background();
1940 if (bg != Qt::NoBrush) {
1941 QRectF contentsRect = r;
1942 contentsRect.setWidth(qMax(r.width(), maximumWidth));
1943 fillBackground(&painter, contentsRect, bg);
1946 QList<QTextLayout::FormatRange> selections;
1947 int blpos = block.position();
1948 int bllen = block.length();
1949 for (
int i = 0; i < context.selections.size(); ++i) {
1950 const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
1951 const int selStart = range.cursor.selectionStart() - blpos;
1952 const int selEnd = range.cursor.selectionEnd() - blpos;
1953 if (selStart < bllen && selEnd > 0
1954 && selEnd > selStart) {
1955 QTextLayout::FormatRange o;
1957 o.length = selEnd - selStart;
1958 o.format = range.format;
1959 selections.append(o);
1960 }
else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
1961 && block.contains(range.cursor.position())) {
1964 QTextLayout::FormatRange o;
1965 QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
1966 o.start = l.textStart();
1967 o.length = l.textLength();
1968 if (o.start + o.length == bllen - 1)
1970 o.format = range.format;
1971 selections.append(o);
1975 bool drawCursor = ((editable || (textInteractionFlags() & Qt::TextSelectableByKeyboard))
1976 && context.cursorPosition >= blpos
1977 && context.cursorPosition < blpos + bllen);
1979 bool drawCursorAsBlock = drawCursor && overwriteMode() ;
1981 if (drawCursorAsBlock) {
1982 if (context.cursorPosition == blpos + bllen - 1) {
1983 drawCursorAsBlock =
false;
1985 QTextLayout::FormatRange o;
1986 o.start = context.cursorPosition - blpos;
1988 o.format.setForeground(palette().base());
1989 o.format.setBackground(palette().text());
1990 selections.append(o);
1994 layout->draw(&painter, offset, selections, er);
1996 if ((drawCursor && !drawCursorAsBlock)
1997 || (editable && context.cursorPosition < -1
1998 && !layout->preeditAreaText().isEmpty())) {
1999 int cpos = context.cursorPosition;
2001 cpos = layout->preeditAreaPosition() - (cpos + 2);
2004 layout->drawCursor(&painter, offset, cpos, cursorWidth());
2008 offset.ry() += r.height();
2009 if (offset.y() > viewportRect.height())
2011 block = block.next();
2014 if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
2015 && (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
2016 painter.fillRect(QRect(QPoint((
int)er.left(), (
int)offset.y()), er.bottomRight()), palette().window());
2023 QTextDocument *doc =
control->document();
2025 QTextOption opt = doc->defaultTextOption();
2026 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2028 if (lineWrap == QPlainTextEdit::NoWrap)
2029 opt.setWrapMode(QTextOption::NoWrap);
2031 opt.setWrapMode(wordWrap);
2033 if (opt.wrapMode() != oldWrapMode)
2034 doc->setDefaultTextOption(opt);
2039
2040void QPlainTextEdit::mousePressEvent(QMouseEvent *e)
2042 Q_D(QPlainTextEdit);
2043#ifdef QT_KEYPAD_NAVIGATION
2044 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus())
2047 d->sendControlEvent(e);
2051
2052void QPlainTextEdit::mouseMoveEvent(QMouseEvent *e)
2054 Q_D(QPlainTextEdit);
2056 const QPoint pos = e->position().toPoint();
2057 d->sendControlEvent(e);
2058 if (!(e->buttons() & Qt::LeftButton))
2060 if (e->source() == Qt::MouseEventNotSynthesized) {
2061 const QRect visible = d->viewport->rect();
2062 if (visible.contains(pos))
2063 d->autoScrollTimer.stop();
2064 else if (!d->autoScrollTimer.isActive())
2065 d->autoScrollTimer.start(100,
this);
2070
2071void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e)
2073 Q_D(QPlainTextEdit);
2074 d->sendControlEvent(e);
2075 if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) {
2076 d->autoScrollTimer.stop();
2077 d->ensureCursorVisible();
2080 if (!isReadOnly() && rect().contains(e->position().toPoint()))
2081 d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
2082 d->clickCausedFocus = 0;
2086
2087void QPlainTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
2089 Q_D(QPlainTextEdit);
2090 d->sendControlEvent(e);
2094
2095bool QPlainTextEdit::focusNextPrevChild(
bool next)
2097 Q_D(
const QPlainTextEdit);
2098 if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
2100 return QAbstractScrollArea::focusNextPrevChild(next);
2103#ifndef QT_NO_CONTEXTMENU
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *e)
2121 Q_D(QPlainTextEdit);
2122 d->sendControlEvent(e);
2126#if QT_CONFIG(draganddrop)
2128
2129void QPlainTextEdit::dragEnterEvent(QDragEnterEvent *e)
2131 Q_D(QPlainTextEdit);
2133 d->sendControlEvent(e);
2137
2138void QPlainTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
2140 Q_D(QPlainTextEdit);
2142 d->autoScrollTimer.stop();
2143 d->sendControlEvent(e);
2147
2148void QPlainTextEdit::dragMoveEvent(QDragMoveEvent *e)
2150 Q_D(QPlainTextEdit);
2151 d->autoScrollDragPos = e->position().toPoint();
2152 if (!d->autoScrollTimer.isActive())
2153 d->autoScrollTimer.start(100,
this);
2154 d->sendControlEvent(e);
2158
2159void QPlainTextEdit::dropEvent(QDropEvent *e)
2161 Q_D(QPlainTextEdit);
2163 d->autoScrollTimer.stop();
2164 d->sendControlEvent(e);
2170
2171void QPlainTextEdit::inputMethodEvent(QInputMethodEvent *e)
2173 Q_D(QPlainTextEdit);
2174#ifdef QT_KEYPAD_NAVIGATION
2175 if (d->control->textInteractionFlags() & Qt::TextEditable
2176 && QApplicationPrivate::keypadNavigationEnabled()
2177 && !hasEditFocus()) {
2182 d->sendControlEvent(e);
2183 const bool emptyEvent = e->preeditString().isEmpty() && e->commitString().isEmpty()
2184 && e->attributes().isEmpty();
2187 ensureCursorVisible();
2191
2192void QPlainTextEdit::scrollContentsBy(
int dx,
int )
2194 Q_D(QPlainTextEdit);
2195 d->setTopLine(d->vbar->value(), dx);
2199
2200QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property)
const
2202 return inputMethodQuery(property, QVariant());
2206
2207QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument)
const
2209 Q_D(
const QPlainTextEdit);
2212 return isEnabled() && !isReadOnly();
2214 case Qt::ImInputItemClipRectangle:
2215 return QWidget::inputMethodQuery(query);
2216 case Qt::ImReadOnly:
2217 return isReadOnly();
2222 const QPointF offset = contentOffset();
2223 switch (argument.userType()) {
2224 case QMetaType::QRectF:
2225 argument = argument.toRectF().translated(-offset);
2227 case QMetaType::QPointF:
2228 argument = argument.toPointF() - offset;
2230 case QMetaType::QRect:
2231 argument = argument.toRect().translated(-offset.toPoint());
2233 case QMetaType::QPoint:
2234 argument = argument.toPoint() - offset;
2240 const QVariant v = d->control->inputMethodQuery(query, argument);
2241 switch (v.userType()) {
2242 case QMetaType::QRectF:
2243 return v.toRectF().translated(offset);
2244 case QMetaType::QPointF:
2245 return v.toPointF() + offset;
2246 case QMetaType::QRect:
2247 return v.toRect().translated(offset.toPoint());
2248 case QMetaType::QPoint:
2249 return v.toPoint() + offset.toPoint();
2257
2258void QPlainTextEdit::focusInEvent(QFocusEvent *e)
2260 Q_D(QPlainTextEdit);
2261 if (e->reason() == Qt::MouseFocusReason) {
2262 d->clickCausedFocus = 1;
2264 QAbstractScrollArea::focusInEvent(e);
2265 d->sendControlEvent(e);
2269
2270void QPlainTextEdit::focusOutEvent(QFocusEvent *e)
2272 Q_D(QPlainTextEdit);
2273 QAbstractScrollArea::focusOutEvent(e);
2274 d->sendControlEvent(e);
2278
2279void QPlainTextEdit::showEvent(QShowEvent *)
2281 Q_D(QPlainTextEdit);
2282 if (d->showCursorOnInitialShow) {
2283 d->showCursorOnInitialShow =
false;
2284 ensureCursorVisible();
2286 d->adjustScrollbars();
2290
2291void QPlainTextEdit::changeEvent(QEvent *e)
2293 Q_D(QPlainTextEdit);
2294 QAbstractScrollArea::changeEvent(e);
2296 switch (e->type()) {
2297 case QEvent::ApplicationFontChange:
2298 case QEvent::FontChange:
2299 d->control->document()->setDefaultFont(font());
2301 case QEvent::ActivationChange:
2302 if (!isActiveWindow())
2303 d->autoScrollTimer.stop();
2305 case QEvent::EnabledChange:
2306 e->setAccepted(isEnabled());
2307 d->control->setPalette(palette());
2308 d->sendControlEvent(e);
2310 case QEvent::PaletteChange:
2311 d->control->setPalette(palette());
2313 case QEvent::LayoutDirectionChange:
2314 d->sendControlEvent(e);
2322
2323#if QT_CONFIG(wheelevent)
2324void QPlainTextEdit::wheelEvent(QWheelEvent *e)
2326 Q_D(QPlainTextEdit);
2327 if (!(d->control->textInteractionFlags() & Qt::TextEditable)) {
2328 if (e->modifiers() & Qt::ControlModifier) {
2329 float delta = e->angleDelta().y() / 120.f;
2334 QAbstractScrollArea::wheelEvent(e);
2340
2341
2342
2343
2344
2345
2346void QPlainTextEdit::zoomIn(
int range)
2352
2353
2354
2355
2356
2357
2358void QPlainTextEdit::zoomOut(
int range)
2364
2365
2366void QPlainTextEdit::zoomInF(
float range)
2371 const float newSize = f.pointSizeF() + range;
2374 f.setPointSizeF(newSize);
2378#ifndef QT_NO_CONTEXTMENU
2380
2381
2382
2383
2384
2385
2386
2388QMenu *QPlainTextEdit::createStandardContextMenu()
2390 Q_D(QPlainTextEdit);
2391 return d->control->createStandardContextMenu(QPointF(),
this);
2395
2396
2397
2398
2399
2400
2401
2402
2404QMenu *QPlainTextEdit::createStandardContextMenu(
const QPoint &position)
2406 Q_D(QPlainTextEdit);
2407 return d->control->createStandardContextMenu(position,
this);
2412
2413
2414QTextCursor QPlainTextEdit::cursorForPosition(
const QPoint &pos)
const
2416 Q_D(
const QPlainTextEdit);
2417 return d->control->cursorForPosition(d->mapToContents(pos));
2421
2422
2423
2424QRect QPlainTextEdit::cursorRect(
const QTextCursor &cursor)
const
2426 Q_D(
const QPlainTextEdit);
2427 if (cursor.isNull())
2430 QRect r = d->control->cursorRect(cursor).toRect();
2431 r.translate(-d->horizontalOffset(),-(
int)d->verticalOffset());
2436
2437
2438
2439QRect QPlainTextEdit::cursorRect()
const
2441 Q_D(
const QPlainTextEdit);
2442 QRect r = d->control->cursorRect().toRect();
2443 r.translate(-d->horizontalOffset(),-(
int)d->verticalOffset());
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2462bool QPlainTextEdit::overwriteMode()
const
2464 Q_D(
const QPlainTextEdit);
2465 return d->control->overwriteMode();
2468void QPlainTextEdit::setOverwriteMode(
bool overwrite)
2470 Q_D(QPlainTextEdit);
2471 d->control->setOverwriteMode(overwrite);
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2488qreal QPlainTextEdit::tabStopDistance()
const
2490 Q_D(
const QPlainTextEdit);
2491 return d->control->document()->defaultTextOption().tabStopDistance();
2494void QPlainTextEdit::setTabStopDistance(qreal distance)
2496 Q_D(QPlainTextEdit);
2497 QTextOption opt = d->control->document()->defaultTextOption();
2498 if (opt.tabStopDistance() == distance || distance < 0)
2500 opt.setTabStopDistance(distance);
2501 d->control->document()->setDefaultTextOption(opt);
2506
2507
2508
2509
2510int QPlainTextEdit::cursorWidth()
const
2512 Q_D(
const QPlainTextEdit);
2513 return d->control->cursorWidth();
2516void QPlainTextEdit::setCursorWidth(
int width)
2518 Q_D(QPlainTextEdit);
2519 d->control->setCursorWidth(width);
2525
2526
2527
2528
2529
2530
2531
2532void QPlainTextEdit::setExtraSelections(
const QList<QTextEdit::ExtraSelection> &selections)
2534 Q_D(QPlainTextEdit);
2535 d->control->setExtraSelections(selections);
2539
2540
2541
2542
2543QList<QTextEdit::ExtraSelection> QPlainTextEdit::extraSelections()
const
2545 Q_D(
const QPlainTextEdit);
2546 return d->control->extraSelections();
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559QMimeData *QPlainTextEdit::createMimeDataFromSelection()
const
2561 Q_D(
const QPlainTextEdit);
2562 return d->control->QWidgetTextControl::createMimeDataFromSelection();
2566
2567
2568
2569
2570
2571bool QPlainTextEdit::canInsertFromMimeData(
const QMimeData *source)
const
2573 Q_D(
const QPlainTextEdit);
2574 return d->control->QWidgetTextControl::canInsertFromMimeData(source);
2578
2579
2580
2581
2582
2583
2584void QPlainTextEdit::insertFromMimeData(
const QMimeData *source)
2586 Q_D(QPlainTextEdit);
2587 d->control->QWidgetTextControl::insertFromMimeData(source);
2591
2592
2593
2594
2595
2596
2597
2598
2600bool QPlainTextEdit::isReadOnly()
const
2602 Q_D(
const QPlainTextEdit);
2603 return !d->control || !(d->control->textInteractionFlags() & Qt::TextEditable);
2606void QPlainTextEdit::setReadOnly(
bool ro)
2608 Q_D(QPlainTextEdit);
2609 Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
2611 flags = Qt::TextSelectableByMouse;
2613 flags = Qt::TextEditorInteraction;
2615 d->control->setTextInteractionFlags(flags);
2616 setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(
this));
2617 QEvent event(QEvent::ReadOnlyChange);
2618 QCoreApplication::sendEvent(
this, &event);
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2633void QPlainTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2635 Q_D(QPlainTextEdit);
2636 d->control->setTextInteractionFlags(flags);
2639Qt::TextInteractionFlags QPlainTextEdit::textInteractionFlags()
const
2641 Q_D(
const QPlainTextEdit);
2642 return d->control->textInteractionFlags();
2646
2647
2648
2649
2650
2651
2652
2653void QPlainTextEdit::mergeCurrentCharFormat(
const QTextCharFormat &modifier)
2655 Q_D(QPlainTextEdit);
2656 d->control->mergeCurrentCharFormat(modifier);
2660
2661
2662
2663
2664
2665void QPlainTextEdit::setCurrentCharFormat(
const QTextCharFormat &format)
2667 Q_D(QPlainTextEdit);
2668 d->control->setCurrentCharFormat(format);
2672
2673
2674QTextCharFormat QPlainTextEdit::currentCharFormat()
const
2676 Q_D(
const QPlainTextEdit);
2677 return d->control->currentCharFormat();
2683
2684
2685
2686
2687
2688
2689
2690void QPlainTextEdit::insertPlainText(
const QString &text)
2692 Q_D(QPlainTextEdit);
2693 d->control->insertPlainText(text);
2698
2699
2700
2701
2702
2703
2704
2705
2706void QPlainTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
2708 Q_D(QPlainTextEdit);
2709 d->control->moveCursor(operation, mode);
2713
2714
2715bool QPlainTextEdit::canPaste()
const
2717 Q_D(
const QPlainTextEdit);
2718 return d->control->canPaste();
2722
2723
2724
2725
2726
2727
2728#ifndef QT_NO_PRINTER
2729void QPlainTextEdit::print(QPagedPaintDevice *printer)
const
2731 Q_D(
const QPlainTextEdit);
2732 d->control->print(printer);
2737
2738
2739
2740
2741
2742
2743
2745bool QPlainTextEdit::tabChangesFocus()
const
2747 Q_D(
const QPlainTextEdit);
2748 return d->tabChangesFocus;
2751void QPlainTextEdit::setTabChangesFocus(
bool b)
2753 Q_D(QPlainTextEdit);
2754 d->tabChangesFocus = b;
2758
2759
2760
2761
2762
2765
2766
2767
2768
2769
2770
2771
2772
2774QPlainTextEdit::LineWrapMode QPlainTextEdit::lineWrapMode()
const
2776 Q_D(
const QPlainTextEdit);
2780void QPlainTextEdit::setLineWrapMode(LineWrapMode wrap)
2782 Q_D(QPlainTextEdit);
2783 if (d->lineWrap == wrap)
2786 d->updateDefaultTextOption();
2787 d->relayoutDocument();
2788 d->adjustScrollbars();
2789 ensureCursorVisible();
2793
2794
2795
2796
2797
2798
2799
2801QTextOption::WrapMode QPlainTextEdit::wordWrapMode()
const
2803 Q_D(
const QPlainTextEdit);
2807void QPlainTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
2809 Q_D(QPlainTextEdit);
2810 if (mode == d->wordWrap)
2813 d->updateDefaultTextOption();
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2830bool QPlainTextEdit::backgroundVisible()
const
2832 Q_D(
const QPlainTextEdit);
2833 return d->backgroundVisible;
2836void QPlainTextEdit::setBackgroundVisible(
bool visible)
2838 Q_D(QPlainTextEdit);
2839 if (visible == d->backgroundVisible)
2841 d->backgroundVisible = visible;
2842 d->updateViewport();
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2862bool QPlainTextEdit::centerOnScroll()
const
2864 Q_D(
const QPlainTextEdit);
2865 return d->centerOnScroll;
2868void QPlainTextEdit::setCenterOnScroll(
bool enabled)
2870 Q_D(QPlainTextEdit);
2871 if (enabled == d->centerOnScroll)
2873 d->centerOnScroll = enabled;
2874 d->adjustScrollbars();
2880
2881
2882
2883
2884bool QPlainTextEdit::find(
const QString &exp, QTextDocument::FindFlags options)
2886 Q_D(QPlainTextEdit);
2887 return d->control->find(exp, options);
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906#if QT_CONFIG(regularexpression)
2907bool QPlainTextEdit::find(
const QRegularExpression &exp, QTextDocument::FindFlags options)
2909 Q_D(QPlainTextEdit);
2910 return d->control->find(exp, options);
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2932
2933
2934
2935
2936
2937
2940
2941
2942
2943
2944
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2962
2963
2964
2965
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2985 Q_Q(QPlainTextEdit);
2987 QTextDocument *document =
control->document();
2988 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());
2989 Q_ASSERT(documentLayout);
2991 int maximumBlockCount = document->maximumBlockCount();
2992 if (maximumBlockCount)
2993 document->setMaximumBlockCount(0);
2995 const bool atBottom = q->isVisible()
2996 && (control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
2997 <= viewport->rect().bottom());
2999 if (!q->isVisible())
3000 showCursorOnInitialShow =
true;
3002 bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;
3003 documentLayout->priv()->blockDocumentSizeChanged =
true;
3010 control->appendPlainText(text);
3017 if (maximumBlockCount > 0) {
3018 if (document->blockCount() > maximumBlockCount) {
3019 bool blockUpdate =
false;
3023 emit q->updateRequest(viewport->rect(), 0);
3026 bool updatesBlocked = documentLayout->priv()->blockUpdate;
3027 documentLayout->priv()->blockUpdate = blockUpdate;
3028 QTextCursor cursor(document);
3029 cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
3030 cursor.removeSelectedText();
3031 documentLayout->priv()->blockUpdate = updatesBlocked;
3033 document->setMaximumBlockCount(maximumBlockCount);
3036 documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
3041 const bool needScroll = !centerOnScroll
3042 || control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
3043 > viewport->rect().bottom();
3045 vbar->setValue(vbar->maximum());
3051
3052
3053
3054
3056void QPlainTextEdit::appendPlainText(
const QString &text)
3058 Q_D(QPlainTextEdit);
3059 d->append(text, Qt::PlainText);
3063
3064
3065
3066
3068void QPlainTextEdit::appendHtml(
const QString &html)
3070 Q_D(QPlainTextEdit);
3071 d->append(html, Qt::RichText);
3076 Q_Q(QPlainTextEdit);
3077 QRect visible = viewport->rect();
3078 QRect cr = q->cursorRect();
3079 if (cr.top() < visible.top() || cr.bottom() > visible.bottom()) {
3083 const bool rtl = q->isRightToLeft();
3084 if (cr.left() < visible.left() || cr.right() > visible.right()) {
3086 hbar->setValue(rtl ? hbar->maximum() - x : x);
3091
3092
3093
3094
3095
3096void QPlainTextEdit::ensureCursorVisible()
3098 Q_D(QPlainTextEdit);
3099 d->ensureCursorVisible(d->centerOnScroll);
3104
3105
3106
3107void QPlainTextEdit::centerCursor()
3109 Q_D(QPlainTextEdit);
3110 d->ensureVisible(textCursor().position(),
true,
true);
3114
3115
3116
3117
3118QTextBlock QPlainTextEdit::firstVisibleBlock()
const
3120 Q_D(
const QPlainTextEdit);
3121 return d->control->firstVisibleBlock();
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137QPointF QPlainTextEdit::contentOffset()
const
3139 Q_D(
const QPlainTextEdit);
3140 return QPointF(-d->horizontalOffset(), -d->verticalOffset());
3145
3146
3147
3148
3149
3150QRectF QPlainTextEdit::blockBoundingGeometry(
const QTextBlock &block)
const
3152 Q_D(
const QPlainTextEdit);
3153 return d->control->blockBoundingRect(block);
3157
3158
3159
3160
3161QRectF QPlainTextEdit::blockBoundingRect(
const QTextBlock &block)
const
3163 QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());
3164 Q_ASSERT(documentLayout);
3165 return documentLayout->blockBoundingRect(block);
3169
3170
3171
3172
3173
3174int QPlainTextEdit::blockCount()
const
3176 return document()->blockCount();
3180
3181
3182QAbstractTextDocumentLayout::PaintContext QPlainTextEdit::getPaintContext()
const
3184 Q_D(
const QPlainTextEdit);
3185 return d->control->getPaintContext(d->viewport);
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3208
3209
3210
3211
3212
3215
3216
3217
3218
3219
3222
3223
3224
3225
3226
3230#include "moc_qplaintextedit.cpp"
3231#include "moc_qplaintextedit_p.cpp"
QRect viewport() const
Returns the viewport rectangle.
bool blockDocumentSizeChanged
int maximumWidthBlockNumber
void layoutBlock(const QTextBlock &block)
qreal blockWidth(const QTextBlock &block)
QPlainTextEditPrivate * mainViewPrivate
QPlainTextEdit * textEdit
void insertFromMimeData(const QMimeData *source) override
bool canInsertFromMimeData(const QMimeData *source) const override
QTextBlock firstVisibleBlock() const
QMimeData * createMimeDataFromSelection() const override
qreal verticalOffset() const
int horizontalOffset() const
void pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode, bool moveCursor=true)
QPlainTextEditControl * control
void updateDefaultTextOption()
void ensureVisible(int position, bool center, bool forceCenter=false)
void updatePlaceholderVisibility()
qreal verticalOffset(int topBlock, int topLine) const
void setTopLine(int visualTopLine, int dx=0)
void verticalScrollbarActionTriggered(int action)
void cursorPositionChanged()
void ensureCursorVisible(bool center=false)
void ensureViewportLayouted()
void setTopBlock(int newTopBlock, int newTopLine, int dx=0)
\inmodule QtCore\reentrant
static QT_BEGIN_NAMESPACE bool shouldEnableInputMethod(QPlainTextEdit *control)
static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, const QRectF &gradientRect=QRectF())